吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1143|回复: 5
收起左侧

[Python 原创] 【指鹿为马】模糊处理 PDF 文本:使用构建的 CMap 对复制的文本进行加扰

[复制链接]
icer233 发表于 2024-9-7 22:13

前言

刷视频的时候看到了关于CMap映射的内容, 挺感兴趣的, 说不定可以做一些有趣的事, 就自己研究了一下

什么是 CMap

在嵌入字体的 PDF 文件中,这些字形存储在表格中,通常遵循源字体中的编码。考虑到减小文件大小,某些文件仅使用字体的子集。例如,要存储短语 , 使用的字体,只需 T、H、E、C、A、S、O、N、M 就足够了。THE CAT SAT ON THE MAT

但并非每种情况,字形和码位都有 1 对 1 的关系。尤其是当连字开始发挥作用时。(是的,我知道 fl 有它自己的码位 ,但可以肯定的是,每当你想搜索 “fly” 或 “flight” 等单词时,你永远不会想输入它。此外,有时字形的位置并不像其码位那样位于正确的位置,而只是 0、1、2、...因此,为了精确识别每个字符形,我们需要一个 map 来链接字符形和它所代表的码位。

以下是 CMap 的一个示例:

/CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo <<
/Registry (F6+0) /Ordering (T1UV) /Supplement 0 >> def
/CMapName /F6+0 def
/CMapType 2 def
1 begincodespacerange <02> <b7> endcodespacerange
19 beginbfchar
<07> <03C0>
<09> <0061>
<0a> <006D>
<0b> <0070>
<1e> <02DA>
<20> <0020>
<22> <0022>
<3d> <003D>
<3f> <003F>
<59> <0059>
<5b> <005B>
<5d> <005D>
<5f> <005F>
<7d> <007D>
<84> <2014>
<85> <2013>
<90> <2019>
<b0> <00B0>
<b7> <00B7>
endbfchar
8 beginbfrange
<24> <25> <0024>
<27> <29> <0027>
<2b> <2e> <002B>
<30> <3b> <0030>
<41> <50> <0041>
<52> <57> <0052>
<61> <7b> <0061>
<8d> <8e> <201C>
endbfrange
6 beginbfrange
<02> <02> [<0066006C>]
<03> <03> [<00540068>]
<04> <04> [<00660069>]
<05> <05> [<00660074>]
<06> <06> [<00660066>]
<08> <08> [<006600660069>]
endbfrange
endcmap CMapName currentdict /CMap defineresource pop end end

CMap 中有 2 个主要部分,和 .它们中的每一个都以一个数字开头,表示它拥有的条目数。它开始beginbfchar, beginbfrange

bfchar

这通常用于一对一的关系。第一个代码是字形 ID,第二个代码表示 Unicode 代码点。例如,表示字形 07 映射到码位 0035。<07> <0035>

bfrange

这按顺序用于批量映射:将字形表中的范围映射到 Unicode 码位。例如:表示:<31> <39> <00F2>

  • 映射 31 至 00F2
  • 映射 32 至 00F3
  • 映射 33 至 00F4
  • 映射 39 到 00FA

此外,还可以将字形分配给多个 Unicode 字符,这在处理连字时很有用。 表示将字形 02 映射到序列 (0066, 006c)。bfrange``<02> <02> [<0066006C>]

如何获取并更改CMap?

使用开源软件QPDF就可以了

执行命令:

qpdf --qdf --object-streams=disable document.pdf decompressed.pdf

使用二进制/十六进制编辑器打开decompressed.pdf, 比如记事本就可以

找到目标字体的CMap的Unicode码并更改

保存后使用命令:

qpdf --compress-streams=y decompressed.pdf output.pdf

重新压缩pdf

举例:

以下是一个我用Typora生成的PDF, 只有一个字"鹿"

  1. 用第一条命令得到decompressed.pdf
  2. 同过工具查到"鹿"和"马"的Unicode分别为U+9E7FU+9A6C
  3. 在PDF中搜索<9E7F>并将其替换为<9A6C>, 并保存
  4. 用第二条命令重新压缩PDF
  5. 成功了! 看起来是"鹿", 复制出来是"马"

一个不完善的程序

如果QPDF没有在电脑PATH里, 需要把qpdf.exe复制到程序根目录

# -*- coding: utf-8 -*-
import os

# 检测输入
if not os.path.exists('./input.pdf'):
    print('请将PDF文件复制到根目录')
    exit()

# 解析pdf
os.system('qpdf --qdf --object-streams=disable input.pdf decompressed.txt')

def chinese_to_unicode(text):
    return ''.join([f'{ord(c):04x}' for c in text])

ori_text = input('请输入要替换的中文字符:')
rep_text = input('替换为:')

ori_uni = chinese_to_unicode(ori_text).upper()
rep_uni = chinese_to_unicode(rep_text).upper()

print('\n原文本:<'+ori_uni+'>'+'\n替换为:<'+rep_uni+'>')

print('\n请在decompressed.txt文件中手动完成替换并保存!')
os.system('pause')
os.system('qpdf --compress-streams=y decompressed.txt output.pdf')
os.system('del decompressed.txt')

程序的问题在于只能改一个字以及必须手动完成替换.

第一个问题很好解决, 第二个问题在于解密出来的PDF强制转为TXT并且使用普通的Python读写是不行的, 毕竟是强制转换, 解决方案是当作二进制文件读写, 但是这样一来替换起来有些麻烦, 就懒得写了, 有兴趣的读者可以写写看

后记

这虽然能一定程度上防止他人复制你的PDF内容, 但或许只能恶心一下别人罢了, 毕竟现在的OCR技术已经很成熟了

本文关于到底如何修改CMap的步骤不是很完善, 只是一个简单的替换, 网上关于这些的资料比较少, 有了解的可以分享一下更具体的方法

参考

混淆 PDF 文本:使用精心制作的 CMap 对复制的文本进行加扰 — 1A23 Blog

PDF转Word,技术壁垒有多厚? #知识科普 #干货分享 - 抖音 (douyin.com)

QDF Mode — QPDF 11.9.1 documentation

免费评分

参与人数 1吾爱币 +7 热心值 +1 收起 理由
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

xiao52 发表于 2024-9-8 12:45
谢谢大神分享,思路很好
lnf920 发表于 2024-9-9 11:59
这个在阿杜比里编辑文本的时候自动开启OCR的。。
xiaozitwo 发表于 2024-9-9 14:27
 楼主| icer233 发表于 2024-9-10 21:23
lnf920 发表于 2024-9-9 11:59
这个在阿杜比里编辑文本的时候自动开启OCR的。。

不会的,不是图片,就像你word文档转pdf不会识别一样,在acrobat看来这都是识别好的,不用识别的。当然你截图再ocr那是另一回事
1122aa 发表于 2024-9-29 15:29
希望出一个限制阅读次数跟阅读时间的
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-15 17:34

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表