|
|
@ -97,7 +97,7 @@ EXIF_TAGS={
|
|
|
|
0x010F: ('Make', ),
|
|
|
|
0x010F: ('Make', ),
|
|
|
|
0x0110: ('Model', ),
|
|
|
|
0x0110: ('Model', ),
|
|
|
|
0x0111: ('StripOffsets', ),
|
|
|
|
0x0111: ('StripOffsets', ),
|
|
|
|
0x0112: ('Qt::Orientation', ),
|
|
|
|
0x0112: ('Orientation', ),
|
|
|
|
0x0115: ('SamplesPerPixel', ),
|
|
|
|
0x0115: ('SamplesPerPixel', ),
|
|
|
|
0x0116: ('RowsPerStrip', ),
|
|
|
|
0x0116: ('RowsPerStrip', ),
|
|
|
|
0x0117: ('StripByteCounts', ),
|
|
|
|
0x0117: ('StripByteCounts', ),
|
|
|
@ -631,7 +631,7 @@ MAKERNOTE_CANON_TAG_0x004={
|
|
|
|
def s2n_motorola(str):
|
|
|
|
def s2n_motorola(str):
|
|
|
|
x=0
|
|
|
|
x=0
|
|
|
|
for c in str:
|
|
|
|
for c in str:
|
|
|
|
x=(long(x) << 8) | ord(c)
|
|
|
|
x=(int(x) << 8) | ord(c)
|
|
|
|
return x
|
|
|
|
return x
|
|
|
|
|
|
|
|
|
|
|
|
# extract multibyte integer in Intel format (big endian)
|
|
|
|
# extract multibyte integer in Intel format (big endian)
|
|
|
@ -707,7 +707,7 @@ class EXIF_header:
|
|
|
|
val=s2n_motorola(slice)
|
|
|
|
val=s2n_motorola(slice)
|
|
|
|
# Sign extension ?
|
|
|
|
# Sign extension ?
|
|
|
|
if signed:
|
|
|
|
if signed:
|
|
|
|
msb=1L << (8*length-1)
|
|
|
|
msb=1 << (8*length-1)
|
|
|
|
if val & msb:
|
|
|
|
if val & msb:
|
|
|
|
val=val-(msb << 1)
|
|
|
|
val=val-(msb << 1)
|
|
|
|
return val
|
|
|
|
return val
|
|
|
@ -750,8 +750,7 @@ class EXIF_header:
|
|
|
|
field_type=self.s2n(entry+2, 2)
|
|
|
|
field_type=self.s2n(entry+2, 2)
|
|
|
|
if not 0 < field_type < len(FIELD_TYPES):
|
|
|
|
if not 0 < field_type < len(FIELD_TYPES):
|
|
|
|
# unknown field type
|
|
|
|
# unknown field type
|
|
|
|
raise ValueError, \
|
|
|
|
raise ValueError('unknown type %d in tag 0x%04X' % (field_type, tag))
|
|
|
|
'unknown type %d in tag 0x%04X' % (field_type, tag)
|
|
|
|
|
|
|
|
typelen=FIELD_TYPES[field_type][0]
|
|
|
|
typelen=FIELD_TYPES[field_type][0]
|
|
|
|
count=self.s2n(entry+4, 4)
|
|
|
|
count=self.s2n(entry+4, 4)
|
|
|
|
offset=entry+8
|
|
|
|
offset=entry+8
|
|
|
@ -807,8 +806,8 @@ class EXIF_header:
|
|
|
|
values, field_offset,
|
|
|
|
values, field_offset,
|
|
|
|
count*typelen)
|
|
|
|
count*typelen)
|
|
|
|
if self.debug:
|
|
|
|
if self.debug:
|
|
|
|
print ' %s: %s' % (tag_name,
|
|
|
|
print(' %s: %s' % (tag_name,
|
|
|
|
repr(self.tags[ifd_name+' '+tag_name]))
|
|
|
|
repr(self.tags[ifd_name+' '+tag_name])))
|
|
|
|
|
|
|
|
|
|
|
|
# extract uncompressed TIFF thumbnail (like pulling teeth)
|
|
|
|
# extract uncompressed TIFF thumbnail (like pulling teeth)
|
|
|
|
# we take advantage of the pre-existing layout in the thumbnail IFD as
|
|
|
|
# we take advantage of the pre-existing layout in the thumbnail IFD as
|
|
|
@ -920,7 +919,7 @@ class EXIF_header:
|
|
|
|
for i in (('MakerNote Tag 0x0001', MAKERNOTE_CANON_TAG_0x001),
|
|
|
|
for i in (('MakerNote Tag 0x0001', MAKERNOTE_CANON_TAG_0x001),
|
|
|
|
('MakerNote Tag 0x0004', MAKERNOTE_CANON_TAG_0x004)):
|
|
|
|
('MakerNote Tag 0x0004', MAKERNOTE_CANON_TAG_0x004)):
|
|
|
|
if self.debug:
|
|
|
|
if self.debug:
|
|
|
|
print ' SubMakerNote BitSet for ' +i[0]
|
|
|
|
print(' SubMakerNote BitSet for ' +i[0])
|
|
|
|
self.canon_decode_tag(self.tags[i[0]].values, i[1])
|
|
|
|
self.canon_decode_tag(self.tags[i[0]].values, i[1])
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
@ -937,7 +936,7 @@ class EXIF_header:
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
val=value[i]
|
|
|
|
val=value[i]
|
|
|
|
if self.debug:
|
|
|
|
if self.debug:
|
|
|
|
print ' '+name+':', val
|
|
|
|
print(' '+name+':', val)
|
|
|
|
self.tags['MakerNote '+name]=val
|
|
|
|
self.tags['MakerNote '+name]=val
|
|
|
|
|
|
|
|
|
|
|
|
# process an image file (expects an open file object)
|
|
|
|
# process an image file (expects an open file object)
|
|
|
@ -973,7 +972,7 @@ def process_file(file, debug=0, noclose=0):
|
|
|
|
|
|
|
|
|
|
|
|
# deal with the EXIF info we found
|
|
|
|
# deal with the EXIF info we found
|
|
|
|
if debug:
|
|
|
|
if debug:
|
|
|
|
print {'I': 'Intel', 'M': 'Motorola'}[endian], 'format'
|
|
|
|
print({'I': 'Intel', 'M': 'Motorola'}[endian], 'format')
|
|
|
|
hdr=EXIF_header(file, endian, offset, debug)
|
|
|
|
hdr=EXIF_header(file, endian, offset, debug)
|
|
|
|
ifd_list=hdr.list_IFDs()
|
|
|
|
ifd_list=hdr.list_IFDs()
|
|
|
|
ctr=0
|
|
|
|
ctr=0
|
|
|
@ -986,7 +985,7 @@ def process_file(file, debug=0, noclose=0):
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
IFD_name='IFD %d' % ctr
|
|
|
|
IFD_name='IFD %d' % ctr
|
|
|
|
if debug:
|
|
|
|
if debug:
|
|
|
|
print ' IFD %d (%s) at offset %d:' % (ctr, IFD_name, i)
|
|
|
|
print(' IFD %d (%s) at offset %d:' % (ctr, IFD_name, i))
|
|
|
|
hdr.tags['Exif Offset'] = offset
|
|
|
|
hdr.tags['Exif Offset'] = offset
|
|
|
|
hdr.tags['Exif Endian'] = endian
|
|
|
|
hdr.tags['Exif Endian'] = endian
|
|
|
|
hdr.tags[IFD_name+' IFDOffset'] = i
|
|
|
|
hdr.tags[IFD_name+' IFDOffset'] = i
|
|
|
@ -995,28 +994,28 @@ def process_file(file, debug=0, noclose=0):
|
|
|
|
exif_off=hdr.tags.get(IFD_name+' ExifOffset')
|
|
|
|
exif_off=hdr.tags.get(IFD_name+' ExifOffset')
|
|
|
|
if exif_off:
|
|
|
|
if exif_off:
|
|
|
|
if debug:
|
|
|
|
if debug:
|
|
|
|
print ' EXIF SubIFD at offset %d:' % exif_off.values[0]
|
|
|
|
print(' EXIF SubIFD at offset %d:' % exif_off.values[0])
|
|
|
|
hdr.dump_IFD(exif_off.values[0], 'EXIF')
|
|
|
|
hdr.dump_IFD(exif_off.values[0], 'EXIF')
|
|
|
|
# Interoperability IFD contained in EXIF IFD
|
|
|
|
# Interoperability IFD contained in EXIF IFD
|
|
|
|
#intr_off=hdr.tags.get('EXIF SubIFD InteroperabilityOffset')
|
|
|
|
#intr_off=hdr.tags.get('EXIF SubIFD InteroperabilityOffset')
|
|
|
|
intr_off=hdr.tags.get('EXIF InteroperabilityOffset')
|
|
|
|
intr_off=hdr.tags.get('EXIF InteroperabilityOffset')
|
|
|
|
if intr_off:
|
|
|
|
if intr_off:
|
|
|
|
if debug:
|
|
|
|
if debug:
|
|
|
|
print ' EXIF Interoperability SubSubIFD at offset %d:' \
|
|
|
|
print(' EXIF Interoperability SubSubIFD at offset %d:' \
|
|
|
|
% intr_off.values[0]
|
|
|
|
% intr_off.values[0])
|
|
|
|
hdr.dump_IFD(intr_off.values[0], 'EXIF Interoperability',
|
|
|
|
hdr.dump_IFD(intr_off.values[0], 'EXIF Interoperability',
|
|
|
|
dict=INTR_TAGS)
|
|
|
|
dict=INTR_TAGS)
|
|
|
|
# deal with MakerNote contained in EXIF IFD
|
|
|
|
# deal with MakerNote contained in EXIF IFD
|
|
|
|
if hdr.tags.has_key('EXIF MakerNote'):
|
|
|
|
if 'EXIF MakerNote' in hdr.tags:
|
|
|
|
if debug:
|
|
|
|
if debug:
|
|
|
|
print ' EXIF MakerNote SubSubIFD at offset %d:' \
|
|
|
|
print(' EXIF MakerNote SubSubIFD at offset %d:' \
|
|
|
|
% intr_off.values[0]
|
|
|
|
% intr_off.values[0])
|
|
|
|
hdr.decode_maker_note()
|
|
|
|
hdr.decode_maker_note()
|
|
|
|
# GPS IFD
|
|
|
|
# GPS IFD
|
|
|
|
gps_off=hdr.tags.get(IFD_name+' GPSInfoOffset')
|
|
|
|
gps_off=hdr.tags.get(IFD_name+' GPSInfoOffset')
|
|
|
|
if gps_off:
|
|
|
|
if gps_off:
|
|
|
|
if debug:
|
|
|
|
if debug:
|
|
|
|
print ' GPS SubIFD at offset %d:' % gps_off.values[0]
|
|
|
|
print(' GPS SubIFD at offset %d:' % gps_off.values[0])
|
|
|
|
hdr.dump_IFD(gps_off.values[0], 'GPS', dict=GPS_TAGS)
|
|
|
|
hdr.dump_IFD(gps_off.values[0], 'GPS', dict=GPS_TAGS)
|
|
|
|
ctr+=1
|
|
|
|
ctr+=1
|
|
|
|
|
|
|
|
|
|
|
@ -1035,7 +1034,7 @@ def process_file(file, debug=0, noclose=0):
|
|
|
|
|
|
|
|
|
|
|
|
# Sometimes in a TIFF file, a JPEG thumbnail is hidden in the MakerNote
|
|
|
|
# Sometimes in a TIFF file, a JPEG thumbnail is hidden in the MakerNote
|
|
|
|
# since it's not allowed in a uncompressed TIFF IFD
|
|
|
|
# since it's not allowed in a uncompressed TIFF IFD
|
|
|
|
if not hdr.tags.has_key('JPEGThumbnail'):
|
|
|
|
if 'JPEGThumbnail' not in hdr.tags:
|
|
|
|
thumb_off=hdr.tags.get('MakerNote JPEGThumbnail')
|
|
|
|
thumb_off=hdr.tags.get('MakerNote JPEGThumbnail')
|
|
|
|
if thumb_off:
|
|
|
|
if thumb_off:
|
|
|
|
file.seek(offset+thumb_off.values[0])
|
|
|
|
file.seek(offset+thumb_off.values[0])
|
|
|
@ -1050,21 +1049,21 @@ if __name__ == '__main__':
|
|
|
|
import sys
|
|
|
|
import sys
|
|
|
|
|
|
|
|
|
|
|
|
if len(sys.argv) < 2:
|
|
|
|
if len(sys.argv) < 2:
|
|
|
|
print 'Usage: %s files...\n' % sys.argv[0]
|
|
|
|
print('Usage: %s files...\n' % sys.argv[0])
|
|
|
|
sys.exit(0)
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
|
|
|
|
for filename in sys.argv[1:]:
|
|
|
|
for filename in sys.argv[1:]:
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
file=open(filename, 'rb')
|
|
|
|
file=open(filename, 'rb')
|
|
|
|
except:
|
|
|
|
except:
|
|
|
|
print filename, 'unreadable'
|
|
|
|
print(filename, 'unreadable')
|
|
|
|
print
|
|
|
|
print()
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
print filename+':'
|
|
|
|
print(filename+':')
|
|
|
|
# data=process_file(file, 1) # with debug info
|
|
|
|
# data=process_file(file, 1) # with debug info
|
|
|
|
data=process_file(file, 1)
|
|
|
|
data=process_file(file, 1)
|
|
|
|
if not data:
|
|
|
|
if not data:
|
|
|
|
print 'No EXIF information found'
|
|
|
|
print('No EXIF information found')
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
|
|
# x=data.keys()
|
|
|
|
# x=data.keys()
|
|
|
|