From bcfa304862d57e17b79e1e3e1dbc99451d34ac55 Mon Sep 17 00:00:00 2001 From: Simon Bruder Date: Sun, 11 Jul 2021 11:08:00 +0200 Subject: [PATCH] cbz2ebook: Replace with python implementation It has multiple advantages: * It processes the images in memory, without writing intermediary files * It supports multithreading * It does not spawn an army of subprocesses * It shows a better progress bar * It is more robust --- cbz2ebook.py | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++ cbz2ebook.sh | 45 ------------------------------ 2 files changed, 78 insertions(+), 45 deletions(-) create mode 100755 cbz2ebook.py delete mode 100755 cbz2ebook.sh diff --git a/cbz2ebook.py b/cbz2ebook.py new file mode 100755 index 0000000..e269428 --- /dev/null +++ b/cbz2ebook.py @@ -0,0 +1,78 @@ +#!/usr/bin/env cached-nix-shell +#!nix-shell -i python3 -p python3 python3Packages.pillow python3Packages.tqdm +from PIL import Image +from concurrent.futures import ThreadPoolExecutor +from tqdm import tqdm +from zipfile import ZipFile +import argparse + + +def should_scale(in_width, in_height, out_width, out_height): + return not ( + (in_width == out_width and in_height <= out_height) + or (in_height == out_height and in_width <= out_width) + ) + + +def scaled_size(in_width, in_height, out_width, out_height): + in_aspect_ratio = float(in_width) / float(in_height) + out_aspect_ratio = float(out_width) / float(out_height) + + if in_aspect_ratio > out_aspect_ratio: + height = out_width / in_aspect_ratio + width = out_width + else: + width = out_height * in_aspect_ratio + height = out_height + + return int(round(width)), round(int(height)) + + +def process_image(im): + # double pages (wider than high) should be rotated + if im.width > im.height: + im = im.transpose(Image.ROTATE_90) + + # convert to greyscale + im = im.convert("L") + + # resize if necessary + if should_scale(im.width, im.height, args.width, args.height): + im = im.resize( + scaled_size(im.width, im.height, args.width, args.height), + resample=Image.LANCZOS, + ) + + return im + + +parser = argparse.ArgumentParser() +parser.add_argument("infile") +parser.add_argument("outfile") +parser.add_argument("-W", "--width", default=1440) +parser.add_argument("-H", "--height", default=1920) +parser.add_argument("-s", "--singlethreaded", action="store_true") +args = parser.parse_args() + +srczip = ZipFile(args.infile) +dstzip = ZipFile(args.outfile, "x") + +srcfiles = sorted( + map(lambda zi: zi.filename, filter(lambda zi: not zi.is_dir(), srczip.infolist(),),) +) + +executor = ThreadPoolExecutor() + +if args.singlethreaded: + mapper = map +else: + mapper = executor.map + +for idx, im in enumerate( + tqdm( + mapper(process_image, map(Image.open, map(srczip.open, srcfiles)),), + total=len(srcfiles), + ) +): + with dstzip.open(f"{idx+1:04d}.jpg", "w") as outpagefile: + im.save(outpagefile, format="JPEG", quality=92) diff --git a/cbz2ebook.sh b/cbz2ebook.sh deleted file mode 100755 index e36f398..0000000 --- a/cbz2ebook.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env cached-nix-shell -#!nix-shell -i zsh -p imagemagick unzip zip zsh -set -e - -size="1440x1920" # Kobo Forma -#size="768x1024" # Amazon Kindle Paperwhite - -vertical_size="$(cut -dx -f2 <<< $size)x$(cut -dx -f1 <<< $size)" - -infile="$(realpath $1)" -outfile="$(realpath $2)" -tmpdir=$(mktemp -d) - -function cleanup { - rm -rf "$tmpdir" -} - -trap cleanup EXIT INT SIGTERM - -cd "$tmpdir" -unzip "$infile" - -# rename files to have a plain 4 digit filename -i=1 -for file in **/*.???; do - mv -n "$file" "$(dirname $file)/$(printf %04d $i).${file##*.}" - i=$((i+1)) -done - -length=$(ls -1 **/*.??? | wc -l) -position=0 -for image in **/*.???; do - width=$(identify -format "%W" "$image") - height=$(identify -format "%H" "$image") - if (($width > $height)); then - mogrify -resize "$vertical_size" -rotate 270 "$image" - else - mogrify -resize "$size" "$image" - fi - position=$(($position + 1)) - echo -ne "$(printf '%3s' $((100 * $position / $length))) % "$(printf "%0*d" "$((72 * $position / $length))" 0 | tr '0' '#')'\r' -done -echo -zip "$outfile" **/*.??? -cd -