Inserting ImageUniqueID into a JPEG's EXIF data without modifying the image using .NET

Viewed 790

I have a requirement to insert a unique ID into image files without modifying the image content – ie it’s just the metadata that I want to modify. I’m starting with the JPEG files because there is an appropriate EXIF property available: ImageUniqueID.

I’m using C# with .NET Core 3.1 for this exercise with ImageSharp. I can change the EXIF data with the ImageSharp using the following code (show simplified without existing record checks, etc):

using (var image = Image.Load(filename))
            {
            var imageUniqueIdentifier = Guid.NewGuid().ToString().ToLower().Replace("-", "");
            image.Metadata.ExifProfile.SetValue(ExifTag.ImageUniqueID, imageUniqueIdentifier);

            var jpegEncoder = new JpegEncoder() { Quality = 100 };
            image.Save(filename, jpegEncoder);
            }

I did play with the Quality setting in the JpegEncoder, but was still getting either unacceptable quality degradation or file size increases.

Is there a way of just reading the meta data, altering it and then writing it back without affecting the image at all?

I also looked at MetadataExtractor.NET but this doesn’t have a write facility and would happily look at other .NET Core methods or libraries.

2 Answers

After some research I've found that there is ExifLibrary which allow you to modify only image metadata. Documentation (examples included)

Example how to add unique image id for jpg file:

var file = ImageFile.FromFile("path_to_jpg_file");
var imageUniqueIdentifier = Guid.NewGuid().ToString().ToLower().Replace("-", "");
file.Properties.Set(ExifLibrary.ExifTag.ImageUniqueID, imageUniqueIdentifier);

file.Save("path_to_jpg_file");

Nuget package: ExifLibNet.

Here is some code that just needs .NET with PresentationCore and WindowsBase. The underlying technology that WPF uses is WIC (Windows Imaging Component). WIC has full support for image metadata.

EXIF's ImageUniqueID is handled specifically as a Windows Property named System.Image.ImageID

Some other properties such as System.Photo.CameraModel can be seen directly in Windows Explorer detailed views if you add the corresponding column "Camera Model", but not System.Image.ImageID, AFAIK.

// needs PresentationCore & WindowsBase references
var frame = BitmapDecoder.Create(new Uri("test1.jpg", UriKind.RelativeOrAbsolute), BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None).Frames[0];

// create encoder, add frame, we need to copy since we want to update metadata
var encoder = BitmapEncoder.Create(frame.Decoder.CodecInfo.ContainerFormat);
var copy = BitmapFrame.Create(frame);

// get frame metadata
var metaData = (BitmapMetadata)copy.Metadata;

// show existing System.Image.ImageID (if any)
Console.WriteLine("ImageUniqueID: " + metaData.GetQuery("System.Image.ImageID"));

// for some reason, we can't use "System.Image.ImageID" to set the meta data
// so use the "Metadata Query Language"
metaData.SetQuery("/app1/ifd/exif/{ushort=42016}", "My Super ID");

// write file back
encoder.Frames.Add(copy);
using (var stream = File.OpenWrite("test1copy.jpg"))
{
    encoder.Save(stream);
}
Related