Tuesday, October 2, 2012

Saving JPEG Metadata the FIRST Time with WPF

So, I've been seeing a bunch of problems at StackOverflow and bumped into this new problem at work...  Turns out that setting the EXIF metadata on an image is EXTREMELY difficult.  Most solutions involve first saving the image and then opening it back up...

Of course, I couldn't just "accept" that.  Unfortunately, the work-around is a bit of a hack, but it does work reliably!

So, in the following example, assume that I have a RenderTargetBitmap from WPF...

                    JpegBitmapEncoder imageEncoder = new JpegBitmapEncoder { QualityLevel = 100 };
                    imageEncoder.Frames.Add(BitmapFrame.Create(renderTarget));

                    using (MemoryStream memoryStream = new MemoryStream())
                    {
                        imageEncoder.Save(memoryStream);
                        memoryStream.Position = 0;

                        JpegBitmapDecoder decoder = new JpegBitmapDecoder(memoryStream, BitmapCreateOptions.None, BitmapCacheOption.Default);
                        BitmapFrame frame = decoder.Frames[0];
                        BitmapMetadata metadata = (BitmapMetadata) frame.Metadata.Clone();

                        metadata.Subject = "This is a test subject.";
                        metadata.Title = "This is a test title.";
                        metadata.Comment = "This is a test comment.";

                        imageEncoder = new JpegBitmapEncoder() { QualityLevel = 100 };
                        imageEncoder.Frames.Add(BitmapFrame.Create((BitmapSource)frame, (BitmapSource)frame.Thumbnail, metadata, frame.ColorContexts));

                        using (var fileStream = new FileStream(saveFileDialog.FileName, FileMode.Create))
                        {
                            imageEncoder.Save(fileStream);
                        }
                    }

This is, of course, a hack -- it saves the image to the memory stream and then is capable of creating a "good" metadata object (normally, this blows up in your face if you try to send one in that you created on the fly).

Now, you can set it up however you like -- go nuts!