我正在尝试从pdf文件中提取一些字体流(合法性不是问题,因为我的公司已经支付了以原始方式显示这些文档的权利-这需要转换,需要提取字体)。
现在,我一直在使用MUTool -但它也提取pdf中的图像以及没有绕过它们的方法,其中一些包含成千上万的图像。所以,我在网上寻找答案,得出了以下解决方案:
我得到所有的字体到一个字体字典,然后我尝试将它们转换成PdfStreams(用于flatedecode,然后写入文件)使用以下代码:
PdfDictionary tg = (PdfDictionary)PdfReader.GetPdfObject((PdfObject)cItem.pObj);
PdfName type = (PdfName)PdfReader.GetPdfObject(tg.Get(PdfName.SUBTYPE));
try
{
int xrefIdx = ((PRIndirectReference)((PdfObject)cItem.pObj)).Number;
PdfObject pdfObj = (PdfObject)reader.GetPdfObject(xrefIdx);
PdfStream str = (PdfStream)(pdfObj);
byte[] bytes = PdfReader.GetStreamBytesRaw((PRStream)str);
}
catch { }
但是,当我得到PdfStream str = (PdfStream)(pdfObj);我得到下面的错误:
Unable to cast object of type 'iTextSharp.text.pdf.PdfDictionary'
to type 'iTextSharp.text.pdf.PdfStream'.
现在,我知道PdfDictionary派生(扩展)PdfObject,所以我不确定我在这里做错了什么。有人请帮助-我要么需要修补这个代码的建议,或者如果完全不正确,要么代码正确提取流或方向到一个地方与所述代码。
谢谢。
编辑修改后的代码在这里:
public static void GetStreams(PdfReader pdf)
{
int page_count = pdf.NumberOfPages;
for (int i = 1; i <= page_count; i++)
{
PdfDictionary pg = pdf.GetPageN(i);
PdfDictionary fObj = (PdfDictionary)PdfReader.GetPdfObject(res.Get(PdfName.FONT));
if (fObj != null)
{
foreach (PdfName name in fObj.Keys)
{
PdfObject obj = fObj.Get(name);
if (obj.IsIndirect())
{
PdfDictionary tg = (PdfDictionary)PdfReader.GetPdfObject(obj);
PdfName type = (PdfName)PdfReader.GetPdfObject(tg.Get(PdfName.SUBTYPE));
int xrefIdx = ((PRIndirectReference)obj).Number;
PdfObject pdfObj = pdf.GetPdfObject(xrefIdx);
if (pdfObj == null && pdfObj.IsStream())
{
PdfStream str = (PdfStream)(pdfObj);
byte[] bytes = PdfReader.GetStreamBytesRaw((PRStream)str);
}
}
}
}
}
}
然而,我仍然收到相同的错误-所以我假设这是一个不正确的方法检索字体流。同样的文档已经使用muTool成功地提取了字体-所以我知道问题出在我身上,而不是pdf。
你的代码中至少有两点是错误的:
- 您将对象强制转换为流而不执行此检查:
if (pdfObj == null && pdfObj.isStream()) { // cast to stream }
当您得到错误消息时,您试图将字典强制转换为流,我99%肯定检查的第二部分将返回false
,而pdfObj.isDictionary()
可能返回true
。 - 你尝试从
PdfReader
提取一个流,你试图将该对象转换为PdfStream
而不是PRStream
。PdfStream
是我们用来创建pdf的对象,PRStream
是我们使用PdfReader
检查pdf时使用的对象。
你应该先解决这个问题。
现在回答你的一般性问题。如果您阅读ISO-32000-1,您会发现字体是使用字体字典定义的。如果字体被(全部或部分)嵌入,字体字典将引用一个流。该流可以包含完整的字体信息,但大多数情况下,您只能获得字形的子集(因为这是创建PDF时的最佳实践)。
看一下我的书《ittext in Action》中的ListFontFiles示例,对字体在PDF中是如何组织的有一个初步的印象。您需要将此示例与ISO-32000-1相结合,以找到有关FONTFILE
, FONTFILE2
和FONTFILE3
之间差异的更多信息。
我还写了一个用字体文件代替未嵌入字体的例子:EmbedFontPostFacto。这个例子用来说明字体替换是多么困难。
如果您需要c#版本的书样例,请访问http://tinyurl.com/iiacsCH16。