2017-02-03 114 views
1

在我的项目中,我遇到了解析PDF文件的必要性,该文件包含由Type3字体呈现的一些字符。所以,我需要做的是将这些字符渲染到BufferedImage中以供进一步处理。使用PDFBox渲染Type3字体字符作为图像

我不知道如果我在寻找正确的方法,但我试图让PDType3CharProc这样的字符:

PDType3Font font = (PDType3Font)textPosition.getFont(); 
PDType3CharProc charProc = font.getCharProc(textPosition.getCharacterCodes()[0]); 

和这个程序的输入流包含以下数据:

54 0 1 -1 50 43 d1 
q 
49 0 0 44 1.1 -1.1 cm 
BI 
/W 49 
/H 44 
/BPC 1 
/IM true 
ID 
<some binary data here> 
EI 
Q 

但不幸的是,我不知道如何使用这些数据来使用PDFBox(或任何其他Java库)将图像呈现为图像。

我正在寻找正确的方向,我能用这些数据做什么? 如果不是,还有其他一些工具可以解决这个问题吗?

+0

我的回答有帮助吗?如果没有,请分享您的Type 3字体的样本PDF代表。正如我在回答中已经提到的,然后在@Tilman的评论中讨论过的,可能会有类型3字体变体的处理方式不同...... – mkl

回答

1

不幸的是,PDFBox开箱即用并没有提供一个类来呈现任意XObject的内容(类型3字体字符特效),至少据我所见。

但它确实提供了一个用于呈现完整PDF页面的类;因此,为了呈现给定的第3种字体字形,可以简单地创建仅包含该字形的页面并呈现该临时页面!

假设,例如,类型3字体被定义一个PDDocument document的第一页上,并且具有名称F1,它的所有字符的特效可以呈现这样的:

PDPage page = document.getPage(0); 
PDResources pageResources = page.getResources(); 
COSName f1Name = COSName.getPDFName("F1"); 
PDType3Font fontF1 = (PDType3Font) pageResources.getFont(f1Name); 
Map<String, Integer> f1NameToCode = fontF1.getEncoding().getNameToCodeMap(); 

COSDictionary charProcsDictionary = fontF1.getCharProcs(); 
for (COSName key : charProcsDictionary.keySet()) 
{ 
    COSStream stream = (COSStream) charProcsDictionary.getDictionaryObject(key); 
    PDType3CharProc charProc = new PDType3CharProc(fontF1, stream); 
    PDRectangle bbox = charProc.getGlyphBBox(); 
    if (bbox == null) 
     bbox = charProc.getBBox(); 
    Integer code = f1NameToCode.get(key.getName()); 

    if (code != null) 
    { 
     PDDocument charDocument = new PDDocument(); 
     PDPage charPage = new PDPage(bbox); 
     charDocument.addPage(charPage); 
     charPage.setResources(pageResources); 
     PDPageContentStream charContentStream = new PDPageContentStream(charDocument, charPage); 
     charContentStream.beginText(); 
     charContentStream.setFont(fontF1, bbox.getHeight()); 
     charContentStream.getOutput().write(String.format("<%2X> Tj\n", code).getBytes()); 
     charContentStream.endText(); 
     charContentStream.close(); 

     File result = new File(RESULT_FOLDER, String.format("4700198773-%s-%s.png", key.getName(), code)); 
     PDFRenderer renderer = new PDFRenderer(charDocument); 
     BufferedImage image = renderer.renderImageWithDPI(0, 96); 
     ImageIO.write(image, "PNG", result); 
     charDocument.close(); 
    } 
} 

RenderType3Character.java测试方法testRender4700198773


考虑到在OP的代码textPosition变量,从文本中提取他很可能尝试此离子使用案例。因此,他必须预先生成上述的位图,并简单地按名称查找它们,或者调整代码以匹配其用例中的可用信息(例如,他可能没有原始页面,只有字体对象;在这种情况下,他不能复制原始页面的资源,而是可以创建一个新的资源对象并将字体对象添加到它)。


不幸的是,OP没有提供样本PDF。因此,我用另一个堆栈溢出问题4700198773.pdfextract text with custom font result non readble进行测试。 OP自己的文件显然可能存在问题。

+0

提醒我,我有一些未提交的PDFDebugger代码。它使用相同的策略(创建PDF)。你的问题有一个小缺陷:当BBox​​非常小时,它不起作用。请参阅PDFBOX-2959文件中的字体T4(这是一个非常奇怪的文件,我不得不承认) –

+0

*“[PDFBOX-2959](https://issues.apache.org/jira/browse/PDFBOX-2959) “* - 有趣的动物,但乍一看有效。好的,对于这种情况,如果上面使用的方法导致退化的边界框,则应该解析内容流并确定实际边界框。这实际上可以与'charProc.getGlyphBBox()'中的解析相结合,因此不会产生太多的额外开销。实现留给读者练习......;) – mkl

+0

@TilmanHausherr [sdnlist.pdf](https://www.treasury.gov/ofac/downloads/sdnlist.pdf)中引用的Type3字体[this问题](http://stackoverflow.com/q/42073700/1729265)也失败了上述方法。哦,OP应该告诉他的文件是否可以正常工作... – mkl