readme.fr

Hot opensource news

Decode EXIF from a raw photo

I’m writing a python script to sort my raw photos. Precisely group my HDR together. The idea is to read EXIF tags inside the raw file. And correlate them to group raw photo for each HDR.

canon-raw-RAW_Quality

I started to use rawkit (https://rawkit.readthedocs.org/en/latest/) but the values of Exif tags I was looking for was not really great.

Someone suggest me to use ExifRead library to read Exif tags in a raw file. In fact it’s a better choice, I’m writting a python script. With ExifRead no need of extra C library dependency.

Python ExifRead provide EXIF.py script to output Exif tags.

EXIF.py 100EOS5D/IMG_8813.CR2

EXIF ApertureValue (Ratio): 3
EXIF DateTimeOriginal (ASCII): 2015:11:08 20:55:05
EXIF FocalLength (Ratio): 24
MakerNote LensModel (ASCII): EF24-70mm f/2.8L II, ... ]
EXIF ISOSpeedRatings (Short): 400
EXIF ExposureTime (Ratio): 1/50
EXIF FNumber (Ratio): 14/5
...
EXIF.py

I was looking for 4 things

  • Iso
  • Exposure time
  • Aperture
  • Date

Unfortunately the value for aperture seems wrong (3 instead of 2.8).

My photo was taken with a 2.8 aperture. I first thought : maybe a rounded value on this flag, it’s a dumb error. I decided to try to find myself the value in the raw file to know what’s going on.

Reading this excellent link Understanding What is stored in a Canon RAW .CR2 file, How and Why, I found the graal to decode a raw file cr2_poster.pdf

At this point, I thought the best value I could get was in my canon specific MakerNote section on the FNumber value. (All values description is here canon_tags)

Tag Id : 3 (In fact 0x0003 that you write 0x3) 
Name : FNumber
canon tag

I opened the file with an Hexa editor (hexedit) and … I was totally lost.

hexedit 100EOS5D/IMG_8813.CR2
hexedit 100EOS5D/IMG_8813.CR2

Key things you need to remember to decode the file :

  • 1) An offset is a address in the file that will contain your value.

hexa

  • 2) Read : C8 05 in the file sould be read 05C8. Example for an offset, the address is 0x5C8

offset

With that, found the Canon MakeNote section is easy.

The quick way is to search directly the 0x927c MarkerNote (so in the file 7C 92) flag that contain the address of the MakerNote section. If you are not able to found that, go throught the IFD section to find the EXIF subsection. And then in that subsection you will find the MakerNote section

Tag     Type   Count        Value
7C 92   07 00  B8 A0 00 00  84 03 00 00
7C 92 07 00 B8 A0 00 00 84 03 00 00

The content is an offset : 84 03 00 00 -> 00 00 03 84 (0x384 address)

Go to this address and search in the MakerNote section the FNumber 0x3

Tag     Type   Count        Value
03 00   03 00  04 00 00 00  C8 05  00 00
03 00 03 00 04 00 00 00 C8 05 00 00

Go to the offset 0x5C8 to find our value (count 4 x type 3 ushort, 16 bits)

0x5C8 : 00 00 00 00  00 00 00 00
0x5C8 : 00 00 00 00 00 00 00 00

And … fail, in fact my canon does not filled this section.

Reading Metadata reference tables for  http://www.exiv2.org/tags.html The FNumber can be found also in standard EXIF subsection.

Let’s try to do the same process to read FNumber in the EXIF subsection “0x829d Exif.Image.FNumbertype 5 Rational” Rational type is composed of 64 bits (numerator and denominator ulongs) Rational_data_type

Tag     Type   Count        Value
9D 82   05 00  01 00 00 00  34 03 00 00
9D 82 05 00 01 00 00 00 34 03 00 00

And then read the 0x334 offset

1C 00 00 00  0A 00 00 00
1C 00 00 00 0A 00 00 00

As we can read in Hexa : 0x1C / 0XA In decimal, do the math : 28/10 = 14/5 = 2.8

Wow, that explain a log this Verify I have this :

EXIF.py 100EOS5D/IMG_8813.CR2 -vv | grep -i 14/5
EXIF FNumber (Ratio): 14/5
EXIF.py

I was looking for 2.8 float and this value is stored in fractional format. So the library don’t convert this value in float, just simplify the fraction.

This is why we have 14/5 and not 2.8 as expected.

Now it’s time to code :

import exifread

with open('100EOS5D/%s' % _file, 'rb') as f:
  # Return Exif tags
  tags = exifread.process_file(f)

  print tags.get('EXIF ISOSpeedRatings').printable
  print tags.get('EXIF FNumber').printable
  ...
python code

And Voila !

gaelL
gaelL on GithubgaelL on LinkedingaelL on Wordpress

, , , ,

Leave a Reply

Your email address will not be published. Required fields are marked *