import struct from ._exceptions import InvalidImageDataError def split_into_segments(data): """Slices JPEG meta data into a list from JPEG binary data. """ if data[0:2] != b"\xff\xd8": raise InvalidImageDataError("Given data isn't JPEG.") head = 2 segments = [b"\xff\xd8"] while 1: if data[head: head + 2] == b"\xff\xda": segments.append(data[head:]) break else: length = struct.unpack(">H", data[head + 2: head + 4])[0] endPoint = head + length + 2 seg = data[head: endPoint] segments.append(seg) head = endPoint if (head >= len(data)): raise InvalidImageDataError("Wrong JPEG data.") return segments def read_exif_from_file(filename): """Slices JPEG meta data into a list from JPEG binary data. """ f = open(filename, "rb") data = f.read(6) if data[0:2] != b"\xff\xd8": raise InvalidImageDataError("Given data isn't JPEG.") head = data[2:6] HEAD_LENGTH = 4 exif = None while len(head) == HEAD_LENGTH: length = struct.unpack(">H", head[2: 4])[0] if head[:2] == b"\xff\xe1": segment_data = f.read(length - 2) if segment_data[:4] != b'Exif': head = f.read(HEAD_LENGTH) continue exif = head + segment_data break elif head[0:1] == b"\xff": f.read(length - 2) head = f.read(HEAD_LENGTH) else: break f.close() return exif def get_exif_seg(segments): """Returns Exif from JPEG meta data list """ for seg in segments: if seg[0:2] == b"\xff\xe1" and seg[4:10] == b"Exif\x00\x00": return seg return None def merge_segments(segments, exif=b""): """Merges Exif with APP0 and APP1 manipulations. """ if segments[1][0:2] == b"\xff\xe0" and \ segments[2][0:2] == b"\xff\xe1" and \ segments[2][4:10] == b"Exif\x00\x00": if exif: segments[2] = exif segments.pop(1) elif exif is None: segments.pop(2) else: segments.pop(1) elif segments[1][0:2] == b"\xff\xe0": if exif: segments[1] = exif elif segments[1][0:2] == b"\xff\xe1" and \ segments[1][4:10] == b"Exif\x00\x00": if exif: segments[1] = exif elif exif is None: segments.pop(1) else: if exif: segments.insert(1, exif) return b"".join(segments)