返回

Img2pdf图片旋转问题:原理与解决方案

python

img2pdf图片旋转问题解析与方案

将图片转换为PDF格式时,一个常见的问题是图片本身的EXIF信息中可能包含旋转角度。如果img2pdf在处理这类图片时,没有按照EXIF信息正确地旋转图片,而是在PDF页面级别设置了旋转,会导致在某些PDF阅读器中显示不正确,或者在后续处理PDF文件时出现意外。目标是让img2pdf根据EXIF旋转图片本身,并生成无旋转属性的PDF页面。

问题根源:EXIF与PDF旋转的冲突

img2pdfrotation=img2pdf.Rotation.ifvalid 参数的设计目的是,如果EXIF数据中包含旋转信息,则根据此信息旋转图片。但实际应用中,可能会出现以下几种情况:

  • 库版本问题 : 早期版本的 img2pdf 在处理EXIF旋转信息时可能存在bug,或者对某些EXIF格式的支持不完整。
  • EXIF数据格式 : EXIF旋转信息的格式不统一,某些格式可能无法被 img2pdf 正确解析。
  • 与其他参数的冲突 : 某些参数的组合使用可能会干扰 rotation 参数的生效。

即使img2pdf能够读取并处理EXIF旋转信息,它也可能选择不在图片层面进行旋转,而是在PDF页面层面设置旋转属性。 这与我们期望的输出结果有所偏差。

解决方案一:手动处理EXIF信息,预先旋转图片

如果img2pdf无法正确处理EXIF旋转,一个可靠的方案是在使用img2pdf之前,先读取EXIF信息,然后使用图像处理库(如PILPillow)手动旋转图片。

步骤:

  1. 使用PILPillow读取图片,并提取EXIF数据。
  2. 解析EXIF数据,获取旋转角度。
  3. 根据旋转角度旋转图片。
  4. 将旋转后的图片传递给img2pdf进行PDF转换。

代码示例:

from io import BytesIO
from PIL import Image, ExifTags
import img2pdf
import requests

def rotate_image(image_bytes):
    """
    读取图片,解析EXIF旋转信息,并旋转图片。
    """
    image = Image.open(BytesIO(image_bytes))
    try:
        for orientation in ExifTags.TAGS.keys():
            if ExifTags.TAGS[orientation] == 'Orientation':
                break
        exif = image._getexif()
        if exif and orientation in exif:
            orientation = exif[orientation]
            if orientation == 3:
                image = image.rotate(180, expand=True)
            elif orientation == 6:
                image = image.rotate(-90, expand=True)  # 注意方向
            elif orientation == 8:
                image = image.rotate(90, expand=True)   # 注意方向
    except (AttributeError, KeyError, IndexError):
        # 没有EXIF信息
        pass
    return image

def convert_image_to_pdf(image_bytes):
    """
    转换图片到PDF,且图片根据EXIF信息完成旋转
    """
    rotated_image = rotate_image(image_bytes)
    img_byte_arr = BytesIO()
    rotated_image.save(img_byte_arr, format='JPEG')
    img_byte_arr = img_byte_arr.getvalue()
    pdf_bytes = img2pdf.convert(img_byte_arr) # 删除rotation参数
    return pdf_bytes

# 下载测试图片
response = requests.get("https://drive.google.com/file/d/1JyCBl5ulQmKIdQnVsvbNo7oNHX7oGIda/view?usp=sharing", stream=True)
response.raise_for_status()
image_data = response.content


# 测试函数
pdf_data = convert_image_to_pdf(image_data)
with open('output.pdf', 'wb') as f:
    f.write(pdf_data)

要点:

  • img2pdf.convert()中,不要再使用 rotation 参数,确保PDF页面不被额外旋转。
  • 这段代码的核心是 rotate_image 函数,它负责从 EXIF 数据中提取旋转信息并实际旋转图像。请确保安装 PILPillow模块。

解决方案二:利用图像处理工具,批量转换图像并去除旋转

这个方法针对已有大量需要转换的图片,可以事先通过命令行工具将它们全部按照正确的方向存储。比如利用 ImageMagick 等工具来达成目的。

步骤:

  1. 安装ImageMagick
  2. 利用mogrify命令读取图片,旋转图片并覆盖原文件,去除 EXIF 信息:
    mogrify -auto-orient *.jpg # 根据EXIF旋转所有jpg图片并覆盖
    mogrify -strip *.jpg # 去除EXIF信息, 可以节省文件空间
    

代码示例:

无代码示例,这是一个纯命令行操作的方法。

注意:
该方法会修改原始图像文件。建议在操作前备份原始数据,避免数据丢失。也可以使用 convert 命令将处理结果保存为新的文件,以保留原始文件。 例如:convert input.jpg -auto-orient output.jpg

总结

上述两个方案都旨在解决 img2pdf 在处理带有EXIF旋转信息的图片时可能出现的问题。首选的方案是预处理图片,确保传递给 img2pdf 的是已经正确旋转的图片,这样可以避免PDF页面级别的旋转属性,获得更可控的输出结果。选择哪一种方法取决于具体需求。