1
0
mirror of https://github.com/sashacmc/photo-importer.git synced 2024-11-24 08:02:14 +02:00

Add jpegtran support

This commit is contained in:
Alexander Bushnev 2022-01-30 02:10:43 +01:00
parent 3aee11e42c
commit bf79a40056
4 changed files with 99 additions and 6 deletions

View File

@ -29,8 +29,8 @@ Standalone web server for fast media import for headless computer
* PyExifTool (pip3 install PyExifTool)
* python3-progressbar
* python3-psutil
* exiftran
* pmount
* exiftran or jpegtran
* pmount (only for server)
### Installation Options:

View File

@ -35,6 +35,9 @@ move_mode = 1
# umask for new folder and copied files
umask = 0o000
# use jpegtran in place of exiftran 0/1
use_jpegtran = 0
[server]
# server port
port = 8080

View File

@ -26,6 +26,7 @@ class Config(object):
'move_mode': 1,
'threads_count': 2,
'umask': '0o000',
'use_jpegtran': 0,
},
'server': {
'port': 8080,

View File

@ -1,11 +1,28 @@
#!/usr/bin/python3
import os
import logging
import exiftool
import tempfile
import subprocess
import concurrent.futures
from photo_importer import config
JPEGTRAN_COMMAND = {
0: None,
1: None,
2: '-flip horizontal',
3: '-rotate 180',
4: '-flip vertical',
5: '-transpose',
6: '-rotate 90',
7: '-transverse',
8: '-rotate 270'
}
ORIENTATION_TAG = 'EXIF:Orientation'
class Rotator(object):
def __init__(self, config, filenames, dryrun):
@ -17,11 +34,20 @@ class Rotator(object):
self.__errors = 0
def run(self):
os.umask(int(self.__config['main']['umask'], 8))
tc = int(self.__config['main']['threads_count'])
processor = self.__process_exiftran
self.__exiftool = None
if int(self.__config['main']['use_jpegtran']):
self.__exiftool = exiftool.ExifTool()
self.__exiftool.start()
processor = self.__process_jpegtran
tc = 1
with concurrent.futures.ThreadPoolExecutor(max_workers=tc) as executor:
futures = {
executor.submit(self.__process, fn):
executor.submit(processor, fn):
fn for fn in self.__filenames}
for future in concurrent.futures.as_completed(futures):
@ -31,7 +57,10 @@ class Rotator(object):
else:
self.__errors += 1
def __process(self, filename):
if self.__exiftool is not None:
self.__exiftool.terminate()
def __process_exiftran(self, filename):
ok = False
try:
cmd = 'exiftran -aip "%s"' % filename
@ -43,12 +72,13 @@ class Rotator(object):
p = subprocess.Popen(
cmd,
shell=True,
universal_newlines=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE).stderr
error = ''
while 1:
line = p.readline().decode("utf-8")
while True:
line = p.readline()
if not line:
break
@ -66,6 +96,65 @@ class Rotator(object):
return ok
def __process_jpegtran(self, filename):
try:
orientation_cmd = self.__get_orientation_cmd(filename)
if orientation_cmd is None:
return True
logging.debug('rotate: jpegtran %s %s' %
(orientation_cmd, filename))
if self.__dryrun:
return True
handle, tmpfile = tempfile.mkstemp(dir=os.path.dirname(filename))
os.close(handle)
cmd = 'jpegtran -copy all -outfile %s %s %s' % \
(tmpfile, orientation_cmd, filename)
p = subprocess.Popen(
cmd,
shell=True,
universal_newlines=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE).stderr
line = p.readline()
if line:
logging.error('jpegtran (%s) failed: %s' % (filename, line))
return False
self.__clear_orientation_tag(tmpfile)
os.remove(filename)
os.rename(tmpfile, filename)
return True
except Exception as ex:
logging.error('Rotator exception (%s): %s' % (filename, ex))
raise
return False
def __get_orientation_cmd(self, fullname):
orientation = self.__exiftool.get_tag(ORIENTATION_TAG, fullname)
if orientation is not None and \
0 <= orientation and orientation < len(JPEGTRAN_COMMAND):
return JPEGTRAN_COMMAND[orientation]
else:
return None
def __clear_orientation_tag(self, fullname):
res = self.__exiftool.set_tags(
{ORIENTATION_TAG: 1}, fullname).decode('utf-8')
if not exiftool.check_ok(res):
raise SystemError('exiftool error: ' + exiftool.format_error(res))
try:
os.remove(fullname + '_original')
except Exception:
pass
def status(self):
return {
'total': len(self.__filenames),