I'm writing python script and I need to obtain exif information from raw photo file (.CR2 for example).
I found Python Rawkit offer the ability to do that.
with Raw(filename=image_path) as raw:
print raw.metadata
Metadata(aperture=-1.2095638073643314e+38, timestamp=4273602232L,
shutter=-1.1962713245823862e+38, flash=True,
focal_length=-1.2228562901462766e+38, height=3753,
iso=-1.182978841800441e+38,
make='Canon', model='EOS 5D Mark II',
orientation=0, width=5634)
But I'm a little bit confused, how read this values ?. For example I'm expecting iso value like 100/200/400 but what is -1.182978841800441e+38 ?
My question is not specific for iso, it's also for shutter, aperture, ...
I ckecked libraw and rawkit doc but was not able to find how read / convert this kind of values.
This part in the doc is not very detailed :
float iso_speed;
ISO sensitivity.
float shutter;
Shutter speed.
Can someone help me understand how to read these values?
Thanks
[Update]
As neo suggest, I will use ExifRead. In fact it's a better choice, I'm writting a python script. With ExifRead no need of extra C library dependency.
I was able to open Canon raw file and parse Exif but unfortunately facing a wrong value for the aperture :
EXIF ApertureValue (Ratio): 3
# My photo was taken in 2.8 (maybe a rounded value on this flag ?)
Quick answer : use Fnumber flag
EXIF FNumber (Ratio): 14/5
14/5 is in fact 2.8 (do the math)
Long answer (how I found / debug that) :
Reading this exelent link Understanding What is stored in a Canon RAW .CR2
file, How and Why ( http://lclevy.free.fr/cr2/ ) I decided to decode myself and know what is going on.
This link send me on the graal to decode a raw file cr2_poster.pdf From that I thought the best value seems to be 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
I opened my file with an Hexa editor (hexedit) and ... I was totally lost.
Key things :
C8 05
in the file should be read 05C8
. Example for an offset, the address is 0x5C8
With that found the MakeNote section is easy.
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
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
Go to the offset 0x5C8
to find our value (count 4 x type 3 ushort, 16 bits)
0x0x5C8 : 00 00 00 00 00 00 00 00
And ... fail, in fact my canon does not filled this section.
Reading http://www.exiv2.org/tags.html The FNumber can be found in EXIF subsection.
Do the same process to find the EXIF subsection and the tag "0x829d Exif.Image.FNumber
type 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
And then read the 0x334
offset
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
Verify I have this value in ExifRead
EXIF.py 100EOS5D/IMG_8813.CR2 -vv | grep -i 14/5
EXIF FNumber (Ratio): 14/5
And voila !
I was looking for 2.8
float and this value is stored in fraction format. So the library don't do the math and just simplify the fraction.
This is why we have 14/5
and not 2.8
as expected.
I suggest you use a library that is focused on EXIF reading. The stuff available in libraw/rawkit is really just a nice extra. I can recommend the ExifRead library. It's pure Python and also damn fast. And it gives you better to understand values.
If compatibility with many formats is more of an issue to you than performance you could call exiftool as a subprocess with -j option to give you a json string which you can turn into a dictionary.
That should set you up for most raw formats and even stuff that isn't images at all. And it is going to squeeze every last bit of exif info out of the file. However in comparison with other options it is rather sluggish (like 200x slower):
from PIL import Image
import PIL.ExifTags
import subprocess
import json
import datetime
import exifread
filePath = "someImage.jpg"
filePath = "someRawImage.CR2"
filePath = "someMovie.mov"
filePath = "somePhotoshopImage.psd"
try:
start = datetime.datetime.now()
img = Image.open(filePath)
exif_0 = {
PIL.ExifTags.TAGS[k]: v
for k, v in img.getexif().items()
if k in PIL.ExifTags.TAGS
}
end = datetime.datetime.now()
print("Pillow time:")
print(end-start)
print(str(len(exif_0)), "tags retrieved")
print (exif_0, "\n")
except:
pass
try:
start = datetime.datetime.now()
exif_1 = json.loads(subprocess.run(["/usr/local/bin/exiftool", "-j", filePath], stdout=subprocess.PIPE).stdout.decode("utf-8"))
end = datetime.datetime.now()
print("subprocess time:")
print(end-start)
print(str(len(exif_1[0])), "tags retrieved")
print(exif_1, "\n")
except:
pass
try:
start = datetime.datetime.now()
f = open(filePath, "rb")
exif_2 = exifread.process_file(f)
end = datetime.datetime.now()
print("Exifread time:")
print(end-start)
print(str(len(exif_2)), "tags retrieved")
print(exif_2, "\n")
except:
pass
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With