Merge branch 'dev'

This commit is contained in:
Mike 2021-01-04 12:51:51 -08:00
commit 22182a5006
3 changed files with 147 additions and 4 deletions

View File

@ -8,6 +8,8 @@ from PIL import Image as PilImage
import os import os
import multiprocessing
import threading
class ApplyImageOrientation: class ApplyImageOrientation:
@ -28,11 +30,51 @@ class ApplyImageOrientation:
"tiff" "tiff"
] ]
def run(self, jpeg=False): def run(self, threads_count=None, jpeg=False):
images_paths = self.get_input_images() images_paths = self.get_input_images()
for image_path in images_paths: lock = threading.RLock()
threads = []
if threads_count is None:
threads_count = multiprocessing.cpu_count()
print("Applying orientation using %s threads" % (threads_count,))
for i in range(threads_count):
t = threading.Thread(
target=self._apply_orientation_thread,
kwargs={
"lock": lock,
"images_paths": images_paths,
"jpeg": jpeg
}
)
threads.append(t)
t.start()
try:
for t in threads:
t.join()
except KeyboardInterrupt:
with RAIILock(lock):
print("Detected keyboard interrupt; Aborting!")
images_paths.clear()
def _apply_orientation_thread(self, lock: threading.RLock, images_paths: list, jpeg: bool):
while True:
with RAIILock(lock) as raii_lock:
if len(images_paths) == 0:
break
image_path = images_paths.pop()
common_path = os.path.commonpath([self.__input_folder, image_path])
print("Rotating: %s (%s remaining)" % (image_path[len(common_path) + 1:], len(images_paths)))
raii_lock.release()
self.apply_orientation( self.apply_orientation(
image_path=image_path, image_path=image_path,
jpeg=jpeg jpeg=jpeg
@ -79,13 +121,17 @@ class ApplyImageOrientation:
rotation_degrees = 0 rotation_degrees = 0
if orientation == exif.Orientation.LEFT_BOTTOM: if orientation == exif.Orientation.LEFT_BOTTOM:
rotation_degrees = 90 rotation_degrees = 90
elif orientation == exif.Orientation.BOTTOM_RIGHT:
rotation_degrees = 180
elif orientation == exif.Orientation.RIGHT_TOP:
rotation_degrees = 270
if rotation_degrees != 0: if rotation_degrees != 0:
pil_image_rotated = pil_image.rotate(rotation_degrees, expand=True) pil_image_rotated = pil_image.rotate(rotation_degrees, expand=True)
else: else:
pil_image_rotated = pil_image pil_image_rotated = pil_image
print(image_basename, pil_image.size, "==>", orientation, "==>", rotation_degrees) # print(image_basename, pil_image.size, "==>", orientation, "==>", rotation_degrees)
image_rotated_file_path = self.make_image_output_path(image_path=image_path, jpeg=jpeg) 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)) self.ensure_folder(os.path.dirname(image_rotated_file_path))
@ -108,3 +154,38 @@ class ApplyImageOrientation:
image_output_path = path_name + ".png" image_output_path = path_name + ".png"
return image_output_path return image_output_path
class RAIILock:
def __init__(self, lock: threading.RLock):
self.__lock = lock
def __enter__(self):
self.acquire()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if self.__lock:
self.release()
self.__lock = None
def acquire(self):
if self.__lock:
self.__lock.acquire()
def release(self):
if self.__lock:
try:
self.__lock.release()
except RuntimeError:
pass

46
README.md Normal file
View File

@ -0,0 +1,46 @@
# Mike's Auto Image Rotator
This program is quite simple: It will look through your jpeg image's exif data and apply rotation automatically.
This is useful for preprocessing images before sending them through a second program that may not support orientation via exif data.
by Mike Peralta
# Requirements
* Python3
* pipenv
# Installation
Enter the repo's directory and install dependencies using pipenv, like so:
```shell script
$ cd /path/to/repo
$ pipenv install
```
# Usage
## Invocation
Invoke directly like so:
```shell script
$ cd /path/to/repo
$ pipenv run python ./main.py --help
```
Invoke in a persistent environment shell like so:
```shell script
$ cd /path/to/repo
$ pipenv shell
$ python main.py --help
```
## Arguments
Use the ***--help*** argument shown above to see all available options.

18
main.py
View File

@ -33,7 +33,22 @@ def main():
dest="output_jpeg", dest="output_jpeg",
default=False, default=False,
action="store_true", action="store_true",
help="Output to jpeg files, not png" help="Output to jpeg files, not png. Should be faster but sacrifices the quality of png."
)
parser.add_argument(
"--threads",
dest="threads_count",
default=None,
type=int,
help="Specify the number of threads to use. Default: Same as the number of detected CPU cores."
)
parser.add_argument(
"--single-thread",
dest="threads_count",
default=None,
action="store_const", const=1,
help="Use only one thread."
) )
args = parser.parse_args() args = parser.parse_args()
@ -45,6 +60,7 @@ def main():
output_folder=args.output_folder output_folder=args.output_folder
) )
app.run( app.run(
threads_count=args.threads_count,
jpeg=args.output_jpeg jpeg=args.output_jpeg
) )