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

Update EXIF metadata without re-encoding JPEG image #530

Open
Webreaper opened this issue Oct 25, 2019 · 5 comments
Open

Update EXIF metadata without re-encoding JPEG image #530

Webreaper opened this issue Oct 25, 2019 · 5 comments

Comments

@Webreaper
Copy link

I'm building an image processing app using .Net Core 3.0 and blazor. I'm using Magick.Net (latest version, Q16-AnyCPU, running on OSX and also on Linux) to read from and write to the IPTC tag list. I have two questions:

  1. My code to add a tag looks something like this:

         string tagToAdd = "New Tag";
         // Read image from file
         using (MagickImage image = new MagickImage(input))
         {
             // Retrieve the exif information
             var profile = image.GetIptcProfile();
    
             if( profile == null )
                 profile = new IptcProfile();
    
             var keywords = profile.Values.Where(x => x.Tag == IptcTag.Keyword)
                                   .Select( x => x.Value )
                                   .ToList();
    
             keywords.Add(tagToAdd);
             string allKeywords = string.Join(",", keywords);
             profile.SetValue(IptcTag.Keyword, allKeywords);
             image.AddProfile(profile);
    
             image.Write(output);
         }
    

Is this the right approach? Is there a better way? There aren't really any good code samples for IPTC writing, so I wanted to check I've not missed an API to just add a single keyword to the existing set of keywords.

  1. Assuming the code above is correct, is this guaranteed to be a no-op on the actual image itself? i.e., what I'm looking for is to just rewrite the IPTC Exif block without re-writing the image. What I don't want this to do is re-encode the JPEG (or touch it at all) because obviously if it does that, after adding 10 keywords in separate operations I'll end up with blotchy artifacts in my images. I know that ExifTool does the tags addition/removal without touching the image data, but want to check if the same assumption for ImageMagick/Magick.Net.

The reason this question cropped up is because I had a 7.6MB image on disk, added a single keyword using the code above, and the resulting image was 6.8MB - which seems to me like it may have re-encoded the image and lost some data into the process. I could just spawn a process and run exiftool, but it's cleaner to do the IPTC tag changes in-process, particularly when the thing I'm writing is cross-platform.

Thanks for the help!

@dlemstra
Copy link
Owner

There is currently no support for editing the metadata without decoding and encoding the image. And I have not seen any other libraries that can do that without spawning a process to do this. It should be possible to add something like that this to this library because there is already a class that can be used to optimize JPEG files without encoding and decoding them. But it could take a long time before something like this will be added.

@Webreaper
Copy link
Author

Thanks for confirming. Glad I checked, as I might have ended up spoiling my original-res photos with tag editing! I'll look at spawning exiftool for now though. Will modify the title of this issue to fit the 'enhancement' tag.

@Webreaper Webreaper changed the title Questions on Reading and Writing IPTC tags Update EXIF metadata without re-encoding JPEG image Oct 26, 2019
@Byron1c
Copy link

Byron1c commented Nov 20, 2019

+1 here... Id very much like to be able to edit the metadata/exif without touching the image.

Please let me know if this should be a separate issue, but I thought it might be appropriate here: I would also like to be able to add/edit the thumbnail image stored in the exif tags 0x501b (ThumbnailData), and 0x5023 (ThumbnailCompression). Or, is this handled in existing code somewhere, and I have missed it? The Exif profile only refers to CreateThumbnail (which only returns an existing thumbnail?), and RemoveThumbnail.

The code I am currently trying to use is as follows, but saving the image results in changes to the jpg itsself when saved. Im unable to copy the properties to MagickImage because it will not accept those IDs.

                    MagickGeometry mg = new MagickGeometry(vSizeX, vSizeY);
                    mg.FillArea = true;
                    mg.IgnoreAspectRatio = false;

                    OpenCL.IsEnabled = false;
                    MagickImage newThumb = (MagickImage)image.Clone();
                    newThumb.Resize(160, 160);

                    newImage = image.ToBitmap();
                    image.Dispose();

                    PropertyItem itemThumb = null;
                    PropertyItem itemThumbCompress = null;

                    if (itemThumb == null) itemThumb = (PropertyItem)FormatterServices.GetUninitializedObject(typeof(PropertyItem));
                    if (itemThumbCompress == null) itemThumbCompress = (PropertyItem)FormatterServices.GetUninitializedObject(typeof(PropertyItem));

                    itemThumb.Id = 0x501b; // PropertyTag ThumbnailData
                    itemThumb.Type = 1;
                    itemThumb.Len = newThumb.ToByteArray().Length;
                    itemThumb.Value = newThumb.ToByteArray();
                    newImage.SetPropertyItem(itemThumb);

                    //#region Create a new Thumbnail Compression property.
                    itemThumbCompress.Id = 0x5023; // PropertyTagThumbnailCompression
                    itemThumbCompress.Type = (short)ExifPropertyDataTypes.UShortArray;
                    itemThumbCompress.Len = 2;
                    itemThumbCompress.Value = new byte[] { 6, 0 };
                    newImage.SetPropertyItem(itemThumbCompress);
                      
                    newImage.Save(vPath);

I also think the ThumbnailDateTime = 0x5033 would be useful
Oh, Im running Q16-AnyCPU too

Thanks heaps for a great extension and all your work Dirk! :)

@GF-Huang
Copy link

This one can update EXIF lossless, bu I don't know does it implement.

http://www.magicexif.com/

image

@wjax
Copy link

wjax commented Oct 31, 2021

I think this repo do extract Exif without reading/decoding whole file.
https://github.com/esskar/ExifLib.Net

I have tested both Magick and this repo and the difference is abismal in memory and time.

Not complaining here, just leting you know that there are some alternatives (I do not know how clean code or proper implementations they are)

A+

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

No branches or pull requests

5 participants