I’ve just put up another revision of my Exif parsing/writing code. There’s only a few changes from last time —
- TCustomExifData now accepts Exif segments that declare themselves to be big endian when they are really small endian or vice versa.
- elTrilinear renamed esTrilinear.
- In the Exif List demo, replaced most of the string array constants with functions so as to prevent access violations when a tag value is out of its corresponding enumerated type’s range.
- Completely removed the MakerNotePosition property from TExifData. Behaviour is now fixed to the old default (mpAuto), which is to stream out maker note data to their original location.
Update 21/2/10: fixed typo in CCR.Exif.pas that caused a one byte memory overwrite error. Rest of the units are unchanged since the original 1.0.1 release.
Having been stuck on v0.9.x for ages due to my somewhat arbrary versioning scheme (or lack of one!), I thought I might as well get a v1.0.0 out, so here it is. Changes since v0.9.9 are as thus:
- Added support for IPTC metadata as stored in Adobe APP13 segments —
- Implemented an IPTC reader/writer class, TIPTCData, in a new unit, CCR.Exif.IPTC.pas.
- The interface of TIPTCData is broadly modelled on TExifData’s — thus, there are ‘sections’ and ‘tags’, with high level tag properties on TIPTCData itself.
- At a lower level, the RemoveMetadataFromJPEG global routine can now delete IPTC data, and you can enumerate the data blocks of an Adobe APP13 segment from an IJPEGSegment instance.
- TJPEGImageEx has received a few amendments —
- Added an IPTCData property.
- Added an overload to Assign that allows for the preservation of any metadata, interpreted by my code or not, when a bitmap is assigned.
- Fixed a bug in which calling the regular Assign didn’t cause the ExifData property to be updated.
- Two more Nikon maker note types now parsed. Thanks goes to Stefan Grube for updating the Exif List demo’s MakerNotes.ini for this.
- Fixed bug of JPEG parsing code not realising a segment with a marker number of 0 has no data.
- Fixed typo in TStreamHelper.ReadLongInt spotted by Jeff Hamblin.
- Changed the types of the ExifImageWidth, ExifImageHeight and FocalLengthIn35mmFilm properties of TCustomExifData so as to give them MissingOrInvalid and AsString sub-properties. (Basically, they now use custom record types that have methods and operator overloads.)
- Changed behaviour of TCustomExifData’s enumerator to not skip empty sections.
- The LoadFromJPEG methods of TExifData are now procedures rather than functions.
- Added a couple more demos, namely an IPTC editor and a console app to strip specified types of metadata from one or more JPEG files.
- Removed all previously deprecated symbols.
[Update 19/1/10 — grr, gremlins. Try downloading again to get a version compilable in D2009 or D2010 (CCR.Exif.JPEGUtils.pas and CCR.Exif.IPTCUtils.pas should now be marked v1.0.0a).]
I’ve just put up another revision of my Delphi Exif parsing code. This revision has two main themes:
- Sanity checks have been added to the parsing code, meaning every single TIFF offset is now checked. Connected to this, and by popular demand (or so it seems), the balance between accepting malformed metadata and raising an exception has now swung a bit towards the former.
- Better maker note support: specifically, the tag structures of Canon, Panasonic and Sony MakerNotes are now understood. The interpretation of maker note tag values is still left to the user however.
Other, more minor changes include:
- Fixed typo in GPS direction tag setter which meant the value could never be changed.
- Added memory leak fix to CCR.XMPUtils.pas suggested by David Hoyle.
- Added delay loading semantics to the XMPPacket property of TCustomExifData, the idea being that attempts to read Exif tags should not ever lead to an EInvalidXMPPacket exception being raised. Equivalent behaviour has been built into the new maker note parser code too.
- More helper methods of the TryGetXXXValue and ReadXXX kind.
- Surfaced two interop IFD tags as properties on TCustomExifData.
- Maker note data are now moved back to their original position on save if the OffsetSchema tag had been set. (Actually, this should have been the case for the previous release but for a bug, typing Inc where I meant Dec.)
- Demos rejigged a bit — PanasonicMakerNoteView.exe removed (its functionality has been added to an improved ExifList.exe), and two new console ones added (CreateXMPSidecar.exe and PanaMakerPatch.exe). You can download compiled versions of the demos from here.
One final note — idly Googling, I’ve found that there’s at least one person around who believes it might be realistic to backport my code to Delphi 7. Two words of advice: don’t bother. You’ll just have one problem after another.
It’s taken a while, but I’ve just completed another revision of my MPL’ed Exif reader/writer code, Exif being the standard format for JPEG metadata (see here). The biggest new feature in terms of effort spent is much better XMP support – the default behaviour is now to update the equivalent XMP property whenever an Exif tag value is changed, though only when the former already exists. If you want, you can get the behaviour of Vista’s (and quite possibly Windows 7’s) Windows Explorer instead, which is to always create an XMP value whenever an Exif one is set, with a single property change – set XMPWritePolicy to xwAlwaysUpdate.
In terms of actual usefulness though, possibly a bigger change is the fact that by default, MakerNote tag data are now always written out to their original location. Unlike implementing proper XMP support, which was a right drag, this turned out to be pretty straightforward. Other than that, I’ve also fixed some bugs and fiddled around with some of the lower level code a bit – in particular, where I had previously assumed the ExifImageWidth and ExifImageHeight tags would always have longword values, I now support word-sized ones too. Moreover, the ‘correct’ positions of the JFIF, Exif and XMP segments are now enforced by TExifData.SaveToJPEG, any comment segments (for example) being moved below.
That said, looking at the CodeCentral stats, it seems quite a few people have downloaded earlier revisions of the code, which makes me think – it could do with a better name! Unfortunately, the most obvious one (dExif) has already been taken. So, any ideas..?
Update 1 (19/10/09): in the hours since I first posted this, I’ve slightly amended the original ZIP to avoid some D2009 issues — the current version of CCR.Exif.pas is thus 0.9.8a.
Update 2 (29/10/09): I’ve also now slightly amended CCR.Exif.XMPUtils.pas. Like CCR.Exif.pas, it now stands at version 0.9.8a.
Another revision of CCR Exif is up. Changes:
- The focus of this release was making the code more aware of what more recent versions of Windows Explorer (amongst other Microsoft applications) do when a person uses them to edit JPEG metadata. For some background, see my post here.
- TExifData.SaveToStream now adds or updates the Microsoft-defined OffsetSchema tag if a MakerNote is defined (see http://support.microsoft.com/kb/927527).
- Various enumerated types have acquired a xxTagMissing value to more easily determine whether the underlying tag actually exists.
- The following symbols have been added (see the documentation for more info):
- PreserveXMPData property to TCustomExifData; default is False.
- IsPadding and SetAsPadding methods to TExifTag; RemovePaddingTag method to TExifSection; RemovePaddingTags method to TCustomExifData. All these concern the padding tags Microsoft applications tend to write out.
- RemoveMetaDataFromJPEG, StreamHasExifHeader and StreamHasXMPHeader global functions to CCR.Exif.
- DigitalZoomRatio, FocalLengthIn35mmFilm, GainControl, ImageUniqueID, MakerNoteDataOffset, Rendered, SceneCaptureType, SubjectDistanceRange, ThumbnailOrientation, ThumbnailResolution, and WhiteBalanceMode properties to TCustomExifData — all surface standard tags I missed out previously.
- JPEGHeader global routine to CCR.Exif.JPEGUtils as a more flexible replacement for ParseJPEGHeader; unlike the latter, it doesn’t take a callback method, being used instead with the for/in syntax.
- The jmExif constant in CCR.Exif.JPEGUtils — use jmApp1 instead. The reason for this change is that Exif and XMP segments share the same marker number; the value of what was jmExif, then, isn’t unique to Exif.
- DefJFIFData global variable in CCR.Exif.JPEGUtils — this hasn’t been used internally since v0.9.5.
- ParseJPEGHeader function in CCR.Exif.JPEGUtils — use JPEGHeader with a for/in loop instead.
- RemoveExifDataFromJPEG functions in CCR.Exif — use the new RemoveMetaDataFromJPEG functions instead. That said, a bug in the overload that takes a stream object has been fixed.
- WriteJPEGMarkerToStream procedures in CCR.Exif.JPEGUtils — renamed WriteJPEGSegmentToStream.
- Custom exception classes slightly rearranged and documented.
- JPEG Dump and Exif List demos updated slightly.
Not exactly a WTF — it’s more of a ‘I can’t believe how lazy they can be’, but as an appendix to my previous post, I’ve noticed that Windows Explorer and other MS apps always rewrite Exif segments in big endian byte order, even when they were originally little endian. A bit odd one might think, given Windows itself is little endian, though understandable to the extent that the JPEG format as a container is always big endian. Alas, but any unicode strings that MS apps write are always written out in little endian format. For the Microsoft-defined tags in the general section (‘main IFD’) this doesn’t cause a problem — for those, MS can define them how it wants! — but for the standard UserComment tag it arguably does. That said, whilst my own Exif code defaults to saving in whatever was the original byte order (and if the user so wishes, he or she can force either big or little endianness), for the UserComment tag specifically, I follow Windows in always outputting UTF-16LE.
Around the time of Vista’s release, a somewhat overexcited blog post by the tech journalist Ed Bott proclaimed the first of the then-new OS’ three ‘killer features’ was its read/write support for XMP metadata in JPEG and TIFF files. Given I want the writing side of my Exif code to work nicely with recent versions of Windows Explorer, I’ve been investigating what the latter’s shiny tagging UI actually does — and to be frank, I don’t find it especially pretty, even if it’s nowhere near as bad as what MS is capable of (the OLE document storage format anyone…?)