#!/usr/bin/env python3 """Compress PDF using Ghostscript.""" import argparse, json, sys, subprocess, shutil from pathlib import Path QUALITY_MAP = { 'low': '/prepress', 'medium': '/ebook', 'high': '/screen', } def find_gs(): """Find Ghostscript executable.""" for name in ['gs', 'gswin64c', 'gswin32c']: path = shutil.which(name) if path: return path # Common paths import platform if platform.system() == 'Windows': import glob for pattern in ['C:/Program Files/gs/*/bin/gswin64c.exe', 'C:/Program Files (x86)/gs/*/bin/gswin32c.exe']: matches = glob.glob(pattern) if matches: return matches[0] return 'gs' def compress(input_path, output_path, level='medium'): gs = find_gs() quality = QUALITY_MAP.get(level, '/ebook') if not output_path: output_path = str(Path(input_path).with_stem(Path(input_path).stem + '_compressed')) cmd = [ gs, '-sDEVICE=pdfwrite', '-dCompatibilityLevel=1.4', f'-dPDFSETTINGS={quality}', '-dNOPAUSE', '-dQUIET', '-dBATCH', f'-sOutputFile={output_path}', input_path ] result = subprocess.run(cmd, capture_output=True, text=True, timeout=300) if result.returncode != 0: raise RuntimeError(f"Ghostscript error: {result.stderr}") return output_path def main(): parser = argparse.ArgumentParser(description='Compress PDF') parser.add_argument('--input', required=True) parser.add_argument('--output', required=True) parser.add_argument('--level', default='medium', choices=['low', 'medium', 'high']) args = parser.parse_args() try: result = compress(args.input, args.output, args.level) original_size = Path(args.input).stat().st_size compressed_size = Path(result).stat().st_size reduction = (1 - compressed_size / original_size) * 100 if original_size > 0 else 0 print(json.dumps({ "success": True, "output": result, "message": f"PDF compressed by {reduction:.1f}% ({original_size} -> {compressed_size} bytes)" })) except Exception as e: print(json.dumps({"success": False, "output": "", "message": str(e)})) sys.exit(1) if __name__ == '__main__': main()