Python图片转PDF脚本异常:仅显示单图且未添加边距
图片转PDF脚本错误分析与修复
原脚本核心错误原因
1. 页面边距与尺寸计算逻辑颠倒
当启用单图单页模式时,原代码错误地将页面尺寸设置为图片尺寸减去两倍边距:
page_width = first_image.width - 2 * margin page_height = first_image.height - 2 * margin
这会导致页面比图片还小,图片加上边距后会超出页面范围;同时所有页面固定使用第一张图的尺寸,没有根据每张图片的实际尺寸动态调整,不符合“PDF页面尺寸匹配对应图片尺寸”的需求。
2. 单图单页模式未添加分页,图片堆叠覆盖
原脚本在single_page=True时,循环绘制图片过程中没有调用c.showPage(),所有图片都被绘制在同一个PDF页面上,后绘制的图片会完全覆盖之前的内容,最终只显示最后一张图片,但所有图片的数据都已嵌入PDF,因此文件大小等于所有图片尺寸的总和。
3. 参数命名歧义
single_page参数命名容易被误解为“所有图片放在同一页”,与实际需求“每张图片单独一页”不符,容易引发逻辑错误。
修复后的完整脚本
import os import logging from PIL import Image from reportlab.lib.pagesizes import letter, portrait from reportlab.pdfgen import canvas # Setup logging to a file logging.basicConfig(filename="pdf_script_log.txt", level=logging.DEBUG, format="%(asctime)s %(levelname)s %(message)s") def convert_images_to_jpg(source_dir, temp_dir, quality, scaling_factor, user_prefers_sharpness): """ Converts images in the source directory to JPG format with specified parameters. Args: source_dir (str): Absolute path to the directory containing image files. temp_dir (str): Absolute path to the temporary directory for storing converted images. quality (int): Quality parameter for image compression (0-100). scaling_factor (float): Scaling factor for resizing images (0.0-1.0). user_prefers_sharpness (bool): Whether sharper downscaling is preferred (True) or not (False). Returns: list: A list of paths to the converted JPG images. """ # Check if there are already converted images in the temporary directory existing_jpg_files = [f for f in os.listdir(temp_dir) if f.endswith('.jpg')] if existing_jpg_files: logging.info("Found existing converted images in the temporary directory. Skipping conversion.") return [os.path.join(temp_dir, f) for f in existing_jpg_files] jpg_images = [] for filename in os.listdir(source_dir): if os.path.isfile(os.path.join(source_dir, filename)): try: img = Image.open(os.path.join(source_dir, filename)) # Convert to RGB for better compression img = img.convert("RGB") # Apply scaling factor new_width = int(img.width * scaling_factor) new_height = int(img.height * scaling_factor) img.thumbnail((new_width, new_height), Image.Resampling.LANCZOS if user_prefers_sharpness else Image.Resampling.BICUBIC) # Save as JPG with specified quality jpg_filename = os.path.join(temp_dir, os.path.splitext(filename)[0] + ".jpg") img.save(jpg_filename, quality=quality) jpg_images.append(jpg_filename) except Exception as e: logging.error(f"Error converting image '{filename}' to JPG format: {e}") return jpg_images def create_pdf(output_dir, desired_name, title, author, keywords, per_image_page=True, margin=20): """ Creates a PDF document from a series of JPG image files. Args: output_dir (str): Output directory for the created PDF. desired_name (str): Desired name for the PDF (without extension). title (str): Title of the PDF. author (str): Author of the PDF. keywords (list): Keywords associated with the PDF. per_image_page (bool, optional): Whether to create a separate page for each image (matching image size + margin). Defaults to True. margin (int, optional): Margin size in pixels for each image on the page. Defaults to 20. """ logging.info("Starting PDF creation...") temp_dir = os.path.join(output_dir, 'temp') jpg_files = [f for f in os.listdir(temp_dir) if f.endswith('.jpg')] if not jpg_files: logging.error("No JPG image files found for PDF creation.") return jpg_files.sort(key=lambda x: int(''.join(filter(str.isdigit, os.path.splitext(x)[0])))) try: pdf_path = os.path.join(output_dir, desired_name + ".pdf") # Initialize canvas without fixed page size (will set per page) c = canvas.Canvas(pdf_path) # Add Metadata to the PDF c.setTitle(title) c.setAuthor(author) c.setKeywords(keywords) # Iterate through all JPG images and draw them for jpg_file in jpg_files: if jpg_file.endswith(".jpg"): image_path = os.path.join(temp_dir, jpg_file) try: img = Image.open(image_path) img_width, img_height = img.size if per_image_page: # Set page size to image size + 2*margin (left/right, top/bottom) page_width = img_width + 2 * margin page_height = img_height + 2 * margin c.setPageSize(portrait((page_width, page_height))) # Calculate image position (margin from each edge) x = margin y = margin else: # Use letter size with margin page_size = portrait(letter) c.setPageSize(page_size) max_width = page_size[0] - 2 * margin max_height = page_size[1] - 2 * margin # Scale image to fit within page bounds while maintaining aspect ratio scale = min(max_width / img_width, max_height / img_height) scaled_width = img_width * scale scaled_height = img_height * scale x = (page_size[0] - scaled_width) / 2 y = (page_size[1] - scaled_height) / 2 img_width, img_height = scaled_width, scaled_height # Draw the image c.drawImage(image_path, x, y, width=img_width, height=img_height) # Add new page after each image c.showPage() except IOError as e: logging.error(f"Error reading image: {image_path} - {e}") # Save the PDF and log success message c.save() logging.info(f"PDF created successfully at: {pdf_path}") except Exception as e: logging.error(f"Error during PDF creation: {e}") # Clean up temporary directory (optional, consider manual review) for file in os.listdir(temp_dir): file_path = os.path.join(temp_dir, file) os.remove(file_path) logging.info("Temporary files cleaned up.") # Main execution try: # Define variables for customization source_dir = "" # Replace with your source directory path output_dir = "" # Replace with your output directory path desired_name = "converted_images" title = "Image Collection PDF" author = "User" keywords = ["images", "pdf", "conversion"] per_image_page = True quality = 60 scaling_factor = 0.7 user_prefers_sharpness = True # Temporary directory for storing converted images temp_dir = os.path.join(output_dir, 'temp') # Create temporary directory if it doesn't exist os.makedirs(temp_dir, exist_ok=True) # Convert images to JPG format jpg_images = convert_images_to_jpg(source_dir, temp_dir, quality, scaling_factor, user_prefers_sharpness) # Create PDF from converted images create_pdf(output_dir, desired_name, title, author, keywords, per_image_page) # Close logging and exit logging.shutdown() logging.info("Script execution completed.") except Exception as e: logging.error(f"An error occurred during script execution: {e}") logging.shutdown()
修复关键点
- 修正页面尺寸计算:将页面尺寸设置为
图片尺寸 + 2*边距,确保图片放在边距位置时刚好适配页面,同时为每张图片动态设置对应页面尺寸。 - 强制分页逻辑:无论哪种模式,每次绘制完图片后都调用
c.showPage(),确保每张图片在独立页面,避免堆叠覆盖。 - 参数命名优化:将
single_page重命名为per_image_page,明确表示“每张图片单独一页”的逻辑。 - 非单图页面模式优化:当禁用单图单页时,自动缩放图片以适配letter页面的边距范围,保持图片比例。
内容的提问来源于stack exchange,提问作者Rafique Suchwani
相关产品推荐
相关产品推荐

