Encryption 使用iText提取文本无效:编码文本还是加密文本?

Encryption 使用iText提取文本无效:编码文本还是加密文本?,encryption,encoding,character-encoding,itext,text-extraction,Encryption,Encoding,Character Encoding,Itext,Text Extraction,我有一个pdf文件,它具有以下安全属性:打印:允许;文档组装:不允许;内容复制:允许复制;可访问性内容拷贝:允许;页面提取:不允许 我尝试使用示例代码获取文本作为文档示例,如下所示: pdftext.Text = null; StringBuilder text = new StringBuilder(); PdfReader pdfReader = new PdfReader(filename); for (int page = 1; page <= pdfReader.NumberOf

我有一个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();
f、 f1、f3、f4返回FALSE…而文档似乎未加密, …所以我不知道是编码问题还是与encrypet字符串相关的问题

有人能帮我吗? 提前谢谢。
G.G.

每当您在使用标准代码从文档中提取文本时遇到问题,首先要做的就是尝试使用Adobe Acrobat Reader从文档中复制并粘贴文本。Adobe Reader copy&paste根据PDF规范的建议执行文本提取,如果失败,通常意味着文档中文本提取所需的必要信息丢失或损坏(由于意外或设计)。要提取文本,需要专门针对特定PDF自定义代码,或者使用OCR

对于手头的文档,AdobeReaderCopy&paste也会产生垃圾,就像使用iText提取时一样。因此,文件中有些可疑之处

查看文档时,会发现字体包含如下映射:

/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 
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);
}
这些字体被证明是Type3字体,也就是说,没有嵌入式字体程序,但每个字形被定义为一个单独的PDF画布,没有进一步的字符信息

因此,在这里也没有什么好处

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

顺便说一句,这种构造通常意味着PDF的生产者明确地想要阻止文本提取


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

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

否则请尝试OCR


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

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);
        }
    }
}
其他页面如下所示:

/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 
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);
}


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

每当您在使用标准代码从文档中提取文本时遇到问题,首先要做的是尝试使用Adobe Acrobat Reader从文档中复制并粘贴文本。Adobe Reader copy&paste根据PDF规范的建议执行文本提取,如果失败,通常意味着文档中文本提取所需的必要信息丢失或损坏(由于意外或设计)。要提取文本,需要专门针对特定PDF自定义代码,或者使用OCR

对于手头的文档,AdobeReaderCopy&paste也会产生垃圾,就像使用iText提取时一样。因此,文件中有些可疑之处

查看文档时,会发现字体包含如下映射:

/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 
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);
}
这些字体被证明是Type3字体,也就是说,没有嵌入式字体程序,但每个字形被定义为一个单独的PDF画布,没有进一步的字符信息

因此,在这里也没有什么好处

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

顺便说一句,这种构造通常意味着PDF的生产者明确地想要阻止文本提取


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

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

否则请尝试OCR


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

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);
        }
    }
}
其他页面如下所示:

/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 
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);
}


现在,您必须将本文档中不同字体和页面的输出彼此进行比较,并与具有代表性的文件选择进行比较。如果你找到一个足够好的图案,你可以尝试这种替换方法。

在调查之后,我发现问题出在custon Encounding上。pdfinfo的结果是:作者:用户创建者:Compart文档API生产者:Compart MFFPDF I/O过滤器2013-03-09 00:51:11创建日期:04/21/16 11:26:59修改日期:06/09/16 10:02:16标记:无表单:无页面:6加密:无页面大小:595.2 x 841.92分(A4)(旋转0度)文件大小:312703字节优化:是PDF版本:1.4 Pdfont的结果是(对于每种字体):名称:[无];类型:类型3;emb:yes;sub:no;uni:yes;因此PDF不加密,而pr