File: thumbspage/piexif/_load.py

File: thumbspage/piexif/_load.py

import struct
import sys
from ._common import *
from ._exceptions import InvalidImageDataError
from ._exif import *
from piexif import _webp
LITTLE_ENDIAN = b"\x49\x49"
def load(input_data, key_is_name=False):
 """
 py:function:: piexif.load(filename)
 Return exif data as dict. Keys(IFD name), be contained, are "0th", "Exif", "GPS", "Interop", "1st", and "thumbnail". Without "thumbnail", the value is dict(tag name/tag value). "thumbnail" value is JPEG as bytes.
 :param str filename: JPEG or TIFF
 :return: Exif data({"0th":dict, "Exif":dict, "GPS":dict, "Interop":dict, "1st":dict, "thumbnail":bytes})
 :rtype: dict
 """
 exif_dict = {"0th":{},
 "Exif":{},
 "GPS":{},
 "Interop":{},
 "1st":{},
 "thumbnail":None}
 exifReader = _ExifReader(input_data)
 if exifReader.tiftag is None:
 return exif_dict
 if exifReader.tiftag[0:2] == LITTLE_ENDIAN:
 exifReader.endian_mark = "<"
 else:
 exifReader.endian_mark = ">"
 pointer = struct.unpack(exifReader.endian_mark + "L",
 exifReader.tiftag[4:8])[0]
 exif_dict["0th"] = exifReader.get_ifd_dict(pointer, "0th")
 first_ifd_pointer = exif_dict["0th"].pop("first_ifd_pointer")
 if ImageIFD.ExifTag in exif_dict["0th"]:
 pointer = exif_dict["0th"][ImageIFD.ExifTag]
 exif_dict["Exif"] = exifReader.get_ifd_dict(pointer, "Exif")
 if ImageIFD.GPSTag in exif_dict["0th"]:
 pointer = exif_dict["0th"][ImageIFD.GPSTag]
 exif_dict["GPS"] = exifReader.get_ifd_dict(pointer, "GPS")
 if ExifIFD.InteroperabilityTag in exif_dict["Exif"]:
 pointer = exif_dict["Exif"][ExifIFD.InteroperabilityTag]
 exif_dict["Interop"] = exifReader.get_ifd_dict(pointer, "Interop")
 if first_ifd_pointer != b"\x00\x00\x00\x00":
 pointer = struct.unpack(exifReader.endian_mark + "L",
 first_ifd_pointer)[0]
 exif_dict["1st"] = exifReader.get_ifd_dict(pointer, "1st")
 if (ImageIFD.JPEGInterchangeFormat in exif_dict["1st"] and
 ImageIFD.JPEGInterchangeFormatLength in exif_dict["1st"]):
 end = (exif_dict["1st"][ImageIFD.JPEGInterchangeFormat] +
 exif_dict["1st"][ImageIFD.JPEGInterchangeFormatLength])
 thumb = exifReader.tiftag[exif_dict["1st"][ImageIFD.JPEGInterchangeFormat]:end]
 exif_dict["thumbnail"] = thumb
 if key_is_name:
 exif_dict = _get_key_name_dict(exif_dict)
 return exif_dict
class _ExifReader(object):
 def __init__(self, data):
 # Prevents "UnicodeWarning: Unicode equal comparison failed" warnings on Python 2
 maybe_image = sys.version_info >= (3,0,0) or isinstance(data, str)
 if maybe_image and data[0:2] == b"\xff\xd8": # JPEG
 segments = split_into_segments(data)
 app1 = get_exif_seg(segments)
 if app1:
 self.tiftag = app1[10:]
 else:
 self.tiftag = None
 elif maybe_image and data[0:2] in (b"\x49\x49", b"\x4d\x4d"): # TIFF
 self.tiftag = data
 elif maybe_image and data[0:4] == b"RIFF" and data[8:12] == b"WEBP":
 self.tiftag = _webp.get_exif(data)
 elif maybe_image and data[0:4] == b"Exif": # Exif
 self.tiftag = data[6:]
 else:
 with open(data, 'rb') as f:
 magic_number = f.read(2)
 if magic_number == b"\xff\xd8": # JPEG
 app1 = read_exif_from_file(data)
 if app1:
 self.tiftag = app1[10:]
 else:
 self.tiftag = None
 elif magic_number in (b"\x49\x49", b"\x4d\x4d"): # TIFF
 with open(data, 'rb') as f:
 self.tiftag = f.read()
 else:
 with open(data, 'rb') as f:
 header = f.read(12)
 if header[0:4] == b"RIFF"and header[8:12] == b"WEBP":
 with open(data, 'rb') as f:
 file_data = f.read()
 self.tiftag = _webp.get_exif(file_data)
 else:
 raise InvalidImageDataError("Given file is neither JPEG nor TIFF.")
 def get_ifd_dict(self, pointer, ifd_name, read_unknown=False):
 ifd_dict = {}
 tag_count = struct.unpack(self.endian_mark + "H",
 self.tiftag[pointer: pointer+2])[0]
 offset = pointer + 2
 if ifd_name in ["0th", "1st"]:
 t = "Image"
 else:
 t = ifd_name
 p_and_value = []
 for x in range(tag_count):
 pointer = offset + 12 * x
 tag = struct.unpack(self.endian_mark + "H",
 self.tiftag[pointer: pointer+2])[0]
 value_type = struct.unpack(self.endian_mark + "H",
 self.tiftag[pointer + 2: pointer + 4])[0]
 value_num = struct.unpack(self.endian_mark + "L",
 self.tiftag[pointer + 4: pointer + 8]
 )[0]
 value = self.tiftag[pointer+8: pointer+12]
 p_and_value.append((pointer, value_type, value_num, value))
 v_set = (value_type, value_num, value, tag)
 if tag in TAGS[t]:
 ifd_dict[tag] = self.convert_value(v_set)
 elif read_unknown:
 ifd_dict[tag] = (v_set[0], v_set[1], v_set[2], self.tiftag)
 #else:
 # pass
 if ifd_name == "0th":
 pointer = offset + 12 * tag_count
 ifd_dict["first_ifd_pointer"] = self.tiftag[pointer:pointer + 4]
 return ifd_dict
 def convert_value(self, val):
 data = None
 t = val[0]
 length = val[1]
 value = val[2]
 if t == TYPES.Byte: # BYTE
 if length > 4:
 pointer = struct.unpack(self.endian_mark + "L", value)[0]
 data = struct.unpack("B" * length,
 self.tiftag[pointer: pointer + length])
 else:
 data = struct.unpack("B" * length, value[0:length])
 elif t == TYPES.Ascii: # ASCII
 if length > 4:
 pointer = struct.unpack(self.endian_mark + "L", value)[0]
 data = self.tiftag[pointer: pointer+length - 1]
 else:
 data = value[0: length - 1]
 elif t == TYPES.Short: # SHORT
 if length > 2:
 pointer = struct.unpack(self.endian_mark + "L", value)[0]
 data = struct.unpack(self.endian_mark + "H" * length,
 self.tiftag[pointer: pointer+length*2])
 else:
 data = struct.unpack(self.endian_mark + "H" * length,
 value[0:length * 2])
 elif t == TYPES.Long: # LONG
 if length > 1:
 pointer = struct.unpack(self.endian_mark + "L", value)[0]
 data = struct.unpack(self.endian_mark + "L" * length,
 self.tiftag[pointer: pointer+length*4])
 else:
 data = struct.unpack(self.endian_mark + "L" * length,
 value)
 elif t == TYPES.Rational: # RATIONAL
 pointer = struct.unpack(self.endian_mark + "L", value)[0]
 if length > 1:
 data = tuple(
 (struct.unpack(self.endian_mark + "L",
 self.tiftag[pointer + x * 8:
 pointer + 4 + x * 8])[0],
 struct.unpack(self.endian_mark + "L",
 self.tiftag[pointer + 4 + x * 8:
 pointer + 8 + x * 8])[0])
 for x in range(length)
 )
 else:
 data = (struct.unpack(self.endian_mark + "L",
 self.tiftag[pointer: pointer + 4])[0],
 struct.unpack(self.endian_mark + "L",
 self.tiftag[pointer + 4: pointer + 8]
 )[0])
 elif t == TYPES.SByte: # SIGNED BYTES
 if length > 4:
 pointer = struct.unpack(self.endian_mark + "L", value)[0]
 data = struct.unpack("b" * length,
 self.tiftag[pointer: pointer + length])
 else:
 data = struct.unpack("b" * length, value[0:length])
 elif t == TYPES.Undefined: # UNDEFINED BYTES
 if length > 4:
 pointer = struct.unpack(self.endian_mark + "L", value)[0]
 data = self.tiftag[pointer: pointer+length]
 else:
 data = value[0:length]
 elif t == TYPES.SShort: # SIGNED SHORT
 if length > 2:
 pointer = struct.unpack(self.endian_mark + "L", value)[0]
 data = struct.unpack(self.endian_mark + "h" * length,
 self.tiftag[pointer: pointer+length*2])
 else:
 data = struct.unpack(self.endian_mark + "h" * length,
 value[0:length * 2])
 elif t == TYPES.SLong: # SLONG
 if length > 1:
 pointer = struct.unpack(self.endian_mark + "L", value)[0]
 data = struct.unpack(self.endian_mark + "l" * length,
 self.tiftag[pointer: pointer+length*4])
 else:
 data = struct.unpack(self.endian_mark + "l" * length,
 value)
 elif t == TYPES.SRational: # SRATIONAL
 pointer = struct.unpack(self.endian_mark + "L", value)[0]
 if length > 1:
 data = tuple(
 (struct.unpack(self.endian_mark + "l",
 self.tiftag[pointer + x * 8: pointer + 4 + x * 8])[0],
 struct.unpack(self.endian_mark + "l",
 self.tiftag[pointer + 4 + x * 8: pointer + 8 + x * 8])[0])
 for x in range(length)
 )
 else:
 data = (struct.unpack(self.endian_mark + "l",
 self.tiftag[pointer: pointer + 4])[0],
 struct.unpack(self.endian_mark + "l",
 self.tiftag[pointer + 4: pointer + 8]
 )[0])
 elif t == TYPES.Float: # FLOAT
 if length > 1:
 pointer = struct.unpack(self.endian_mark + "L", value)[0]
 data = struct.unpack(self.endian_mark + "f" * length,
 self.tiftag[pointer: pointer+length*4])
 else:
 data = struct.unpack(self.endian_mark + "f" * length,
 value)
 elif t == TYPES.DFloat: # DOUBLE
 pointer = struct.unpack(self.endian_mark + "L", value)[0]
 data = struct.unpack(self.endian_mark + "d" * length,
 self.tiftag[pointer: pointer+length*8])
 else:
 raise ValueError("Exif might be wrong. Got incorrect value " +
 "type to decode.\n" +
 "tag: " + str(val[3]) + "\ntype: " + str(t))
 if isinstance(data, tuple) and (len(data) == 1):
 return data[0]
 else:
 return data
def _get_key_name_dict(exif_dict):
 new_dict = {
 "0th":{TAGS["Image"][n]["name"]:value for n, value in exif_dict["0th"].items()},
 "Exif":{TAGS["Exif"][n]["name"]:value for n, value in exif_dict["Exif"].items()},
 "1st":{TAGS["Image"][n]["name"]:value for n, value in exif_dict["1st"].items()},
 "GPS":{TAGS["GPS"][n]["name"]:value for n, value in exif_dict["GPS"].items()},
 "Interop":{TAGS["Interop"][n]["name"]:value for n, value in exif_dict["Interop"].items()},
 "thumbnail":exif_dict["thumbnail"],
 }
 return new_dict



AltStyle によって変換されたページ (->オリジナル) /