
pypdf Transformation 类全解析用 2D 变换矩阵实现 PDF 页面的平移、缩放与旋转【免费下载链接】pypdfA pure-python PDF library capable of splitting, merging, cropping, and transforming the pages of PDF files项目地址: https://gitcode.com/GitHub_Trending/py/pypdf本指南以 pypdf 的 Transformation 类API 文档见 docs/modules/Transformation.rst为核心深入讲解 PDF 页面 2D 变换矩阵的数学原理、Transformation对象的各种构造与操作方法以及如何通过PageObject.add_transformation()将变换应用到真实 PDF 页面。读完本文你将能够用 pypdf 精确控制页面内容的缩放、平移、旋转与镜像并能理解底层cm操作符与矩阵乘法的实现细节。PDF 中的 2D 变换矩阵从数学到六元组在 PDF 规范中两个坐标系之间的变换由一个 3×3 变换矩阵表示其形式固定为a b 0 c d 0 e f 1坐标变换通过矩阵乘法表达a b 0 [ x′ y′ 1 ] [ x y 1 ] × c d 0 e f 1因为矩阵的第三列固定为0 0 1真正可变只有 6 个元素所以 PDF 中通常用一个六元素数组[ a b c d e f ]来描述该矩阵。在 pypdf 中这个六元组被称为压缩变换矩阵Compressed Transformation Matrix对应的类型别名定义于 types.pyCompressedTransformationMatrix与TransformationMatrixType。这种表示是 pypdfTransformation类的数学基础也是我们理解后续所有方法的前提任何平移、缩放、旋转本质上都是在修改这 6 个数字。Transformation 类速览构造与矩阵访问Transformation定义于 pypdf/_page.py并从pypdf顶层导出见 pypdf/init.py因此可以直接from pypdf import Transformation。构造函数签名如下Transformation(ctm: CompressedTransformationMatrix (1, 0, 0, 1, 0, 0))默认参数(1, 0, 0, 1, 0, 0)是单位矩阵——不做任何变换。例如from pypdf import Transformation op Transformation() # 单位变换什么都不做 op Transformation((1, 0, 0, -1, 0, 0)) # 沿 x 轴的垂直镜像类提供了两个与矩阵直接相关的接口matrix属性把压缩六元组展开为 3×3 元组形式((a, b, 0), (c, d, 0), (e, f, 1))便于阅读和参与数学运算compress(matrix)静态方法是matrix的逆操作把 3×3 矩阵压缩回(a, b, c, d, e, f)六元组。translate、scale、rotate等方法的内部实现都依赖它。__repr__输出格式为Transformation(ctm(a, b, c, d, e, f))便于调试时观察当前矩阵状态。核心变换操作translate / scale / rotateTransformation提供了三个构建基础变换的方法每个方法都返回一个新的Transformation实例原始对象不会被修改——这使它们可以像不可变操作一样安全地链式调用。translate(tx, ty)平移def translate(self, tx: float 0, ty: float 0) - Transformation在 x 轴方向平移txy 轴方向平移ty。从源码 pypdf/_page.py 可以看到实现非常直观平移只影响矩阵的平移分量e、fm self.ctm return Transformation(ctm(m[0], m[1], m[2], m[3], m[4] tx, m[5] ty))scale(sx, sy)缩放def scale(self, sx: Optional[float] None, sy: Optional[float] None) - Transformation沿 x 轴缩放sx、沿 y 轴缩放sy。源码 pypdf/_page.py 中有两个值得注意的行为sx与sy都可选若两者均为None抛出ValueError若只给一个另一个自动取相同值即等比例缩放缩放是**相对于坐标系原点通常为页面左下角**进行的docstring 明确提示如果需要相对页面其他位置缩放可以结合translate调整页面内容或页面盒子。op Transformation().scale(2) # 等比例放大 2 倍 op Transformation().scale(sx2, sy3) # x 轴 2 倍、y 轴 3 倍rotate(rotation)旋转def rotate(self, rotation: float) - Transformation按角度制degrees旋转页面内容。实现中先通过math.radians转为弧度再构造标准旋转矩阵rotation math.radians(rotation) op ( (math.cos(rotation), math.sin(rotation), 0), (-math.sin(rotation), math.cos(rotation), 0), (0, 0, 1), )注意旋转同样是围绕坐标系原点进行的且正值方向取决于页面坐标系约定旋转角度不限于 90° 的整数倍任何角度都可用。transform(m)复合变换def transform(self, m: Transformation) - Transformation将另一个变换m应用到当前变换上返回新实例。从实现看本质是 3×3 矩阵乘法ctm Transformation.compress(matrix_multiply(self.matrix, m.matrix)) return Transformation(ctm)matrix_multiply是通用矩阵乘法工具定义于 pypdf/_utils.py。docstring 中给出了用transform实现镜像的经典示例from pypdf import PdfWriter, Transformation height, width 40, 50 page PdfWriter().add_blank_page(800, 600) op Transformation((1, 0, 0, -1, 0, height)) # 垂直镜像 op Transformation().transform(Transformation((-1, 0, 0, 1, width, 0))) # 水平镜像 page.add_transformation(op)链式调用示例因为所有操作都返回新的Transformation可以一行写出复合变换——这也正是类 docstring 的官方示例from pypdf import PdfWriter, Transformation page PdfWriter().add_blank_page(800, 600) op Transformation().scale(sx2, sy3).translate(tx10, ty20) page.add_transformation(op)apply_on把变换作用到单个点def apply_on( self, pt: Union[tuple[float, float], list[float]], as_object: bool False, ) - Union[tuple[float, float], list[float]]除了作用于整页内容Transformation还可以直接计算单个点变换后的坐标。输入(x, y)返回(x′, y′)若传入list则返回list传入tuple则返回tuple。参数as_objectTrue时返回的元素类型为 pypdf 的FloatObject适合直接写回 PDF 对象树否则为普通float。变换公式在 pypdf/_page.py 中实现x′ x * a y * c e y′ x * b y * d f例如对一个translate(10, 20)后的变换调用apply_on((0, 0))会得到(10.0, 20.0)——这可以用于在写入前预览变换效果或计算旋转后页面盒子的新角点。将变换应用到页面PageObject.add_transformation仅仅构造Transformation对象还不会产生任何效果真正让变换生效的是PageObject.add_transformation()定义于 pypdf/_page.pydef add_transformation( self, ctm: Union[Transformation, CompressedTransformationMatrix], expand: bool False, ) - None参数说明ctm既可以传Transformation对象也可以直接传 6 元组(a, b, c, d, e, f)expand是否扩展页面以容纳变换后的内容默认False。该方法与用户指南 docs/user/cropping-and-transforming.md 相互印证——该文档同时提到对 90° 整数倍的旋转页面级方法PageObject.rotate(90)通常比page.add_transformation(Transformation().rotate(...))更合适因为前者会同时更新页面方向属性而add_transformation适合任意角度与复合变换的场景。底层做了什么cm 操作符与内容流从源码可以梳理出add_transformation的完整调用链若传入Transformation对象先取出其ctm六元组通过内部方法_add_transformation_matrix把变换写入页面内容流调用content.isolate_graphics_state()隔离图形状态确保变换只作用于目标内容、不影响页面其他部分用replace_contents(content)写回更新后的内容流。变换最终会以 PDF 内容流操作符cm的形式写入文件。Transformation._to_cm()方法pypdf/_page.py负责生成这条指令格式为a b c d e f cm数值按 4 位小数格式化。cm是 PDF 中最基本的坐标变换操作符阅读器看到它就会按照矩阵参数重新映射后续绘制的图形。expandTrue自动扩展页面盒子如果变换如平移导致内容超出了原页面边界可以设置expandTrue。源码会计算mediabox四个角点经变换后的新坐标然后重新设置mediabox.lower_left与mediabox.upper_right使页面盒子恰好包住变换后的内容self.mediabox.lower_left (min(new_x), min(new_y)) self.mediabox.upper_right (max(new_x), max(new_y))注意它只调整媒体框mediabox不含裁剪等其他盒子。完整实战合成旋转、缩放与平移下面是一个可直接运行的完整示例演示如何读取 PDF、构造复合变换并写出结果文件from pypdf import PdfReader, PdfWriter, Transformation reader PdfReader(input.pdf) writer PdfWriter() for i, page in enumerate(reader.pages): if i 0: # 第一页逆时针旋转 45 度并放大 1.5 倍 op Transformation().rotate(-45).scale(1.5) elif i 1: # 第二页水平镜像并向下平移 50 个单位 op Transformation((-1, 0, 0, 1, page.mediabox.width, 0)).translate(ty-50) else: # 其余页放大 2 倍并扩展页面以容纳新内容 op Transformation().scale(2) page.add_transformation(op, expandTrue) writer.add_page(page) with open(out-transformed.pdf, wb) as f: writer.write(f)与页面级 API 的关系Transformation不是 pypdf 中唯一操作页面几何的途径理解它们的分工有助于写出更恰当的代码PageObject.rotate(angle)页面级旋转自动处理 90° 整数倍的页面方向推荐用于纠正扫描方向PageObject.scale(sx, sy)页面级缩放除变换内容外还会同步缩放bleedbox、trimbox、artbox、cropbox、mediabox等全部页面盒子并处理注解见 pypdf/_page.pyPageObject.merge_transformed_page(page2, ctm, over, expand)将另一页以给定变换矩阵叠加到当前页上PageObject.merge_translate(page2, tx, ty, over, expand)merge_transformed_page的便捷封装其实现就是op Transformation().translate(tx, ty)后调用merge_transformed_page见 pypdf/_page.py。也就是说Transformation是这些页面级 API 的底层数学引擎凡是需要任意矩阵变换的场景最终都会落到Transformationcm操作符上。小结pypdf.Transformation用一个六元组完整表达了 PDF 的 2D 仿射变换并通过translate、scale、rotate、transform、apply_on等返回新实例的方法提供了安全、可链式调用的操作体验。配合PageObject.add_transformation()与expand参数开发者可以精确控制页面内容的缩放、平移、旋转与镜像理解其底层的 3×3 矩阵乘法与cm操作符写入机制则能在排查内容流问题时做到心中有数。相关阅读docs/modules/Transformation.rstAPI 文档、docs/user/cropping-and-transforming.md裁剪与变换用户指南、pypdf/_utils.py矩阵乘法实现。【免费下载链接】pypdfA pure-python PDF library capable of splitting, merging, cropping, and transforming the pages of PDF files项目地址: https://gitcode.com/GitHub_Trending/py/pypdf创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考