#!/usr/bin/env python3 from pdf2image import convert_from_path import os import shutil import argparse import threading import tempfile from pathlib import Path ################################################## # to do: # 1) √ Keep only the SMALLEST file. No need to keep the others # 2) √ Have a concept of "working dir" and "target dir" Use the appropriate one (use tempfile for default working directory) # 3) √ make extraction of PDF into a function # 4) √ ability to skip portions of the program by args # 5) Optimize code - loop things instead of calling them x times # 6) √ Use other image file types (JPG, PNG, etc...) # ################################################## def zip_jpg(file, image_type): print('Creating ZIP file from images') try: command = f"zip {file}.cbz ./*.{image_type} >/dev/null" os.system(command) except OSError as error: print(f"Command {command} gave the following error: {error}") def rar_jpg(file, image_type): print('Creating RAR file from images') try: command = f"rar a {file}.cbr ./*.{image_type} >/dev/null" os.system(command) except OSError as error: print(f"Command {command} gave the following error: {error}") def sz_jpg(file, image_type): print('Creating 7z file from images') try: command = f"7z a {file}.cb7 ./*.{image_type} >/dev/null" os.system(command) except OSError as error: print(f"Command {command} gave the following error: {error}") def gtar_jpg(file, image_type): print('Creating GZ file from images') try: command = f"tar czfP {file}.gz.cbt ./*.{image_type} >/dev/null" os.system(command) except OSError as error: print(f"Command {command} gave the following error: {error}") def btar_jpg(file, image_type): print('Creating BZ file from images') try: command = f"tar cjfP {file}.bz.cbt ./*.{image_type} >/dev/null" os.system(command) except OSError as error: print(f"Command {command} gave the following error: {error}") def xtar_jpg(file, image_type): print('Creating XZ file from images') try: command = f"tar cJfP {file}.xz.cbt ./*.{image_type} >/dev/null" os.system(command) except OSError as error: print(f"Command {command} gave the following error: {error}") def convert_bytes(num): """ this function will convert bytes to MB.... GB... etc """ for x in ['bytes', 'KB', 'MB', 'GB', 'TB']: if num < 1024.0: return "%3.2f %s" % (num, x) num /= 1024.0 def file_size(file_path): """ this function will return the file size """ if os.path.isfile(file_path): file_info = os.stat(file_path) return file_info.st_size else: return 'File Not found ' + file_path def extract_pdf(origin_file, work_dir, image_type): print ("Saving images from PDF to memory") images = convert_from_path(origin_file) num = len(images) print (f"Saving {num} images from memory to disk ({image_type.upper()} {work_dir})") for i in range(num): images[i].save(f"{work_dir}/page{i}.{image_type}", image_type) def report_save_smallest(type_dict, file, dest_dir): print ("Reporting compressed file sizes") small_size = 0.0 small_file = '' for key, value in type_dict.items(): now_file = file + value now_size = file_size(now_file) if small_size == 0.0 or now_size < small_size: small_size = now_size small_file = now_file size_str = convert_bytes(now_size) print (f"Size of {key}: {size_str}") print(f"Copying smallest file ({small_file}) to destination ({dest_dir})") shutil.copy2(small_file, dest_dir) def clean_work_dir(work_dir, filename, image_extension): for p in Path(work_dir).glob(filename+".*"): p.unlink() for p in Path(work_dir).glob("page*."+image_extension): p.unlink() if __name__ == '__main__': parser = argparse.ArgumentParser(description="Convert a PDF file to multiple Comic Book reading formats") parser.add_argument('--pdf', type=str, help='Name of PDF to convert', required=True) parser.add_argument('--ofn', type=str, help='Output File Name: Name of the comic book files to create (no extension! It will be added accordingly to the file type)', required=True) parser.add_argument('--odn', default=os.getcwd(), type=str, help='Output Directory Name: Destination folder for the output file (default: current folder)') parser.add_argument('--work_dir', default=None, type=str, help='Name of the folder to save the images and multiple compressed files (working folder). Contents in the folder will be aggressively deleted. If none, temp folder will be used.') parser.add_argument('--skip_clean', default=None, action='store_const', const=True, help='do NOT clean up the working directory, leave the images and compressed files (only works if work_dir is specified)') parser.add_argument('--skip_extract', default=None, action='store_const', const=True, help='do NOT extract the PDF. Go to work_dir and start compressing the images there.') parser.add_argument('--skip_compress', default=None, action='store_const', const=True, help='do NOT create the compressed comic book files.') parser.add_argument('--image_type', default='webp', choices=['webp', 'jpeg', 'png', 'tiff', 'bmp', 'ppm'], help='Convert PDF to this type of image. Default=webp') args = parser.parse_args() type_dict = { 'Zip': '.cbz', 'Rar': '.cbr', '7zip': '.cb7', 'Gtar': '.gz.cbt', 'Btar': '.bz.cbt', 'Xtar': '.xz.cbt' } if args.skip_clean and (args.work_dir == None): print("\nIf you want to skip_clean, you must give me a work_dir. Otherwise the app will use a 'temp system' that gets auto-deleted when the app exits\n") exit() if args.skip_extract and (args.work_dir == None): print("\nIf you want to skip_extract, you must tell me where to start compressing the images - give me a word_dir\n") exit() initial_cwd = os.getcwd() origin_file = args.pdf target_name = args.ofn image_type = args.image_type if not os.path.exists(args.odn): os.mkdir(args.odn) if args.work_dir != None: use_temp_dir = False if not os.path.exists(args.work_dir): os.mkdir(args.work_dir) created_work = True else: created_work = False work_dir = args.work_dir else: use_temp_dir = True temp_obj = tempfile.TemporaryDirectory(dir=args.work_dir, delete=True) work_dir = temp_obj.name if not args.skip_extract: extract_pdf(origin_file, work_dir, image_type) if not args.skip_compress: print (f"Compressing images into comic book files ({target_name}) on work folder: {work_dir}") os.chdir(work_dir) zip = threading.Thread(target=zip_jpg, args=(target_name,image_type)) rar = threading.Thread(target=rar_jpg, args=(target_name,image_type)) sz = threading.Thread(target=sz_jpg, args=(target_name,image_type)) gtar = threading.Thread(target=gtar_jpg, args=(target_name,image_type)) btar = threading.Thread(target=btar_jpg, args=(target_name,image_type)) xtar = threading.Thread(target=xtar_jpg, args=(target_name,image_type)) xtar.start() btar.start() sz.start() zip.start() rar.start() gtar.start() xtar.join() btar.join() sz.join() zip.join() rar.join() gtar.join() report_save_smallest(type_dict, target_name, args.odn) os.chdir(initial_cwd) size = convert_bytes(file_size(origin_file)) print (f"Size of source PDF: {size}") if not args.skip_clean: # print("____________________skip: "+args.skip_clean ) print("\nClean up of work_dir...") if use_temp_dir: temp_obj.cleanup() else: clean_work_dir(work_dir, target_name, image_type) if created_work: shutil.rmtree(work_dir) print("\nWe be done")