Share

EXIF.py

Tracker: Bugs

8 Fails to read iPhoto-edited header and other complex headers - ID: 2685159
Last Update: Comment added ( nobody )

After editing a JPEG file in iPhoto 08, the EXIF data is not found by
EXIF.py. The data is still there, but the EXIF header is shifted further
down the header package and EXIF.py only seems to look at a fixed location
in the file. (In the specific case of iPhoto IPTC data is shifted before
regular EXIF data and EXIF.py thus fails to "find" the EXIF.) I believe
this also causes iPhoto-edited EXIF to fail to be found on some web sites,
suggesting they also use EXIF.py

The fix is to use a more complex parse of the EXIF JPEG file headers and/or
APP segments. I don't have the docs handy to specify how this needs to be
done. An image is attached that illustrates this.


dude_5 ( g501 ) - 2009-03-12 14:11

8

Open

None

Nobody/Anonymous

None

None

Public


Comments ( 2 )




Date: 2009-08-30 15:26
Sender: nobody

A similar problem occurs when pyexiv2 is used to add a comment to an image.

After this EXIF.py is unbale to parse the EXIF header. Also when I use
file to identify the file type I notice that it no longer recognizes the
EXIF header:
Before adding the comment:
DSC02299.JPG: JPEG image data, EXIF standard 2.21

And after adding a comment:

[m8ram@minastirith 23]$ python
Python 2.5.2 (r252:60911, Sep 30 2008, 15:42:03)
[GCC 4.3.2 20080917 (Red Hat 4.3.2-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyexiv2
>>> imgExifv2 = pyexiv2.Image('DSC02299.JPG')
>>> imgExifv2.readMetadata()
>>> newComment = imgExifv2.getComment()
>>> print newComment

>>> newComment = 'Original file name: DSC02299.JPG'
>>> imgExifv2.setComment(newComment)
>>> imgExifv2.writeMetadata()
>>>
[m8ram@minastirith 23]$ file *
DSC02299.JPG: JPEG image data

When I use jhead to add the comment the EXIF header is still recognized by
file and can still be read using EXIF.py.

Tools like jhead and gthumb still display them but it breaks anything
relying on EXIF.py

The attached patch does not resolve this issue.


Date: 2009-03-13 01:46
Sender: g501SourceForge.net Donor

I have a fix. I believe the problem arises if the APP2 segment comes before
APP1. The fix is as follows (a context diff).
I am also attached a fixed version of EXIF.py. Greg Dudek.

*** /Users/dudek/Code/Interest/EXIF.py 2009-03-12 21:46:11.000000000
-0400
--- EXIF.py 2009-03-12 21:45:34.000000000 -0400
***************
*** 4,10 ****
# Library to extract EXIF information from digital camera image files
# http://sourceforge.net/projects/exif-py/
#
! # VERSION 1.1.0
#
# To use this library call with:
# f = open(path_name, 'rb')
--- 4,10 ----
# Library to extract EXIF information from digital camera image files
# http://sourceforge.net/projects/exif-py/
#
! # VERSION 1.1.1
#
# To use this library call with:
# f = open(path_name, 'rb')
***************
*** 1615,1633 ****
elif data[0:2] == '\xFF\xD8':
# it's a JPEG file
if debug: print "JPEG format recognized."
while data[2] == '\xFF' and data[6:10] in ('JFIF', 'JFXX',
'OLYM', 'Phot'):
length = ord(data[4])*256+ord(data[5])
f.read(length-8)
# fake an EXIF beginning of file
data = '\xFF\x00'+f.read(10)
fake_exif = 1
! if data[2] == '\xFF' and data[6:10] == 'Exif':
# detected EXIF header
offset = f.tell()
endian = f.read(1)
else:
# no EXIF information
if debug: print "no EXIF header"
return {}
else:
# file format not recognized
--- 1615,1668 ----
elif data[0:2] == '\xFF\xD8':
# it's a JPEG file
if debug: print "JPEG format recognized."
+ base = 0
while data[2] == '\xFF' and data[6:10] in ('JFIF', 'JFXX',
'OLYM', 'Phot'):
length = ord(data[4])*256+ord(data[5])
f.read(length-8)
# fake an EXIF beginning of file
data = '\xFF\x00'+f.read(10)
fake_exif = 1
! base = base + length
!
! # Big ugly patch to deal with APP2 (or other) data coming before
APP1
! f.seek(0)
! data = f.read(base+4000) # in theory, this could be insufficient
--gd
! base = 2
! while 1:
! if data[base:base+2]=='\xFF\xE1':
! # APP1
! #print "APP1 at base",hex(base)
! #print "Length",hex(ord(data[base+2])),
hex(ord(data[base+3]))
! #print "Code",data[base+4:base+8]
! if data[base+4:base+8] == "Exif":
! base = base-2
! break
! base=base+ord(data[base+2])*256+ord(data[base+3])+2
! elif data[base:base+2]=='\xFF\xE2':
! # APP2
! #print "APP2 at base",hex(base)
! #print "Length",hex(ord(data[base+2])),
hex(ord(data[base+3]))
! #print "Code",data[base+4:base+8]
! base=base+ord(data[base+2])*256+ord(data[base+3])+2
! elif data[base:base+2]=='\xFF\xE0':
! # APP0
! #print "APP0 at base",hex(base)
! #print "Length",hex(ord(data[base+2])),
hex(ord(data[base+3]))
! #print "Code",data[base+4:base+8]
! base=base+ord(data[base+2])*256+ord(data[base+3])+2
! else:
! break
!
! f.seek(base+12)
! if data[2+base] == '\xFF' and data[6+base:10+base] == 'Exif':
# detected EXIF header
offset = f.tell()
endian = f.read(1)
+ #HACK TEST: endian = 'M'
else:
# no EXIF information
if debug: print "no EXIF header"
+ if debug: print "Had",hex(ord(data[2+base])) , "and",
data[6+base:10+base]
return {}
else:
# file format not recognized


File Added: EXIF.py


Log in to comment.

Attached Files ( 2 )

Filename Description Download
EXIF.py Fixed version of EXIF.py as per patch above Download
ihaveexif.jpg Image with EXIF data that is not detected/parsed Download

Changes ( 3 )

Field Old Value Date By
File Added 317613: EXIF.py 2009-03-13 01:46 g501
priority 5 2009-03-12 14:12 g501
File Added 317533: ihaveexif.jpg 2009-03-12 14:11 g501