From ce307c09d2e4ee131f9c589ba9a4423582c79ded Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Mon, 13 Sep 2021 13:39:27 +0200 Subject: [PATCH] + convert images in sub-directories + exiftool: if xmp sidecar exists, use it. Otherwise: use image file + skip already blurred images --- .idea/blur-exif-face-tags.iml | 8 ++++++++ .idea/modules.xml | 2 +- README.md | 2 +- blur.py | 18 ++++++++++++++++-- exif.py | 32 ++++++++++++++++++-------------- main.py | 16 +++++++++++++--- 6 files changed, 57 insertions(+), 21 deletions(-) create mode 100644 .idea/blur-exif-face-tags.iml diff --git a/.idea/blur-exif-face-tags.iml b/.idea/blur-exif-face-tags.iml new file mode 100644 index 0000000..6807b60 --- /dev/null +++ b/.idea/blur-exif-face-tags.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index 611bab0..181a238 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,7 +2,7 @@ - + \ No newline at end of file diff --git a/README.md b/README.md index e889923..f10d1f1 100644 --- a/README.md +++ b/README.md @@ -31,4 +31,4 @@ Many thanks to * https://www.thregr.org/~wavexx/software/facedetect/#blurring-faces-within-an-image * "Make blur all around a rectangle in image with PIL", https://stackoverflow.com/q/56987112/6334421 -* Example image: https://unsplash.com/photos/1qfy-jDc_jo?utm_source=unsplash&utm_medium=referral&utm_content=creditShareLink \ No newline at end of file +* Example image: https://unsplash.com/photos/1qfy-jDc_jo?utm_source=unsplash&utm_medium=referral&utm_content=creditShareLink diff --git a/blur.py b/blur.py index 07e0efc..7ae8916 100644 --- a/blur.py +++ b/blur.py @@ -12,7 +12,7 @@ import exif class NormalizedRectangle: """ - x, y, width and height are normalized: Their values are in the range [0, 1] + x, y, width and height are normalized: Their values are in the range [0, 1]. """ x: float @@ -82,5 +82,19 @@ def blur_rectangle2(image_src: Path, normalized_rectangles: List[NormalizedRecta # Save image if image_dst is None: - image_dst = image_src.parent.joinpath(f'{image_src.stem}_blurred{image_src.suffix}') + image_dst = get_image_dst(image_src) im.save(image_dst) + + +def get_image_dst(image: Path): + return image.parent.joinpath(f'{image.stem}{stem_suffix()}{image.suffix}') + + +def stem_suffix(): + """ + Modified images will be saved with a different filename. + This suffix will be added to their stem. + """ + + # return ' [blurred]' + return '_blurred' diff --git a/exif.py b/exif.py index 0c7287f..bebb52d 100644 --- a/exif.py +++ b/exif.py @@ -23,19 +23,12 @@ class Image: if len(self.files) == 0: raise Exception else: - raise Exception + raise Exception(f'{image_file}') def get_image_file(self): return self.files[0] - def get_xmp_metadata(self) -> AnyStr: - # TODO: Try to read xmp metadata from the image file itself, if there is no sidecar xmp file - - xmp_sidecar = self.get_xmp_sidecar() - with open(xmp_sidecar, "r") as f: - return f.read() - - def get_xmp_sidecar(self): + def get_xmp_file(self): """ :return: The sidecar xmp file, if it exists. Otherwise None is returned. """ @@ -46,6 +39,17 @@ class Image: return file return None + def get_metadata_file(self): + """ + If a sidecar xmp file exists, it is preferred over the image file itself. + + :return: A file containing the image metadata. + """ + metadata = self.get_xmp_file() + if metadata is None: + metadata = self.get_image_file() + return metadata + def __str__(self): return f'Image: {self.__dict__}' @@ -75,12 +79,12 @@ class ExifImageRegion: def get_exif_image_regions(image: Image) -> List[ExifImageRegion]: - sidecar: Path = image.get_xmp_sidecar() + img_metadata_file: Path = image.get_metadata_file() - names_str = exec.execute_save(['exiftool', '-RegionName', str(sidecar)]) - r_types_str = exec.execute_save(['exiftool', '-RegionType', str(sidecar)]) - area_units_str = exec.execute_save(['exiftool', '-RegionAreaUnit', str(sidecar)]) - rectangles_str = exec.execute_save(['exiftool', '-RegionRectangle', str(sidecar)]) + names_str = exec.execute_save(['exiftool', '-RegionName', str(img_metadata_file)]) + r_types_str = exec.execute_save(['exiftool', '-RegionType', str(img_metadata_file)]) + area_units_str = exec.execute_save(['exiftool', '-RegionAreaUnit', str(img_metadata_file)]) + rectangles_str = exec.execute_save(['exiftool', '-RegionRectangle', str(img_metadata_file)]) names = names_str.strip().split(':', 1)[1].strip().split(', ') r_types = r_types_str.strip().split(':', 1)[1].strip().split(', ') diff --git a/main.py b/main.py index 5873469..3cc278d 100644 --- a/main.py +++ b/main.py @@ -1,3 +1,4 @@ +import os from pathlib import Path from typing import List @@ -29,9 +30,18 @@ def blur_image(image: exif.Image): def main(): - for child in image_directory.iterdir(): - if child.suffix.lower() in image_extensions: - blur_image(exif.Image(child)) + # Convert all images in the image_directory, including subdirectories. + for _, _, files in os.walk(image_directory): + for relative_file_str in files: + file: Path = Path.joinpath(image_directory, relative_file_str) + if file.suffix.lower() in image_extensions: + + if file.stem.endswith(blur.stem_suffix()): + print(f'Skipped the following image as it is already blurred:\n\t{file}') + elif blur.get_image_dst(file).exists(): + print(f'Skipped the following image as it\'s blurred output does already exist:\n\t{file}') + else: + blur_image(exif.Image(file)) if __name__ == '__main__':