/// <summary> /// Validates the png header. /// </summary> /// <exception cref="NotSupportedException"> /// Thrown if the image does pass validation. /// </exception> private void ValidateHeader() { if (!ColorTypes.ContainsKey(this.header.ColorType)) { throw new NotSupportedException("Color type is not supported or not valid."); } if (!ColorTypes[this.header.ColorType].Contains(this.header.BitDepth)) { throw new NotSupportedException("Bit depth is not supported or not valid."); } if (this.header.FilterMethod != 0) { throw new NotSupportedException("The png specification only defines 0 as filter method."); } if (this.header.InterlaceMethod != 0) { // TODO: Support interlacing throw new NotSupportedException("Interlacing is not supported."); } this.PngColorType = (PngColorType)this.header.ColorType; }
private static void TestPngEncoderCore <TPixel>( TestImageProvider <TPixel> provider, PngColorType pngColorType, PngFilterMethod pngFilterMethod, int compressionLevel = 6, int paletteSize = 255, bool appendPngColorType = false, bool appendPngFilterMethod = false, bool appendPixelType = false, bool appendCompressionLevel = false, bool appendPaletteSize = false) where TPixel : struct, IPixel <TPixel> { using (Image <TPixel> image = provider.GetImage()) { if (!HasAlpha(pngColorType)) { image.Mutate(c => c.MakeOpaque()); } var encoder = new PngEncoder { PngColorType = pngColorType, PngFilterMethod = pngFilterMethod, CompressionLevel = compressionLevel, Quantizer = new WuQuantizer(paletteSize) }; string pngColorTypeInfo = appendPngColorType ? pngColorType.ToString() : string.Empty; string pngFilterMethodInfo = appendPngFilterMethod ? pngFilterMethod.ToString() : string.Empty; string compressionLevelInfo = appendCompressionLevel ? $"_C{compressionLevel}" : string.Empty; string paletteSizeInfo = appendPaletteSize ? $"_PaletteSize-{paletteSize}" : string.Empty; string debugInfo = $"{pngColorTypeInfo}{pngFilterMethodInfo}{compressionLevelInfo}{paletteSizeInfo}"; //string referenceInfo = $"{pngColorTypeInfo}"; // Does DebugSave & load reference CompareToReferenceInput(): string actualOutputFile = ((ITestImageProvider)provider).Utility.SaveTestOutputFile(image, "png", encoder, debugInfo, appendPixelType); if (TestEnvironment.IsMono) { // There are bugs in mono's System.Drawing implementation, reference decoders are not always reliable! return; } IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(actualOutputFile); string referenceOutputFile = ((ITestImageProvider)provider).Utility.GetReferenceOutputFileName("png", debugInfo, appendPixelType, true); using (var actualImage = Image.Load <TPixel>(actualOutputFile, referenceDecoder)) using (var referenceImage = Image.Load <TPixel>(referenceOutputFile, referenceDecoder)) { float paletteToleranceHack = 80f / paletteSize; paletteToleranceHack = paletteToleranceHack * paletteToleranceHack; ImageComparer comparer = pngColorType == PngColorType.Palette ? ImageComparer.Tolerant(ToleranceThresholdForPaletteEncoder * paletteToleranceHack) : ImageComparer.Exact; comparer.VerifySimilarity(referenceImage, actualImage); } } }
static PixelFormat MakePixelFormat(byte bitDepth, PngColorType colorType) { if (bitDepth == 8 && colorType == (PngColorType.Indexed | PngColorType.Color)) { return(PixelFormat.Format8bppIndexed); } throw new InvalidDataException("Unknown pixel format"); }
public void Encode_WithPngTransparentColorBehaviorClear_Works(PngColorType colorType) { // arrange var image = new Image <Rgba32>(50, 50); var encoder = new PngEncoder() { TransparentColorMode = PngTransparentColorMode.Clear, ColorType = colorType }; Rgba32 rgba32 = Color.Blue; for (int y = 0; y < image.Height; y++) { System.Span <Rgba32> rowSpan = image.GetPixelRowSpan(y); // Half of the test image should be transparent. if (y > 25) { rgba32.A = 0; } for (int x = 0; x < image.Width; x++) { rowSpan[x].FromRgba32(rgba32); } } // act using var memStream = new MemoryStream(); image.Save(memStream, encoder); // assert memStream.Position = 0; using var actual = Image.Load <Rgba32>(memStream); Rgba32 expectedColor = Color.Blue; if (colorType == PngColorType.Grayscale || colorType == PngColorType.GrayscaleWithAlpha) { var luminance = ColorNumerics.Get8BitBT709Luminance(expectedColor.R, expectedColor.G, expectedColor.B); expectedColor = new Rgba32(luminance, luminance, luminance); } for (int y = 0; y < actual.Height; y++) { System.Span <Rgba32> rowSpan = actual.GetPixelRowSpan(y); if (y > 25) { expectedColor = Color.Transparent; } for (int x = 0; x < actual.Width; x++) { Assert.Equal(expectedColor, rowSpan[x]); } } }
private static void TestPngEncoderCore <TPixel>( TestImageProvider <TPixel> provider, PngColorType pngColorType, PngFilterMethod pngFilterMethod, PngBitDepth bitDepth, PngInterlaceMode interlaceMode, PngCompressionLevel compressionLevel = PngCompressionLevel.DefaultCompression, int paletteSize = 255, bool appendPngColorType = false, bool appendPngFilterMethod = false, bool appendPixelType = false, bool appendCompressionLevel = false, bool appendPaletteSize = false, bool appendPngBitDepth = false, PngChunkFilter optimizeMethod = PngChunkFilter.None) where TPixel : unmanaged, IPixel <TPixel> { using (Image <TPixel> image = provider.GetImage()) { var encoder = new PngEncoder { ColorType = pngColorType, FilterMethod = pngFilterMethod, CompressionLevel = compressionLevel, BitDepth = bitDepth, Quantizer = new WuQuantizer(new QuantizerOptions { MaxColors = paletteSize }), InterlaceMethod = interlaceMode, ChunkFilter = optimizeMethod, }; string pngColorTypeInfo = appendPngColorType ? pngColorType.ToString() : string.Empty; string pngFilterMethodInfo = appendPngFilterMethod ? pngFilterMethod.ToString() : string.Empty; string compressionLevelInfo = appendCompressionLevel ? $"_C{compressionLevel}" : string.Empty; string paletteSizeInfo = appendPaletteSize ? $"_PaletteSize-{paletteSize}" : string.Empty; string pngBitDepthInfo = appendPngBitDepth ? bitDepth.ToString() : string.Empty; string pngInterlaceModeInfo = interlaceMode != PngInterlaceMode.None ? $"_{interlaceMode}" : string.Empty; string debugInfo = $"{pngColorTypeInfo}{pngFilterMethodInfo}{compressionLevelInfo}{paletteSizeInfo}{pngBitDepthInfo}{pngInterlaceModeInfo}"; string actualOutputFile = provider.Utility.SaveTestOutputFile(image, "png", encoder, debugInfo, appendPixelType); // Compare to the Magick reference decoder. IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(actualOutputFile); // We compare using both our decoder and the reference decoder as pixel transformation // occurs within the encoder itself leaving the input image unaffected. // This means we are benefiting from testing our decoder also. using (var imageSharpImage = Image.Load <TPixel>(actualOutputFile, new PngDecoder())) using (var referenceImage = Image.Load <TPixel>(actualOutputFile, referenceDecoder)) { ImageComparer.Exact.VerifySimilarity(referenceImage, imageSharpImage); } } }
/// <summary> /// Initializes a new instance of the <see cref="PngEncoderCore"/> class. /// </summary> /// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param> /// <param name="options">The options for influencing the encoder</param> public PngEncoderCore(MemoryManager memoryManager, IPngEncoderOptions options) { this.memoryManager = memoryManager; this.pngColorType = options.PngColorType; this.compressionLevel = options.CompressionLevel; this.gamma = options.Gamma; this.quantizer = options.Quantizer; this.threshold = options.Threshold; this.writeGamma = options.WriteGamma; }
public void Encode_PreserveTrns(string imagePath, PngBitDepth pngBitDepth, PngColorType pngColorType) { var options = new PngEncoder(); var testFile = TestFile.Create(imagePath); using (Image <Rgba32> input = testFile.CreateImage()) { PngMetadata inMeta = input.Metadata.GetFormatMetadata(PngFormat.Instance); Assert.True(inMeta.HasTrans); using (var memStream = new MemoryStream()) { input.Save(memStream, options); memStream.Position = 0; using (var output = Image.Load <Rgba32>(memStream)) { PngMetadata outMeta = output.Metadata.GetFormatMetadata(PngFormat.Instance); Assert.True(outMeta.HasTrans); switch (pngColorType) { case PngColorType.Grayscale: if (pngBitDepth.Equals(PngBitDepth.Bit16)) { Assert.True(outMeta.TransparentGray16.HasValue); Assert.Equal(inMeta.TransparentGray16, outMeta.TransparentGray16); } else { Assert.True(outMeta.TransparentGray8.HasValue); Assert.Equal(inMeta.TransparentGray8, outMeta.TransparentGray8); } break; case PngColorType.Rgb: if (pngBitDepth.Equals(PngBitDepth.Bit16)) { Assert.True(outMeta.TransparentRgb48.HasValue); Assert.Equal(inMeta.TransparentRgb48, outMeta.TransparentRgb48); } else { Assert.True(outMeta.TransparentRgb24.HasValue); Assert.Equal(inMeta.TransparentRgb24, outMeta.TransparentRgb24); } break; } } } } }
/// <summary> /// Initializes a new instance of the <see cref="PngEncoderCore"/> class. /// </summary> /// <param name="options">The options for influencing the encoder</param> public PngEncoderCore(IPngEncoderOptions options) { this.ignoreMetadata = options.IgnoreMetadata; this.paletteSize = options.PaletteSize > 0 ? options.PaletteSize.Clamp(1, int.MaxValue) : int.MaxValue; this.pngColorType = options.PngColorType; this.compressionLevel = options.CompressionLevel; this.gamma = options.Gamma; this.quantizer = options.Quantizer; this.threshold = options.Threshold; this.writeGamma = options.WriteGamma; }
/// <inheritdoc /> public async Task <Image> DecodeAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken) { PngDecoderCore decoder = new(configuration, true); IImageInfo info = await decoder.IdentifyAsync(configuration, stream, cancellationToken).ConfigureAwait(false); stream.Position = 0; PngMetadata meta = info.Metadata.GetPngMetadata(); PngColorType color = meta.ColorType.GetValueOrDefault(); PngBitDepth bits = meta.BitDepth.GetValueOrDefault(); switch (color) { case PngColorType.Grayscale: if (bits == PngBitDepth.Bit16) { return(!meta.HasTransparency ? await this.DecodeAsync <L16>(configuration, stream, cancellationToken).ConfigureAwait(false) : await this.DecodeAsync <La32>(configuration, stream, cancellationToken).ConfigureAwait(false)); } return(!meta.HasTransparency ? await this.DecodeAsync <L8>(configuration, stream, cancellationToken).ConfigureAwait(false) : await this.DecodeAsync <La16>(configuration, stream, cancellationToken).ConfigureAwait(false)); case PngColorType.Rgb: if (bits == PngBitDepth.Bit16) { return(!meta.HasTransparency ? await this.DecodeAsync <Rgb48>(configuration, stream, cancellationToken).ConfigureAwait(false) : await this.DecodeAsync <Rgba64>(configuration, stream, cancellationToken).ConfigureAwait(false)); } return(!meta.HasTransparency ? await this.DecodeAsync <Rgb24>(configuration, stream, cancellationToken).ConfigureAwait(false) : await this.DecodeAsync <Rgba32>(configuration, stream, cancellationToken).ConfigureAwait(false)); case PngColorType.Palette: return(await this.DecodeAsync <Rgba32>(configuration, stream, cancellationToken).ConfigureAwait(false)); case PngColorType.GrayscaleWithAlpha: return((bits == PngBitDepth.Bit16) ? await this.DecodeAsync <La32>(configuration, stream, cancellationToken).ConfigureAwait(false) : await this.DecodeAsync <La16>(configuration, stream, cancellationToken).ConfigureAwait(false)); case PngColorType.RgbWithAlpha: return((bits == PngBitDepth.Bit16) ? await this.DecodeAsync <Rgba64>(configuration, stream, cancellationToken).ConfigureAwait(false) : await this.DecodeAsync <Rgba32>(configuration, stream, cancellationToken).ConfigureAwait(false)); default: return(await this.DecodeAsync <Rgba32>(configuration, stream, cancellationToken).ConfigureAwait(false)); } }
/// <inheritdoc /> public Image Decode(Configuration configuration, Stream stream) { PngDecoderCore decoder = new(configuration, true); IImageInfo info = decoder.Identify(configuration, stream); stream.Position = 0; PngMetadata meta = info.Metadata.GetPngMetadata(); PngColorType color = meta.ColorType.GetValueOrDefault(); PngBitDepth bits = meta.BitDepth.GetValueOrDefault(); switch (color) { case PngColorType.Grayscale: if (bits == PngBitDepth.Bit16) { return(!meta.HasTransparency ? this.Decode <L16>(configuration, stream) : this.Decode <La32>(configuration, stream)); } return(!meta.HasTransparency ? this.Decode <L8>(configuration, stream) : this.Decode <La16>(configuration, stream)); case PngColorType.Rgb: if (bits == PngBitDepth.Bit16) { return(!meta.HasTransparency ? this.Decode <Rgb48>(configuration, stream) : this.Decode <Rgba64>(configuration, stream)); } return(!meta.HasTransparency ? this.Decode <Rgb24>(configuration, stream) : this.Decode <Rgba32>(configuration, stream)); case PngColorType.Palette: return(this.Decode <Rgba32>(configuration, stream)); case PngColorType.GrayscaleWithAlpha: return((bits == PngBitDepth.Bit16) ? this.Decode <La32>(configuration, stream) : this.Decode <La16>(configuration, stream)); case PngColorType.RgbWithAlpha: return((bits == PngBitDepth.Bit16) ? this.Decode <Rgba64>(configuration, stream) : this.Decode <Rgba32>(configuration, stream)); default: return(this.Decode <Rgba32>(configuration, stream)); } }
/// <summary> /// Initializes a new instance of the <see cref="PngEncoderCore"/> class. /// </summary> /// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param> /// <param name="options">The options for influencing the encoder</param> public PngEncoderCore(MemoryAllocator memoryAllocator, IPngEncoderOptions options) { this.memoryAllocator = memoryAllocator; this.pngBitDepth = options.BitDepth; this.use16Bit = this.pngBitDepth.Equals(PngBitDepth.Bit16); this.pngColorType = options.ColorType; this.pngFilterMethod = options.FilterMethod; this.compressionLevel = options.CompressionLevel; this.gamma = options.Gamma; this.quantizer = options.Quantizer; this.threshold = options.Threshold; this.writeGamma = options.WriteGamma; }
private static void TestPngEncoderCore <TPixel>( TestImageProvider <TPixel> provider, PngColorType pngColorType, int compressionLevel = 6, int paletteSize = 0, bool appendPngColorType = false, bool appendPixelType = false, bool appendCompressionLevel = false, bool appendPaletteSize = false) where TPixel : struct, IPixel <TPixel> { using (Image <TPixel> image = provider.GetImage()) { if (!HasAlpha(pngColorType)) { image.Mutate(c => c.MakeOpaque()); } var encoder = new PngEncoder { PngColorType = pngColorType, CompressionLevel = compressionLevel, PaletteSize = paletteSize }; string pngColorTypeInfo = appendPngColorType ? pngColorType.ToString() : ""; string compressionLevelInfo = appendCompressionLevel ? $"_C{compressionLevel}" : ""; string paletteSizeInfo = appendPaletteSize ? $"_PaletteSize-{paletteSize}" : ""; string debugInfo = $"{pngColorTypeInfo}{compressionLevelInfo}{paletteSizeInfo}"; //string referenceInfo = $"{pngColorTypeInfo}"; // Does DebugSave & load reference CompareToReferenceInput(): string actualOutputFile = ((ITestImageProvider)provider).Utility.SaveTestOutputFile(image, "png", encoder, debugInfo, appendPixelType); IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(actualOutputFile); string referenceOutputFile = ((ITestImageProvider)provider).Utility.GetReferenceOutputFileName("png", debugInfo, appendPixelType); using (var actualImage = Image.Load <TPixel>(actualOutputFile, referenceDecoder)) using (var referenceImage = Image.Load <TPixel>(referenceOutputFile, referenceDecoder)) { ImageComparer comparer = pngColorType == PngColorType.Palette ? ImageComparer.Tolerant(ToleranceThresholdForPaletteEncoder) : ImageComparer.Exact; comparer.VerifySimilarity(referenceImage, actualImage); } } }
private static string SavePng <TPixel>(TestImageProvider <TPixel> provider, PngColorType pngColorType) where TPixel : unmanaged, IPixel <TPixel> { using (Image <TPixel> sourceImage = provider.GetImage()) { if (pngColorType != PngColorType.RgbWithAlpha) { sourceImage.Mutate(c => c.MakeOpaque()); } var encoder = new PngEncoder { ColorType = pngColorType }; return(provider.Utility.SaveTestOutputFile(sourceImage, "png", encoder)); } }
public virtual string GetColorTypeDescription() { int?value = _directory.GetInteger(PngDirectory.TagColorType); if (value == null) { return(null); } PngColorType colorType = PngColorType.FromNumericValue((int)value); if (colorType == null) { return(null); } return(colorType.GetDescription()); }
private static bool IsPaletted(byte bitDepth, PngColorType colorType) { if (bitDepth == 8) { if (colorType == (PngColorType.Indexed | PngColorType.Color)) { return(true); } if (colorType == (PngColorType.Color | PngColorType.Alpha) || colorType == PngColorType.Color) { return(false); } } throw new InvalidDataException("Unknown pixel format (" + bitDepth + "-bit, " + colorType + ") specified"); }
public PngHeader( int width, int height, byte bitDepth, PngColorType colorType, byte compressionMethod, byte filterMethod, PngInterlaceMode interlaceMethod) { this.Width = width; this.Height = height; this.BitDepth = bitDepth; this.ColorType = colorType; this.CompressionMethod = compressionMethod; this.FilterMethod = filterMethod; this.InterlaceMethod = interlaceMethod; }
static bool IsPaletted(byte bitDepth, PngColorType colorType) { if (bitDepth == 8 && colorType == (PngColorType.Indexed | PngColorType.Color)) { return(true); } if (bitDepth == 8 && colorType == (PngColorType.Color | PngColorType.Alpha)) { return(false); } if (bitDepth == 8 && colorType == PngColorType.Color) { return(false); } throw new InvalidDataException("Unknown pixel format"); }
/// <summary> /// Validates the png header. /// </summary> /// <exception cref="NotSupportedException"> /// Thrown if the image does pass validation. /// </exception> private void ValidateHeader() { if (!ColorTypes.ContainsKey(this.header.ColorType)) { throw new NotSupportedException("Color type is not supported or not valid."); } if (!ColorTypes[this.header.ColorType].Contains(this.header.BitDepth)) { throw new NotSupportedException("Bit depth is not supported or not valid."); } if (this.header.FilterMethod != 0) { throw new NotSupportedException("The png specification only defines 0 as filter method."); } if (this.header.InterlaceMethod != PngInterlaceMode.None && this.header.InterlaceMethod != PngInterlaceMode.Adam7) { throw new NotSupportedException("The png specification only defines 'None' and 'Adam7' as interlaced methods."); } this.PngColorType = (PngColorType)this.header.ColorType; }
public void WorksWithAllBitDepths <TPixel>(TestImageProvider <TPixel> provider, PngColorType pngColorType, PngBitDepth pngBitDepth) where TPixel : struct, IPixel <TPixel> { TestPngEncoderCore( provider, pngColorType, PngFilterMethod.Adaptive, pngBitDepth, appendPngColorType: true, appendPixelType: true, appendPngBitDepth: true); }
public void EncodeGeneratedPatterns <TPixel>(TestImageProvider <TPixel> provider, PngColorType pngColorType) where TPixel : struct, IPixel <TPixel> { using (Image <TPixel> image = provider.GetImage()) { PngEncoderOptions options = new PngEncoderOptions() { PngColorType = pngColorType }; provider.Utility.TestName += "_" + pngColorType; provider.Utility.SaveTestOutputFile(image, "png", new PngEncoder(), options); } }
public void InfersColorTypeAndBitDepth <TPixel>(TestImageProvider <TPixel> provider, PngColorType pngColorType, PngBitDepth pngBitDepth) where TPixel : unmanaged, IPixel <TPixel> { using (Stream stream = new MemoryStream()) { PngEncoder.Encode(provider.GetImage(), stream); stream.Seek(0, SeekOrigin.Begin); var decoder = new PngDecoder(); Image image = decoder.Decode(Configuration.Default, stream); PngMetadata metadata = image.Metadata.GetPngMetadata(); Assert.Equal(pngColorType, metadata.ColorType); Assert.Equal(pngBitDepth, metadata.BitDepth); } }
public void WorksWithAllBitDepthsAndExcludeAllFilter <TPixel>(TestImageProvider <TPixel> provider, PngColorType pngColorType, PngBitDepth pngBitDepth) where TPixel : unmanaged, IPixel <TPixel> { foreach (var filterMethod in PngFilterMethods) { foreach (PngInterlaceMode interlaceMode in InterlaceMode) { TestPngEncoderCore( provider, pngColorType, (PngFilterMethod)filterMethod[0], pngBitDepth, interlaceMode, appendPngColorType: true, appendPixelType: true, appendPngBitDepth: true, optimizeMethod: PngChunkFilter.ExcludeAll); } } }
public void WorksWithAllBitDepths <TPixel>(TestImageProvider <TPixel> provider, PngColorType pngColorType, PngBitDepth pngBitDepth) where TPixel : unmanaged, IPixel <TPixel> { // TODO: Investigate WuQuantizer to see if we can reduce memory pressure. if (TestEnvironment.RunsOnCI && !TestEnvironment.Is64BitProcess) { return; } foreach (var filterMethod in PngFilterMethods) { foreach (PngInterlaceMode interlaceMode in InterlaceMode) { TestPngEncoderCore( provider, pngColorType, (PngFilterMethod)filterMethod[0], pngBitDepth, interlaceMode, appendPngColorType: true, appendPixelType: true, appendPngBitDepth: true); } } }
public void IsNotBoundToSinglePixelType <TPixel>(TestImageProvider <TPixel> provider, PngColorType pngColorType) where TPixel : unmanaged, IPixel <TPixel> { foreach (PngInterlaceMode interlaceMode in InterlaceMode) { TestPngEncoderCore( provider, pngColorType, PngFilterMethod.Adaptive, PngBitDepth.Bit8, interlaceMode, appendPixelType: true, appendPngColorType: true); } }
public void WorksWithDifferentSizes <TPixel>(TestImageProvider <TPixel> provider, PngColorType pngColorType) where TPixel : unmanaged, IPixel <TPixel> { TestPngEncoderCore( provider, pngColorType, PngFilterMethod.Adaptive, PngBitDepth.Bit8, PngInterlaceMode.None, appendPngColorType: true); }
static PixelFormat MakePixelFormat(byte bitDepth, PngColorType colorType) { if (bitDepth == 8 && colorType == (PngColorType.Indexed | PngColorType.Color)) return PixelFormat.Format8bppIndexed; throw new InvalidDataException("Unknown pixelformat"); }
/// <summary> /// Encodes the image to the specified stream from the <see cref="Image{TColor}"/>. /// </summary> /// <typeparam name="TColor">The pixel format.</typeparam> /// <param name="image">The <see cref="ImageBase{TColor}"/> to encode from.</param> /// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param> public void Encode <TColor>(Image <TColor> image, Stream stream) where TColor : struct, IPixel <TColor> { Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); this.width = image.Width; this.height = image.Height; // Write the png header. this.chunkDataBuffer[0] = 0x89; // Set the high bit. this.chunkDataBuffer[1] = 0x50; // P this.chunkDataBuffer[2] = 0x4E; // N this.chunkDataBuffer[3] = 0x47; // G this.chunkDataBuffer[4] = 0x0D; // Line ending CRLF this.chunkDataBuffer[5] = 0x0A; // Line ending CRLF this.chunkDataBuffer[6] = 0x1A; // EOF this.chunkDataBuffer[7] = 0x0A; // LF stream.Write(this.chunkDataBuffer, 0, 8); // Ensure that quality can be set but has a fallback. this.quality = this.options.Quality > 0 ? this.options.Quality : image.MetaData.Quality; this.quality = this.quality > 0 ? this.quality.Clamp(1, int.MaxValue) : int.MaxValue; this.pngColorType = this.options.PngColorType; this.quantizer = this.options.Quantizer; // Set correct color type if the color count is 256 or less. if (this.quality <= 256) { this.pngColorType = PngColorType.Palette; } if (this.pngColorType == PngColorType.Palette && this.quality > 256) { this.quality = 256; } // Set correct bit depth. this.bitDepth = this.quality <= 256 ? (byte)ImageMaths.GetBitsNeededForColorDepth(this.quality).Clamp(1, 8) : (byte)8; // Png only supports in four pixel depths: 1, 2, 4, and 8 bits when using the PLTE chunk if (this.bitDepth == 3) { this.bitDepth = 4; } else if (this.bitDepth >= 5 || this.bitDepth <= 7) { this.bitDepth = 8; } this.bytesPerPixel = this.CalculateBytesPerPixel(); PngHeader header = new PngHeader { Width = image.Width, Height = image.Height, ColorType = (byte)this.pngColorType, BitDepth = this.bitDepth, FilterMethod = 0, // None CompressionMethod = 0, InterlaceMethod = 0 }; this.WriteHeaderChunk(stream, header); // Collect the indexed pixel data if (this.pngColorType == PngColorType.Palette) { this.CollectIndexedBytes(image, stream, header); } this.WritePhysicalChunk(stream, image); this.WriteGammaChunk(stream); using (PixelAccessor <TColor> pixels = image.Lock()) { this.WriteDataChunks(pixels, stream); } this.WriteEndChunk(stream); stream.Flush(); }
private static bool HasAlpha(PngColorType pngColorType) => pngColorType == PngColorType.GrayscaleWithAlpha || pngColorType == PngColorType.RgbWithAlpha;
public void IsNotBoundToSinglePixelType <TPixel>(TestImageProvider <TPixel> provider, PngColorType pngColorType) where TPixel : struct, IPixel <TPixel> { TestPngEncoderCore(provider, pngColorType, appendPixelType: true, appendPngColorType: true); }
public void WorksWithDifferentSizes <TPixel>(TestImageProvider <TPixel> provider, PngColorType pngColorType) where TPixel : struct, IPixel <TPixel> { TestPngEncoderCore(provider, pngColorType, appendPngColorType: true); }
public void IsNotBoundToSinglePixelType <TPixel>(TestImageProvider <TPixel> provider, PngColorType pngColorType) where TPixel : struct, IPixel <TPixel> { TestPngEncoderCore( provider, pngColorType, PngFilterMethod.Adaptive, PngBitDepth.Bit8, appendPixelType: true, appendPngColorType: true); }