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

Data loss observed with ImageMagick v7.1.0-5 while converting a specific JPG file to a 200 DPI B/W output TIFF file using ImageMagick library APIs. #4121

Closed
pprasanthk opened this issue Aug 26, 2021 · 38 comments

Comments

@pprasanthk
Copy link

ImageMagick version

7.1.0-5

Operating system

Windows

Operating system, version and so on

Any version of Windows OS.

Description

Hi,

I have downloaded the latest version of ImageMagick (7.1.0-5), tested the previously reported issue in bug (#4059) and this issue is fixed.

We noticed another issue with this 7.1.0-5 version of ImageMagick with Q8 flavor. We tried to convert the attached input.jpg file (input.zip) to a 200x200 black and white tiff and observed that the output is blurred. But, when we tried this conversion using the previous version of ImageMagick (7.1.0-4), output was clear. We have also attached both the outputs here with for your reference (output_v7.1.0-4.zip and output_v7.1.0-5.zip). We are using ImageMagick library APIs for this conversion.

When we tried the same above conversion (input.jpg) with Q16 flavor, the output is a blank white TIFF file.

Could you please help us with this or let us know if we are missing anything here?

--
Thanks
Prasanth

Steps to Reproduce

ImageMagick_Sample.zip

Images

input.zip
output_v7.1.0-4.zip
output_v7.1.0-5.zip

@snibgo
Copy link

snibgo commented Aug 26, 2021

We tried to convert the attached input.jpg file (input.zip) to a 200x200 black and white tiff and observed that the output is blurred.

The output does not look blurred to me. I don't think an image that is only black and white can look blurred.

I do see a difference, that output_v7.1.0-4.tif seems to be dithered, and output_v7.1.0-5.tif is not dithered.

(Dithering means that middle tones have a proportion of black and white pixels that depends on the intensity of the input.)

Perhaps the default setting for dithering has changed. If you care about dithering, I suggest you explicitly set it. At the command line, this could be:

magick input_2.jpg -dither FloydSteinberg -compress Group4 -type bilevel x.tiff

... or:

magick input_2.jpg -dither FloydSteinberg +compress -type bilevel x.tiff

As I said in the other thread: Group4 compression reduces the image to black and white only. If you care about how that is done, it is best to do that explicitly before saving the file, eg with threshold or colors or posterize or remap, and with or without dithering.

@pprasanthk
Copy link
Author

Hi,

Thank you very much for the reply.

I tried the conversion using the sample code that I attached using both versions of ImageMagick 7.1.0-4 and 7.1.0-5.
Please find below my observations regarding the change in the output between both the versions of ImageMagick:

Please see that the output with v7.1.0-4 contains some gray shading near the letter F in the left side of the image and also horse rider's face is a little clear. Here is the output with v7.1.0-4:
EbenfurtG4200_v7.1.0-4.zip

Please see that the output with v7.1.0-5 does not contains the gray shading near the letter F in the left side of the image and also the horse rider's face is not that clear when compared to the output with v7.1.0-4. Here is the output with v7.1.0-5:
EbenfurtG4200_v7.1.0-5.zip

I also tried both the magick commands using ImageMagick v7.1.0-5 version that you suggested and noted that this output is the same as the one that I got with my sample code using ImageMagick v7.1.0-5.

Even though you mentioned that the default setting for dither would have changed, but my query is that the sample code is giving different outputs which might affect my end customers as they will start seeing different images. It would be great if we can have a setting or command line option or Magick API with ImageMagick v7.1.0-5, which would bring back the same output which we used to get with ImageMagick v7.1.0-4.

Could you please help me with this?

--
Thanks
Prasanth

@snibgo
Copy link

snibgo commented Aug 26, 2021

Please see that the output with v7.1.0-4 contains some gray shading near the letter F in the left side of the image ...

I can't see any gray shading. I can see only black pixels and white pixels.

IM says there is only black and white:

magick EbenfurtG4200_v7.1.0-4.tif -verbose info:

Image:
:
:
  Colorspace: Gray
  Type: Bilevel
  Endianness: Undefined
  Depth: 1-bit
  Channel depth:
    Gray: 1-bit
  Channel statistics:
    Pixels: 3101766
    Gray:
      min: 0  (0)
      max: 1 (1)
      mean: 0.24705 (0.24705)
      median: 0 (0)
      standard deviation: 0.431296 (0.431296)
      kurtosis: -0.624132
      skewness: 1.17297
      entropy: 0.806569
  Colors: 2
  Histogram:
    2335474: (0,0,0) #000000 gray(0)
    766292: (255,255,255) #FFFFFF gray(255)

Exiftool confirms the file has 1 bit per sample, so has only two colours:

f:\web\im>exiftool EbenfurtG4200_v7.1.0-4.tif
ExifTool Version Number         : 12.13
File Name                       : EbenfurtG4200_v7.1.0-4.tif
:
:
Bits Per Sample                 : 1

@fmw42
Copy link

fmw42 commented Aug 26, 2021

When you have a fine mix of grainy black and white pixels, that can look "gray". But if you zoom in, you will see that each grain is either black or white and that there is no actual gray values.

@pprasanthk
Copy link
Author

Hi,

Please find the gray shading marked in YELLOW circles in the attached screenshot which was taken from the output of v7.1.0-4.
Screenshot_v7.0.1-4.zip

My worry is that dithering is not happening with v7.1.0-5 as it used to happen with v7.1.0-4 and before. It would be great if we can have a setting or command line option or Magick API with ImageMagick v7.1.0-5, which would bring back the same output which we used to get with ImageMagick v7.1.0-4.

Could you please help me with this?

--
Thanks
Prasanth

@snibgo
Copy link

snibgo commented Aug 26, 2021

Please find the gray shading marked in YELLOW circles in the attached screenshot ...

But you are "zoomed out", so the viewing software is combining multiple image pixels into a single screen pixel. So black and white pixels are merged into gray.

Your image has no gray pixels.

@pprasanthk
Copy link
Author

Hi,

Got it. But, it looks like dithering is not consistent across v7.1.0-4 and v7.1.0-5. Can you please check what exactly caused this output change in v7.1.0-5 and how or with which setting can we get the v7.1.0-4's output with v7.1.0-5?

--
Thanks
Prasanth

@snibgo
Copy link

snibgo commented Aug 26, 2021

I don't know what has changed between 7.1.0-4 and 7.1.0-5.

To ensure consistency, I suggest you explicitly convert to black and white, before saving the image.

@fmw42
Copy link

fmw42 commented Aug 26, 2021

I tried a number of dithers, but nothing reproduces it that I can find. I think this will need be reviewed by the IM developers.

@snibgo
Copy link

snibgo commented Aug 26, 2021

The following gives a result that is very close to EbenfurtG4200_v7.1.0-4.tif:

magick input_2.jpg -colorspace Gray -normalize -dither FloydSteinberg -colors 2 -auto-level x.png

@pprasanthk
Copy link
Author

Hi snibbo,

I tested with the above command line and the output is very close to EbenfurtG4200_v7.1.0-4.tif. But, I am curious to know which change in IM v7.1.0-5 introduced this change in the output file.

I would like to request someone from IM developers to check this.

--
Thanks
Prasanth

@snibgo
Copy link

snibgo commented Aug 27, 2021

There is a major change in MagickCore\attribute.c, function SetImageType(), for BilevelType. See the new source at https://github.com/ImageMagick/ImageMagick/blob/main/MagickCore/attribute.c. The new processing converts to grayscale, then thresholds at 50%, then quantizes to 256 colors. The quantization seems pointless as the image should already contain just two colors: black and white.

EDIT Correction, SetImageType() not BilevelImage().

There might be other relevant changes.

@urban-warrior
Copy link
Member

The previous color reduction algorithm uses a tree-merge algorithm which sometimes would end up with 1 merged color rather than 2. We added the BiLevel() method call to ensure each image would end up with exactly 2 colors, except, when the original image only had one color or the colors parameter is 1. A better solution may be to restore the previous behavior and try to perhaps enhance the color reduction algorithm to ensure we always get at least 2 colors when merging when the colors parameter is 2.

@fmw42
Copy link

fmw42 commented Aug 28, 2021

Perhaps a -define to allow the user to pick one of the two methods?

urban-warrior pushed a commit to ImageMagick/ImageMagick6 that referenced this issue Aug 28, 2021
@urban-warrior
Copy link
Member

As you know, few image processing algorithms return satisfactory results for all use cases. Our goal is to capture the majority of the use cases and for the one-offs, have the user choose their own methods from the plethora of options available.

@fmw42
Copy link

fmw42 commented Aug 28, 2021

What about making the tree-merge method as a stand-alone threshold method. That way the use can pre-process the image with any way they want before output to compressed TIFF?

@urban-warrior
Copy link
Member

The tree-merge method is already captured in our color reduction algorithm @ https://imagemagick.org/script/quantize.php.

@fmw42
Copy link

fmw42 commented Aug 28, 2021

@urban-warrior This does not reproduce his result.

magick input.jpg -colorspace gray -colors 2 -compress group4 x.tif

x.tif.zip

His previous result

output_v7.1.0-4.tif.zip

His result is much smoother in apparent "gray". So how can he reproduce that? That is why I was suggesting a standalone method that does exactly that. Perhaps you know how to modify my command above to get his result. If so, that would solve the issue.

@urban-warrior
Copy link
Member

Did you try @snibgo suggestion above?

@snibgo
Copy link

snibgo commented Aug 28, 2021

An important point about "-colors 2" is that for a typical grayscale image it does not transform to black and white. It transforms to a dark gray and a light gray. Any input areas with colours that were darker than that dark gray will become a solid black, and areas that were lighter than that light gray will become solid white. The only areas that show dithering will be those that were between the dark and light grays.

This may be reasonable for some uses and not for others, of course.

Personally, I don't care what "-type bilevel" does when saving TIFF files, because I prefer a lower-level control, eg "-threshold" or "-colors" or "-remap", with or without dithering, at my choice.

@snibgo
Copy link

snibgo commented Aug 28, 2021

We added the BiLevel() method call to ensure each image would end up with exactly 2 colors...

But v7.1.0-5 thresholds at QuantumLevel/2. If all the intensities are below this level the result is all black; if they are all above then the result is all white.

Instead we could threshold at the mid-point between the lightest and darkest. Or at the 50% point of a cumulative histogram, so half the pixels become white and the other half become black.

There are many possibilities. I'm not really in favour of a "-define". If the user cares about how an image is transformed to black and white, they should use explicit operations for that task.

@fmw42
Copy link

fmw42 commented Aug 28, 2021

The point was to reproduce the same method used in the older version of ImageMagick, not a close approximation.

@urban-warrior
Copy link
Member

The previous method had a flaw which we are currently investigating. Certain images were reduced to 1 rather than 2 colors.

@snibgo
Copy link

snibgo commented Aug 28, 2021

A useful operation would be "-colorsexact N" that reduced to exactly N colours, provided the input has at least N unique colours.

That would solve the problem with the 7.1.0-4 code, as well as providing a facility that users sometimes ask for.

I don't know if the current colour reduction code can be adapted for this, or if a new algorithm is needed.

@pprasanthk
Copy link
Author

@snibgo
This 7.1.0-4 behavior/output is there with older versions of ImageMagick as well. Below is the command line that we tried:
convert.exe input.jpg -quality 50 -type bilevel -density 300 output.tiff
This is showing a different output when we compare with the older versions of ImageMagick.

It would be great to have the old 7.1.0-4 behavior with the latest 7.1.0-5 aw well.

It would be great if we can have the required command line option or Magick API with ImageMagick v7.1.0-5, which would bring back the same output which we used to get with ImageMagick v7.1.0-4.

Could you please help us with this?

--
Thanks
Prasanth

@urban-warrior
Copy link
Member

urban-warrior commented Aug 30, 2021

We have a patch in ImageMagick 7.1.0-6 Beta (clone the Github master branch). Give it a try and see if you get expected results. You might find slight differences. Recall, we want stable behavior in ImageMagick releases, however, if we find a bug, the patch may modify the behavior as a side-effect of the fix.

@fmw42
Copy link

fmw42 commented Aug 31, 2021

The output on the 7.1.0.6 beta does not seem much different from the 7.1.0.5 release and is much "grainier" than the 7.1.0.4 version using the command:

magick input.jpg -colorspace gray -colors 2 -compress group4 x.tif

Is there a better command?

@urban-warrior
Copy link
Member

We compared the two releases-- and found them comparable :-). 7.1.0-6 gave a better rendition of the horses nose and legs as compared to 7.1.0-4. We used ImageMagick_Sample.cpp to produce the output image, not the ImageMagick command-line. We still need to ensure that color reduction does not return just one color.

@fmw42
Copy link

fmw42 commented Aug 31, 2021

Perhaps the 7.1.0.6 beta that I downloaded does not have your change. I compare from my command above and what the OP provided from his download. However, I cannot reproduce his 7.1.0.4 result. I get a different result.

magick compare -metric rmse output_v7.1.0.-6.tif output_v7.1.0-4.tif null:
18126.1 (0.276587)

netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this issue Sep 13, 2021
2021-09-04  7.1.0-6  <quetzlzacatenango@image...>
  * Release ImageMagick version 7.1.0-6 GIT revision 19033:7c589e780:20210904

2021-08-21  7.1.0-6  <quetzlzacatenango@image...>
  * Tweak the bilevel image type (reference
    ImageMagick/ImageMagick#4121).
  * Converting from LAB to RGB leads to wrong colors (reference
    ImageMagick/ImageMagick#4105).
@pprasanthk
Copy link
Author

Hi,

We downloaded the latest version of ImageMagick and noticed that dithering is still not properly applied for the following files as it used to get applied in v7.1.0-4. Could you please help us with this?

ZeroDensity_Input
ColorEbenfurt

--
Thanks
Prasanth

@urban-warrior
Copy link
Member

Try adding -dither FloydSteinberg to your command-line. Does that help? If not, post your command here with an example of expected results so we can investigate.

@pprasanthk
Copy link
Author

Hi urban-warrior,

It looks like a different dithering algorithm is being used with 7.1.0-7, but it looks more like the output with 7.0.10-0.

Could you please clarify us the below questions:
• Which dithering algorithm is by used default?
• What was changed between IM 7.0.10-0 and 7.1.0-7?

I have attached the outputs with both 7.0.10-0 and 7.1.0-7 (with the new command line -dither FloydSteinberg ) for your reference.

outputs.zip

--
Thanks
Prasanth

@urban-warrior
Copy link
Member

Post a link to your original source image. We will need to run some tests to see why the output results differ. Its possible its a side-effect of a bug fix. We'll need to perform forensic first to decide.

@pprasanthk
Copy link
Author

Please find the original source image below:
TestImage.zip

@urban-warrior
Copy link
Member

urban-warrior commented Sep 20, 2021

Try this command with ImageMagick version 7.1.0-8:

magick TestImage.tiff -resize 2481x3508 -dither FloydSteinberg -compress group4 fax.tiff

It returns similar results to ImageMagick version 7.0.10-0 .

@pprasanthk
Copy link
Author

Hi urban-warrior,

I will try this but I am more curious to know,
• Which dithering algorithm is by used default?
• What was changed between IM 7.0.10-0 and 7.1.0-7?

@urban-warrior
Copy link
Member

The default dithering algorithm is Riemersma. What changed? The default dithering algorithm. Explicitly set it to FloydSteinberg to restore previous behavior.

@pprasanthk
Copy link
Author

pprasanthk commented Sep 21, 2021

Hi urban-warrior,

Thanks for the confirmation that the default dithering algorithm was changed from Riemersma to FloydSteinberg. I tried your last command and noticed that the command line -resize 2481x3508 is mandatory to get the behavior similar to v7.0.10-0.
Could you please clarify about the introduction of this new extra parameter -resize 2481x3508, which I believe is not there in v7.0.10-0.
Also, don't you think changing the aspect ratio of the image will distort the image and also parameters for this resize command line change from image to image, and also for different displays on which these images are displayed?

--
Thanks
Prasanth

bmwiedemann pushed a commit to bmwiedemann/openSUSE that referenced this issue Sep 24, 2021
https://build.opensuse.org/request/show/920266
by user pgajdos + dimstar_suse
- version update to 7.1.0.8
  * Check for `null` in InvokeDelegate() (reference
    ImageMagick/ImageMagick#4225).
  * Fixed incorrect check when module is used as the domain in policy.xml
    that could allow the use of a disabled module. (reference
    GHSA-qvhr-jj4p-j2qr).
  * Prevent color reduction merging into one color (reference
    ImageMagick/ImageMagick#4059)
  * Tweak the bilevel image type (reference
    ImageMagick/ImageMagick#4121).
  * Converting from LAB to RGB leads to wrong colors (reference
    ImageMagick/ImageMagick#4105).
  * Added option (-dng:read-thumbnail=true) to read the thumbnail of a raw
    Imag
freebsd-git pushed a commit to freebsd/freebsd-ports that referenced this issue Nov 12, 2021
From [1]:

2021-10-28  7.1.0-13  Dirk Lemstra <[email protected]>
  * Fix stack overflow when parsing malicious ps image file (report from
    Muhammad Aldo Firmansyah).

2021-10-15  7.1.0-12  <quetzlzacatenango@image...>
  * Fix x64 build.

2021-10-11  7.1.0-11  <quetzlzacatenango@image...>
  * Fix connected component abort trap (reference
    ImageMagick/ImageMagick#4372).
  * Fix possible unitialized values (reference
    ImageMagick/ImageMagick#4379).
  * Fix stack overflow when parsing malicious tiff image file (report from
    Muhammad Aldo Firmansyah).

2021-10-03  7.1.0-10  <quetzlzacatenango@image...>
  * Improved algorithm for automatic calculation of pointsize for caption and
    labels.
  * Support -auto-orient option in the identify utlity.

2021-10-03  7.1.0-9  Dirk Lemstra <[email protected]>
  * Squash a dump truck load of VisualStudio compiler warnings.
  * Improved algorithm for automatic calculation of word breaks and pointsize
    for caption and labels.
  * Improve wrapping between words and within words (reference

2021-09-17  7.1.0-8  Dirk Lemstra <[email protected]>
  * Check for `null` in InvokeDelegate() (reference
    ImageMagick/ImageMagick#4225).

2021-09-11  7.1.0-7  Dirk Lemstra <[email protected]>
  * Fixed incorrect check when module is used as the domain in policy.xml
    that could allow the use of a disabled module. (reference
  * Prevent color reduction merging into one color (reference
    ImageMagick/ImageMagick#4059)

2021-08-21  7.1.0-6  <quetzlzacatenango@image...>
  * Tweak the bilevel image type (reference
    ImageMagick/ImageMagick#4121).
  * Converting from LAB to RGB leads to wrong colors (reference
    ImageMagick/ImageMagick#4105).

2021-08-12  7.1.0-5  Dirk Lemstra <[email protected]>
  * Added option (-dng:read-thumbnail=true) to read the thumbnail of a raw
    Image and store it as a profile called dng:thumbnail.
  * Heap-based buffer overflow in TIFF coder (alert from Hunter Mitchell).
  * Grayscale image write optimization.

2021-07-17  7.1.0-4  <quetzlzacatenango@image...>
  * Trim no longer returns an empty image on 1-pixel width input (reference
    ImageMagick/ImageMagick#3896).
  * remove virtual canvas offset from difference image.

2021-07-03  7.1.0-3  Dirk Lemstra <[email protected]>
  * Added option to set the pixel format option of ffmpeg when reading or
    writing a video file with -define video:pixel-format=<value>.
  * system() is not supported under IOS.
  * Accelerate subimage-search with FFT's (contributed by Fred).

2021-06-25  7.1.0-2  <quetzlzacatenango@image...>
  * malloc() corruption fix (reference
    ImageMagick/ImageMagick6#159).

2021-06-19  7.1.0-1  Dirk Lemstra <[email protected]>
  * Added option to set the vsync option of ffmpeg when reading or writing a
    video file with -define video:vsync=<value>.

2021-06-02  7.1.0-0  <quetzlzacatenango@image...>
  * SVG no longer hangs when handling class in <defs> (reference
    ImageMagick/ImageMagick#3818).
  * Bump minor version (reference
    ImageMagick/ImageMagick#3768)

2021-06-02  7.0.11-15  <quetzlzacatenango@image...>
  * Raise exception for invalid compose:args geometry (reference
    ImageMagick/ImageMagick#3765).

2021-05-20  7.0.11-14  Dirk Lemstra <[email protected]>
  * Added support for reading and writing 16-bit jxl images.

2021-05-12  7.0.11-13  Dirk Lemstra <[email protected]>
  * Fixed reading and writing the XMP chunk in a WebP image (reference
    ImageMagick/ImageMagick#3617).
  * Added support to set the jpeg-xl encoding effort with
    -define jxl:effort=<number>

2021-05-09  7.0.11-13  <quetzlzacatenango@image...>
  * label and caption sanity check is too conservative.

[1] https://github.com/ImageMagick/ImageMagick/blob/main/ChangeLog
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

5 participants