我有一个pdf文件,其作为以下安全属性:printing:allowed;文件汇编:不允许;内容副本:允许;可访问性的内容副本:允许;页面提取:不允许;
我尝试将带有示例代码的文本作为文档示例获取,如下所示:
Bubble
但是输出文本是带有“”的行? ? ???????的\ n? ??? ? “价值观;
似乎文件已加密或我们遇到编码问题......
请注意以下几行
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 ...似乎文件没有加密, ...所以我不知道是否是与加密字符串有关的编码问题或问题...
有人可以帮帮我吗? 提前致谢。 G.G。答案 0 :(得分:4)
每当您使用标准代码从文档中提取文本时遇到问题,首先要做的是尝试使用Adobe Acrobat Reader复制并粘贴文本。 Adobe Reader复制和粘贴根据PDF规范的建议实现文本提取,如果失败,这通常意味着文档中文本提取所需的必要信息要么丢失要么被破坏(意外或设计)。要提取文本,需要专门针对特定PDF自定义代码或使用OCR。
如果手头有文件,Adobe Reader复制和粘贴也会导致垃圾,就像用iText提取一样。因此,文件中有一些可疑的内容。
检查文档,发现字体包含 ToUnicode 映射,如下所示:
/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私人使用区的字符U + E0xx。正如该区域的名称所示,具有这些值的字符没有共同含义。
因此,根据PDF规范进行文本提取将返回具有未定义含义的字符串,其结果与您在iText中观察到的结果相同,或者我在Adobe Reader中看到过。
有时在这种情况下,人们仍然可以通过忽略 ToUnicode 地图并使用字体编码或嵌入字体程序中的信息来强制执行正确的文本提取。
不幸的是,这里编码实际上包含与 ToUnicode 地图相同的信息,例如与上面相同的字体
/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。
以下代码将页面添加到文档中,该文档将 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);
}
}
}
我将它应用到您的文档中:
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);
}
其他页面如下所示:
现在,您必须将本文档的不同字体和页面的输出与代表性文件选择的输出进行比较。如果你找到了足够好的模式,你可以尝试这种替代方式。