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);
                    }
            }
        }
示例#2
0
        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;
                        }
                    }
                }
            }
        }
示例#3
0
        /// <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));
            }
        }
示例#4
0
        /// <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));
            }
        }
示例#5
0
 /// <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;
 }
示例#6
0
        public void Encode_PreserveBits(string imagePath, PngBitDepth pngBitDepth)
        {
            var testFile = TestFile.Create(imagePath);

            using (Image <Rgba32> input = testFile.CreateRgba32Image())
            {
                using (var memStream = new MemoryStream())
                {
                    input.Save(memStream, PngEncoder);

                    memStream.Position = 0;
                    using (var output = Image.Load <Rgba32>(memStream))
                    {
                        PngMetadata meta = output.Metadata.GetPngMetadata();

                        Assert.Equal(pngBitDepth, meta.BitDepth);
                    }
                }
            }
        }
示例#7
0
        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);
            }
        }
示例#8
0
 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);
         }
     }
 }
示例#9
0
        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);
                }
            }
        }
示例#10
0
 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);
 }
示例#11
0
        internal static async Task WriteImageToFileAsync(string fileName, Image <Gray8> image, PngBitDepth bitDepth = PngBitDepth.Bit1)
        {
            var outputFolder = await GetOutputFolderAsync();

            var imageFile = await outputFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);

            using (var stream = await imageFile.OpenAsync(FileAccessMode.ReadWrite))
            {
                using (IOutputStream outputStream = stream.GetOutputStreamAt(0))
                {
                    var encoder = new PngEncoder();
                    encoder.ColorType = PngColorType.Grayscale;
                    encoder.BitDepth  = bitDepth;
                    image.Save(outputStream.AsStreamForWrite(), encoder);
                    await outputStream.FlushAsync();
                }
            }
        }
示例#12
0
        private static void TestPngEncoderCore <TPixel>(
            TestImageProvider <TPixel> provider,
            PngColorType pngColorType,
            PngFilterMethod pngFilterMethod,
            PngBitDepth bitDepth,
            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
                {
                    ColorType        = pngColorType,
                    FilterMethod     = pngFilterMethod,
                    CompressionLevel = compressionLevel,
                    BitDepth         = bitDepth,
                    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);

                bool referenceOutputFileExists = File.Exists(referenceOutputFile);

                using (var actualImage = Image.Load <TPixel>(actualOutputFile, referenceDecoder))
                {
                    // TODO: Do we still need the reference output files?
                    Image <TPixel> referenceImage = referenceOutputFileExists
                                               ? Image.Load <TPixel>(referenceOutputFile, referenceDecoder)
                                               : image;

                    float paletteToleranceHack = 80f / paletteSize;
                    paletteToleranceHack = paletteToleranceHack * paletteToleranceHack;
                    ImageComparer comparer = pngColorType == PngColorType.Palette
                                                 ? ImageComparer.Tolerant(ToleranceThresholdForPaletteEncoder * paletteToleranceHack)
                                                 : ImageComparer.Exact;
                    try
                    {
                        comparer.VerifySimilarity(referenceImage, actualImage);
                    }
                    finally
                    {
                        if (referenceOutputFileExists)
                        {
                            referenceImage.Dispose();
                        }
                    }
                }
            }
        }