Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible bug in quantize() implementation #644

Closed
tfuxu opened this issue Dec 9, 2023 · 5 comments
Closed

Possible bug in quantize() implementation #644

tfuxu opened this issue Dec 9, 2023 · 5 comments

Comments

@tfuxu
Copy link

tfuxu commented Dec 9, 2023

I was investigating a bug in my app affecting a specific image that would become fully transparent after applying effects using Wand. After some testing, I found that quantize() method was making this issue.

I've tested it with different colorspaces, and it appears that setting the colorspace to gray fixes this issue. This isn't ideal, as my app also supports color images, and I would have to manually detect if image is grayscale or RGB, whereas it appears that ImageMagick doesn't have this issue and can automatically detect it.

I tested quantization in ImageMagick CLI and Magick++, and couldn't reproduce this issue in either of them.

Minimal Wand reproducer:

from wand.image import Image

with Image(filename="imagedeep.png") as img:
    img.quantize(10)
    img.save(filename="imagedeep-wand.png")

Tested ImageMagick CLI command:

convert imagedeep.png -colors 10 imagedeep-magi.png

Tested C++ code:

#include <Magick++.h> 
#include <iostream> 

using namespace std;
using namespace Magick;

int main(int argc, char **argv)
{
  InitializeMagick(*argv);

  // Construct the image object
  Image image("imagedeep.png");

  try {
    // Reduce image color palette to 10 colors
    image.quantizeColors(10);
    image.quantize(true);

    // Write the image to a file
    image.write("imagedeep-magick.png");
  } catch(Exception &error_) {
      cout << "Caught exception: " << error_.what() << endl;
      return 1;
    }

  return 0;
}

Affected image:

imagedeep

@emcconville
Copy link
Owner

Set measure_error=True kwarg to match expected behavior.

from wand.image import Image

with Image(filename="imagedeep.png") as img:
    img.quantize(10, measure_error=True)
    img.save(filename="imagedeep-wand.png")

With the CLI -colors 10, the quantize-info struct pulls the default measure-error value from the previously loaded image-info. We don't get this behavior with the C/C++ APIs. In C it's a measure-error argument to the MagickQuantizeImage method. In C++ Magick::Image.quantize(true).

@emcconville
Copy link
Owner

Oh wait. This might be something completely different. The input image has colorspace of GrayscaleAlpha but the pixel data is in sRGB. This is confusing somethings. Wand (and C-API's MagickWand) is attempting to quantize in RGBA, and C++ & CLI is operating in graya. This might take more debugging.

@emcconville
Copy link
Owner

Try the following...

from wand.version import MAGICK_VERSION_NUMBER
from wand.image import Image
with Image(filename='imagedeep.png') as img:
    if MAGICK_VERSION_NUMBER < 0x700:
        img.quantize(10, colorspace_type='undefined')
    else:
        img.quantize(10, colorspace_type='undefined', dither='undefined')
    img.save(filename='imagedeep-wand.png')

Please post if that works (with or without measure_error=True to match C++).
This bug might just be a case of the wrong default values in the method's kwargs.

@tfuxu
Copy link
Author

tfuxu commented Dec 12, 2023

It works properly with undefined color space and results are the same both with and without measure_error set.

@emcconville
Copy link
Owner

Cool. I'll have this patch up shortly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants