Reputation: 553
I'm trying to add Exif data to images using System.Windows.Media.Imaging. Most of the sample codes I can find work for JPGs but not Tiffs. Apparently, the codes could not expand the header to add new Exif fields. Any ideas what are missing in the code below. The output JPGs will have "Focal Length" and "Latitude" values in the Exif. But the output TIF wont.
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Media.Imaging;
namespace TestExifCs
{
class Program
{
#define DO_TIFF
static void RunSample(string originalPath)
{
BitmapCreateOptions createOptions = BitmapCreateOptions.PreservePixelFormat | BitmapCreateOptions.IgnoreColorProfile;
uint paddingAmount = 2048;
using (Stream originalFile = File.Open(originalPath, FileMode.Open, FileAccess.Read))
{
BitmapDecoder original = BitmapDecoder.Create(originalFile, createOptions, BitmapCacheOption.None);
// Pick the appropriate decoder.
#ifdef DO_TIFF
string outputPath = @"C:\temp\out.tif";
TiffBitmapEncoder output = new TiffBitmapEncoder();
#else
string outputPath = @"C:\temp\out.jpg";
JpegBitmapEncoder output = new JpegBitmapEncoder();
#endif
if (original.Frames[0] != null && original.Frames[0].Metadata != null)
{
BitmapMetadata metadata = original.Frames[0].Metadata.Clone() as BitmapMetadata;
// Expand the image file directory for new items.
metadata.SetQuery("/app1/ifd/PaddingSchema:Padding", paddingAmount);
metadata.SetQuery("/app1/ifd/exif/PaddingSchema:Padding", paddingAmount);
// Add focal length
byte[] f = new byte[8] { 0x70, 0x03, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00 };
metadata.SetQuery("/app1/ifd/exif/{uint=37386}", f);
// Add latitude
byte[] bArray = new byte[0x18] { 0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x42, 0xd7, 0x04, 0x00, 0x10, 0x27, 0x00, 0x00 };
metadata.SetQuery("/app1/ifd/gps/subifd:{ulong=2}", bArray);
// Create a new frame identical to the one from the original image, except for the added metadata
output.Frames.Add(BitmapFrame.Create(original.Frames[0], original.Frames[0].Thumbnail, metadata, original.Frames[0].ColorContexts));
}
using (Stream outputFile = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite))
{
output.Save(outputFile);
}
}
}
static void Main(string[] args)
{
RunSample("C:\\temp\\test.tif");
}
}
}
Upvotes: 0
Views: 915
Reputation: 56
I have encountered the same problem, but I was trying to set an EXIF tag with System.Drawing.Image.SetPropertyItem(). It looks to me like the C# System libraries just don't support manipulating EXIF tags in TIFFs the same way they do in JPEGs.
The TIFF format supports its own set of tags in a table called the Image File Directory (IFD). Each entry in the IFD has a 2-byte "Tag" defining what the entry is. I can edit most entries in this table using the C# libraries: I can read/write entries with "Tags" defined by the TIFF format (eg. ImageWidth=0x100), and I can read/write entries with arbitrary "private" tags that I make up on my own.
EXIF is supported in TIFF by using a private IFD entry with "Type" = "Exif IFD" = 0x8769", which contains an offset to a new IFD which contains all the EXIF-specific tags. Although I can read other private TIFF Tags, I cannot retrieve the "Exif IFD" entry using GetPropertyItem(). I noticed that there were a few TIFF Tags that I was not allowed to read, and they were all of the sort which contained an offset to another IFD.
I was able to write a TIFF IFD entry with the EXIF IFD Tag. Fortunately, I was trying to write TIFF tags, not read them, so I worked around the lack of support by doing it by hand; creating a simple EXIF IFD, appending it to the end of my file, and editing the TIFF EXIF IFD entry to point to it. Windows Explorer was then able to read the EXIFs from my TIFF.
Upvotes: 0