- 图像处理
【免费下载链接】PyMuPDF
PyMuPDF is a high performance Python library for data extraction, analysis, conversion & manipulation of PDF (and other) documents.
PyMuPDF 的IRect类是以整数坐标定义的矩形边界框(bounding box),与浮点型的Rect几乎同构,专门用于描述像素区域(如渲染时接收图像数据的区域)。本篇基于官方文档 docs/irect.rst 并结合 src/init.py 中的真实实现,系统讲解 IRect 的构造方式、空/无限/有效等边界语义、全部方法与属性,以及它在 Pixmap 创建、局部渲染和包围盒计算中的实际用法。读完本文,你将能熟练地在像素级场景中构建、转换、求交与检测 IRect,并理解其底层取整与坐标换算机制。
IRect 是什么:Rect 的整数坐标兄弟类
IRect是一个由四个整数x0, y0, x1, y1定义的矩形边界框,与 Rect 非常相似,唯一的区别是四个角坐标全部为整数。它主要用于指定一块"像素区域",例如在渲染时接收图像数据;而Rect则用于浮点坐标下的页面几何描述(单位是点,72 点 = 1 英寸)。
从源码看,IRect 的方法与属性与 Rect 同名,且许多实现直接复用了 Rect 的对应方法,再对结果取整。例如 src/init.py 中:
def __add__(self, p): return Rect.__add__(self, p).round() def intersect(self, r): return Rect.intersect(self, r).round() def transform(self, m): return Rect.transform(self, m).round()也就是说,IRect的绝大多数运算都是"先按 Rect 的浮点逻辑计算,再通过round()收拢回整数网格"。因此,凡是在 Rect 一节中讨论过的空、有效、无限等矩形语义,对 IRect 同样成立(详见下文"边界语义"小节)。
构造 IRect:五种重载与底层取整逻辑
IRect 的构造器是重载的,官方文档 docs/irect.rst 给出以下形式:
| 构造形式 | 说明 |
|---|---|
IRect() | 全零矩形,即IRect(0, 0, 0, 0) |
IRect(x0, y0, x1, y1) | 四个整数坐标 |
IRect(irect) | 由另一个 IRect 拷贝,生成新副本 |
IRect(sequence) | 由包含 4 个数字的 Python 序列构造 |
IRect(p0, p1)/IRect(p0, x1, y1)/IRect(x0, y0, p1) | 由点与坐标混合构造(源码 docstring 中也列出了这几种) |
其中"sequence"必须是包含 4 个数字的 Python 序列类型(list、tuple 等均可)。非整数的数字会被截断,非数值会抛出异常——这一点在 tests/test_geometry.py 的test_irect中有明确验证:IRect(1)、IRect(1, 2, 3, 4, 5)、IRect((1, 2, 3, 4, 5))、IRect(1, 2, 3, "x")均会报错。
取整方向:不是简单的 int() 截断
值得注意的细节是:IRect 构造时的"截断"并非对四个坐标统一做int()取整。查看 util_make_irect 的实现:
def util_make_irect( *args, p0=None, p1=None, x0=None, y0=None, x1=None, y1=None): a, b, c, d = util_make_rect( *args, p0=p0, p1=p1, x0=x0, y0=y0, x1=x1, y1=y1) def convert(x, ceil): if ceil: return int(math.ceil(x)) else: return int(math.floor(x)) a = convert(a, False) b = convert(b, False) c = convert(c, True) d = convert(d, True) return a, b, c, d前两个坐标x0, y0向下取整(floor),后两个坐标x1, y1向上取整(ceil)。这与 Rect.round() 的语义完全一致:左上角向外扩,右下角向外扩,得到的是"包含"原矩形的最小整数矩形,而不是简单的四舍五入。这保证了 IRect 总是完整覆盖它所对应的浮点矩形区域。
边界语义:空、有效、无限
IRect 继承了 Rect 的全部边界语义(参见 docs/rect.rst,其中明确说明这些论述同样适用于 IRect):
- 有效(valid):
x0 <= x1且y0 <= y1,即右下角确实位于左上角的东南方向。注意在 MuPDF 坐标系中 y 轴方向是从上到下的。源码中is_valid属性(src/init.py)正是这样判断的。 - 空(empty):
x0 >= x1或y0 >= y1。无效矩形必然是空矩形。width与height在坐标倒挂时被置为 0,因为源码中宽度定义为max(0, self.x1 - self.x0)(src/init.py)。 - 无限(infinite):整个 PyMuPDF 中恰好只有一个无限矩形,定义是
x0 = y0 = FZ_MIN_INF_RECT且x1 = y1 = FZ_MAX_INF_RECT。它包含一切其他矩形,主要用于技术性用途(例如某函数调用形式上需要一个矩形参数、但语义上希望"忽略"该参数时)。无限矩形不是空的。
这两个关键常量在 src/init.py 中定义:
# largest 32bit integers surviving C float conversion roundtrips # used by MuPDF to define infinite rectangles FZ_MIN_INF_RECT = -0x80000000 # -2147483648 FZ_MAX_INF_RECT = 0x7fffff80 # 2147483520之所以选择这两个值,是因为它们是能在 C float 转换往返中幸存下来的最大/最小 32 位整数。普通矩形坐标也不能超出FZ_MIN_INF_RECT到FZ_MAX_INF_RECT的范围。
对应的顶层工厂函数INFINITE_IRECT()、INFINITE_RECT()、INFINITE_QUAD()、EMPTY_RECT()定义在 src/init.py:
def INFINITE_IRECT(): return IRect(FZ_MIN_INF_RECT, FZ_MIN_INF_RECT, FZ_MAX_INF_RECT, FZ_MAX_INF_RECT)方法与属性总览
官方文档给出如下速查表,本文后续将逐项展开:
| 属性 / 方法 | 简述 |
|---|---|
IRect.contains | 检查另一个对象是否被包含 |
IRect.get_area | 计算矩形面积 |
IRect.intersect | 与另一矩形的公共部分 |
IRect.intersects | 检查是否存在非空交集 |
IRect.morph | 以一点和一矩阵进行变换 |
IRect.torect | 变换到另一矩形的矩阵 |
IRect.norm | 欧几里得范数 |
IRect.normalize | 使矩形有限(规范化角点) |
IRect.bottom_left | 左下角点,别名bl |
IRect.bottom_right | 右下角点,别名br |
IRect.height | 矩形高度 |
IRect.is_empty | 矩形是否为空 |
IRect.is_infinite | 矩形是否为无限 |
IRect.rect | 对应的Rect等价物 |
IRect.top_left | 左上角点,别名tl |
IRect.top_right | 右上角点,别名tr |
IRect.quad | 由四角构成的Quad |
IRect.width | 矩形宽度 |
IRect.x0 | 左上角 X 坐标 |
IRect.x1 | 右下角 X 坐标 |
IRect.y0 | 左上角 Y 坐标 |
IRect.y1 | 右下角 Y 坐标 |
核心方法详解
get_area([unit]):按像素、英寸、厘米或毫米计算面积
get_area()计算矩形面积,不带参数时等价于abs(IRect)的数值。与空矩形一样,无限矩形的面积也是 0。可选的unit参数支持四种单位:"px"(像素,默认)、"in"(英寸)、"cm"(厘米)、"mm"(毫米),返回类型为float。
其底层换算逻辑见 src/init.py 的_rect_area:
def _rect_area(width, height, args): unit = args[0] if args else 'px' u = {"px": (1, 1), "in": (1.0, 72.0), "cm": (2.54, 72.0), "mm": (25.4, 72.0)} f = (u[unit][0] / u[unit][1]) ** 2 return f * width * height可见换算基准是"72 点 = 1 英寸":例如get_area("cm")即(2.54/72.0) ** 2 * width * height,把以点(像素)为单位的面积换算为平方厘米。
intersect(ir):原地求交
计算当前矩形与ir的公共矩形区域并原地替换当前矩形。若二者任一为空,结果也为空;若任一为无限,则取另一个作为结果(两者皆无限则结果无限)。源码实现是先走Rect.intersect再round():
def intersect(self, r): """Restrict rectangle to intersection with rectangle r.""" return Rect.intersect(self, r).round()注意它是返回新对象而非就地修改(docstring 中"restrict"的语义),使用时应接收返回值。
contains(x):包含检测
检查x是否被包含在矩形中。x可以是rect_like、point_like或一个数字。语义细节:
- 若
x是空矩形,则永远返回 True; - 若当前矩形为空,则对非空矩形或点永远返回 False;
- 若
x是数字,则检查它是否为四个分量之一(即等于 x0、y0、x1、y1 中的某一个); x in irect与irect.contains(x)完全等价(源码中__contains__直接委托给Rect.__contains__,见 src/init.py)。
值得提醒的是,由于矩形是"半开"的(见下文语义小节),只有左上角(x0, y0)永远属于矩形,其余三个角不属于。
intersects(r):非空交集检测
检查当前矩形与rect_like参数r是否包含非空的公共 IRect。若二者任一为无限或空,则恒为 False。返回值类型为bool。源码同样委托给Rect.intersects(src/init.py)。
torect(rect):计算变换矩阵(v1.19.3 新增)
计算把当前矩形变换到目标矩形rect的矩阵。要求两个矩形都不能为空或无限,否则抛出ValueError。返回值是一个 Matrix,满足self * mat = rect,典型用途是在页面坐标与 Pixmap 像素坐标之间做变换。
其实现(src/init.py)非常直观——先平移到原点、再缩放、再平移到位:
def torect(self, r): r = Rect(r) if self.is_infinite or self.is_empty or r.is_infinite or r.is_empty: raise ValueError("rectangles must be finite and not empty") return ( Matrix(1, 0, 0, 1, -self.x0, -self.y0) * Matrix(r.width / self.width, r.height / self.height) * Matrix(1, 0, 0, 1, r.x0, r.y0) )morph(fixpoint, matrix):以固定点进行仿射变换(v1.17.0 新增)
以点fixpoint为固定点、用matrix对矩形应用矩阵变换,返回一个新的 Quad。它是同名 quad 方法的包装:若矩形为无限,则返回无限 Quad(INFINITE_QUAD())。源码:
def morph(self, p, m): if self.is_infinite: return INFINITE_QUAD() return self.quad.morph(p, m)norm():欧几里得范数(v1.16.0 新增)
把矩形视为四个数字组成的向量,返回其欧几里得范数:
def norm(self): return math.sqrt(sum([c*c for c in self]))normalize():让矩形变得"有限"
通过交换角点使矩形规范化:若x1 < x0则交换 x0/x1,若y1 < y0则交换 y0/y1。完成后右下角确实位于左上角的东南方向(但结果仍可能是空矩形)。源码为原地修改并返回自身(src/init.py):
def normalize(self): """Replace rectangle with its valid version.""" if self.x1 < self.x0: self.x0, self.x1 = self.x1, self.x0 if self.y1 < self.y0: self.y0, self.y1 = self.y1, self.y0 return self属性详解:角点、尺寸与类型转换
IRect 的所有角点属性都以 Point 对象返回(源码 src/init.py):
| 属性 | 别名 | 值 |
|---|---|---|
top_left | tl | Point(x0, y0) |
top_right | tr | Point(x1, y0) |
bottom_left | bl | Point(x0, y1) |
bottom_right | br | Point(x1, y1) |
尺寸与坐标属性:
width:abs(x1 - x0)的整数结果(源码中实现为max(0, self.x1 - self.x0),倒挂时归零);height:同理,max(0, self.y1 - self.y0);x0/y0:左 / 上侧角点的坐标(int);x1/y1:右 / 下侧角点的坐标(int)。
状态属性:
is_empty:True当且仅当x0 >= x1 or y0 >= y1(src/init.py);is_infinite:True当且仅当恰好是那个唯一的无限矩形,即x0 == y0 == FZ_MIN_INF_RECT and x1 == y1 == FZ_MAX_INF_RECT(src/init.py)。
类型转换属性:
rect:以浮点数表示相同坐标的 Rect,实现为Rect(self)(src/init.py);quad:由四角构成的四边形Quad(irect.tl, irect.tr, irect.bl, irect.br)(src/init.py)。
另外,IRect 还额外提供了include_point(p)与include_rect(r)(源码 src/init.py),分别把矩形扩张到包含某点 / 某矩形并返回新的 IRect——注意这两个方法在官方速查表中未列出,但源码与测试均确认其存在:
def include_point(self, p): rect = self.rect.include_point(p) return rect.irect def include_rect(self, r): rect = self.rect.include_rect(r) return rect.irect这在"逐步收集多个点/块的包围盒"场景中非常实用,tests/test_geometry.py 对此有验证,例如IRect(10, 20, 100, 200).include_point(Point(150, 250))结果为(10, 20, 150, 250),而include_rect((0, 0, 0, 0))(空矩形)不会改变原矩形。
序列协议与算术运算符
IRect 遵循 Python 序列协议(详见文档 docs/irect.rst 末尾的 note),因此:
- 四个分量可以通过索引访问:
irect[0]到irect[3],对应(x0, y0, x1, y1)(源码__getitem__,src/init.py); - 也支持索引赋值:
irect[2] = 5会执行int(5)后写入对应分量,越界抛出IndexError(源码__setitem__,src/init.py); len(irect)恒为 4;支持与元组等长序列比较(__eq__);- 支持哈希(
__hash__),因此 IRect 可以作为字典键或集合成员。
算术运算符方面,矩形可与 Matrix 相乘、与 Point/向量做加减等,完整规则见 docs/algebra.rst。IRect 的运算符实现(src/init.py)模式统一——先按 Rect 的规则运算,再round()回整数,例如:
def __add__(self, p): return Rect.__add__(self, p).round() def __and__(self, x): return Rect.__and__(self, x).round() # 交集 def __or__(self, x): return Rect.__or__(self, x).round() # 并集 def __mul__(self, m): return Rect.__mul__(self, m).round() # 矩阵变换与 Rect 的互转:Rect.irect / round()
从浮点 Rect 到 IRect 的转换有两个途径:
Rect.irect属性,等价于Rect.round()方法的结果;Rect.round()方法,生成包含该矩形的最小 IRect。注意这不是简单地对各边做四舍五入:左上角向左上取整、右下角向右下取整。文档 docs/rect.rst 给出示例:
>>> pymupdf.Rect(0.5, -0.01, 123.88, 455.123456).round() IRect(0, -1, 124, 456)同时也提醒了一个可能的悖论:非空 Rect 取整后可能得到空 IRect,因为 MuPDF 的算法允许 1e-3 的容差,例如Rect(100, 100, 200, 100.001)非空,但其round()结果是IRect(100, 100, 200, 100)——空的。设计像素区域裁剪逻辑时需留意这一点。
反向转换则直接使用irect.rect属性,得到浮点坐标的等价 Rect,便于参与页面级(以点为单位的)几何运算。
实战应用:像素区域与渲染裁剪
IRect 最典型的应用场景就是像素级操作。下面结合仓库测试与源码给出几个真实用例。
1. 用 IRect 直接构造 Pixmap
在 tests/test_general.py 中,IRect 被直接用于指定 Pixmap 的尺寸与像素区域:
from pymupdf import IRect, Pixmap, CS_RGB, Colorspace image = Pixmap(Colorspace(CS_RGB), IRect(0, 0, 13, 37))因为像素缓冲区需要整数行列数,用 IRect 描述"接收图像数据的区域"是语义上最自然的选择——这正是官方文档对 IRect 用途的原始定义。
2. 用 IRect 做局部渲染裁剪
在 tests/test_pixmap.py 中,IRect 被用作页面渲染的 clip 区域:
page.get_pixmap(clip=pymupdf.IRect(0, 0, 100, 100)).save("test_3134_irect.jpg")当需要只渲染页面左上角 100×100 像素的矩形区域时,直接传入 IRect 作为clip即可,避免对整页进行不必要的渲染。
3. 文本/绘图包围盒的取整
在 tests/test_general.py 中,从词块数据得到的浮点 bbox 通过.irect转成整数坐标:
bbox1 = pymupdf.Rect(w1[:4]).irect # its IRect coordinates bbox0 = pymupdf.Rect(w0[:4]).irect这在需要把文本块坐标对齐到像素网格(例如与图像遮罩、高亮框对齐)时非常实用,保证了取整方向始终是"外扩包含",不会遗漏任何浮点覆盖区域。
4. 借助 torect 做坐标映射
当需要把一个 IRect 区域(例如像素窗口)映射到另一个矩形(例如页面矩形)时,torect()返回的 Matrix 可以直接用于坐标变换:
src = pymupdf.IRect(0, 0, 100, 100) # 像素窗口 dst = page.rect # 页面区域 mat = src.torect(dst) # self * mat = dst小结
- IRect 是 PyMuPDF 的整数坐标矩形,与 Rect 共享全部语义,但专门面向像素级区域(图像缓冲区、渲染裁剪);
- 构造时
x0/y0向下取整、x1/y1向上取整(util_make_irect),保证 IRect 完整覆盖对应的浮点矩形; - 空 / 有效 / 无限三种状态有精确的代数定义,无限矩形全库唯一,由
FZ_MIN_INF_RECT/FZ_MAX_INF_RECT常量界定(src/init.py); - 全部运算通过"Rect 计算 +
round()取整"实现(src/init.py),行为可预测、结果始终为整数; - 典型用途包括 Pixmap 构造、
clip局部渲染、包围盒像素对齐以及借助torect()进行坐标映射。
进一步阅读:Rect 与矩形语义、Point 点类型、Quad 四边形、Matrix 矩阵、几何代数运算,以及仓库中对应的单元测试 tests/test_geometry.py 与 tests/test_pixmap.py。
- 图像处理
【免费下载链接】PyMuPDF
PyMuPDF is a high performance Python library for data extraction, analysis, conversion & manipulation of PDF (and other) documents.
相关推荐
目标检测边界框完全指南:从构造原理到坐标转换详解
目标检测边界框完全指南:从构造原理到坐标转换详解 Object Detection Metrics 是评估目标检测算法性能最流行的工具库,其中的 Boundin
人工智能计算机视觉模型评测YOLOv10 实时目标距离计算实战:基于边界框质心与像素-米换算的完整指南
YOLOv10 实时目标距离计算实战:基于边界框质心与像素 米换算的完整指南 距离计算是计算机视觉空间分析中的常见需求。本文基于当前 YOLOv10 仓库(Ne
人工智能深度学习计算机视觉CANN ops-cv ToAbsoluteBBox 算子解析:归一化边界框到绝对像素坐标的 NPU 实现指南
CANN ops cv ToAbsoluteBBox 算子解析:归一化边界框到绝对像素坐标的 NPU 实现指南 ToAbsoluteBBox 是 CANN op
算子库人工智能计算机视觉图像处理CANN
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考