diff --git a/ui/medashare/metadata/crw.py b/ui/medashare/metadata/crw.py index b74de31..1700d6c 100644 --- a/ui/medashare/metadata/crw.py +++ b/ui/medashare/metadata/crw.py @@ -15,7 +15,7 @@ import struct # CRW: https://web.archive.org/web/20081230095207/http://xyrion.org/ciff/CIFFspecV1R04.pdf # CR2: https://web.archive.org/web/20230404015346/http://lclevy.free.fr/cr2/ # JPEG: https://www.w3.org/Graphics/JPEG/itu-t81.pdf -# JFIF: http://www.w3.org/Graphics/JPEG/jfif3.pdf +# JFIF: https://www.w3.org/Graphics/JPEG/jfif3.pdf # EXIF: https://www.cipa.jp/std/documents/e/DC-X008-Translation-2019-E.pdf # # Exif Tags: @@ -407,11 +407,7 @@ class CanonMakerNote(enum.IntEnum): PictureStylePC = 0x4009 canonmakernotehandlers = { - CanonMakerNote.FirmwareVersion: lambda fh, endian, res, off: - tuple(res.split(b'\x00', 1)), - CanonMakerNote.Lens: lambda fh, endian, res, off: - res.split(b'\x00', 1)[0], - } +} # Needed by Exif class TIFFResolutionUnit(enum.IntEnum): @@ -892,10 +888,16 @@ def tiff_bytes(endian, data): return map(ord, data) def tiff_ascii(endian, data): - if data[-1] != '\x00': - return data # XXX - Canon MakerNote requires this. - #raise ValueError, 'string does not terminate with NUL' - return data[:-1] + if data[-2:] == b'\x00\x00': + # multipl strings + return [ x.decode('ASCII') for x in data[:-2].split(b'\x00') ] + + if data[-1] != 0: + #print('d:', repr(data)) + #raise ValueError('string does not terminate with NUL') + return data + + return data[:-1].decode('ascii') def tiff_short(endian, data): return struct.unpack(endian + 'H' * (len(data) // 2), data) @@ -922,10 +924,15 @@ tifftypes = { 4: (tiff_long, 4), 5: (tiff_rational, 8), + #6: sbyte + # Exif Types 7: (lambda x, y: y, 1), # byte string + #8: sshort 9: (tiff_slong, 4), 10: (tiff_srational, 8), + #11: single float + #12: double float } TIFF_IFD_CNT = 'H' @@ -942,6 +949,7 @@ def tiff_ifd(fh, endian, off): for i in range(cnt): tag, ttype, length, valoff = entries[i * TIFF_IFD_ENTRY_CNT:(i + 1) * TIFF_IFD_ENTRY_CNT] + #print('t:', repr(tag), repr(ttype), repr(length), repr(valoff)) typefun, typequantum = tifftypes[ttype] blength = length * typequantum if blength <= 4: @@ -1021,26 +1029,6 @@ def getendian(val): return endian -class fileoff: - '''A wrapper around a file object that pretends it - starts at off. - ''' - - def __init__(self, fh, off): - self.fh = fh - self.off = off - - def seek(self, arg, whence=0): - if whence == 0: - arg += self.off - return self.fh.seek(arg, whence) - - def read(self, *args): - return self.fh.read(*args) - - def tell(self): - return self.th.tell() - self.off - def idcrw(fh): fh.seek(0) isjpeg = False @@ -1059,6 +1047,7 @@ def idcrw(fh): while True: fh.seek(pos) data = fh.read(10) + marklen = int.from_bytes(data[2:4], 'big') if data == b'': raise ValueError('unexpected end of file') @@ -1068,14 +1057,14 @@ def idcrw(fh): if data[:2] != b'\xff\xe1' or data[4:10] != b'Exif\x00\x00': # Skip over marker - pos += 2 + int.from_bytes(data[2:4], 'big') + pos += 2 + marklen continue # required due to coverage bug if True: #pragma: no cover break - fh = fileoff(fh, fh.tell()) + fh = BytesIO(fh.read(marklen - 8)) endian = getendian(fh.read(2)) isjpeg = True @@ -1235,6 +1224,7 @@ class _TestCRW(unittest.TestCase): self.assertEqual(ci[0][TIFFTag.ExifIFDPointer][ExifTag.ExposureTime][0], Fraction(1, 200)) #print(repr(ci)) + #print(repr(ci[0][TIFFTag.ExifIFDPointer][ExifTag.MakerNote][CanonMakerNote.SerialInfo])) def test_jpegexif(self): with open(self.fixtures / 'exif.jpeg', 'rb') as fp: @@ -1242,5 +1232,7 @@ class _TestCRW(unittest.TestCase): self.assertEqual(ci[0][TIFFTag.ExifIFDPointer][ExifTag.ISOSpeedRatings][0], 100) self.assertEqual(ci[0][TIFFTag.ExifIFDPointer][ExifTag.UserComment], b'UNICODE\x00' + 'abc123สวัสดี'.encode('utf-16-be')) - self.assertEqual(ci[0][TIFFTag.ExifIFDPointer][ExifTag.LensMake], b'Random Lens Maker\x00') - self.assertEqual(ci[0][TIFFTag.ImageDescription], b'Some comment\x00') + self.assertEqual(ci[0][TIFFTag.ExifIFDPointer][ExifTag.LensMake], 'Random Lens Maker') + self.assertEqual(ci[0][TIFFTag.ImageDescription], 'Some comment') + + #print(repr(ci))