SixLabors/ImageSharp

Saving png with [0,0,0] and [1,1,1] values makes all values [1,1,1]

drozzy opened this issue · 5 comments

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

ImageSharp version

3.0.2

Other ImageSharp packages and versions

N/A

Environment (Operating system, version and so on)

Mac

.NET Framework version

7.0.5

Description

I'm storing two classes in an image as colors: [0, 0, 0] and [1, 1, 1].

However, when I try to save the PNG image composed only of two colors [0,0,0] and [1,1,1] it somehow converts ALL the pixels to one color.

I suspected some sort of compression and tried the following to no avail:

var encoder = new SixLabors.ImageSharp.Formats.Png.PngEncoder()
            {
                CompressionLevel = SixLabors.ImageSharp.Formats.Png.PngCompressionLevel.NoCompression,
                SkipMetadata = true,
                BitDepth = SixLabors.ImageSharp.Formats.Png.PngBitDepth.Bit8,
                PixelSamplingStrategy = new SixLabors.ImageSharp.Processing.Processors.Quantization.ExtensivePixelSamplingStrategy()
            };
            image.SaveAsPng(destPath, encoder);

Steps to Reproduce

Take an existing image and map some colors to [0,0,0] and others to [1,1,1] and the resulting image on disk will be [1,1,1].

Images

No response

Can you please provide some more information here?

What are the dimensions of the image, what is the distribution of colors?

During quantization the image is diffused by default which will definitely be having an effect on the output. Try turning off error diffusion by passing a custom quantizer.

How do I turn off the diffusion? I couldn't figure that out.

Image dimensions are 1600x1200. Here is an example output of a save png by ImageSharp (see attached). As you can see every pixel color is identical, even thought I explicitly set different colors, including [0,0,0], [1,1,1], [2,2,2] and [3,3,3] (and can see they are different before calling save).

13

Tried setting Dither to null and doesn't work...

            var options = new SixLabors.ImageSharp.Processing.Processors.Quantization.QuantizerOptions()
            {
                Dither = null
            };

            var encoder = new SixLabors.ImageSharp.Formats.Png.PngEncoder()
            {
                CompressionLevel = SixLabors.ImageSharp.Formats.Png.PngCompressionLevel.NoCompression,
                SkipMetadata = true,
                BitDepth = SixLabors.ImageSharp.Formats.Png.PngBitDepth.Bit8,
                PixelSamplingStrategy = new SixLabors.ImageSharp.Processing.Processors.Quantization.ExtensivePixelSamplingStrategy(),
                Quantizer = new SixLabors.ImageSharp.Processing.Processors.Quantization.WuQuantizer(options)
            };
            image.SaveAsPng(destPath, encoder);

Here is my replace color functions:

private static void RemapImageColorsInPlace(Image<Rgb24> img, List<ColorMap> colorsMap)
        {


            for (int x = 0; x < img.Width; x++)
            {
                for (int y = 0; y < img.Height; y++)
                {
                    foreach (var map in colorsMap)
                    {
                        if (img[x, y] == map.From)
                        {

                            img[x, y] = map.To;
                            break;
                        }
                    }
                }
            }
        }

and here is an example mapping:

var colorsMap = new List<ColorMap>
        {
            new ColorMap(new Rgb24(128, 0, 0), new Rgb24(2, 2, 2)),
            new ColorMap(new Rgb24(0, 128, 0), new Rgb24(1, 1, 1)), 
            new ColorMap(new Rgb24(128, 128, 0), new Rgb24(2, 2, 2)),
            new ColorMap(new Rgb24(0, 0, 0), new Rgb24(3, 3, 3))
        };

Ok, looks like OctreeQuantizer with Dither null worked.

Thanks!