V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
bard99
V2EX  ›  Java

有个思源宋体的字体使用疑惑,请大佬指点

  •  
  •   bard99 · 2023-08-16 15:33:31 +08:00 · 2186 次点击
    这是一个创建于 460 天前的主题,其中的信息可能已经有所发展或是发生改变。

    U+2f04 ⼄

    U+4e59 乙

    在使用 itext 的 html2pdf 生成 PDF 文件,发现一个奇怪的问题。 举个例子,我的原始文本是:乙方。这个乙方就是输入法正常打出来的乙方,拼音:yifang 。Unicode 为 U+4e59 。

    但是生成的 PDF 文件,却变成了:⼄。Unicode 为 U+2f04 。拼音查不出来,好像因为是一个部首?

    我是用的思源宋体的粗体,然后产生了这个问题。后面我换了一个字体,狮尾四季春。PDF 生成的文字就正常了,生成的也是乙方。拼音:yifang 。Unicode 为 U+4e59 。

    我去查了一下,确实这是 2 个字符:

    但是思源宋体也是同时有这 2 个字符:

    那导致这个转换不一致的原因是什么呢?

    1. 我看了下 html2pdf 的源码 debug ,找了半天没找到关于字体这里转换字符的逻辑。
    2. 但是我想了下,原始文本是乙方,乙的 Unicode 是 U+4e59 ,那应该 html2pdf 在思源宋体里面找 U+4e59 编码的字符使用就好了,但这里不应该会找错啊?

    困扰了半天了,求助下了解的大佬~

    17 条回复    2023-08-16 19:59:40 +08:00
    tabris17
        1
    tabris17  
       2023-08-16 16:00:10 +08:00   ❤️ 1
    应该是 iText 的 bug
    我用字体工具查看了思源宋体,发现代码点$2F04,$4E59 共用一个字形,可能 iText 在处理字体输出后就取了小的那个 Unicode 码
    NessajCN
        2
    NessajCN  
       2023-08-16 16:05:41 +08:00
    你是怎么查看转换完的 pdf 的字符编码的?
    bard99
        3
    bard99  
    OP
       2023-08-16 16:13:10 +08:00
    @tabris17 大佬,怎么看是共用了一个字型呢?
    bard99
        4
    bard99  
    OP
       2023-08-16 16:14:56 +08:00
    @NessajCN 直接复制 PDF 的文本出来,然后就可以查询了:
    我帖子里用的是 birdfont: https://birdfont.org/
    mw2c
        5
    mw2c  
       2023-08-16 16:15:45 +08:00
    https://juejin.cn/post/6844903729439703053
    https://gist.github.com/gettalong/d894c29b551917573c708cd5110653a0
    找到这两篇文章,猜测是生成 PDF 时 itext 对文字进行了 NFC Normalization 处理
    tabris17
        6
    tabris17  
       2023-08-16 16:15:46 +08:00
    @bard99 https://font.qqe2.com/ 在线字体编辑器
    bard99
        7
    bard99  
    OP
       2023-08-16 16:18:51 +08:00
    @tabris17 难道上面截图里,表示的是 2f04 引用了 4e59 的字型?感觉可以说得通啊!
    bard99
        8
    bard99  
    OP
       2023-08-16 16:21:05 +08:00
    @tabris17 #6
    看到了,果然共用了字型!
    NessajCN
        9
    NessajCN  
       2023-08-16 16:22:23 +08:00
    @bard99 你从 pdf 里直接拷贝是不能准确到编码的,只能靠识别,所以就是你 copy 的时候识别错了
    bard99
        10
    bard99  
    OP
       2023-08-16 16:31:33 +08:00
    @NessajCN #9 感谢指正,试了下确实如你所说。 实际上我中间省略了一些过程,我是 debug 过程中,使用 itext 的 PdfReaderContentParser 读取生成后 PDF 文件,然后取出文本内容,在这里拿到了异常的 ⼄⽅ u2f04 。
    uleh
        11
    uleh  
       2023-08-16 16:32:18 +08:00
    @NessajCN 文本型的 PDF 是可以直接复制的。全图的那种才是 OCR 识别
    NessajCN
        12
    NessajCN  
       2023-08-16 16:37:59 +08:00   ❤️ 1
    @bard99 pdf 呈现内容的方式是这样的:拿到字体绘制逻辑,然后根据实际的字显示字形。而 pdf 文件里本身只会存这种「显示方式」也就是只会存字形,除非它另外也存了一份 toUnicode 映射,这个是可存可不存的。所以你 copy pdf 出现编码不对是很正常的。这是 pdf 为了应付盗版山寨而特意为之的行为。
    bard99
        13
    bard99  
    OP
       2023-08-16 17:30:13 +08:00
    @mw2c 这 2 篇文字涨知识了,感谢。然后我本地试了一下 4 种正规化的结果,打印如下:

    这个结果看上去,好像可以得出:
    - 只有「部首」字符(如:2f04 )在正规化后,可以变成正常的「单音」字符(如:4e59 )。
    - 而「单音」字符的正规化,得到的仍然是它本身。

    如果这 2 个结论对的话,在我的场景里,却是「单音」字符,转换后得到了「部首」字符,那就不符合这个结论了。
    tabris17
        14
    tabris17  
       2023-08-16 17:41:55 +08:00
    @bard99 如果是 NFC 的话,不至于换一个字体就正常了。

    可以查看一下狮尾四季春字体,2F04 和 4E59 两个字有没有共用一个字形,如果不是,则 BUG 的可能性更大一些
    mw2c
        15
    mw2c  
       2023-08-16 18:01:08 +08:00
    @bard99 不好意思,我没仔细看帖子。应该是和 PDF 嵌入字体的方式有关。找到另一篇文章,作者也是换了一个字体就正常了。作者最后也有补充:
    ```PDF 内部存储文字并不是以 Unicode 的方式,而是有独立的编码方式 ANSI 、Identity-H 等。然后在用户复制文字的时候通过/ToUnicode 转换出 Unicode 编码。```
    https://xobo.org/unicode-normalization-nfd-nfc-nfkd-nfkc/
    bard99
        16
    bard99  
    OP
       2023-08-16 19:09:54 +08:00
    @tabris17 #14 刚用 fontstore 试了狮尾四季春、SiHei 字体,发现他们都没有给 2F04 编码添加字型!所以这 2 个字体生成的 PDF ,文字都是正常的,都是 4E59 编码的「乙」!
    bard99
        17
    bard99  
    OP
       2023-08-16 19:59:40 +08:00   ❤️ 1
    @mw2c #15 @tabris17
    我刚才做了几个实验,猜测找到了原因:

    我使用 WPS 先生成 word ,再将 word 转成 PDF 。使用的是思源宋体:


    然后使用 Python 脚本读取 PDF 内容和 Unicode 编码值:

    发现 WPS 生成 PDF 的文字是正常的「 4e59 」编码!

    对比之下,我之前使用 itext 生成的 PDF 。使用的是思源宋体:

    使用 Python 脚本读取 PDF 内容和 Unicode 编码值:

    这个 PDF 的文字是异常的「 2f04 」编码!

    所以猜测可能就是 itext 的 bug:
    1. 对于共用字型的字体,如:2f04 和 4e59 ,字型为「⼄」和「乙」。
    2. itext 程序的 bug ,导致了在使用 html 生成 PDF 的过程中
    3. 首先 html 文本传入的是 4e59 ,然后 itext 根据 4e59 找到了字体「乙-2f04/4e59 」
    4. 然后写入生成 PDF 的过程中,使用了「乙」的字型,但错误的使用了 2f04 的 Unicode 编码!
    a. 对于 WPS 来说没有这个问题,会使用 4e59 的 Unicode 编码。
    5. 所以原因,还是 itext 的问题! [至于具体的原因,还得 debug 去看了;看了半天没看出来逻辑在哪里...] !
    a. 初步推测,itext 根据 4e59 找到了字体「乙-2f04/4e59 」,然后写入 PDF 时写入了「乙-2f04 」,很可能就是获取了第一个 Unicode 编码值!而 WPS 可能是写入了「乙」,然后 Unicode 编码值则从原始文本获取,这样就关联正确了!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5294 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 09:40 · PVG 17:40 · LAX 01:40 · JFK 04:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.