A request for help: TIFF writing

I guess your problem is coming from the thumbnail(s) in the RAW file. I had to deal with the same problem in photoflow, and came up with a pretty simple solution with EXIV2. You can check the lines of code starting from here.

Hope this helps!

2 Likes

Interestingly, it didn’t help. I guess I’ll have to list all the tags and see which ones cause problems…

You might want to look at darktable/exif.cc at master · darktable-org/darktable · GitHub and grep for dt_remove_exif_keys in there. We have a few places with lists of EXIF tags that may not be written to the exported images.

1 Like

I, uh, finally got around to implementing this exif cleanup from darktable, but it seems like when I write exif data to a TIFF it still ends up having 4 subimages of some sort.

Unlike before, where the first image was the good one and the other three weren’t, now the first two both contain the full image, the third one is a corrupt thumbnail (below), and the fourth simply crashes GIMP.

At this point I’m not sure what to do besides disable TIFF exif writing again. The TIFFs crash Photoshop, which is obviously not desirable behavior.

Right now, I just use the rather dodge-ily-documented libtiff extensions to write a limited bit of exif:

Are you using exiv2?

Yeah, I’m using exiv2. From what I gather it’s incompatible with libtiff.

I’ll try your method tonight probably.

There is also a line in dt saying you cannot write metadata via Exiv2 to an open TIFF file, you have to close it first and do it in a second pass. Or rather, you cannot write to a multi-page file, so you have to close after the first page, then add Exif, then append other pages.

I’m getting a few errors.

libtiff complains “cannot modify tag Compression while writing” even though I’m not modifying the tag.

The TIFFSetDirectory and TIFFSetField calls fail too, with libtiff complaining “unknown tag 34665” which is the TIFFTAG_EXIFIFD as in your code.

Any ideas?

Hmmm… I’m gonna guess right now that what you’re experiencing has to do with something you’re doing that I’m not doing before line 230… :slight_smile:

I offer very few options for writing TIFFs, and compression is not one of them. Just a guess.

Back to exiv2, my understanding of its operation is that you build a data structure with the tags you want, then you apply that data structure to the image file with code that looks like this:

Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(file);
image->setExifData(exifData);
image->writeMetadata();

from Exiv2 - Image metadata library and tools

This is creating new subimages in the file?

Or something. I do not understand why it does this.

In any case, I got your method working to write the basic exposure info, thanks a lot!

After digging into the whole metadata thing a couple of years ago, I decided to rely on the raw file as the canonical source for all data related to the capture, and store only exposure information, if that, in my renditions. I used the various image libraries’ metadata writing functions, although jpeg and png required supplementary support to organize the tags in the IFDs.

The one bit of crucial metadata in my little world is the processing toolchain that describes how the rendition is produced from the source (raw) file, and I currently store that in EXIF:ImageDescription. One day I’ll explore using the XMP tags, but that’s a low priority right now.

I fiddled a bit with exiv2 in considering it for the upcoming rawproc 1.0. The main challenge was replacing or complementing all use of my image data C++ map structure, which also gets stuff like libraw-collected information and things I use internally. I’ll probably revisit when I resume consideration of how to embed the toolchain…

@ggbutcher

Seems like your TIFF writing code puts a floating point as the EXIF shutter speed tag, which should be rational…

I’m going to have to figure out how darktable manages to use exiv2 on TIFFs without breaking all sorts of things.

Ah, a to-do I’d forgotten about. I’m fairly certain liftoff has a way to write rationals, will try to look it up, seems we have internet at cabin-in-the-woods now…

I also think both libtiff or exiv2 should handle this for you transparently…

E.g. TIFFTAG_XRESOLUTION is a RATIONAL, but TIFFSetField understands if (or even expects?) a float is passed as the argument.

1 Like

I think Exiv2 works alright, as long as I don’t try and copy allllll the EXIF data over.

For now I’m trying copying just the same 4, using Exiv2, and it seems to work, but I don’t have Photoshop to check for crashes…

I’d let L48-L58 be handled by exiv2 as well, you only need the libtiff lines above to define the image content/format before writing out the buffers.

As for what is “minimal” (and wether it goes into Exif.Image/IFD0 vs Exif.Photo/ExifIFD), just check Tables 17 and 18 in the Exif spec for what is mandatory.

Back from cabin-in-the-woods, where the internet proved to be another kind of dodgy…

  1. Inspecting my code brought forth recall of the original development journey. I remember now thinking, “nice, libtiff doesn’t require formatting a rational”, so I just let it save my internal float value thinking it would handle the dirty work. Bad assumption…

  2. Thinking about your original problem, based on my present understanding of exiv2 it now seems you were using the Exiv2 data structure you originally read from the input file, which for a raw would have contained the IFDs with the ancilliary renditions, thumbnails, embededd JPEGs, etc. Starting with a new Exiv2 instance and populating it for export should be alleviating that.

  3. Got me to re-consider using exiv2, but I’m coming back to the same conclusion: for renditions, I don’t want to pass on much past shutterspeed/aperture/ISO/date, and feel compelled to include orientation/photometricinterpretation for interoperability. Accordingly, I’m going to fix my present use of the libtiff/jpeg/png libraries (particularly exposuretime as a rational in TIFF) instead of using another library. If this doesn’t meet some ‘standard’ or other expectation, well, my first priority isn’t a customer base, anyway…

After investigation, it appears libtiff is writing a rational, exiftool -v confirms that.:

  | + [ExifIFD directory with 4 entries]
  | | 0)  ExposureTime = 0.001333329827 (5726608/4294967295)
  | | 1)  FNumber = 8 (8/1)
  | | 2)  ISO = 560
  | | 3)  FocalLength = 105 (105/1)

Not a pretty rational, but it is equivalent to 1/750sec…

Ah, so it’s just some applications not reading it correctly.

I did recall some people online mentioning that libtiff doesn’t do it very cleanly…