#!/usr/bin/env python import os from PIL import Image, ExifTags from shutil import copyfile orientation = 0x0112 # image exif info for Orientation 274 device = 0x010f # image exif info for Make 271 src_dir = 'todo' thumbnail_config = { 'max_size': 50 * 1024, # 50 kB 'min_wh': 400, # 0 measn not to resize height or width 'min_quality': 20, # jpg quality 'quality_fall': 5, # quality will decrease per step 'bytes_quality': 220 * 1024, # every x byte get 1 quality decrease 'debug': True, 'output_dir': 'todo', } opt_config = { 'max_size': 2 * 1024 * 1024, # 2 MB 'min_wh': 1560, # 0 measn not to resize height or width 'min_quality': 75, # jpg quality 'quality_fall': 3, # quality will decrease per step 'bytes_quality': 1024 * 1024, # every x byte get 1 quality decrease 'debug': True, 'output_dir': 'todo', } # config = thumbnail_config config = opt_config def init_exif_keys(): global orientation global device for key in ExifTags.TAGS.keys(): if ExifTags.TAGS[key] == 'Orientation': orientation = key elif ExifTags.TAGS[key] == 'Make': device = key def resize(src_path, output_path): max_size = config['max_size'] min_wh = config['min_wh'] min_quality = config['min_quality'] quality_fall = config['quality_fall'] bytes_quality = config['bytes_quality'] debug = config['debug'] if not os.path.exists(output_path): os.mkdir(output_path) files = list(os.listdir(src_path)) print('⬇ resize and copy {} files from {} to {}'.format(len(files), src_path, output_path)) for file in files: if debug: print('# process file', file) src_file = os.path.join(src_path, file) src_size = os.path.getsize(src_file) if os.path.isdir(src_file): continue if src_file.endswith('DS_Store'): os.remove(src_file) continue output_file = os.path.join(output_path, file) img = Image.open(src_file) img = process_exif(img) if (src_size > max_size): min_px = min(img.size) if min_px > min_wh: scale = min_px / float(min_wh) w, h = int(img.width / scale), int(img.height / scale) img = img.resize((w, h), Image.ANTIALIAS) quality = int(100 - src_size / bytes_quality) if quality < min_quality: quality = min_quality if debug: print('init quality is', quality) img.save(output_file, optimize=True, quality=quality) while os.path.getsize(output_file) > max_size and quality > min_quality: quality -= quality_fall if debug: print('+ adjust quality to', quality) img.save(output_file, optimize=True, quality=quality) img.close() else: copyfile(src_file, output_file) return len(files) def process_exif(image): if hasattr(image, '_getexif') and isinstance(image._getexif(), dict): exif = image._getexif() # if device in exif and exif[device] == 'Apple': # Canon XiaoMi Apple if orientation in exif: if exif[orientation] == 3: image = image.rotate(180, expand=True) elif exif[orientation] == 6: image = image.rotate(270, expand=True) elif exif[orientation] == 8: image = image.rotate(90, expand=True) return image if __name__ == '__main__': init_exif_keys() cnt = 0 output_dir = config['output_dir'] for file in os.listdir(src_dir): src_path = os.path.join(src_dir, file) if os.path.isdir(src_path): output_path = os.path.join(output_dir, file) cnt += resize(src_path, output_path) print('cnt:', cnt)