dlemstra / Magick.NET

The .NET library for ImageMagick
Apache License 2.0
3.47k stars 415 forks source link

Incorrect density information when reading an image #1077

Closed mdemettre closed 2 years ago

mdemettre commented 2 years ago

Description

I am updating the version of Magick.NET from v7.14.2 to 8.4.0. I have some failing tests and it looks like reading an image results in incorrect denisty infomation.

I have an image that has a density of 72x72 (verified in photoshop and properties of the file). screenshot

When loading the image with the new version of Magick.NET the denisty is shows as 300x300.

v7.14.2

v7 14 2

v8.4.0

v8 4 0

Steps to Reproduce

var path = @"C:\TestFiles\imageMagick\test.jpg";
var image = new MagickImage();
image.Read(path); 
Console.WriteLine($"Density = X: {image.Density.X}. Y: {image.Density.Y}. Units: {image.Density.Units}.");

On version 7.14.2 - density 72x72 inch (expected) On version 8.4.0 - density 300x300 inch

Example Image

Any help would be really appreciated.

dlemstra commented 2 years ago

This is happening because the exif profile of the image contains this information. When an image has an exif profile the density from that profile will overrule the density of the image itself.

mdemettre commented 2 years ago

Thanks for getting back to me so fast!

Is there a reason why this changed between the versions? I need to be able to read the real image denisty. Is there a way to do that?

Could you please explain why setting the density and then reading the image back has different values?

image.Density = new Density(72, DensityUnit.PixelsPerInch);
image.Write(outPath);
var _image = new MagickImage();
_image.Read(outPath);
// _image.density = 300x300

Thank you

dlemstra commented 2 years ago

There is currently no way to ignore the density from the exif profile. This will overrule the density stored on the image. We would need to introduce an option for that.

And I don't know why the density is different when you read it back. I suspect it has to do with your input image but without the actual image I cannot answer your questions.

dlemstra commented 2 years ago

I can reproduce the issue with your file but I have no idea why the resultion is changed back to 300. We update the exif profile and when I do this var profile = image.GetExifProfile(); var xresolution= profile.GetValue(ExifTag.XResolution); after the image is written the value is 72. Will need to investigate this further to check that is happening.

mdemettre commented 2 years ago

Thanks for looking into this more. I still don't know why it's happeneing either. It would be really helpful to have some further information on this.

dlemstra commented 2 years ago

I finally figured out what was happening. The 8bim profile of your image contains an exif profile. When the image is read the exif profile of the image is read from the 8bim profile. We then update the exif profile of the image and save the file. But the exif profile inside the 8bim profile is not updated with the new density and will overrule the other exif profile when the image is read again. I just pushed a patch to fix this that will become available in the next release.

dlemstra commented 2 years ago

I also decided to introduce a new setting that would make it possible to disable using the information from the exif profile. In the next version of Magick.NET there will be a new property called SyncImageWithExifProfile that will be added to the MagickImageReadSettings that can be used to disable use of the exif profile data.

dlemstra commented 2 years ago

The new release has been published.

mdemettre commented 1 year ago

Hi @dlemstra, We just updated from version 8.5 to version 13.0.1 and it looks like we're having the same issue again. Any ideas?

dlemstra commented 1 year ago

A unit test was added for this to make sure this won't be break in new releases. Can you check my unit test?

amytant commented 1 year ago

@dlemstra Hi Dirk, I had a look at the existing unit test and it seems like the current issue @mdemettre and I have (incorrect Density information when reading an image) is not due to the exif tags not getting updated (as was the case previously), but instead it seems like in version 13.0.1 the tiff X/Y resolution tags aren't getting updated and the Density info seems to get read from those instead of the (correct) exif tags.

See the test project where I've reproduced this with 2 TIFF files and 1 JPEG file. After thumbnail/resize the files have a density of 72x72, but ImageMagick is not reading this correctly.

dlemstra commented 1 year ago

Thanks for proving me with all these input images @amytant , makes it a lot easier to check what is happening. You can also use a GitHub repository to share a test project. I also noticed that you are doing both new MagickImage(stream) and .Read(stream), this means that you are reading the image twice.

Test_Jpg.Jpg: It seems that you are using image.Thumbnail and that removes the exif profile from the image, only the icc profile is preserved. I have updated the documentation to make this more clear. But it looks like ImageMagick is still using information from the profiles that was stored in them when writing the PNG file. I just pushed a patch to the ImageMagick repository to fix this and this will be fixed in the next release of Magick.NET.

Test_TIFF_Transparent.tif You are saving the image as a WebP file and this format doesn't have an option to store the Density. But in your situation there is an xmp profile and ImageMagick is not making any changes in that profile. I will need to investigate if and how we can do that. Your solution for now would be to remove the `xmp profile and you will get the default DPI (0x0).

Test_TIFF.tif This image has a similar issue as the previous image. The xmp profile is used when the image is being loaded and this will overwrite the other DPI information stored in the image. Removing the xmp profile will now solve your issue but as said earlier I will see if we can update the profile.

dlemstra commented 1 year ago

I was able to update the xmp profile in the ImageMagick library so those other/extra issue will be resolved in the next release.

amytant commented 1 year ago

@dlemstra Thank you for the swift explanation and resolution.

The double stream read was an oversight in the test project, thank you for informing me about it.

For the WebP issue, we need to preserve image metadata during an image resize so removing the xmp profile doesn't seem like an option. Glad to hear you're able to update the xmp profile in the upcoming release, but it's still unclear to us why file properties like Density are being read from XMP metadata - is this a fallback?

And can you give an indication for when the next Magick.NET release with these fixes will be available?

dlemstra commented 1 year ago

The WebP format doesn't store the density information in some kind of metadata field. The xmp/exif profiles are used to store that information.

I will publish a new release soon. Maybe this week, maybe next week.

amytant commented 1 year ago

@dlemstra Thank you for the new release! It has resolved our issues.