diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs b/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs index a5a45a684d..6196792480 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Formats.Png internal static class PngEncoderOptionsHelpers { /// - /// Adjusts the options. + /// Adjusts the options based upon the given metadata. /// /// The options. /// The PNG metadata. @@ -28,12 +28,12 @@ namespace SixLabors.ImageSharp.Formats.Png where TPixel : struct, IPixel { // Always take the encoder options over the metadata values. - options.Gamma = options.Gamma ?? pngMetadata.Gamma; + options.Gamma ??= pngMetadata.Gamma; - options.ColorType = options.ColorType ?? SuggestColorType() ?? pngMetadata.ColorType; - options.BitDepth = options.BitDepth ?? SuggestBitDepth() ?? pngMetadata.BitDepth; + options.ColorType ??= SuggestColorType() ?? pngMetadata.ColorType; + options.BitDepth ??= SuggestBitDepth() ?? pngMetadata.BitDepth; - options.InterlaceMethod = options.InterlaceMethod ?? pngMetadata.InterlaceMethod; + options.InterlaceMethod ??= pngMetadata.InterlaceMethod; use16Bit = options.BitDepth == PngBitDepth.Bit16; bytesPerPixel = CalculateBytesPerPixel(options.ColorType, use16Bit); @@ -132,100 +132,68 @@ namespace SixLabors.ImageSharp.Formats.Png /// Bytes per pixel. private static int CalculateBytesPerPixel(PngColorType? pngColorType, bool use16Bit) { - switch (pngColorType) + return pngColorType switch { - case PngColorType.Grayscale: - return use16Bit ? 2 : 1; - - case PngColorType.GrayscaleWithAlpha: - return use16Bit ? 4 : 2; - - case PngColorType.Palette: - return 1; - - case PngColorType.Rgb: - return use16Bit ? 6 : 3; + PngColorType.Grayscale => use16Bit ? 2 : 1, + PngColorType.GrayscaleWithAlpha => use16Bit ? 4 : 2, + PngColorType.Palette => 1, + PngColorType.Rgb => use16Bit ? 6 : 3, // PngColorType.RgbWithAlpha - default: - return use16Bit ? 8 : 4; - } + _ => use16Bit ? 8 : 4, + }; } /// - /// Comes up with the appropriate PngColorType for some kinds of - /// IPixel. This is not exhaustive because not all options have - /// reasonable defaults + /// Returns a suggested for the given + /// This is not exhaustive but covers many common pixel formats. /// private static PngColorType? SuggestColorType() - where TPixel : struct, IPixel + where TPixel : struct, IPixel { - Type tPixel = typeof(TPixel); - - if (tPixel == typeof(Alpha8)) - { - return PngColorType.GrayscaleWithAlpha; - } - - if (tPixel == typeof(Argb32)) - { - return PngColorType.RgbWithAlpha; - } - - if (tPixel == typeof(Rgb24)) - { - return PngColorType.Rgb; - } - - if (tPixel == typeof(Gray16)) - { - return PngColorType.Grayscale; - } - - if (tPixel == typeof(Gray8)) - { - return PngColorType.Grayscale; - } - - return default; + return typeof(TPixel) switch + { + Type t when t == typeof(A8) => PngColorType.GrayscaleWithAlpha, + Type t when t == typeof(Argb32) => PngColorType.RgbWithAlpha, + Type t when t == typeof(Bgr24) => PngColorType.Rgb, + Type t when t == typeof(Bgra32) => PngColorType.RgbWithAlpha, + Type t when t == typeof(L8) => PngColorType.Grayscale, + Type t when t == typeof(L16) => PngColorType.Grayscale, + Type t when t == typeof(La16) => PngColorType.GrayscaleWithAlpha, + Type t when t == typeof(La32) => PngColorType.GrayscaleWithAlpha, + Type t when t == typeof(Rgb24) => PngColorType.Rgb, + Type t when t == typeof(Rgba32) => PngColorType.RgbWithAlpha, + Type t when t == typeof(Rgb48) => PngColorType.Rgb, + Type t when t == typeof(Rgba64) => PngColorType.RgbWithAlpha, + Type t when t == typeof(RgbaVector) => PngColorType.RgbWithAlpha, + _ => default(PngColorType?) + }; } /// - /// Comes up with the appropriate PngBitDepth for some kinds of - /// IPixel. This is not exhaustive because not all options have - /// reasonable defaults + /// Returns a suggested for the given + /// This is not exhaustive but covers many common pixel formats. /// private static PngBitDepth? SuggestBitDepth() - where TPixel : struct, IPixel + where TPixel : struct, IPixel { - Type tPixel = typeof(TPixel); - - if (tPixel == typeof(Alpha8)) - { - return PngBitDepth.Bit8; - } - - if (tPixel == typeof(Argb32)) - { - return PngBitDepth.Bit8; - } - - if (tPixel == typeof(Rgb24)) - { - return PngBitDepth.Bit8; - } - - if (tPixel == typeof(Gray16)) - { - return PngBitDepth.Bit16; - } - - if (tPixel == typeof(Gray8)) - { - return PngBitDepth.Bit8; - } - - return default; + return typeof(TPixel) switch + { + Type t when t == typeof(A8) => PngBitDepth.Bit8, + Type t when t == typeof(Argb32) => PngBitDepth.Bit8, + Type t when t == typeof(Bgr24) => PngBitDepth.Bit8, + Type t when t == typeof(Bgra32) => PngBitDepth.Bit8, + Type t when t == typeof(L8) => PngBitDepth.Bit8, + Type t when t == typeof(L16) => PngBitDepth.Bit16, + Type t when t == typeof(La16) => PngBitDepth.Bit8, + Type t when t == typeof(La32) => PngBitDepth.Bit16, + Type t when t == typeof(Rgb24) => PngBitDepth.Bit8, + Type t when t == typeof(Rgba32) => PngBitDepth.Bit8, + Type t when t == typeof(Rgb48) => PngBitDepth.Bit16, + Type t when t == typeof(Rgba64) => PngBitDepth.Bit16, + Type t when t == typeof(RgbaVector) => PngBitDepth.Bit16, + _ => default(PngBitDepth?) + }; } } } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index cacb3e42fe..1fa131c914 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -202,46 +202,51 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } [Theory] - // does the following make sense? Or is it supposed to encode a 16bpp with two 8bit channels? - [WithBlankImages(1, 1, PixelTypes.Alpha8, PngColorType.GrayscaleWithAlpha, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.A8, PngColorType.GrayscaleWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.Argb32, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] - // [WithBlankImages(1, 1, PixelTypes.Bgr565, Can't reasonably be inferred)] - // [WithBlankImages(1, 1, PixelTypes.Bgra4444, Can't reasonably be inferred)] - // [WithBlankImages(1, 1, PixelTypes.Byte4, I'm not sure)] - // [WithBlankImages(1, 1, PixelTypes.HalfSingle, I'm not sure)] - // [WithBlankImages(1, 1, PixelTypes.HalfVector2, I'm not sure)] - // [WithBlankImages(1, 1, PixelTypes.HalfVector4, I'm not sure)] - // [WithBlankImages(1, 1, PixelTypes.NormalizedByte2, I'm not sure)] - // [WithBlankImages(1, 1, PixelTypes.NormalizedByte4, I'm not sure)] - // [WithBlankImages(1, 1, PixelTypes.NormalizedShort4, I'm not sure)] - // [WithBlankImages(1, 1, PixelTypes.Rg32, I'm not sure)] - // [WithBlankImages(1, 1, PixelTypes.Rgba1010102, I'm not sure)] - // [WithBlankImages(1, 1, PixelTypes.Rgba32, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] - // [WithBlankImages(1, 1, PixelTypes.Rgba64, PngColorType.RgbWithAlpha, PngBitDepth.Bit16)] - // [WithBlankImages(1, 1, PixelTypes.RgbaVector, I'm not sure)] - // [WithBlankImages(1, 1, PixelTypes.Short2, I'm not sure)] - // [WithBlankImages(1, 1, PixelTypes.Short4, I'm not sure)] + [WithBlankImages(1, 1, PixelTypes.Bgr565, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.Bgra4444, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.Byte4, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.HalfSingle, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.HalfVector2, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.HalfVector4, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.NormalizedByte2, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.NormalizedByte4, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.NormalizedShort4, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.Rg32, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.Rgba1010102, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.Rgba32, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.RgbaVector, PngColorType.RgbWithAlpha, PngBitDepth.Bit16)] + [WithBlankImages(1, 1, PixelTypes.Short2, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.Short4, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.Rgb24, PngColorType.Rgb, PngBitDepth.Bit8)] - // [WithBlankImages(1, 1, PixelTypes.Bgr24, I'm not sure)] - // [WithBlankImages(1, 1, PixelTypes.Bgra32, I'm not sure)] + [WithBlankImages(1, 1, PixelTypes.Bgr24, PngColorType.Rgb, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.Bgra32, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.Rgb48, PngColorType.Rgb, PngBitDepth.Bit16)] - // [WithBlankImages(1, 1, PixelTypes.Bgra5551, I'm not sure)] - [WithBlankImages(1, 1, PixelTypes.Gray8, PngColorType.Grayscale, PngBitDepth.Bit8)] - [WithBlankImages(1, 1, PixelTypes.Gray16, PngColorType.Grayscale, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.Rgba64, PngColorType.RgbWithAlpha, PngBitDepth.Bit16)] + [WithBlankImages(1, 1, PixelTypes.Bgra5551, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.L8, PngColorType.Grayscale, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.L16, PngColorType.Grayscale, PngBitDepth.Bit16)] + [WithBlankImages(1, 1, PixelTypes.La16, PngColorType.GrayscaleWithAlpha, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.La32, PngColorType.GrayscaleWithAlpha, PngBitDepth.Bit16)] public void InfersColorTypeAndBitDepth(TestImageProvider provider, PngColorType pngColorType, PngBitDepth pngBitDepth) where TPixel : struct, IPixel { - Stream stream = new MemoryStream(); - PngEncoder encoder = new PngEncoder(); - encoder.Encode(provider.GetImage(), stream); + using (Stream stream = new MemoryStream()) + { + var encoder = new PngEncoder(); + encoder.Encode(provider.GetImage(), stream); - stream.Seek(0, SeekOrigin.Begin); + stream.Seek(0, SeekOrigin.Begin); - PngDecoder decoder = new PngDecoder(); + var decoder = new PngDecoder(); - Image image = decoder.Decode(Configuration.Default, stream); + Image image = decoder.Decode(Configuration.Default, stream); - Assert.True(image is Image); + PngMetadata metadata = image.Metadata.GetPngMetadata(); + Assert.Equal(pngColorType, metadata.ColorType); + Assert.Equal(pngBitDepth, metadata.BitDepth); + } } [Theory] diff --git a/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs b/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs index c795563134..eb8860eb6f 100644 --- a/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs +++ b/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -62,11 +62,15 @@ namespace SixLabors.ImageSharp.Tests L8 = 1 << 23, - Gray16 = 1 << 24, + L16 = 1 << 24, + + La16 = 1 << 25, + + La32 = 1 << 26, // TODO: Add multi-flag entries by rules defined in PackedPixelConverterHelper // "All" is handled as a separate, individual case instead of using bitwise OR All = 30 } -} \ No newline at end of file +}