Story#
新增于 v1.21.0
方法 / 属性 |
简短描述 |
---|---|
“重置”故事输出至其起始位置 |
|
计算故事内容以适应提供的矩形区域 |
|
将计算出的内容写入当前页面 |
|
回调函数,用于记录当前处理的故事内容 |
|
故事的底层 body |
|
将故事放置并绘制到 DocumentWriter |
|
迭代布局HTML内容到 DocumentWriter |
|
类似于 |
|
类似于 |
|
查找包含故事 |
|
Class API
- class Story#
- __init__(self, html=None, user_css=None, em=12, archive=None)#
创建一个 story (故事),可选地提供 HTML 和 CSS 源代码。 HTML 将被解析,并作为 DOM(文档对象模型)存储在 Story 中。
该结构可以被修改:可以使用 Xml 类的方法添加、复制、修改或删除内容(文本、图像)。
完成后, story 可以写入任何设备; 在典型的使用场景中,该设备可能由 DocumentWriter 提供,以创建新页面。
以下是一些一般性说明:
Story 构造函数会解析并验证提供的 HTML 以创建 DOM。
PyMuPDF 提供了多种方法来操作 HTML 源代码,允许访问底层 DOM 的 节点。文档可以完全从头开始以编程方式构建,或者对现有 DOM 进行任意修改。有关该接口的详细信息,请参阅 Xml 类。
如果不再需要对 DOM 进行更改,则 story 准备好进行布局,并可写入一系列设备(通常是由 DocumentWriter 提供的设备,以生成新页面)。
下一步是放置 story 并将其写入输出。这可以直接完成,通过循环调用
place()
和draw()
,或者使用write()
或write_stabilized()
方法让它自动处理循环。选择哪种方式主要取决于个人偏好。如果选择手动方式,建议使用以下循环:
获取一个合适的设备进行写入;通常通过从 DocumentWriter 请求一个新的空白页面。
确定页面上的一个或多个矩形区域,这些区域将用于接收 story 数据。请注意,并非每个页面都需要使用相同的矩形区域集。
将每个矩形传递给 story 以进行放置,了解该矩形的填充情况,以及是否还有未适应的 story 数据。这一步可以重复多次,并调整矩形区域,直到获得满意的结果。
在此阶段,可以通过调用
element_positions()
方法请求有关已放置项目的位置的详细信息。如果heading
属性为非零整数(对应于 HTML 标签 h1 - h6),或者id
属性不为None
(对应于 HTML 标签 id),或者href
属性不为None
(对应于 HTML 标签 href),则该元素被视为“感兴趣的元素”。这对于自动生成目录(Table of Contents)、索引或类似用途非常方便。使用
draw()
方法将该矩形绘制到设备上。如果最近一次
place()
调用表明所有 story 数据均已适应,则停止。否则,循环回到前面:如果当前设备(页面)上还有更多的矩形需要填充,则返回到步骤 3;如果没有,则返回步骤 1 以获取新设备(页面)。
另一种方式,如果使用 DocumentWriter,
可以使用
write()
或write_stabilized()
方法。 这些方法会自动处理所有循环, 只需提供控制行为的回调(主要是一个枚举矩形/页面的回调函数)。story 的内容将如何分布到哪些矩形 / 页面,完全由 Story 对象控制,无法预知。
图像可以包含在 story 中,并与周围文本一起放置。
多个 story 可以独立地写入同一页面。例如,可以使用不同的 story 分别处理页眉、页脚、正文文本、注释框等。
- 参数:
html (str) – HTML 源代码。如果省略,将生成一个基本的最小结构(见下文)。 如果提供,则无需是完整的 HTML 文档。 内置解析器会容忍(大多数)HTML 语法错误,并接受 HTML 片段,如
"<b>Hello, <i>World!</i></b>"
。user_css (str) – CSS 源代码。如果提供,则必须包含有效的 CSS 规则。
em (float) – 默认文本字体大小。
archive – 一个 Archive 对象,用于加载渲染资源。 目前支持的资源类型包括图像和字体。 如果省略,story 将不会查找任何此类数据,因此可能会导致输出不完整。
备注
除了实际的 archive 对象,也可以提供创建 Archive 的有效参数。 例如,
story = pymupdf.Story(archive=pymupdf.Archive("myfolder"))
可以简化为story = pymupdf.Story(archive="myfolder")
。
- place(where)#
计算 story 内容中可以适应提供矩形的部分。 该方法会维护一个指针,指示 story 内容已经写入的位置, 并在下一次调用时从该指针处继续。
- 参数:
where (rect_like) – 将当前内容布局到该矩形中。该矩形必须是页面 MediaBox 的子矩形。
- 返回类型:
tuple[bool, rect_like]
- 返回:
一个布尔值
more
和一个矩形filled
。 如果more == 0
,则 story 的所有内容均已写入; 否则,仍有内容等待写入后续矩形或页面。filled
是where
中实际被填充的部分。
- draw(dev, matrix=None)#
将
Story.place()
计算出的内容写入页面。
- element_positions(function, args=None)#
在 story 计算出 HTML 元素在当前页面的位置后, 让它提供这些信息 - 必须在
Story.place()
之后立即调用。Story 将位置信息传递给 function,例如可用于生成目录(Table of Contents)。
- 参数:
function (callable) – 接受一个
ElementPosition
对象的 Python 函数。 该函数会被 Story 对象调用来处理位置信息。 该函数 必须 是一个接受 唯一 一个参数的可调用对象。args (dict) – 可选字典,包含应添加到
ElementPosition
实例中的 额外信息, 例如当前输出页面编号。 该字典的每个键必须是符合 Python 标识符规则的字符串。 下面会详细说明完整的信息集。
- reset()#
将 story 文档倒回到起始位置,以便重新开始输出。
- write(writer, rectfn, positionfn=None, pagefn=None)#
将 story 放置并绘制到 DocumentWriter,避免调用代码 需要手动实现循环来调用
Story.place()
和Story.draw()
。- 参数:
writer – DocumentWriter 实例,或
None
。rectfn –
一个可调用对象,接受
(rect_num: int, filled: Rect)
并返回(mediabox, rect, ctm)
:mediabox:
None
或者表示新页面的矩形。rect: 下一块应放置内容的矩形区域。
ctm:
None
或 Matrix 变换矩阵。
positionfn –
None
,或一个可调用对象,接受(position: ElementPosition)
:position: 一个
ElementPosition
实例,具有额外的.page_num
成员。
该函数通常会在生成标题元素或具有
id
的元素时被多次调用。pagefn –
None
,或一个可调用对象,接受(page_num, mediabox, dev, after)
: 在每个页面的开始 (after=0
) 和结束 (after=1
) 处调用。
- static write_stabilized(writer, contentfn, rectfn, user_css=None, em=12, positionfn=None, pagefn=None, archive=None, add_header_ids=True)#
静态方法,对 HTML 内容进行迭代布局,并写入 DocumentWriter。
例如,这允许在确保页码稳定的情况下添加目录(Table of Contents)部分。
该方法会重复执行以下操作:
使用
(contentfn(), user_css, em, archive)
创建新的 Story 实例。通过内部调用
Story.write()
进行布局,并使用None
作为 writer 提取ElementPosition
列表,该列表会传递给下一次contentfn()
调用。当
contentfn()
生成的 HTML 内容不再变化时,执行最终迭代,并使用writer
进行最终写入。
- 参数:
writer – 一个 DocumentWriter。
contentfn – 一个函数,接受
ElementPositions
列表,并返回包含 HTML 内容的字符串。 返回的 HTML 可以依赖于该列表,例如用于在文档开头生成目录。rectfn –
一个可调用对象,接受
(rect_num: int, filled: Rect)
并返回(mediabox, rect, ctm)
:mediabox:
None
或者新页面的矩形。rect: 下一个应放置内容的矩形区域。
ctm: Matrix 变换矩阵。
pagefn –
None
,或一个可调用对象,接受(page_num, mediabox, dev, after)
; 在每个页面的开始 (after=0
) 和结束 (after=1
) 处调用。archive – 资源存储 Archive,可用于加载图像和字体。
add_header_ids – 若为
True
,则对所有没有id
的 HTML 标题标签(如<h1>
-<h6>
)添加唯一的id
, 以便自动生成目录。
- 返回:
None
。
- write_with_links(rectfn, positionfn=None, pagefn=None)#
- static write_stabilized_with_links(contentfn, rectfn, user_css=None, em=12, positionfn=None, pagefn=None, archive=None, add_header_ids=True)#
类似于
write_stabilized()
,但没有writer
参数, 而是返回一个包含内部 HTML 链接的 PDF Document。
- class FitResult#
Story.fit*()
方法的返回结果。成员:
big_enough
:若
True
,表示内容适应成功。filled
:最后一次
Story.place()
调用填充的矩形。more
:若
False
,表示适应成功。numcalls
:调用了
self.place()
的次数。parameter
:适应成功的参数值,或最大的失败参数值。
- Rect:
由
parameter
生成的矩形。
- fit(self, fn, pmin=None, pmax=None, delta=0.001, verbose=False)#
查找能包含
self
的最优矩形。返回一个
Story.FitResult
实例。成功时,
self.place()
的最后一次调用会使用返回的矩形,因此可以直接调用self.draw()
进行绘制。- 参数:
fn –
一个可调用对象,接受一个浮点数
parameter
并返回pymupdf.Rect()
。 如果返回的矩形为空,则认为故事无法适应该矩形,并不会调用self.place()
。该函数必须保证
self.place()
在fn(parameter)
增大时单调递增。 这通常意味着宽度和高度随着parameter
的增大而增大或保持不变。pmin – 要考虑的最小参数值;
None
表示负无穷大。pmax – 要考虑的最大参数值;
None
表示正无穷大。delta – 返回
parameter
的最大误差。verbose – 若为
True
,则输出诊断信息。
- fit_scale(self, rect, scale_min=0, scale_max=None, delta=0.001, verbose=False)#
查找范围
scale_min..scale_max
内的最小scale
值,使得scale * rect
足够大,可以包含self
。返回一个
Story.FitResult
实例。- 参数:
rect – 原始矩形。
scale_min – 需要考虑的最小缩放比例,必须大于等于
0
。scale_max – 需要考虑的最大缩放比例,必须大于等于
scale_min
,或None
表示无限。delta – 返回的缩放比例的最大误差。
verbose – 若为
True
,则输出诊断信息。
- fit_height(self, width, height_min=0, height_max=None, origin=(0, 0), delta=0.001, verbose=False)#
查找范围
height_min..height_max
内的最小高度,使得(width, height)
的矩形足够大, 可以包含self
。返回一个
Story.FitResult
实例。- 参数:
width – 矩形的宽度。
height_min – 需要考虑的最小高度,必须大于等于
0
。height_max – 需要考虑的最大高度,必须大于等于
height_min
,或None
表示无限。origin – 矩形的
(x0, y0)
坐标。delta – 返回的高度的最大误差。
verbose – 若为
True
,则输出诊断信息。
- fit_width(self, height, width_min=0, width_max=None, origin=(0, 0), delta=0.001, verbose=False)#
查找范围
width_min..width_max
内的最小宽度,使得(width, height)
的矩形足够大, 可以包含self
。返回一个
Story.FitResult
实例。- 参数:
height – 矩形的高度。
width_min – 需要考虑的最小宽度,必须大于等于
0
。width_max – 需要考虑的最大宽度,必须大于等于
width_min
,或None
表示无限。origin – 矩形的
(x0, y0)
坐标。delta – 返回的宽度的最大误差。
verbose – 若为
True
,则输出诊断信息。
New in v1.21.0
Method / Attribute |
Short Description |
---|---|
“rewind” story output to its beginning |
|
compute story content to fit in provided rectangle |
|
write the computed content to current page |
|
callback function logging currently processed story content |
|
the story’s underlying body |
|
places and draws Story to a DocumentWriter |
|
iterative layout of html content to a DocumentWriter |
|
like |
|
like |
|
Finds optimal rect that contains the story |
|
Class API
元素定位回调函数#
Element Positioning CallBack function
回调函数可用于记录关于故事输出的信息。该函数对信息的访问是只读的:它无法影响故事的输出。
使用此方法执行故事的典型循环如下所示:
HTML = """
<html>
<head></head>
<body>
<h1>Header level 1</h1>
<h2>Header level 2</h2>
<p>Hello MuPDF!</p>
</body>
</html>
"""
MEDIABOX = pymupdf.paper_rect("letter") # 页面大小
WHERE = MEDIABOX + (36, 36, -36, -36) # 留出0.5英寸的边框
story = pymupdf.Story(html=HTML) # 创建故事
writer = pymupdf.DocumentWriter("test.pdf") # 创建写入器
pno = 0 # 当前页码
more = 1 # 完成时设置为0
while more: # 循环,直到所有故事内容处理完
dev = writer.begin_page(MEDIABOX) # 创建设备以在页面上写入
more, filled = story.place(WHERE) # 计算页面上的内容位置
story.element_positions(recorder, {"page": pno}) # 另外提供页面号码
story.draw(dev)
writer.end_page()
pno += 1 # 增加页码
writer.close() # 关闭输出文件
def recorder(elpos):
pass
The callback function can be used to log information about story output. The function’s access to the information is read-only: it has no way to influence the story’s output.
A typical loop for executing a story with using this method would look like this:
HTML = """
<html>
<head></head>
<body>
<h1>Header level 1</h1>
<h2>Header level 2</h2>
<p>Hello MuPDF!</p>
</body>
</html>
"""
MEDIABOX = pymupdf.paper_rect("letter") # size of a page
WHERE = MEDIABOX + (36, 36, -36, -36) # leave borders of 0.5 inches
story = pymupdf.Story(html=HTML) # make the story
writer = pymupdf.DocumentWriter("test.pdf") # make the writer
pno = 0 # current page number
more = 1 # will be set to 0 when done
while more: # loop until all story content is processed
dev = writer.begin_page(MEDIABOX) # make a device to write on the page
more, filled = story.place(WHERE) # compute content positions on page
story.element_positions(recorder, {"page": pno}) # provide page number in addition
story.draw(dev)
writer.end_page()
pno += 1 # increase page number
writer.close() # close output file
def recorder(elpos):
pass
ElementPosition 类的属性#
Attributes of the ElementPosition class
必须向 Story.element_positions()
提供的函数传递一个参数。它是一个具有以下属性的对象:
传递给 recorder
函数的参数是一个具有以下属性的对象:
elpos.depth
(int) – 该元素在盒子结构中的深度。elpos.heading
(int) – 标题级别,0 表示没有标题,1-6 对应于 h1 - h6。elpos.href
(str) –href
属性的值,如果未定义,则为 None。elpos.id
(str) –id
属性的值,如果未定义,则为 None。elpos.rect
(tuple) – 元素在页面上的位置。elpos.text
(str) – 元素的即时文本。elpos.open_close
(int bit field) – 位 0 设置:打开元素,位 1 设置:关闭元素。与可能包含其他元素的元素相关,因此这些元素可能在创建/打开后不能立即关闭。elpos.rect_num
(int) – 到目前为止故事中填充的矩形数量。elpos.page_num
(int) – 页码;仅在使用pymupdf.Story.write*()
函数时存在。
Exactly one parameter must be passed to the function provided by Story.element_positions()
. It is an object with the following attributes:
The parameter passed to the recorder
function is an object with the following attributes:
elpos.depth
(int) – depth of this element in the box structure.elpos.heading
(int) – the header level, 0 if no header, 1-6 for h1 - h6.elpos.href
(str) – value of thehref
attribute, or None if not defined.elpos.id
(str) – value of theid
attribute, or None if not defined.elpos.rect
(tuple) – element position on page.elpos.text
(str) – immediate text of the element.elpos.open_close
(int bit field) – bit 0 set: opens element, bit 1 set: closes element. Relevant for elements that may contain other elements and thus may not immediately be closed after being created / opened.elpos.rect_num
(int) – count of rectangles filled by the story so far.elpos.page_num
(int) – page number; only present when usingpymupdf.Story.write*()
functions.