From 6e083f39e8f27045a4caf34c5e0d04d24e1fa23b Mon Sep 17 00:00:00 2001 From: Esa Kataja Date: Tue, 3 Dec 2024 23:45:35 +0200 Subject: [PATCH] Implement parallel processing for optimization steps using ThreadPoolExecutor. --- pdf_cleaner.py | 60 +++++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/pdf_cleaner.py b/pdf_cleaner.py index 13fd1f0..86ee242 100755 --- a/pdf_cleaner.py +++ b/pdf_cleaner.py @@ -15,6 +15,7 @@ from pdf2image import convert_from_path import settings from settings import OptimizationLevel from PIL import Image +import concurrent.futures class Settings: TRIM_PADDING_PIXELS = 20 @@ -326,37 +327,50 @@ def optimize(level): # Step 1: Convert to monochrome if level >= 2 if int(opt_level) >= int(OptimizationLevel.MONOCHROME): print("\nConverting to monochrome...") - for i, file_path in enumerate(temp_files, 1): - print(f"[{i}/{total_files}] Converting {os.path.basename(file_path)}...", end='', flush=True) - # Only optimize if this is the final step (level 2) - if convert_to_monochrome(file_path, is_final=(opt_level == OptimizationLevel.MONOCHROME)): - successful['monochrome'] += 1 - print(" ") - else: - print(" ") + with concurrent.futures.ThreadPoolExecutor() as executor: + futures = {executor.submit(convert_to_monochrome, file_path, (opt_level == OptimizationLevel.MONOCHROME)): file_path for file_path in temp_files} + for future in concurrent.futures.as_completed(futures): + file_path = futures[future] + try: + if future.result(): + successful['monochrome'] += 1 + print(f"Converted {os.path.basename(file_path)}") + else: + print(f"Failed to convert {os.path.basename(file_path)}") + except Exception as exc: + print(f"{os.path.basename(file_path)} generated an exception: {exc}") # Step 2: Always trim whitespace print("\nTrimming whitespace from images...") - for i, file_path in enumerate(temp_files, 1): - print(f"[{i}/{total_files}] Processing {os.path.basename(file_path)}...", end='', flush=True) - # Only optimize if this is the final step (level 1) - if trim_whitespace(file_path, is_final=(opt_level == OptimizationLevel.TRIM)): - successful['trim'] += 1 - print(" ") - else: - print(" ") + with concurrent.futures.ThreadPoolExecutor() as executor: + futures = {executor.submit(trim_whitespace, file_path, (opt_level == OptimizationLevel.TRIM)): file_path for file_path in temp_files} + for future in concurrent.futures.as_completed(futures): + file_path = futures[future] + try: + if future.result(): + successful['trim'] += 1 + print(f"Trimmed {os.path.basename(file_path)}") + else: + print(f"Failed to trim {os.path.basename(file_path)}") + except Exception as exc: + print(f"{os.path.basename(file_path)} generated an exception: {exc}") # Step 3: Run optipng if level = 3 if opt_level == OptimizationLevel.FULL: if check_optipng_installed(): print("\nOptimizing PNG files with optipng...") - for i, file_path in enumerate(temp_files, 1): - print(f"[{i}/{total_files}] Optimizing {os.path.basename(file_path)}...", end='', flush=True) - if run_optipng(file_path): - successful['optipng'] += 1 - print(" ") - else: - print(" ") + with concurrent.futures.ThreadPoolExecutor() as executor: + futures = {executor.submit(run_optipng, file_path): file_path for file_path in temp_files} + for future in concurrent.futures.as_completed(futures): + file_path = futures[future] + try: + if future.result(): + successful['optipng'] += 1 + print(f"Optimized {os.path.basename(file_path)}") + else: + print(f"Failed to optimize {os.path.basename(file_path)}") + except Exception as exc: + print(f"{os.path.basename(file_path)} generated an exception: {exc}") else: print("\nNote: optipng not found. Skipping PNG optimization.")