First commit

This commit is contained in:
Mike 2021-01-04 12:00:05 -08:00
commit 6b00f62a2c
5 changed files with 252 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
#
**/.idea/
**/__pycache__/

110
ApplyImageOrientation.py Normal file
View File

@ -0,0 +1,110 @@
import exif
from exif import Image as ExifImage
from PIL import Image as PilImage
import os
class ApplyImageOrientation:
def __init__(self, input_folder, output_folder):
self.ensure_folder(output_folder)
assert os.path.isdir(input_folder), "Invalid input folder: %s" % input_folder
assert os.path.isdir(output_folder), "Invalid output folder: %s" % output_folder
self.__input_folder = os.path.abspath(input_folder)
self.__output_folder = os.path.abspath(output_folder)
self.__valid_image_extensions = [
"jpeg", "jpg",
"png",
"tiff"
]
def run(self, jpeg=False):
images_paths = self.get_input_images()
for image_path in images_paths:
self.apply_orientation(
image_path=image_path,
jpeg=jpeg
)
@staticmethod
def ensure_folder(folder_path):
os.makedirs(folder_path, exist_ok=True)
def get_input_images(self):
return self.get_directory_images(self.__input_folder)
def get_directory_images(self, path):
images_files_paths = []
for current_dir, subdirs, files in os.walk(path):
for file_name in files:
file_path = os.path.join(current_dir, file_name)
file_basename, file_extension = os.path.splitext(file_path)
if file_extension:
file_extension = file_extension[1:]
file_extension = file_extension.lower()
if file_extension in self.__valid_image_extensions:
images_files_paths.append(file_path)
return images_files_paths
def apply_orientation(self, image_path, jpeg=False):
image_basename = os.path.basename(image_path)
with open(image_path, "rb") as f:
exif_image = ExifImage(f)
orientation = exif_image.orientation
pil_image = PilImage.open(image_path)
rotation_degrees = 0
if orientation == exif.Orientation.LEFT_BOTTOM:
rotation_degrees = 90
if rotation_degrees != 0:
pil_image_rotated = pil_image.rotate(rotation_degrees, expand=True)
else:
pil_image_rotated = pil_image
print(image_basename, pil_image.size, "==>", orientation, "==>", rotation_degrees)
image_rotated_file_path = self.make_image_output_path(image_path=image_path, jpeg=jpeg)
self.ensure_folder(os.path.dirname(image_rotated_file_path))
pil_image_rotated.save(image_rotated_file_path, None if jpeg else "png")
def get_image_relative_path(self, image_path):
image_path_relative = image_path[len(self.__input_folder):]
return image_path_relative
def make_image_output_path(self, image_path, jpeg=False):
image_path_relative = self.get_image_relative_path(image_path=image_path)
image_output_path = self.__output_folder + image_path_relative
if not jpeg:
path_name, extension = os.path.splitext(image_output_path)
image_output_path = path_name + ".png"
return image_output_path

13
Pipfile Normal file
View File

@ -0,0 +1,13 @@
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"
[packages]
exif = "*"
pillow = "*"
[dev-packages]
[requires]
python_version = "3"

69
Pipfile.lock generated Normal file
View File

@ -0,0 +1,69 @@
{
"_meta": {
"hash": {
"sha256": "1900f06584008e6cfdf5a311b77e1a8370d743e22ffdead6bbf0ce186dad4e9f"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.python.org/simple",
"verify_ssl": true
}
]
},
"default": {
"exif": {
"hashes": [
"sha256:87699a3032b902dc72b6e565c51ce2711390cb6d5a7689ff12e04ba427dc95c2",
"sha256:dc53ffc2e09245676944367b0b7038d6cb7d73175d80b4ec9d84333d1af17500"
],
"index": "pypi",
"version": "==1.0.4"
},
"pillow": {
"hashes": [
"sha256:165c88bc9d8dba670110c689e3cc5c71dbe4bfb984ffa7cbebf1fac9554071d6",
"sha256:22d070ca2e60c99929ef274cfced04294d2368193e935c5d6febfd8b601bf865",
"sha256:2353834b2c49b95e1313fb34edf18fca4d57446675d05298bb694bca4b194174",
"sha256:39725acf2d2e9c17356e6835dccebe7a697db55f25a09207e38b835d5e1bc032",
"sha256:3de6b2ee4f78c6b3d89d184ade5d8fa68af0848f9b6b6da2b9ab7943ec46971a",
"sha256:47c0d93ee9c8b181f353dbead6530b26980fe4f5485aa18be8f1fd3c3cbc685e",
"sha256:5e2fe3bb2363b862671eba632537cd3a823847db4d98be95690b7e382f3d6378",
"sha256:604815c55fd92e735f9738f65dabf4edc3e79f88541c221d292faec1904a4b17",
"sha256:6c5275bd82711cd3dcd0af8ce0bb99113ae8911fc2952805f1d012de7d600a4c",
"sha256:731ca5aabe9085160cf68b2dbef95fc1991015bc0a3a6ea46a371ab88f3d0913",
"sha256:7612520e5e1a371d77e1d1ca3a3ee6227eef00d0a9cddb4ef7ecb0b7396eddf7",
"sha256:7916cbc94f1c6b1301ac04510d0881b9e9feb20ae34094d3615a8a7c3db0dcc0",
"sha256:81c3fa9a75d9f1afafdb916d5995633f319db09bd773cb56b8e39f1e98d90820",
"sha256:887668e792b7edbfb1d3c9d8b5d8c859269a0f0eba4dda562adb95500f60dbba",
"sha256:93a473b53cc6e0b3ce6bf51b1b95b7b1e7e6084be3a07e40f79b42e83503fbf2",
"sha256:96d4dc103d1a0fa6d47c6c55a47de5f5dafd5ef0114fa10c85a1fd8e0216284b",
"sha256:a3d3e086474ef12ef13d42e5f9b7bbf09d39cf6bd4940f982263d6954b13f6a9",
"sha256:b02a0b9f332086657852b1f7cb380f6a42403a6d9c42a4c34a561aa4530d5234",
"sha256:b09e10ec453de97f9a23a5aa5e30b334195e8d2ddd1ce76cc32e52ba63c8b31d",
"sha256:b6f00ad5ebe846cc91763b1d0c6d30a8042e02b2316e27b05de04fa6ec831ec5",
"sha256:bba80df38cfc17f490ec651c73bb37cd896bc2400cfba27d078c2135223c1206",
"sha256:c3d911614b008e8a576b8e5303e3db29224b455d3d66d1b2848ba6ca83f9ece9",
"sha256:ca20739e303254287138234485579b28cb0d524401f83d5129b5ff9d606cb0a8",
"sha256:cb192176b477d49b0a327b2a5a4979552b7a58cd42037034316b8018ac3ebb59",
"sha256:cdbbe7dff4a677fb555a54f9bc0450f2a21a93c5ba2b44e09e54fcb72d2bd13d",
"sha256:d355502dce85ade85a2511b40b4c61a128902f246504f7de29bbeec1ae27933a",
"sha256:dc577f4cfdda354db3ae37a572428a90ffdbe4e51eda7849bf442fb803f09c9b",
"sha256:dd9eef866c70d2cbbea1ae58134eaffda0d4bfea403025f4db6859724b18ab3d"
],
"index": "pypi",
"version": "==8.1.0"
},
"plum-py": {
"hashes": [
"sha256:9328ec7502046134c5f16b04d85947559006e200d7268b7d5ed30f88735a48e5"
],
"version": "==0.3.1"
}
},
"develop": {}
}

53
main.py Executable file
View File

@ -0,0 +1,53 @@
#!/usr/bin/env python3
from ApplyImageOrientation import ApplyImageOrientation
import argparse
def main():
parser = argparse.ArgumentParser(
prog="Mike's Auto Image Orientation Applier"
)
parser.add_argument(
"--input", "--dir", "--folder",
dest="input_folder",
required=True,
type=str,
help="Specify an input folder of images"
)
parser.add_argument(
"--output", "--output-dir", "--output-folder",
dest="output_folder",
required=True,
type=str,
help="Specify an output folder for the images"
)
parser.add_argument(
"--jpg", "--jpeg",
dest="output_jpeg",
default=False,
action="store_true",
help="Output to jpeg files, not png"
)
args = parser.parse_args()
assert args.input_folder != args.output_folder, "Input and Output folders must be different"
app = ApplyImageOrientation(
input_folder=args.input_folder,
output_folder=args.output_folder
)
app.run(
jpeg=args.output_jpeg
)
if __name__ == "__main__":
main()