Git Product home page Git Product logo

Comments (11)

dothinking avatar dothinking commented on August 12, 2024 1

就现状来看,请问我如何单独检测判断这种情况(每一个字是否有与字体相同颜色的描边),我应当使用什么技术方法,希望可以得到您的指点。

我也没有这个问题的通用解决方案,因为真实情况非常复杂,而且涉及很多PDF规范的基本知识。下面的分析过程,希望对你有所启发。开始之前,铺垫几点基础:

  • 一个PDF文件可以类比一个为网页,通过源码格式可以看到背后的脚本。PDF规范(1.7版有1300多页)严格定义了如何渲染PDF页面,即你所看到的样式。

  • 不同于标记语言,PDF通常用关键字表示内容,例如x y l表示从当前点连一条线到(x,y)x y w h re表示以左下角(x,y)为顶点画一个宽wh的矩形

  • 关于文字的定义在规范的第五章,关键点

    • 文本包围在一组BTET
    • Tj显示文本内容例如some text Tj
    • Tr表示渲染模式,其中2 Tr表示填充+描边模式,也就是我们关心的模拟加粗效果
    • TdTm定义了文本的位置,以左下角点为参考

删除你的测试文件中多余部分,仅留下下图部分便于分析

image

借助PyMuPDF库,读取PDF源码

import fitz

>>> doc = fitz.open('testfile.pdf')
>>> c = doc[0].getContents() # cross reference list in page 1
>>> c
[12]
>>> source = doc.xref_stream(12)
>>> for line in source.split(b'\n'): print(line)

b'/P<</MCID 27>> BDC'
b'q'
b'0 0 595.32 841.92 re W* n'
b'BT'
b'0 g 0 G .686 w 2 Tr/F0 24 Tf 116.9 589.66 Td'
b'<32C7> Tj'
b'ET'
b'Q'
b'EMC'
b'/P<</MCID 28>> BDC'
b'q'
b'0 0 595.32 841.92 re W* n'
b'BT'
b'0 g 0 G .686 w 2 Tr/F0 24 Tf 141.02 589.66 Td'
b'<32C7> Tj'
b'ET'
b'Q'
b'EMC'
b'/P<</MCID 29>> BDC'
b'q'
b'0 0 595.32 841.92 re W* n'
b'BT'
b'0 g 0 G .686 w 2 Tr/F0 24 Tf 165.14 589.66 Td'
b'<32C7> Tj'
b'ET'
b'Q'
b'EMC'
b'/P<</MCID 44>> BDC'
b'q'
b'0 0 595.32 841.92 re W* n'
b'BT'
b'0 g/F0 24 Tf 117.62 527.23 Td'
b'<34F634F634F6> Tj'
b'ET'
b'Q'
b'EMC'
b''

找出BTET之间的部分,一共4组,以第一组为例

b'BT'
b'0 g 0 G .686 w 2 Tr/F0 24 Tf 141.02 589.66 Td'
b'<32C7> Tj'
b'ET'
  • 0 g 0 G表示描边色和填充色都是黑色
  • .686 w描边粗细为0.686pt,也就是一开始我用PDF编辑器截图中的border width=0.7pt
  • 2 Tr渲染模式=2,即填充+描边
  • 24 Tf字号24
  • 141.02 589.66 Td左下角点坐标
  • <32C7> Tj文字内容

通过BTET,以及2 Tr可以筛选出我们准备处理的模拟加粗的文本,但是光文本还不能唯一确定,还需要知道位置。注意PDF规范以页面左下角点为原点,而PyMUPDF的原点在左上角,我们将PDF的(141.02 589.66)转到PyMuPDF坐标系得到(141.02, 252.34)

>>> doc[0].rect
Rect(0.0, 0.0, 595.3200073242188, 841.9199829101562) # 页面高度842
>>> y = 842-589.66
>>> y
252.34000000000003

以上得到了(141.02, 252.34)位置处的文字需要加粗,同理处理其他位置。接下来对应到PyMuPDF提取出的文本中去

>>> doc[0].getText('dict')
{
  'width': 595.3200073242188, 
  'height': 841.9199829101562, 
  'blocks': [{
    'number': 0, 
    'type': 0, 
    'bbox': (116.9000015258789, 231.635009765625, 189.13999938964844, 255.635009765625), 
    'lines': [{'
      spans': [{
        'size': 24.0, 
        'flags': 4, 
        'font': 'SimSun', 
        'color': 0, 
        'ascender': 0.859375, 
        'descender': -0.140625, 
        'text': '粗粗粗', 
        'origin': (116.9000015258789, 252.260009765625), 
        'bbox': (116.9000015258789, 231.635009765625, 189.13999938964844, 255.635009765625)
      }], 
      'wmode': 0, 
      'dir': (1.0, 0.0), 
      'bbox': (116.9000015258789, 231.635009765625, 189.13999938964844, 255.635009765625)
    }]}, 
    {
      'number': 1, 
      ....
    }]
}

以上可知粗粗粗的边框矩形为(116.90, 231.64, 189.14, 255.64),而先前得到的位置点(141.02, 252.34)正好在此范围内,可知这部分需要加粗,设置flags属性为flags+=2**4(具体参考此处的参数说明)。

pdf2docxBlock对象与上述getText('dict')的字典结构比较类似,按上述步骤更新Block后再创建docx,可以实现对这类文本的加粗。

from pdf2docx.

dothinking avatar dothinking commented on August 12, 2024

很好的一个问题,多谢提供测试文件。

我用PDF编辑器查看测试文件中“加粗”的字体,发现字体属性的粗体其实是“”——也就是说,字体上并非粗体的宋体,只是看起来比较粗。请看右侧属性的第三行和第五行,表示加了0.7pt的黑色描边,也就是在普通宋体的基础上描了一圈,使其看起来像粗体。pdf2docx借助第三方库PyMuPDF提取字体属性(字体/斜体/粗体、字号、颜色等),因为其本质上并非粗体,所以出现了你遇到的问题。

image

from pdf2docx.

dothinking avatar dothinking commented on August 12, 2024

再进一步,PDF文件出现这种描边“加粗”冒充粗体的原因是什么?

原因是当初从Word或其他格式转换到PDF的电脑缺少粗体宋体这种字体,所以转换后的PDF无法保存粗体字体信息,而是替代以描边加粗这种补救方式来保证看起来是粗体。一个小常识,为何PDF随便到哪儿打印都能保证相同的样式?以字体为例,PDF会把所有用到的字体都嵌入到PDF文件中去,这样即便打印室电脑上没安装该字体,也能正确显示和打印。而这是MS Word无法做到的,例如对于这个测试文件,原来的电脑上没有宋体-粗体这种字体,Word文档却能模拟显示出加粗的效果。

我的电脑上安装了粗体宋体SimSun Bold,刚好可以做个对比试验:

  1. Word文档中选择宋体+加粗。无论有没有安装粗体字体,Word都会显示加粗的效果

image

  1. 另存为PDF查看字体属性。因为有粗体字体加持,此时Bold属性显示为True

image

from pdf2docx.

dothinking avatar dothinking commented on August 12, 2024

那如果已经是测试文件这个样子了(通过描边模拟粗体),pdf2docx如何正确转换粗体?

很抱歉,通过上面的分析可知,目前无法处理这种情况,并且考虑到这个问题的实际意义和优先级,短期内也不会进行修复。但理论上,可以通过检测每一个字是否有与字体相同颜色的描边来判断是否需要额外加粗。另外,斜体也是类似的情况。

from pdf2docx.

aiprogramming avatar aiprogramming commented on August 12, 2024

那如果已经是测试文件这个样子了(通过描边模拟粗体),pdf2docx如何正确转换粗体?

很抱歉,通过上面的分析可知,目前无法处理这种情况,并且考虑到这个问题的实际意义和优先级,短期内也不会进行修复。但理论上,可以通过检测每一个字是否有与字体相同颜色的描边来判断是否需要额外加粗。另外,斜体也是类似的情况。

以上分析的非常精彩。
可能由于我们所处的地域不同,习惯有所不同。实际生产使用word过程中,字体选择后,在需要加粗时会直接使用word中的bold选项,而不会单独下载XX字体-粗体的字体。我身边所有的同事,也包括我在内编辑word时也会这样。我猜国内朋友也是这样使用的。

就现状来看,请问我如何单独检测判断这种情况(每一个字是否有与字体相同颜色的描边),我应当使用什么技术方法,希望可以得到您的指点。

from pdf2docx.

dothinking avatar dothinking commented on August 12, 2024

可能由于我们所处的地域不同,习惯有所不同。实际生产使用word过程中,字体选择后,在需要加粗时会直接使用word中的bold选项,而不会单独下载XX字体-粗体的字体。我身边所有的同事,也包括我在内编辑word时也会这样。我猜国内朋友也是这样使用的。

是的,作为用户都是像你这样操作的。但是MS Word在接受了你的操作后,背后设置的实际是XX字体-粗体XX字体-斜体,并且恰好系统已经安装了常见字体。而一旦不存在这样的字体,就出现了这种等效粗体的情况。举个例子,看一下我们熟悉的Times New Roman字体(C:\Windows\Fonts),你会发现常规粗体斜体的每种组合都对应了一种字体,而不仅仅只是Times New Roman

image

from pdf2docx.

dothinking avatar dothinking commented on August 12, 2024

上游库PyMuPDf与本问题相关的两个issue:

from pdf2docx.

dothinking avatar dothinking commented on August 12, 2024

暂时关闭,如有问题欢迎继续探讨。

from pdf2docx.

aiprogramming avatar aiprogramming commented on August 12, 2024

image

请问这个工具叫什么名字

from pdf2docx.

dothinking avatar dothinking commented on August 12, 2024

一个PDF编辑器:PDF-XChange,选择对象(文本、图片、形状)后可以显示基本属性

from pdf2docx.

aiprogramming avatar aiprogramming commented on August 12, 2024

非常感谢

from pdf2docx.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.