def get_created_date(im: Image) -> dt.datetime: if im._getexif() and 36867 in im._getexif(): created_date = im._getexif()[36867] else: created_date = '1990:1:1 0:0:0' created_date = created_date.strip() photo_date = dt.datetime(1990, 1, 1) try: photo_date = dt.datetime.strptime(created_date, '%Y:%m:%d %H:%M:%S') except Exception as ex: logging.debug(ex) return photo_date
def get_exif_orientation(image: Image) -> int: """Returns exif orientation (1-8) or 0 if no exif data""" if hasattr(image, "_getexif"): exif = image._getexif() if exif is not None and EXIF_ORIENTATION in exif.keys(): return exif[EXIF_ORIENTATION] return 0
def _check_rotation_exif(image: Image) -> Image: """ Checks the rotational exif data on a given image and rotates it accordingly. :param image: :return: Rotated image. :rtype: PIL.Image """ for orientation in ExifTags.TAGS.keys(): if ExifTags.TAGS[orientation] == 'Orientation': try: exif = dict(image._getexif().items()) val = exif[orientation] except (AttributeError, KeyError): return image if val == 3: image = image.rotate(180, expand=True) elif val == 6: image = image.rotate(270, expand=True) elif val == 8: image = image.rotate(90, expand=True) return image return image
def image_transpose_exif(im: Image): """ Apply Image.transpose to ensure 0th row of pixels is at the visual top of the image, and 0th column is the visual left-hand side. Return the original image if unable to determine the orientation. As per CIPA DC-008-2012, the orientation field contains an integer, 1 through 8. Other values are reserved. Parameters ---------- im: PIL.Image The image to be rotated. """ exif_orientation_tag = 0x0112 exif_transpose_sequences = [ # Val 0th row 0th col [], # 0 (reserved) [], # 1 top left [Image.FLIP_LEFT_RIGHT], # 2 top right [Image.ROTATE_180], # 3 bottom right [Image.FLIP_TOP_BOTTOM], # 4 bottom left [Image.FLIP_LEFT_RIGHT, Image.ROTATE_90], # 5 left top [Image.ROTATE_270], # 6 right top [Image.FLIP_TOP_BOTTOM, Image.ROTATE_90], # 7 right bottom [Image.ROTATE_90], # 8 left bottom ] try: seq = exif_transpose_sequences[im._getexif()[exif_orientation_tag] # pylint: disable=protected-access ] except Exception: return im else: return functools.reduce(type(im).transpose, seq, im)
def check_metadata(image_file: Image): """ For decreasing image size better to delete unnecessary metadata :param image_file: JpegImageFile, WebPImageFile """ exif = image_file._getexif() assert_that(exif, equal_to(None), 'EXIF (metadata) must be empty for a smaller image file size')
def get_exif(img: Image) -> tp.Dict[str, str]: info = img._getexif() exif_obj = {} if info is not None: for tag, value in info.items(): decoded = ExifTags.TAGS.get(tag, tag) exif_obj[decoded] = value return exif_obj
def rotate_image(image: Image) -> Image: ALLOCATION={3: 180, 6: -90, 8: 90} #{orientation value : rotation angle} exif=image._getexif() # print(f"exif={exif}") if exif != None and 274 in exif: if exif[274] in ALLOCATION: return image.rotate(ALLOCATION[exif[274]], expand=True) else: return image else: return image
def rotate_img(img: Image) -> Image: try: #exif情報取得 exifinfo = img._getexif() #exif情報からOrientationの取得 orientation = exifinfo.get(0x112, 1) #画像を回転 img = rotateImage(img, orientation) except: pass return img
def generate_exif_dict(image: Image, close: bool = True) -> Dict: """ Generate a dictionary of dictionaries. The outer dictionary keys are the names of individual items, eg Make, Model etc. The outer dictionary values are themselves dictionaries with the following keys: tag: the numeric code for the item names raw: the data as stored in the image, often in a non-human-readable format processed: the raw data if it is human-readable, or a processed version if not. """ try: exif_data_PIL = image._getexif() exif_data = {} for k, v in PIL.ExifTags.TAGS.items(): try: if k in exif_data_PIL: value = exif_data_PIL[k] else: value = None except TypeError: raise Exception(f"{image.filename}: invalid exif_data.") if len(str(value)) > 64: value = str(value)[:65] + "..." exif_data[v] = { "tag": k, "raw": value, "processed": value, } if close: image.close() exif_data = _process_exif_dict(exif_data) return exif_data except IOError as ioe: raise
def _get_creation_time(path: Path, img: Image) -> Optional[datetime]: if hasattr(img, '_getexif'): exif = img._getexif() if exif and _EXIF.CREATION_DATE in exif: creation_date_str = exif[_EXIF.CREATION_DATE] try: return datetime.strptime(creation_date_str, '%Y:%m:%d %H:%M:%S') except ValueError: logger.error('Error parsing creation date "{}" of image {}' .format(creation_date_str, path), exc_info=True) return None return None
def get_metadata(image: Image) -> dict: exif_tags = TAGS.items() exif = image._getexif() metadata = {} if not exif: return metadata for k, v in exif_tags: if k in exif: metadata[v] = str(exif[k]) return metadata
def exif_rotate(image: Image) -> Image: if hasattr(image, '_getexif') is False: return image exif_dict = dict(image._getexif().items()) orientation = exif_dict.get(name_to_tag_num['Orientation']) if orientation == 3: return image.rotate(180, expand=True) elif orientation == 6: return image.rotate(270, expand=True) elif orientation == 8: return image.rotate(90, expand=True) return image
def _rotate_exif_orientation(self, img: Image) -> Image: """Rotate the image according to metadata in the payload. Some cameras do not rotate the image, they just add orientation metadata to the file, so we rotate it here. """ if not hasattr(img, '_getexif'): return img # PIL.PngImagePlugin.PngImageFile apparently lacks EXIF tags = img._getexif() if tags is None: return img orientation = tags.get(self.EXIF_TAGS['Orientation']) if orientation is None: return img degrees = self.EXIF_ROTATION_FIX.get(orientation) return img.rotate(degrees) if degrees else img
def get_exif(image: Image): _exif = {} info = image._getexif() for tag, value in info.items(): decoded = ExifTags.TAGS.get(tag, tag) _exif[decoded] = value return { 'ISOSpeedRatings': get_int(_exif, 'ISOSpeedRatings'), 'FocalLength': get_string(_exif, 'FocalLengthIn35mmFilm') if 'FocalLengthIn35mmFilm' in _exif else parse_tuple(_exif, 'FocalLength'), 'FNumber': parse_tuple(_exif, 'FNumber'), 'ExposureTime': parse_tuple(_exif, 'ExposureTime', True), 'Make': get_string(_exif, 'Make'), 'Model': get_string(_exif, 'Model'), 'ExposureProgram': get_value(_exif, 'ExposureProgram', exposure_programs) }
def rotate_image(im: Image) -> Image: try: orientation = -1 for orientation in ExifTags.TAGS.keys(): if ExifTags.TAGS[orientation] == 'Orientation': break exif = dict(im._getexif().items()) if orientation in exif and exif[orientation] == 3: im = im.rotate(180, expand=True) elif orientation in exif and exif[orientation] == 6: im = im.rotate(270, expand=True) elif orientation in exif and exif[orientation] == 8: im = im.rotate(90, expand=True) except Exception as ex: logging.debug(ex) return im
def exif_rotate(image: Image) -> Image: if not hasattr(image, "_getexif"): return image exif_data = image._getexif() if exif_data is None: return image exif_dict = dict(exif_data.items()) orientation = exif_dict.get(name_to_tag_num["Orientation"]) if orientation == 3: return image.rotate(180, expand=True) elif orientation == 6: return image.rotate(270, expand=True) elif orientation == 8: return image.rotate(90, expand=True) return image
def exif_rotate(image: Image) -> Image: if not hasattr(image, '_getexif'): return image exif_data = image._getexif() if exif_data is None: # nocoverage # don't have a test image for this case, but it happens return image exif_dict = dict(exif_data.items()) orientation = exif_dict.get(name_to_tag_num['Orientation']) if orientation == 3: return image.rotate(180, expand=True) elif orientation == 6: return image.rotate(270, expand=True) elif orientation == 8: return image.rotate(90, expand=True) return image
def exif_rotate(image: Image) -> Image: if not hasattr(image, '_getexif'): return image exif_data = image._getexif() if exif_data is None: return image exif_dict = dict(exif_data.items()) orientation = exif_dict.get(name_to_tag_num['Orientation']) if orientation == 3: return image.rotate(180, expand=True) elif orientation == 6: return image.rotate(270, expand=True) elif orientation == 8: return image.rotate(90, expand=True) return image
def rotate_upright(self, image: Image): """ Rotate a PIL image to upright depending on its current orientation according to EXIF data. """ try: for orientation in ExifTags.TAGS.keys(): if ExifTags.TAGS[orientation] == "Orientation": break exif = dict(image._getexif().items()) orientation = exif[orientation] if orientation == 3: image = image.rotate(180, expand=True) elif orientation == 6: image = image.rotate(270, expand=True) elif orientation == 8: image = image.rotate(90, expand=True) except (AttributeError, KeyError) as e: pass return image
def rotate_image(image: Image): """ 画像ファイルをEXIF情報に合わせて回転 """ if image is None: raise ValueError orientation = 1 exif_info = image._getexif() if exif_info: orientation = exif_info.get(0x112, 1) ans = image if orientation == 2: # 左右反転 ans = image.transpose(Image.FLIP_LEFT_RIGHT) elif orientation == 3: # 180度回転 ans = image.transpose(Image.ROTATE_180) elif orientation == 4: # 上下反転 ans = image.transpose(Image.FLIP_TOP_BOTTOM) elif orientation == 5: # 左右反転して90度回転 ans = image.transpose(Image.FLIP_LEFT_RIGHT).transpose( Image.ROTATE_90) elif orientation == 6: # 270度回転 ans = image.transpose(Image.ROTATE_270) elif orientation == 7: # 左右反転して270度回転 ans = image.transpose(Image.FLIP_LEFT_RIGHT).transpose( Image.ROTATE_270) elif orientation == 8: # 90度回転 ans = image.transpose(Image.ROTATE_90) return ans
def extract_exif(image: Image) -> dict: """ Args: image: Returns: """ try: exif_data = image._getexif() if exif_data is not None: exif = { ExifTags.TAGS[k]: decode_byte_exif(v) for k, v in exif_data.items() if k in ExifTags.TAGS } else: exif = {} except (AttributeError, OSError): # Not all file types (e.g. .gif) have exif information. exif = {} return exif
def orientation_correction(image: Image) -> Image: """ Depending on how camera was held some images might get messed up orientation after thumbnail function resizes them. Full explanation and solution were borrowed from https://stackoverflow.com/questions/4228530/pil-thumbnail-is-rotating-my-image :param image: Original image :return: image """ # only present in JPEGs if not hasattr(image, '_getexif'): return image # returns None if no EXIF data e = image._getexif() if e is None: return image # pick correct orientation code from ExifTags orientation = None for key in ExifTags.TAGS.keys(): if ExifTags.TAGS[key] == 'Orientation': orientation = key break # get orientation number exif = dict(e.items()) orientation = exif.get(orientation, None) if orientation == 3: return image.transpose(Image.ROTATE_180) if orientation == 6: return image.transpose(Image.ROTATE_270) if orientation == 8: return image.transpose(Image.ROTATE_90) return image
def get_creation_date(img: Image): info = img._getexif() for tag in info.keys(): if TAGS.get(tag, tag) == 'DateTimeOriginal': return info[tag] return None
def set_faux_dpi(image: Image, dpi: int) -> Image: """ Sets the image's DPI Exif metadata without actually changing the image """ print_exif(image) image._getexif()
def print_exif(image: Image) -> None: for (k, v) in image._getexif().items(): print('%s = %s' % (TAGS.get(k), v))
def get_exif(image: Image) -> dict: image.verify() return image._getexif()