diff --git a/src/reCBZ/__main__.py b/src/reCBZ/__main__.py index cf81838..1f12c41 100644 --- a/src/reCBZ/__main__.py +++ b/src/reCBZ/__main__.py @@ -191,6 +191,11 @@ def main(): dest="size_str", type=str, help="rescale images to the specified resolution") + images_group.add_argument( "--keepratio", + default=None, + dest="keep_ratio", + action="store_true", + help="keep aspect ratio with --size") images_group.add_argument( "--noup", # rescale_group default=None, dest="no_upscale", diff --git a/src/reCBZ/archive.py b/src/reCBZ/archive.py index e813c82..cc498da 100644 --- a/src/reCBZ/archive.py +++ b/src/reCBZ/archive.py @@ -23,6 +23,25 @@ SOURCE_NAME:str = 'Source' chapter_prefix:str = 'v' # :) :D C: +def get_size_that_preserves_ratio(*, img_size, size_of_viewport): + # derived from https://pillow.readthedocs.io/en/stable/_modules/PIL/Image.html#Image.thumbnail (HPND) + import math + def round_aspect(number, key): + return max(min(math.floor(number), math.ceil(number), key=key), 1) + + x, y = size_of_viewport + + width, height = img_size + + aspect = width / height + if x / y >= aspect: + x = round_aspect(y * aspect, key=lambda n: abs(aspect - n / y)) + else: + y = round_aspect( + x / aspect, key=lambda n: 0 if n == 0 else abs(aspect - x / n) + ) + return x, y + def write_zip(savepath, chapters): new_zip = ZipFile(savepath,'w') @@ -128,13 +147,18 @@ def convert_page_worker(source, options, savedir=None): if page.landscape: new_size = new_size[::-1] n_width, n_height = new_size + if options['keep_ratio']: + resize_size = get_size_that_preserves_ratio(img_size=(width, height), size_of_viewport=new_size) + log_buff += f'|trans: keeping ratio: size changed from {(width, height)} to {resize_size}\n' + else: + resize_size = new_size # downscaling if (width > n_width and height > n_height and not options['nodown']): - img = img.resize((new_size), config.RESAMPLE_TYPE) + img = img.resize(resize_size, config.RESAMPLE_TYPE) # upscaling elif not options['noup']: - img = img.resize((new_size), config.RESAMPLE_TYPE) + img = img.resize(resize_size, config.RESAMPLE_TYPE) LossyFmt.quality = options['quality'] @@ -248,6 +272,7 @@ def __init__(self, filename:str): self._page_opt['format'] = get_format_class(config.img_format) self._page_opt['quality'] = config.img_quality self._page_opt['size'] = config.img_size + self._page_opt['keep_ratio'] = config.keep_ratio self._page_opt['grayscale'] = config.grayscale self._page_opt['noup'] = config.no_upscale self._page_opt['nodown'] = config.no_downscale diff --git a/src/reCBZ/config.py b/src/reCBZ/config.py index 7639e39..dae4b62 100644 --- a/src/reCBZ/config.py +++ b/src/reCBZ/config.py @@ -29,6 +29,7 @@ img_format:str = _cfg["image"]["img_format"] img_quality:int = _cfg["image"]["img_quality"] img_size:tuple = _cfg["image"]["img_size"] +keep_ratio:bool = _cfg["image"]["keep_ratio"] no_upscale:bool = _cfg["image"]["no_upscale"] no_downscale:bool = _cfg["image"]["no_downscale"] grayscale:bool = _cfg["image"]["grayscale"] diff --git a/src/reCBZ/defaults.toml b/src/reCBZ/defaults.toml index 5d1031d..b2b4386 100644 --- a/src/reCBZ/defaults.toml +++ b/src/reCBZ/defaults.toml @@ -35,6 +35,8 @@ img_format = '' img_quality = 80 # new image width / height. set to 0,0 to preserve original dimensions img_size = [0,0] +# preserve aspect ratio +keep_ratio = false # set to True to disable upscaling of images smaller than resolution no_upscale = false # set to True to disable downscaling of images larger than resolution