@@ -1466,23 +1466,48 @@ private void SanitizeAndSetEncoderOptions<TPixel>(
14661466
14671467 // Use options, then check metadata, if nothing set there then we suggest
14681468 // a sensible default based upon the pixel format.
1469- this . colorType = encoder . ColorType ?? pngMetadata . ColorType ?? SuggestColorType < TPixel > ( ) ;
1470- if ( ! encoder . FilterMethod . HasValue )
1469+ PngColorType ? colorType = encoder . ColorType ?? pngMetadata . ColorType ;
1470+ byte ? bits = ( byte ? ) ( encoder . BitDepth ?? pngMetadata . BitDepth ) ;
1471+
1472+ if ( colorType is null || bits is null )
14711473 {
1472- // Specification recommends default filter method None for paletted images and Paeth for others.
1473- this . filterMethod = this . colorType is PngColorType . Palette ? PngFilterMethod . None : PngFilterMethod . Paeth ;
1474+ PixelTypeInfo info = TPixel . GetPixelTypeInfo ( ) ;
1475+ PixelComponentInfo ? componentInfo = info . ComponentInfo ;
1476+
1477+ colorType ??= SuggestColorType < TPixel > ( in info ) ;
1478+
1479+ if ( bits is null )
1480+ {
1481+ // TODO: Update once we stop abusing PixelTypeInfo in decoders.
1482+ if ( componentInfo . HasValue )
1483+ {
1484+ PixelComponentInfo c = componentInfo . Value ;
1485+ bits = ( byte ) SuggestBitDepth < TPixel > ( in c ) ;
1486+ }
1487+ else
1488+ {
1489+ bits = ( byte ) PngBitDepth . Bit8 ;
1490+ }
1491+ }
14741492 }
14751493
14761494 // Ensure bit depth and color type are a supported combination.
14771495 // Bit8 is the only bit depth supported by all color types.
1478- byte bits = ( byte ) ( encoder . BitDepth ?? pngMetadata . BitDepth ?? SuggestBitDepth < TPixel > ( ) ) ;
1479- byte [ ] validBitDepths = PngConstants . ColorTypes [ this . colorType ] ;
1496+ byte [ ] validBitDepths = PngConstants . ColorTypes [ colorType . Value ] ;
14801497 if ( Array . IndexOf ( validBitDepths , bits ) == - 1 )
14811498 {
14821499 bits = ( byte ) PngBitDepth . Bit8 ;
14831500 }
14841501
1485- this . bitDepth = bits ;
1502+ this . colorType = colorType . Value ;
1503+ this . bitDepth = bits . Value ;
1504+
1505+ if ( ! encoder . FilterMethod . HasValue )
1506+ {
1507+ // Specification recommends default filter method None for paletted images and Paeth for others.
1508+ this . filterMethod = this . colorType is PngColorType . Palette ? PngFilterMethod . None : PngFilterMethod . Paeth ;
1509+ }
1510+
14861511 use16Bit = bits == ( byte ) PngBitDepth . Bit16 ;
14871512 bytesPerPixel = CalculateBytesPerPixel ( this . colorType , use16Bit ) ;
14881513
@@ -1611,53 +1636,44 @@ private static int CalculateBytesPerPixel(PngColorType? pngColorType, bool use16
16111636
16121637 /// <summary>
16131638 /// Returns a suggested <see cref="PngColorType"/> for the given <typeparamref name="TPixel"/>
1614- /// This is not exhaustive but covers many common pixel formats.
16151639 /// </summary>
1640+ /// <param name="info">The pixel type info.</param>
16161641 /// <typeparam name="TPixel">The type of pixel format.</typeparam>
1617- private static PngColorType SuggestColorType < TPixel > ( )
1642+ private static PngColorType SuggestColorType < TPixel > ( in PixelTypeInfo info )
16181643 where TPixel : unmanaged, IPixel < TPixel >
1619- => default ( TPixel ) switch
1620- {
1621- A8 => PngColorType . GrayscaleWithAlpha ,
1622- Argb32 => PngColorType . RgbWithAlpha ,
1623- Bgr24 => PngColorType . Rgb ,
1624- Bgra32 => PngColorType . RgbWithAlpha ,
1625- L8 => PngColorType . Grayscale ,
1626- L16 => PngColorType . Grayscale ,
1627- La16 => PngColorType . GrayscaleWithAlpha ,
1628- La32 => PngColorType . GrayscaleWithAlpha ,
1629- Rgb24 => PngColorType . Rgb ,
1630- Rgba32 => PngColorType . RgbWithAlpha ,
1631- Rgb48 => PngColorType . Rgb ,
1632- Rgba64 => PngColorType . RgbWithAlpha ,
1633- RgbaVector => PngColorType . RgbWithAlpha ,
1634- _ => PngColorType . RgbWithAlpha
1644+ {
1645+ if ( info . AlphaRepresentation == PixelAlphaRepresentation . None )
1646+ {
1647+ return info . ColorType switch
1648+ {
1649+ PixelColorType . Grayscale => PngColorType . Grayscale ,
1650+ _ => PngColorType . Rgb ,
1651+ } ;
1652+ }
1653+
1654+ return info . ColorType switch
1655+ {
1656+ PixelColorType . Grayscale | PixelColorType . Alpha or PixelColorType . Alpha => PngColorType . GrayscaleWithAlpha ,
1657+ _ => PngColorType . RgbWithAlpha ,
16351658 } ;
1659+ }
16361660
16371661 /// <summary>
16381662 /// Returns a suggested <see cref="PngBitDepth"/> for the given <typeparamref name="TPixel"/>
1639- /// This is not exhaustive but covers many common pixel formats.
16401663 /// </summary>
1664+ /// <param name="info">The pixel type info.</param>
16411665 /// <typeparam name="TPixel">The type of pixel format.</typeparam>
1642- private static PngBitDepth SuggestBitDepth < TPixel > ( )
1666+ private static PngBitDepth SuggestBitDepth < TPixel > ( in PixelComponentInfo info )
16431667 where TPixel : unmanaged, IPixel < TPixel >
1644- => default ( TPixel ) switch
1645- {
1646- A8 => PngBitDepth . Bit8 ,
1647- Argb32 => PngBitDepth . Bit8 ,
1648- Bgr24 => PngBitDepth . Bit8 ,
1649- Bgra32 => PngBitDepth . Bit8 ,
1650- L8 => PngBitDepth . Bit8 ,
1651- L16 => PngBitDepth . Bit16 ,
1652- La16 => PngBitDepth . Bit8 ,
1653- La32 => PngBitDepth . Bit16 ,
1654- Rgb24 => PngBitDepth . Bit8 ,
1655- Rgba32 => PngBitDepth . Bit8 ,
1656- Rgb48 => PngBitDepth . Bit16 ,
1657- Rgba64 => PngBitDepth . Bit16 ,
1658- RgbaVector => PngBitDepth . Bit16 ,
1659- _ => PngBitDepth . Bit8
1660- } ;
1668+ {
1669+ int bits = info . GetMaximumComponentPrecision ( ) ;
1670+ if ( bits > ( int ) PixelComponentBitDepth . Bit8 )
1671+ {
1672+ return PngBitDepth . Bit16 ;
1673+ }
1674+
1675+ return PngBitDepth . Bit8 ;
1676+ }
16611677
16621678 private unsafe struct ScratchBuffer
16631679 {
0 commit comments