Exiv2/exiv2

Canon 1Ds thumbnail colour corrupted.

Opened this issue · 15 comments

8i8 commented

Describe the bug
I have been investigating a bug in darktable when using my canon 1Ds camera, the thumbnails for the cameras tiff format are auto extracted from the files by exiv2. The Images that are returned have a colour matrix problem, the highlights are out of gamut and apear to be overflowing into totaly different colour ranges; I suspect an issue with the word size.

To Reproduce
The same result can be reproduced by running exiv2 from the command line on a cannon native tif that contains the cameras raw data, using the -ep flags to extract a thumbnail.
exiv2 -ep
The resulting image contains the colour artefact.

Expected behaviour
I expected to obtain a preview image with the correct colours.

Desktop (please complete the following information):

  • OS: debian 9.8
  • Compiler & Version: gcc version 6.3.0 20170516 (Debian 6.3.0-18+deb9u1)
  • Compilation mode and/or compiler flags: dpkg 0.25-3.1+deb9u1

Additional context
The canon file contains a small tiff as a preview image, this displays correctly if I browse the files using the gnome desktop or open them with eye of gnome, a preview tiff is displayed correctly.
If I open the extracted preview with gimp it throws a warning that the file is in 16bit format that is not supported by gimp.
I have converted one of the generated previews in to a jpeg to display here.
20190604_0034-preview1

Thank you for your consideration.

Iain Hill

@8i8 Thank you for reporting this. Can you attach to original file and I will investigate. Have you investigated extracting the thumbnail with ExifTool?

I'm focused at the moment on releasing Exiv2 v0.27.2-RC1 by the end of this week and Exiv2 v0.27.2 by 2019-06-30. I've assigned this to Milestone v0.27.3 which is scheduled for 2019-09-30.

8i8 commented

That would be my pleasure, thank you for addressing this. I have not been able to extract a preview of a thumbnail image with ExifTool either. I have been trying to extract the image using libtiff and some simple C code but am very new to working with tiffs in this way and as such have not yet succeeded in this, I gathered so far that there is a small preview tiff in the first tiff directory which is the image that the OS is using, that the the raw data is is s second directory.

Please find attached the file that you have requested, I have simply changed the file extension from .TIF to .jpg so as to be able to upload it here.

20190604_0034

Thank you.

Thanks for attaching the file. I've reproduced your report.

My suspicion here is the the preview is BGR encoded instead of RGB encoded. In the preview, the strong red/purple is in the location the sand (yellow = R+G) in the original. Looking at the metadata in the preview/tiff:

574 rmills@rmillsmm-local:~/Downloads $ exiv2 -pa foo-preview1.tif 
Exif.Image.ImageWidth                        Short       1  168
Exif.Image.ImageLength                       Short       1  112
Exif.Image.BitsPerSample                     Short       3  16 16 16
Exif.Image.Compression                       Short       1  Uncompressed
Exif.Image.PhotometricInterpretation         Short       1  RGB  <--- This is suspicious
Exif.Image.StripOffsets                      Long        1  180
Exif.Image.SamplesPerPixel                   Short       1  3
Exif.Image.RowsPerStrip                      Short       1  112
Exif.Image.StripByteCounts                   Long        1  112896
Exif.Image.XResolution                       Rational    1  72
Exif.Image.YResolution                       Rational    1  72
Exif.Image.ResolutionUnit                    Short       1  inch
$ open

I've messed about with the extracted image. Exif.Image.PhotometricInterpretation is at byte 67.

582 rmills@rmillsmm-local:~/Downloads $ exiv2 -pR foo-preview1.tif 
STRUCTURE OF TIFF FILE (II): foo-preview1.tif
 address |    tag                              |      type |    count |    offset | value
      10 | 0x0100 ImageWidth                   |     SHORT |        1 |           | 168
      22 | 0x0101 ImageLength                  |     SHORT |        1 |           | 112
      34 | 0x0102 BitsPerSample                |     SHORT |        3 |       158 | 16 16 16
      46 | 0x0103 Compression                  |     SHORT |        1 |           | 1
      58 | 0x0106 PhotometricInterpretation    |     SHORT |        1 |           | 2  <-- 2 (byte 67) = RGB
      70 | 0x0111 StripOffsets                 |      LONG |        1 |           | 180
      82 | 0x0115 SamplesPerPixel              |     SHORT |        1 |           | 3
      94 | 0x0116 RowsPerStrip                 |     SHORT |        1 |           | 112
     106 | 0x0117 StripByteCounts              |      LONG |        1 |           | 112896
     118 | 0x011a XResolution                  |  RATIONAL |        1 |       164 | 72/1
     130 | 0x011b YResolution                  |  RATIONAL |        1 |       172 | 72/1
     142 | 0x0128 ResolutionUnit               |     SHORT |        1 |           | 2
END foo-preview1.tif
583 rmills@rmillsmm-local:~/Downloads $ 

I've tried other values (by editing with a binary editor) and some values cause the preview to be "psychedelic". I haven't found a setting to make it look correct. The values of PhotometricInterpretation are in the code in src/tags_int.cpp. There isn't a setting for BGR

If you have PhotoShop, I believe you can extract the 3 colour channels from the preview. Then create a new file using the three colour "plates". If you can do that, we'd know for certain that there's something odd about the colour encoding.

Can you say anything about how the file has been post-processed. Did this come directly from the Camera, or has any other software been editing the file?

8i8 commented

This is directly from the camera, I am using darktable which does not edit the images them selves and no other software has been used. I am using gimp as my image editor, which is indicating a bit depth error on opening, however it does open the file; I have no idea if I can do as you mention in gimp, will take a look and see if it is possible.

OK. So we've eliminated the possibility that the preview has been corrupted by post-processing. Gimp is very capable, so I think it will have a feature to do "plate separation" and recombination.

I didn't write the image preview code. In general Exiv2 knows nothing about pixels. It is focues on metadata and it's highly likely that it simply copies the preview image from the metadata without understanding what it means! It's likely that the preview image has been extracted correctly. That the extracted image looks wrong in a desktop image viewer is a surprise. Preview images are usually little JPEGs and here it's a little TIFF.

Why are you concerned about this?

8i8 commented

The concern is that darktable is using the image in its film strip for selection, which means that display is not working as it ought to on the light table and on import; I am looking for a solution to that. There are apparently some digital backs that have the same issue when using tiff/raw files too. But that is only hearsay on my part after chatting with a fellow photographer on irc. I just did a small job for a friend and it is a little awkward to explain the colouring when examining the contact sheet on import :)

8i8 commented

GNOME desktop is displaying the thumbs ok here, curious to know what it is ...
I have just tried on an image in gimp, using decompose followed by recompose has automatically repaired the colours as you have suspected, however there is a large part of the coloured data that is now black; I wonder if this is not due to the raw having 12bit colour depth or something like that? I will generate a thumb like this and convert it to jpg to display here.

8i8 commented

Ah no the colours in the first image that I tried were misleading as it had very little colour. Here are some thumbnails with the colours swapped as you mentioned, it does not appear to be the issue; What do you think?
20190604_0034-rgb-compose-blue-green-swap
20190604_0034-rgb-compose-red-blue-swap
20190604_0034-rgb-compose-red-green-swap
When I open the file with gimp, it gives me the choice between two images; The first image opens fine and is the thumbnail where as the second image opens with the bit bit depth warning, are we extracting from the first image or the second?
Here is the thumb from the first when simply opened with gimp:
20190604_0034-gimp-thumb
It is a larger size too, which leads me to wonder if we are extracting the thumbnail with exiv2 where gimp is opening a different directory?
IU have found some info on canons use of the tiff format and its tags here:
http://www.rags-int-inc.com/PhotoTechStuff/RawStandards/ShortCanon1DS.html
And had been reading about the tiffs use of directories here:
And managed to get the directory count using libtiff's TIFFReadDirectory() and then TIFFSetDirectory(), I don't know if this could be of any use or if you are using libtiff; I am not very familiar with c++ as yet.

GNOME desktop uses Exiv2 for metadata, so it almost certainly uses Exiv2 to extract the preview.

Exiv2 doesn't use LibTIFF, we have our own TIFF parser which was written by Andreas, the founder of Exiv2. I don't know why he didn't use LibTiff as it is a very good library.

If you're getting a larger thumbnail somewhere, I suspect the "big image" is being resampled. There's only one preview present and that's the 168x112 16bits/channel tiff.

You can dump the TiffDirectories and tags with tiffdump (or exiv2 -pS)

665 rmills@rmillsmbp:~/Downloads $ tiffdump foo.tif 
foo.tif:
Magic: 0x4d4d <big-endian> Version: 0x2a
Directory 0: offset 16 (0x10) next 175616 (0x2ae00)
SubFileType (254) LONG (4) 1<0>
ImageWidth (256) SHORT (3) 1<8193>
ImageLength (257) SHORT (3) 1<49152>
BitsPerSample (258) SHORT (3) 3<8 8 8>
Compression (259) SHORT (3) 1<256>
Photometric (262) SHORT (3) 1<512>
Make (271) ASCII (2) 6<Canon\0>
Model (272) ASCII (2) 14<Canon EOS-1DS\0>
StripOffsets (273) LONG (4) 1<2490368>
Orientation (274) SHORT (3) 1<256>
SamplesPerPixel (277) SHORT (3) 1<768>
RowsPerStrip (278) SHORT (3) 1<49152>
StripByteCounts (279) LONG (4) 1<8913408>
XResolution (282) RATIONAL (5) 1<72>
YResolution (283) RATIONAL (5) 1<72>
PlanarConfig (284) SHORT (3) 1<256>
ResolutionUnit (296) SHORT (3) 1<512>
DateTime (306) ASCII (2) 20<2019:06:04 08:40:30\0>
33723 (0x83bb) BYTE (1) 4255<0x1c 0x1 00 00 0x2 00 0x2 0x1c 0x1 0x5 0x4 00 00 00 00 00 00 00 00 00 00 00 00 00 ...>
34665 (0x8769) LONG (4) 1<3859873792>

Directory 1: offset 175616 (0x2ae00) next 0 (0)
ImageWidth (256) SHORT (3) 1<43008>
ImageLength (257) SHORT (3) 1<28672>
BitsPerSample (258) SHORT (3) 3<16 16 16>
Compression (259) SHORT (3) 1<256>
Photometric (262) SHORT (3) 1<512>
StripOffsets (273) LONG (4) 1<1085276672>
SamplesPerPixel (277) SHORT (3) 1<768>
RowsPerStrip (278) SHORT (3) 1<28672>
StripByteCounts (279) LONG (4) 1<12124416>
XResolution (282) RATIONAL (5) 1<72>
YResolution (283) RATIONAL (5) 1<72>
ResolutionUnit (296) SHORT (3) 1<512>
666 rmills@rmillsmbp:~/Downloads $ 

The Exiv2 equivalent produces much prettier output:

667 rmills@rmillsmbp:~/Downloads $ exiv2 -pS foo.tif 
STRUCTURE OF TIFF FILE (MM): foo.tif
 address |    tag                              |      type |    count |    offset | value
      18 | 0x00fe NewSubfileType               |      LONG |        1 |           | 0
      30 | 0x0100 ImageWidth                   |     SHORT |        1 |           | 288
      42 | 0x0101 ImageLength                  |     SHORT |        1 |           | 192
      54 | 0x0102 BitsPerSample                |     SHORT |        3 |       262 | 8 8 8
      66 | 0x0103 Compression                  |     SHORT |        1 |           | 1
      78 | 0x0106 PhotometricInterpretation    |     SHORT |        1 |           | 2
      90 | 0x010f Make                         |     ASCII |        6 |       268 | Canon
     102 | 0x0110 Model                        |     ASCII |       14 |       274 | Canon EOS-1DS
     114 | 0x0111 StripOffsets                 |      LONG |        1 |           | 9728
     126 | 0x0112 Orientation                  |     SHORT |        1 |           | 1
     138 | 0x0115 SamplesPerPixel              |     SHORT |        1 |           | 3
     150 | 0x0116 RowsPerStrip                 |     SHORT |        1 |           | 192
     162 | 0x0117 StripByteCounts              |      LONG |        1 |           | 165888
     174 | 0x011a XResolution                  |  RATIONAL |        1 |       290 | 72/1
     186 | 0x011b YResolution                  |  RATIONAL |        1 |       298 | 72/1
     198 | 0x011c PlanarConfiguration          |     SHORT |        1 |           | 1
     210 | 0x0128 ResolutionUnit               |     SHORT |        1 |           | 2
     222 | 0x0132 DateTime                     |     ASCII |       20 |       306 | 2019:06:04 08:40:30
     234 | 0x83bb IPTCNAA                      |      BYTE |     4255 |       326 | ............................... ...
     246 | 0x8769 ExifTag                      |      LONG |        1 |           | 4582
  175618 | 0x0100 ImageWidth                   |     SHORT |        1 |           | 168
  175630 | 0x0101 ImageLength                  |     SHORT |        1 |           | 112
  175642 | 0x0102 BitsPerSample                |     SHORT |        3 |    175766 | 16 16 16
  175654 | 0x0103 Compression                  |     SHORT |        1 |           | 1
  175666 | 0x0106 PhotometricInterpretation    |     SHORT |        1 |           | 2
  175678 | 0x0111 StripOffsets                 |      LONG |        1 |           | 176192
  175690 | 0x0115 SamplesPerPixel              |     SHORT |        1 |           | 3
  175702 | 0x0116 RowsPerStrip                 |     SHORT |        1 |           | 112
  175714 | 0x0117 StripByteCounts              |      LONG |        1 |           | 112896
  175726 | 0x011a XResolution                  |  RATIONAL |        1 |    175772 | 72/1
  175738 | 0x011b YResolution                  |  RATIONAL |        1 |    175780 | 72/1
  175750 | 0x0128 ResolutionUnit               |     SHORT |        1 |           | 2
END foo.tif
668 rmills@rmillsmbp:~/Downloads $ 

Here's a curiosity. The original image is MM encoded and the preview is II:

678 rmills@rmillsmbp:~/Downloads $ dmpf foo.tif | head -1
       0        0: MM.*............  ->  4d 4d 00 2a 00 00 00 10 ba b0 ac bb 00 02 ae 00
679 rmills@rmillsmbp:~/Downloads $ dmpf foo-preview1.tif | head -1
       0        0: II*.............  ->  49 49 2a 00 08 00 00 00 0c 00 00 01 03 00 01 00
680 rmills@rmillsmbp:~/Downloads $ 

However the preview is correctly II encoded, otherwise I couldn't print the structure correctly. However, the image is 16 bits per sample (2 bytes/pixel) Perhaps the pixels need to be byte-swapped when rewritten!

680 rmills@rmillsmbp:~/Downloads $ exiv2 -pS foo-preview1.tif 
STRUCTURE OF TIFF FILE (II): foo-preview1.tif
 address |    tag                              |      type |    count |    offset | value
      10 | 0x0100 ImageWidth                   |     SHORT |        1 |           | 168
      22 | 0x0101 ImageLength                  |     SHORT |        1 |           | 112
      34 | 0x0102 BitsPerSample                |     SHORT |        3 |       158 | 16 16 16
      46 | 0x0103 Compression                  |     SHORT |        1 |           | 1
      58 | 0x0106 PhotometricInterpretation    |     SHORT |        1 |           | 2
      70 | 0x0111 StripOffsets                 |      LONG |        1 |           | 180
      82 | 0x0115 SamplesPerPixel              |     SHORT |        1 |           | 3
      94 | 0x0116 RowsPerStrip                 |     SHORT |        1 |           | 112
     106 | 0x0117 StripByteCounts              |      LONG |        1 |           | 112896
     118 | 0x011a XResolution                  |  RATIONAL |        1 |       164 | 72/1
     130 | 0x011b YResolution                  |  RATIONAL |        1 |       172 | 72/1
     142 | 0x0128 ResolutionUnit               |     SHORT |        1 |           | 2
END foo-preview1.tif
681 rmills@rmillsmbp:~/Downloads $ 

I really don't know what's happening here. It would be interesting to get the code for the GNOME desktop and investigate how it works.

Anyway, I want to release Exiv2 v0.27.2-RC1 today or tomorrow and can't spend more time on this at the moment. I've set the milestone for this to v0.27.3 which is scheduled for 2019-09-30. If you make any discoveries about this, please let me know especially if you decide to close this issue.

The pixel byte-swap idea isn't good. The code in PreviewProperties LoaderTiff::getProperties() in src/preview.cpp#836 writes II files:

        TiffParser::encode(mio, 0, 0, Exiv2::littleEndian, preview, emptyIptc, emptyXmp);

I think it should "inherit" the encoding from the source image. Anyway, I hacked that to be bigEndian and extracted the preview from your MM file and the preview has been correctly written as MM. Sadly the image is black on my image viewer (Preview.app on MacOS-X).

A good idea which appears to be wrong!

8i8 commented

Thank you for the time that you have put into this already, sure I understand that you have other deadlines to meet and work to do. I am curious as to why there are two different sized images marked.
The thumb output by exif2 is 168 x 112px not the expected 288 x 192px ; Surely not the target preview image that is being defined above, it would appear that it is not the image preview that is 288 x 192 that is being delivered by exiv2?

I did notice in the tif spec or some where in one of the docs that there is a thumbnail image that is 168 x 112, as an inbuilt thumbnail device, if you will excuse the notion, and that the tif preview is a separate image altogether.

You are right. There seems to be another image which is identified by tiffinfo:

706 rmills@rmillsmbp:~/gnu/github/exiv2/0.27-maintenance/build $ tiffinfo ~/Downloads/foo.tif  | grep Image
TIFFReadDirectory: Warning, /Users/rmills/Downloads/foo.tif: wrong data type 1 for "RichTIFFIPTC"; tag ignored.
  Image Width: 288 Image Length: 192
  Image Width: 168 Image Length: 112
707 rmills@rmillsmbp:~/gnu/github/exiv2/0.27-maintenance/build $ 

Although I am an unpaid volunteer, there are people expecting the release to appear as scheduled. I regret that I can't spend more time on this at the moment.

8i8 commented

Thank you for looking at it now, I was not expecting you to do so so quickly and I appreciate it very much. I do understand your work load and am not expecting any immediate solution. It is a pleasure discussing this with you, who knows perhaps I will try and read some of the c++ code, it is all fantastic experience. If I can I will try to move further on the issue myself, when and if you have time any help will be greatly appreciated; No rush though.
I thank you for work that you have already done, It makes software like darktable run, which for me is a game changer as I now use only open source software.

I'm always happy to help. The days leading up to release are usually hectic because stuff left on the shelf demands attention. I'm glad you like open-source. The support is so much better than commercial alternatives and the price is right.

I've discuss Preview/Thumbnails in my book. This part of Exiv2 works well for thumbnails stored in the Exif metadata. However there are previews stored in other parts of the image. Different image formats (JPEG, PNG, DNG etc...) use format dependent mechanisms to store those preview/thumbnails. There is another open issue: #710 concerning this topic.

The work required to update all the image handlers is large and cannot be undertaken before Exiv2 v1.00 which is scheduled for 2021-12-15.