使用 iText 提取文本不起作用:编码或加密文本?

2023-12-10

我有一个 pdf 文件,其安全属性如下:打印:允许;文件组装:不允许;内容复制:允许;可访问性内容副本:允许;页面提取:不允许;

我尝试获取带有示例代码的文本作为文档示例,如下所示:

pdftext.Text = null;
StringBuilder text = new StringBuilder();
PdfReader pdfReader = new PdfReader(filename);
for (int page = 1; page <= pdfReader.NumberOfPages; page++)
{
    ITextExtractionStrategy strategy = new SimpleTextExtractionStrategy();
    string currentText = PdfTextExtractor.GetTextFromPage(pdfReader, page, strategy);
    text.Append(System.Environment.NewLine);
    text.Append("\n Page Number:" + page);
    text.Append(System.Environment.NewLine);
    currentText = Encoding.UTF8.GetString(ASCIIEncoding.Convert(Encoding.Default, Encoding.UTF8, Encoding.Default.GetBytes(currentText)));
    text.Append(currentText);
    progressBar1.Value++;

    }

pdftext.Text += text.ToString();
pdfReader.Close();

但输出文本是带有“”的行??? ? ??????\n?? ??? ? ” 价值观;

似乎文件已加密或者我们有编码问题......

请注意,在以下几行中

var f = pdfReader.IsOpenedWithFullPermissions; -> FALSE
var f1 = pdfReader.IsEncrypted(); - > FALSE
var f2 = pdfReader.ComputeUserPassword(); - > NULL
var f3 = pdfReader.Is128Key(); - > FALSE
var f4 = pdfReader.HasUsageRights();

f、f1、f3、f4 返回 FALSE ...似乎该文档未加密, ...所以我不知道是否是编码问题或与加密字符串相关的问题...

有人可以帮助我吗? 提前致谢。 G.G.


每当您在使用标准代码从文档中提取文本时遇到困难时,要做的第一件事就是尝试使用 Adob​​e Acrobat Reader 从中复制和粘贴文本。 Adobe Reader 复制和粘贴根据 PDF 规范的建议实现文本提取,如果失败,这通常意味着文档中文本提取所需的必要信息丢失或损坏(意外或有意)。要提取文本,需要专门针对特定 PDF 自定义代码或诉诸 OCR。

对于手头的文档,Adobe Reader 复制粘贴也会产生垃圾,就像使用 iText 提取时一样。因此,该文件中存在可疑之处。

检查文档发现字体包含转Unicode像这样的映射:

/CIDInit /ProcSet
findresource begin 12 dict begin begincmap /CIDSystemInfo<</Registry(Adobe)
/Ordering(Identity)
/Supplement 0
>>
def
/CMapName/F18 def
1 begincodespacerange <0000> <FFFF> endcodespacerange
44 beginbfrange
<20> <20> <0020>
<21> <21> <E0F9>
<22> <22> <E0F1>
<23> <23> <E0FA>
<24> <24> <E0F7>
<25> <25> <E0A3>
<26> <26> <E084>
<27> <27> <E097>
<28> <28> <E098>
<29> <29> <E09A>
<2A> <2A> <E08A>
<2B> <2B> <E099>
<2C> <2C> <E0A5>
<2D> <2D> <E086>
<2E> <2E> <E094>
<2F> <2F> <E0DE>
<30> <30> <E0A6>
<31> <31> <E096>
<32> <32> <E088>
<33> <33> <E082>
<34> <34> <E04C>
<35> <35> <E0A4>
<36> <36> <E0F6>
<37> <37> <E0F2>
<38> <38> <E0D8>
<39> <39> <E0AA>
<3A> <3A> <E06C>
<3B> <3B> <E087>
<3C> <3C> <E095>
<3D> <3D> <E0C4>
<3E> <3E> <E07E>
<3F> <3F> <E055>
<40> <40> <E089>
<41> <41> <E085>
<42> <42> <E083>
<43> <43> <E070>
<44> <44> <E0E6>
<45> <45> <E080>
<46> <46> <E0C8>
<47> <47> <E0F4>
<48> <48> <E062>
<49> <49> <E0F3>
<4A> <4A> <E04E>
<4B> <4B> <E05E>
endbfrange
endcmap CMapName currentdict /CMap defineresource pop end end 

也就是说,如果您对此不感兴趣,则字体声称它们的所有字形(0x20 处的空格字形除外)都代表来自Unicode 专用区域。正如该区域的名称所示,具有这些值的字符没有共同含义。

因此,根据 PDF 规范的文本提取将返回具有未定义含义的字符串,其结果正如您在 iText 中观察到的或我在 Adob​​e Reader 中看到的那样。


有时在这种情况下,人们仍然可以通过忽略来强制执行正确的文本提取转Unicode地图并使用任一字体Encoding或嵌入字体程序内的信息。

不幸的是事实证明这里Encoding实际上包含与转Unicode地图,例如对于与上面相同的字体

/Differences [ 32 /space /uniE0F9 /uniE0F1 /uniE0FA /uniE0F7 /uniE0A3 /uniE084 /uniE097 /uniE098 
/uniE09A /uniE08A /uniE099 /uniE0A5 /uniE086 /uniE094 /uniE0DE /uniE0A6 /uniE096 
/uniE088 /uniE082 /uniE04C /uniE0A4 /uniE0F6 /uniE0F2 /uniE0D8 /uniE0AA /uniE06C 
/uniE087 /uniE095 /uniE0C4 /uniE07E /uniE055 /uniE089 /uniE085 /uniE083 /uniE070 
/uniE0E6 /uniE080 /uniE0C8 /uniE0F4 /uniE062 /uniE0F3 /uniE04E /uniE05E ] 

字体是 Type3 字体,即没有嵌入字体程序,但每个字形都被定义为单独的 PDF 画布,没有进一步的字符信息。

因此,在这里也没有什么收获。

实际上,这些小的 PDF 画布包含各自字形的内联位图图形,这也是文档图形质量较差的原因(如果您没有立即看到这一点,只需放大一点,您就会看到参差不齐的轮廓)字形)。

顺便说一句,这样的构造通常意味着 PDF 的制作者明确希望阻止文本提取。


如果您碰巧必须从许多此类文档中提取文本,您可以尝试确定从 U+E0xx 字符到实际合理的 Unicode 字符的映射,并将该映射应用于提取的文本。

如果所有这些文档中的所有字体碰巧对相同的实际字符使用相同的 U+E0xx 代码点,在投入一定量的初始工作后,您将能够从这些文档中提取文本。

否则请尝试 OCR。


以下代码将页面添加到文档中,该文档映射转Unicode显示的字符的值:

void AddFontsTo(PdfReader reader, PdfStamper stamper)
{
    int documentPages = reader.NumberOfPages;
    for (int page = 1; page <= documentPages; page++)
    {
        // ignore inherited resources for now
        PdfDictionary pageResources = reader.GetPageResources(page);
        if (pageResources == null)
            continue;
        PdfDictionary pageFonts = pageResources.GetAsDict(PdfName.FONT);
        if (pageFonts == null || pageFonts.Size == 0)
            continue;

        List<BaseFont> fonts = new List<BaseFont>();
        List<string> fontNames = new List<string>();
        HashSet<char> chars = new HashSet<char>();
        foreach (PdfName key in pageFonts.Keys)
        {
            PdfIndirectReference fontReference = pageFonts.GetAsIndirectObject(key);
            if (fontReference == null)
                continue;
            DocumentFont font = (DocumentFont) BaseFont.CreateFont((PRIndirectReference)fontReference);
            if (font == null)
                continue;

            PdfObject toUni = PdfReader.GetPdfObjectRelease(font.FontDictionary.Get(PdfName.TOUNICODE));
            CMapToUnicode toUnicodeCmap = null; 
            if (toUni is PRStream)
            {
                try
                {
                    byte[] touni = PdfReader.GetStreamBytes((PRStream)toUni);
                    CidLocationFromByte lb = new CidLocationFromByte(touni);
                    toUnicodeCmap = new CMapToUnicode();
                    CMapParserEx.ParseCid("", toUnicodeCmap, lb);
                }
                catch
                {
                    toUnicodeCmap = null;
                }
            }
            if (toUnicodeCmap == null)
                continue;
            ICollection<int> mapValues = toUnicodeCmap.CreateDirectMapping().Values;
            if (mapValues.Count == 0)
                continue;

            fonts.Add(font);
            fontNames.Add(key.ToString());

            foreach (int value in mapValues)
                chars.Add((char)value);
        }
        if (fonts.Count == 0 || chars.Count == 0)
            continue;

        Rectangle size = (fonts.Count > 10) ? PageSize.A4.Rotate() : PageSize.A4;

        PdfPTable table = new PdfPTable(fonts.Count + 1);
        table.AddCell("Page " + page);
        foreach (String name in fontNames)
        {
            table.AddCell(name);
        }
        table.HeaderRows = 1;
        float[] widths = new float[fonts.Count + 1];
        widths[0] = 2;
        for (int i = 1; i <= fonts.Count; i++)
            widths[i] = 1;
        table.SetWidths(widths);
        table.WidthPercentage = 100;

        List<char> charList = new List<char>(chars);
        charList.Sort();
        foreach (char character in charList)
        {
            table.AddCell(((int)character).ToString("X4"));
            foreach (BaseFont font in fonts)
            {
                table.AddCell(new PdfPCell(new Phrase(character.ToString(), new Font(font))));
            }
        }

        stamper.InsertPage(reader.NumberOfPages + 1, size);
        ColumnText columnText = new ColumnText(stamper.GetUnderContent(reader.NumberOfPages));
        columnText.AddElement(table);
        columnText.SetSimpleColumn(size);
        while ((ColumnText.NO_MORE_TEXT & columnText.Go(false)) == 0)
        {
            stamper.InsertPage(reader.NumberOfPages + 1, size);
            columnText.Canvas = stamper.GetUnderContent(reader.NumberOfPages);
            columnText.SetSimpleColumn(size);
        }
    }
}

我将它应用到你的文档中,如下所示:

string input = @"4700198773.pdf";
string output = @"4700198773-fonts.pdf";

using (PdfReader reader = new PdfReader(input))
using (FileStream stream = new FileStream(output, FileMode.Create, FileAccess.Write))
using (PdfStamper stamper = new PdfStamper(reader, stream))
{
    AddFontsTo(reader, stamper);
}

附加页面如下所示:

first page of fonts for document page 1

现在,您必须将本文档的不同字体和页面的输出相互比较,并与代表性文件选择的输出进行比较。如果你发现足够好的模式,你可以尝试这种替换方式。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 iText 提取文本不起作用:编码或加密文本? 的相关文章

  • 如何更改 C++ 中存储在字符串中的文件扩展名?

    好吧 事情就是这样 我正在大学学习 C 课程 但不知道如何更改文件的扩展名 首先 我们要做的是读取 txt 文件并计算单词 句子 元音等 我明白了 但下一步是困扰我的问题 然后 我们假设使用与输入文件相同的文件名创建一个新文件 但扩展名为
  • 如何使用 python 标准库 zipfile 检查 zip 文件是否已加密?

    我正在使用 python 的标准库 zipfile 来测试存档 zf zipfile ZipFile archive name if zf testzip None checksum OK True 我收到这个运行时异常 File pack
  • 在 Python 中使用 SQLCipher - 最简单的方法 [重复]

    这个问题在这里已经有答案了 我正在编写一个可以在加密的 SQLite 数据库上运行的 Python 实用程序 最终我会将此类实用程序转换为可执行文件 以便更轻松地交付给团队的其他成员 我读了很多关于 SQLCipher 的页面 但他们都谈论
  • Java - 使用数组中的值的replace()方法正在更改数组值?

    我正在做类似的事情 public static String list a b c d It gives me a NullPointeException if I didn t use static public String encry
  • 如何从 AES 加密字符串添加/删除 PKCS7 填充?

    我正在尝试使用 128 位 AES 加密 ECB 来加密 解密字符串 我想知道如何添加 删除 PKCS7 填充 看起来 Mcrypt 扩展可以处理加密 解密 但必须手动添加 删除填充 有任何想法吗 让我们来看看 RFC 5652 加密消息语
  • 在 ruby​​ 中读/写受密码保护和加密的文件

    我想加密一个 ruby 程序将从中加载数据的文件 此外 我需要程序在启动时提示输入密码 该密码将用于解密文件 换句话说 该文件需要加密地驻留在计算机上 只有拥有密码的用户才能运行该应用程序 我已经开始研究 openpgp 但据我了解 这仍然
  • 恢复 SQL Server 数据库 - 主密钥未打开

    我必须制作远程 SQL Server 数据库的本地副本 我通过使用 Management Studio 中的 任务 gt 备份 来完成此操作 然后 我在本地恢复了备份 该备份似乎包含了所有内容 表 用户 对称密钥和证书 当我尝试执行需要打开
  • .png 和 .jpg 文件解密

    我正在尝试修改我正在使用的软件的图形资产 出于审美目的 我想很难对图形资产做一些有害的事情 但开发人员对它们进行了加密 我不确定他为什么决定这样做 因为我使用和修改了一堆类似的软件 而这些软件的开发人员并没有打扰 因为我看不出为什么需要加密
  • 为什么 Assembly.GetManifestResourceStream() 中的文本以三个垃圾字符开头?

    我有一个 SQL 文件作为嵌入式资源添加到我的 VS NET 2008 项目中 每当我使用以下代码读取文件的内容时 返回的字符串总是以三个垃圾字符开头 然后是我期望的文本 我认为这与我正在使用的 Encoding Default 有关 但这
  • MySQL连接字符集问题

    我在 Mac 上使用带有 MySQL 的 velosurf 没有任何编码问题 但是当我切换到 Linux 计算机时 从 velosurf 获得的值未正确编码 我发现这可能是默认连接字符集的问题 在 Mac 上我得到 mysql gt sho
  • 如何在 Excel 中对“高”字符进行 HTML 编码或音译?

    在 Excel 中 如何将包含重音字符 大引号等的单元格内容转换为相同字符的 HTML 或音译纯文本版本 我们有一个 XLS 文档 其中包含一些 高 字符 数据已通过数据库连接提取 并且 Excel 似乎正确处理不同代码页中的各个单元格 或
  • 我必须使用什么加密程序来通过 HTTP 协议发送加密的“电子邮件”和“密码”值?

    我正在使用 Ruby on Rails 3 我想通过 HTTP 协议发送 电子邮件 和 密码 值 我知道 我不应该 但我需要 我需要从发送用户凭据我的客户申请到一个我的服务应用 我可以使用公共和私人RSA密钥来实现这一点 但如果是这样 我不
  • Emoji 字符无法编码为 JSON

    我有一个UITextView我称之为messageField 其中的数据messageField is POST ed 以 JSON 格式发送到服务器 当用户输入表情符号字符时 我无法将数据编码为JSON 我认为 Emoji 使用 Unic
  • Java BigInteger bitLength() 方法忽略前导 0 位

    Java jre1 8 0 45 我完成了椭圆曲线类的调试 并在记录密钥的所有特征时 我还记录了密钥的位长度 对于椭圆曲线 其位长度并不总是偶数 我通过 BigInteger 显示密钥的位长度 ECPrivateKey oPK genera
  • 加密数据库字段的好方法?

    我被要求加密数据库中的各种数据库字段 问题是这些字段在读取后需要解密 我在用着Django and SQL Server 2005 有什么好主意吗 See 在 SQL Server 2005 数据库中使用对称加密 https web arc
  • RSA SignatureException:签名长度不正确

    我在签署 rsa 签名时遇到问题 我有一个用私钥加密的签名 然而 当我尝试使用公钥验证它时遇到问题 我得到以下异常 java security SignatureException Signature length not correct
  • 有效地将位图数组转换为视频

    使用 Jcodec 库 我成功地从 Bitmap 对象数组生成视频文件并将其存储在 Android 文件系统上 但是 那encoding时间太长了 我考虑过缩小每个位图以加快速度 但这似乎不起作用 尽管进行了广泛的研究 我还是很难找到有用的
  • TextMarginFinder 用于验证适印性

    我试图使用 TextMarginFinder 来证明打印时奇数页和偶数页正确备份 我的代码基于 http itextpdf com examples iia php id 280 http itextpdf com examples iia
  • 为什么 iconv 在 php:7.4-fpm-alpine docker 中返回空字符串

    给出以下代码
  • 在 PHP 中使用 phpseclib 时出现 RSA 问题

    我正在尝试在 phpseclib 中使用 RSA 实现 我认为在函数中执行一次代码并重新使用该函数会更容易 当我尝试向代码发送短信时 我收到一条错误消息 提示 解密错误 测试还让我意识到每次代码运行时密文都是不同的 所以我显然在那里做错了什

随机推荐

  • 如何对 ObservableCollection 进行分页?

    我有一个列表框 里面有太多项目 并且 UI 变得越来越慢 虚拟化已打开 等等 因此 我正在考虑仅显示前 20 个项目 并允许用户浏览结果集 即 ObservableCollection 有人知道 ObservableCollection 是
  • VS2012 ASP.Net错误消息无法连接到配置的开发Web服务器

    我上周购买了一台新的 Windows 8 电脑 首先我在上面安装了 VS 2010 但后来它无法正常工作 所以我卸载了 VS 2010 然后安装了 VS 2012 专业版和 SQL Server 2012 现在我可以创建 Windows 应
  • 以本地语言输出的日期函数[重复]

    这个问题在这里已经有答案了 我正在尝试使用意大利语格式输出日期date 如下 然而 它仍然以英文格式发布 我还能做什么 有什么不对 该解决方案必须是特定于脚本的 而不是服务器范围的 date 不支持区域设置 你应该使用strftime 及其
  • 从不同按钮切换模式弹出窗口

    我试图从菜单中的不同按钮打开此弹出窗口 但是 弹出窗口内容将保持不变 Thanks Banick function OpenModalT var modal document getElementById myModalT modal st
  • 如何使用RecyclerView android仅选择一个RadioButton?

    我有一个带有RadioButton的RecyclerView 我只想同时选择一个不多的RadioButton 我的代码使它工作正常 但是当我从上到下重复选择时 选择消失了 我该如何修复它 谢谢 private RadioButton las
  • 异常:AAPT2 错误:检查日志以获取详细信息

    Task processDebugResources Failed to execute aapt com android ide common process ProcessException Failed to execute aapt
  • Blazor WebAssembly 发布失败

    我正在尝试发布一个针对 NET 5 0 的 Blazor WebAssembly 应用程序 我使用默认设置从 Visual Studio 2019 创建了一个新的 Web 部署发布配置文件 该网站已发布到 IIS 但浏览器显示 500 19
  • Angular:点击浏览器后退按钮将用户带回家[重复]

    这个问题在这里已经有答案了 如果用户位于我的角度平台中 当用户单击浏览器的后退按钮时 我想将用户带到主页 还有一个边缘情况需要处理 如果用户通过谷歌搜索 Facebook 或直接输入链接来到我们的平台 那么我们不能执行此行为 但如果他已经在
  • Jenkins 和 NodeJS 插件 - 权限被拒绝错误

    我已经成功地在 Raspberry Pi 上设置了一个 Jenkins 实例 并且在最终遇到这个绊脚石之前已经安装了 NodeJS 插件 Started by an SCM change Building in workspace var
  • Protobuf-net 序列化枚举值超出范围

    C 允许将任何整数值分配给 enum 当我尝试使用值超出范围的枚举字段序列化 通过 protobuf net 对象时 它会抛出异常 没有线值映射到枚举 PersonLevel 我的枚举 PersonLevel 没有 Flags 属性 Pro
  • glBufferData分配的内存什么时候释放?

    假设我为统一缓冲区分配内存 如下所示 GLuint length 0x1000 GLuint myBuffer glGenBuffers 1 myBuffer glBindBuffer GL UNIFORM BUFFER myBuffer
  • 抛出奇怪的 org. Threeten.bp.DateTimeException ?

    我的代码运行得很好 今天突然我开始遇到这个异常 org threeten bp DateTimeException Field DayOfMonth cannot be printed as the value 1872095944 max
  • PHP 转换特殊字符,如 ş 到 s、ţ 到 t、ă 到 a

    我不知道如何命名我需要的内容 我想在 PHP 中将字符转换为更 正常 的字符集 例如 to become s to become t to become a 我有罗马尼亚城镇名称 我想在 URL 中使用更多 正常 字符 我想我想将罗马尼亚字
  • 退出时删除共享内存

    我有两个脚本 一个用于创建和写入共享内存块 第二个用于读取该共享内存 问题是 当第一个脚本结束时 即使我不取消链接 共享内存也会被删除 这是我的第一个脚本 import argparse import csv import os impor
  • 模板中的读取路径[重复]

    这个问题在这里已经有答案了 有没有办法读取当前页面的路径 例如 我在 www example com foo bar 我想阅读 foo bar 我必须在模板文件中执行此操作而不修改视图 并且我有太多视图文件而无法编辑每个视图文件 Cheer
  • 在可序列化对象上获取 NotSerializedException

    基本上 我编写了一个程序 将形状绘制到屏幕上 并将每个形状保存到 ArrayList 中 我想要做的是弄清楚如何将 ArrayList 保存到文件中 以便我可以稍后调用它并编辑已经存在的形状 因此 当我已经将对象 Shape 可序列化时 我
  • 在 HTML 页面上并排显示两个图像

    我试图并排放置两个相同大小的图像 如果我使用一个table然后我就可以并排显示两个图像 但在我的 CSS 样式表中 我对表格使用了自定义格式 这也显示在包含图像的页面上 我想只显示两个图像 没有任何自定义背景 边框等 我尝试使用div sp
  • 字符串前面的 b 有何作用?

    binary b Binary string 创建一个字符串会产生什么后果binary 我在文档中找不到任何关于此的提示 刚刚在浏览 language scanner 时发现了这个小小的好奇心 这是永远不会发布的 PHP 版本 6 的前向兼
  • 是否有另一种方法在工作人员中加载额外的包(并行计算)?

    R 中并行化的一种方法是通过snowfall包裹 要将自定义函数发送给工作人员 您可以使用sfExport 参见乔里斯的帖子here 我有一个自定义函数 它依赖于非基本包中未自动加载的函数 因此 当我并行运行我的函数时 R 会崩溃 因为某些
  • 使用 iText 提取文本不起作用:编码或加密文本?

    我有一个 pdf 文件 其安全属性如下 打印 允许 文件组装 不允许 内容复制 允许 可访问性内容副本 允许 页面提取 不允许 我尝试获取带有示例代码的文本作为文档示例 如下所示 pdftext Text null StringBuilde