diff --git "a/docs/2020-07-14-pdf2docx\345\274\200\345\217\221\346\246\202\350\246\201\357\274\232\346\217\220\345\217\226\346\226\207\346\234\254\343\200\201\345\233\276\347\211\207\345\222\214\345\275\242\347\212\266.md" "b/docs/2020-07-14-pdf2docx\345\274\200\345\217\221\346\246\202\350\246\201\357\274\232\346\217\220\345\217\226\346\226\207\346\234\254\343\200\201\345\233\276\347\211\207\345\222\214\345\275\242\347\212\266.md" index 1b047f2..5a96bb5 100644 --- "a/docs/2020-07-14-pdf2docx\345\274\200\345\217\221\346\246\202\350\246\201\357\274\232\346\217\220\345\217\226\346\226\207\346\234\254\343\200\201\345\233\276\347\211\207\345\222\214\345\275\242\347\212\266.md" +++ "b/docs/2020-07-14-pdf2docx\345\274\200\345\217\221\346\246\202\350\246\201\357\274\232\346\217\220\345\217\226\346\226\207\346\234\254\343\200\201\345\233\276\347\211\207\345\222\214\345\275\242\347\212\266.md" @@ -21,9 +21,9 @@ tags: [python] - 将图片块整合到文本块`TextBlock`中,作为`line`>`span`级别的元素 -- `block`增加了布局参数,例如`alignment`,`left_space`,`before_space`,用以保存后续段落布局解析结果 +- 增加布局参数,例如`alignment`,`left_space`,`before_space`,用以保存后续段落布局解析结果 + -- 新增了表格块`TableBlock`,用以保存表格解析结果 !!! warning "注意" 后续版本中发现`extractDICT()`获取图片存在问题(如只能获取完全显示在页面中的图片、丢失alpha通道),还需配合`page.getImageList()`处理;另外,v0.5.0版本中对浮动图片也进行了支持,详见以下两篇图片相关的记录。 @@ -154,11 +154,11 @@ EMC ## 总结 -借助`PyMuPDF`从PDF提取文本、图片和形状数据,它们构成了`pdf2docx`的基础数据: +借助`PyMuPDF`从PDF提取文本、图片和形状数据,它们构成了`pdf2docx`的两类基础数据: -- `Block`代表主体内容,例如文本/图片组成的`TextBlock`和表格结构的`TableBlock`,它们都将作为Word中的段落。 +- 块元素`Block`,代表主体内容,例如直接提取出的文本/图片组成的`TextBlock`,以及后续解析得到的表格结构`TableBlock`。 -- `Shape`代表格式内容,例如描边`Stroke`将对应下划线、表格边框等,填充`Fill`将对应文本高亮、单元格背景色等。 +- 形状元素`Shape`,代表格式内容,例如描边`Stroke`将对应下划线、表格边框等,填充`Fill`将对应文本高亮、单元格背景色等。 [^1]: [TextPage](https://pymupdf.readthedocs.io/en/latest/textpage.html) diff --git "a/docs/2020-08-15-pdf2docx\345\274\200\345\217\221\346\246\202\350\246\201\357\274\232\350\247\243\346\236\220\350\241\250\346\240\274.md" "b/docs/2020-08-15-pdf2docx\345\274\200\345\217\221\346\246\202\350\246\201\357\274\232\350\247\243\346\236\220\350\241\250\346\240\274.md" index c40e2a3..b1daa1a 100644 --- "a/docs/2020-08-15-pdf2docx\345\274\200\345\217\221\346\246\202\350\246\201\357\274\232\350\247\243\346\236\220\350\241\250\346\240\274.md" +++ "b/docs/2020-08-15-pdf2docx\345\274\200\345\217\221\346\246\202\350\246\201\357\274\232\350\247\243\346\236\220\350\241\250\346\240\274.md" @@ -84,7 +84,7 @@ PDF中没有语义上的表格的概念,所以需要根据外观上的表格 ## 数据结构 -表格块`TableBlock`继承了第一类基本数据`Block`的结构(详见[PDF提取](2020-07-14-pdf2docx开发概要:提取文本、图片和形状.md)),同时新增了表征表格结构的`Row`和`Cell`。其中`Cell`也是布局级别的对象,嵌套了下一级的`Block`和`Shape`。 +表格块`TableBlock`继承了块元素`Block`的结构(详见[PDF提取](2020-07-14-pdf2docx开发概要:提取文本、图片和形状.md)),同时新增了表征表格结构的`Row`和`Cell`。其中`Cell`是布局级别的对象(`Layout`),嵌套了下一级的块元素和形状元素,如此递归,直到块元素中不再包含表格,即只有表征文本和图片的`TextBlock`。 ```python diff --git "a/docs/2020-08-27-pdf2docx\345\274\200\345\217\221\346\246\202\350\246\201\357\274\232\350\247\243\346\236\220\346\256\265\350\220\275.md" "b/docs/2020-08-27-pdf2docx\345\274\200\345\217\221\346\246\202\350\246\201\357\274\232\350\247\243\346\236\220\346\256\265\350\220\275.md" index 31e6276..7ce4324 100644 --- "a/docs/2020-08-27-pdf2docx\345\274\200\345\217\221\346\246\202\350\246\201\357\274\232\350\247\243\346\236\220\346\256\265\350\220\275.md" +++ "b/docs/2020-08-27-pdf2docx\345\274\200\345\217\221\346\246\202\350\246\201\357\274\232\350\247\243\346\236\220\346\256\265\350\220\275.md" @@ -9,13 +9,13 @@ tags: [python] --- -经过[表格解析](2020-08-15-pdf2docx开发概要:解析表格.md)后,我们得到了整合的文本/图片/表格`Block`。其中文本/图片块将被重建为段落,表格块将被重建为表格,单元格内文本/图片块按照相同的逻辑处理。在此基础上,计算相邻元素之间的间距,例如竖直方向的前后段间距、水平方向的段落缩进。 +经过[表格解析](2020-08-15-pdf2docx开发概要:解析表格.md)后,我们得到了整合的块元素:文本/图片块`TextBlock`和表格块`TableBlock`。其中文本/图片块将被重建为段落,表格块将被重建为表格,单元格内的块元素按照相同的逻辑进行递归处理。在此基础上,计算相邻元素之间的间距,例如竖直方向的前后段间距、水平方向的段落缩进。 ## 竖直方向定位:段间距 -`Block`块级元素之间通过间距确定相对位置关系。由于Word中 **段落具有段前/段后间距属性**,文本块将被作为定位的参考元素。 +块级元素之间通过间距确定相对位置关系。由于Word中 **段落具有段前/段后间距属性**,文本块将被作为定位的参考元素。 竖直间距确定原则: @@ -37,20 +37,20 @@ tags: [python] 已知块的高度和内部行数,容易计算得到平均行距。Word中有两种设置行间距的方式: -- 固定值:直接设置为计算出的平均行距,优点是定位精确,缺点是不会随着字号的变化而改变,不利于编辑。例如一旦增大字号,则有可能导致显示不全。 +- 固定值:直接设置为计算出的平均行距,优点是定位精确,缺点是不会随着字号的变化而改变,不利于编辑。例如一旦增大字号,则有可能导致该行文本显示不全。 -- 倍数行距:与单倍行距的比值,优缺点与固定值行距正好相反。 +- 倍数行距:与单倍行距的比值,优缺点刚好与固定行距相反。 综合来看,倍数行距有更好的适应性,v0.5.2版开始启用倍数行距。 -注意,倍数行距并非与字号的简单比值或者流传的1.2倍的比例关系,而是 **与具体字体相关**。单开一篇介绍倍数行距计算问题: +注意,倍数行距并非行高与字号的简单比值或者流传的1.2倍的比例关系,而是 **与具体字体相关**。单开一篇介绍倍数行距计算问题: > [此坑待填...](to_do) ## 水平方向定位:对齐方式与缩进 -水平方向从内部(块内元素的对齐关系)和外部(页面中的位置)两个方面确定对齐方式:左/居中/右/分散对齐。其中左对齐为默认方式,因为结合段落左缩进和制表符,总能正确定位任何块间元素。 +水平方向从内部(块内元素`Line`的对齐关系)和外部(页面中的位置)两个方面确定对齐方式:左/居中/右/分散对齐。其中左对齐为默认方式,因为结合段落左缩进和制表符,总能正确定位任何块间元素。 **内部对齐关系**:行与行之间位置关系 @@ -81,9 +81,17 @@ tags: [python] - 如果只有一行,则将这个放宽放到极限,即设置相应边距等于0。 +## 文本样式 + +以上解析结果确定了段落在页面中的位置和呈现样式,接下来深入到段内文本。`PyMuPDF`提取的原始文本块自带了字体、颜色、斜体、粗体等属性,但是`高亮`、`下划线`、`删除线`等具体样式需要进一步根据 **文本和形状的位置关系** 来判定。 + +具体参考下文: + +> [pdf2docx开发概要:解析文本样式](2020-07-20-pdf2docx开发概要:解析文本样式.md) + ## 数据结构 -综上,文本块`TextBlock`在标准`Block`数据结构(`Line`->`Span`->`Char`)的基础上,加入了如下定位相关属性: +综上,文本块`TextBlock`在标准`Block`数据结构(`Line`->`Span`->`Char`)的基础上,引入了如下定位相关属性: ```python # text block diff --git "a/docs/2021-05-30-pdf2docx\345\274\200\345\217\221\346\246\202\350\246\201\357\274\232\350\247\243\346\236\220\351\241\265\351\235\242\345\270\203\345\261\200.md" "b/docs/2021-05-30-pdf2docx\345\274\200\345\217\221\346\246\202\350\246\201\357\274\232\350\247\243\346\236\220\351\241\265\351\235\242\345\270\203\345\261\200.md" index 43f7361..f217b74 100644 --- "a/docs/2021-05-30-pdf2docx\345\274\200\345\217\221\346\246\202\350\246\201\357\274\232\350\247\243\346\236\220\351\241\265\351\235\242\345\270\203\345\261\200.md" +++ "b/docs/2021-05-30-pdf2docx\345\274\200\345\217\221\346\246\202\350\246\201\357\274\232\350\247\243\346\236\220\351\241\265\351\235\242\345\270\203\345\261\200.md" @@ -8,7 +8,7 @@ tags: [python] --- -[前文](2020-07-14-pdf2docx开发概要:提取文本、图片和形状.md)介绍了从PDF直接提取出的基本数据文本/图片/表格块`Block`和形状`Shape`,但是它们目前还只有位置数据,接下来要做的是解析语义数据,也就是从`Block`解析出段落和段落属性如段间距、对齐方式,从`Shape`解析出文本样式例如下划线、高亮及其作用的文本、解析表格样式如边框颜色、背景色及其包含的段落。我们先从页面布局开始。 +[前文](2020-07-14-pdf2docx开发概要:提取文本、图片和形状.md)介绍了从PDF直接提取出的基本数据:块元素`Block`和形状`Shape`,但是它们目前还只有位置数据,接下来要做的是解析语义数据,例如从块元素解析出表格和普通段落,从形状元素解析出文本样式例如下划线、高亮及其作用的文本、解析表格样式如边框颜色、背景色及其包含的段落。我们先从页面布局开始。 ## 数据结构 @@ -17,9 +17,9 @@ tags: [python] - `Page`类对应物理上的一个页面,具有尺寸、边距、页眉页脚等属性,主要内容按照流式布局顺序被分为一个或者多个`Section` -- `Section`对应Word中的Section,表示具有类似结构的布局,例如一个或者多个分栏`Column` +- `Section`对应Word的节(Section),表示具有类似结构的布局,例如一个或者多个分栏`Column` -- `Column`对应Word中的Column,表示分栏中的一列。对于普通的排版,主要元素都在一个`Section`的一个`Column`下 +- `Column`对应Word的分栏(Column),表示分栏中的一列。对于普通的排版,块元素和形状元素都在一个`Section`的一个`Column`下 ``` ┌───────────────────────────────────┐ @@ -42,14 +42,14 @@ tags: [python] ## 页眉页脚 -理论上,无法从单个页面识别出页眉和页脚,所以需要从文档级别、多个Pages一起对比结构相似性,从而从页面开始部分分离出页眉、从页面结束部分分离出页脚。同时,需要处理一些不确定因素,例如页码、奇偶页不同的页眉页脚。 +理论上,无法从单个页面识别出页眉和页脚,所以需要从文档级别即多个Pages一起对比结构相似性,从而从页面开始部分分离出页眉、从页面结束部分分离出页脚。同时,需要处理一些不确定因素,例如页码、奇偶页不同的页眉页脚。 截至`v0.5.2`,这部分依然占坑待处理中。 ## 页面大小与页边距 -`PyMuPDF`提取的数据直接包括了页面宽度和高度,然后根据 **除去页眉页脚后** 的所有块级元素所占据的区域计算页边距,例如最小左上角点确定了左边距和上边距。 +`PyMuPDF`提取的数据直接包括了页面宽度和高度,然后根据 **除去页眉页脚后** 的所有块级、形状元素所占据的区域计算页边距,例如最小左上角点确定了左边距和上边距。 `python-docx`中页面`section`对象恰好提供了这六个属性,例如`page_width`、`left_margin`。于是页面基本形式得以确定。 @@ -59,7 +59,7 @@ tags: [python] 早期版本通过表格来实现分栏布局,从0.5.2版开始引入`Section`和`Column`,以保证页面逻辑的合理性,同时减少嵌套表格的泛滥。 !!! note "注意" - 兼顾通用性和降低复杂度,目前仅支持单栏或者两栏的布局,更多的分栏将被解析为表格。 + 为兼顾通用性和降低复杂度,目前仅支持单栏或者两栏的布局,更多的分栏将被解析为表格。 ### 分栏逻辑 @@ -82,10 +82,10 @@ tags: [python] 每一个`Section`在页面竖直方向的位置 **由前一个段落的段后间距** 确定,因此在确定好`Section`后,计算当前`Section`开始位置`y0`与前一个`Section`结束位置`y1`的差值,作为`Section`的一个属性`before_space`。 -使用`python-docx`重建`Section`时,设置前一个`Section`最后一个段落的段后间距等于当前`Section`的`before_space`即可。两个`Column`之间设置列分隔符`WD_SECTION.NEW_COLUMN`。 +使用`python-docx`重建`Section`时,设置前一个`Section`最后一个段落的段后距离等于当前`Section`的`before_space`即可。两个`Column`之间设置列分隔符`WD_SECTION.NEW_COLUMN`。 -!!! warning "页面第一个`Section`的处理" +!!! warning "每一页第一个`Section`的处理" - 计算`before_space`时,前一个参考位置为页面上边距。 - 重建`Section`时,新建一个空段落作为设置段后间距的参考。 @@ -107,7 +107,7 @@ tags: [python] └────────────────────────────────┘ ``` -解析出`TableBlock`后,继续根据位置关系将`Block`和`Shape`分配到相应的单元格中去。由此可知,容纳`Block`和`Shape`的单元格也是一个`Layout`对象,可以继续进行单元格内的嵌套表格和段落解析。这样的设计确保可以递归解析出无限嵌套的表格,同时也有助于将PDF的浮动布局转化为流动布局,便于在Word中重建。 +PDF直接提取出的块元素只有`TextBlock`,结合形状元素(潜在的表格边框、单元格背景色)解析出`TableBlock`后,继续根据位置关系将表格范围内的`Block`和`Shape`分配到相应的单元格中去。由此可知,容纳`Block`和`Shape`的单元格也是一个`Layout`对象,可以继续进行单元格内的嵌套表格和段落解析。这样的设计确保可以递归解析出无限嵌套的表格,同时也有助于将PDF的浮动布局转化为流动布局,便于在Word中重建。 至于表格的具体解析方法,单开一篇进行具体介绍: