Search code examples
javaexifapache-commons-imaging

Write JPEG Exif DateTimeOriginal and TimeZoneOffset from scratch using Apache Commons Imaging


I have a JPEG file from which I have removed all metadata. Using Java with Apache Commons Imaging I want to add custom metadata to the JPEG from scratch. Using ExifRewriter().updateExifMetadataLossy(…) I have managed to update the following Exif tags because they are in IFD0:

  • ImageDescription (0x010E)
  • Artist (0x013B)
  • Copyright (0x8298)

I get IFD0 using getOrCreateRootDirectory(); using getOrCreateExifDirectory() doesn't seem to work if I'm creating metadata from scratch:

TiffOutputSet tiffOutputSet = new TiffOutputSet();
TiffOutputDirectory exifDirectory = tiffOutputSet.getOrCreateRootDirectory();
…
TagInfoAscii tagImageDescription = new TagInfoAscii("ImageDescription", 0x010E, -1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
…
exifDirectory.add(tagImageDescription, "foo bar")
…
new ExifRewriter().updateExifMetadataLossy(byteSource, outputStream, tiffOutputSet);

This is working but the last piece of (this section of the) puzzle is to add image creation timestamp information. This would be these Exif tags:

  • DateTimeOriginal (0x9003)
  • SubSecTimeOriginal (0x9291)
  • TimeZoneOffset (0x882a)

However these Exif tags don't seem to be in some other Exif directory. (Going from metadata-extractor, it would seem to be the "sub IDF" directory). But how do I get this other Exif SubIFD directory in Apache Commons Imaging so that I can add these tags? (Remember that I am writing all this metadata from scratch, not modifying metadata.)


Solution

  • From a separate answer I discovered that what I want is the method TiffOutputSet.getOrCreateExifDirectory(). Apparently Apache Commons Imaging uses its own naming convention:

    • IFD0: Apache Commons Imaging calls this the "root directory"
    • SubIFD: Apache Commons Imaging calls this the "Exif directory"

    It thus appears I can do this:

    TiffOutputSet tiffOutputSet = new TiffOutputSet();
    TiffOutputDirectory exifDirectory = tiffOutputSet.getOrCreateRootDirectory();
    TiffOutputDirectory subExifDirectory = tiffOutputSet.getOrCreateExifDirectory();
    …
    TagInfoAscii tagImageDescription = new TagInfoAscii("ImageDescription", 0x010E, -1, TiffDirectoryType.EXIF_DIRECTORY_IFD0);
    …
    exifDirectory.add(tagImageDescription, "foo bar")
    subExifDirectory.add(EXIF_TAG_DATE_TIME_ORIGINAL, dateString); //TODO format appropriately
    …
    new ExifRewriter().updateExifMetadataLossy(byteSource, outputStream, tiffOutputSet);