Java 使用PDFBox将Type3字体字符呈现为图像

Java 使用PDFBox将Type3字体字符呈现为图像,java,pdf,pdfbox,Java,Pdf,Pdfbox,在我的项目中,我不得不解析PDF文件,其中包含一些由Type3字体呈现的字符。所以,我需要做的是将这些字符渲染到BuffereImage中以进行进一步处理 我不确定我是否以正确的方式查看,但我正在尝试为这些字符获取PDType3CharProc: PDType3Font font = (PDType3Font)textPosition.getFont(); PDType3CharProc charProc = font.getCharProc(textPosition.getCharacterC

在我的项目中,我不得不解析PDF文件,其中包含一些由Type3字体呈现的字符。所以,我需要做的是将这些字符渲染到BuffereImage中以进行进一步处理

我不确定我是否以正确的方式查看,但我正在尝试为这些字符获取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库使用这些数据将角色渲染成图像

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

不幸的是,PDFBox开箱即用并没有提供一个类来呈现任意XObject的内容,如type 3 font char procs,至少在我看来是这样的

但它确实提供了一个用于呈现完整PDF页面的类;因此,要呈现给定的Type3字体图示符,只需创建一个只包含该图示符的页面并呈现该临时页面

例如,假设在PDDocument文档的第一页上定义了type 3字体,并将其命名为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();
    }
}
试验方法testRender4700198773

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


不幸的是,OP没有提供PDF样本。因此,我在测试中使用了另一个堆栈溢出问题中的一个。OP自己的文件可能仍然存在问题。

我偶然发现了同样的问题,通过修改PDFRenderer和底层PageDrawer,我能够呈现Type3字体:

只需使用Type3PDRenderer而不是PDFRendered。当然,如果你有多种字体,这需要更多的修改来处理它们


编辑:使用pdfbox 2.0.9测试提醒我,我有一些未提交的PDFDebugger代码。它使用相同的策略创建PDF。你的有一个小缺点:当BBox很小的时候它就不工作了。请看PDFBOX-2959文件中的T4字体,这是一个非常奇怪的文件,我必须承认-有趣的动物,但乍一看是有效的。好的,对于这种情况,如果上面使用的方法导致退化的边界框,那么应该解析内容流并确定实际的边界框。这实际上可以和charProc.getGlyphBBox中的解析相结合,所以不会产生太多额外的开销。实现留给读者作为练习@Tilmahauser中引用的Type3字体也无法通过上述方法。哦,好吧,OP应该告诉他的文件是否工作正常……它们显示在PDFDebugger字体显示中,与昨天相比有所变化,尽管字形是颠倒的。@tilmahauser字体确实可以颠倒镜像两次。可能你没有应用矩阵?我的答案有用吗?如果没有,请为您的Type3字体共享一个示例PDF代表。正如我在回答中已经提到的,然后在对它的评论中与@Tilman讨论过的,可能会有第3类字体的变化需要以不同的方式处理。。。
class Type3PDFRenderer extends PDFRenderer
{

    private PDFont font;

    public Type3PDFRenderer(PDDocument document, PDFont font)
    {
        super(document);
        this.font = font;
    }

    @Override
    protected PageDrawer createPageDrawer(PageDrawerParameters parameters) throws IOException
    {
        FontType3PageDrawer pd = new FontType3PageDrawer(parameters, this.font);
        pd.setAnnotationFilter(super.getAnnotationsFilter());//as done in the super class
        return pd;
    }       
}

class FontType3PageDrawer extends PageDrawer
{

    private PDFont font;

    public FontType3PageDrawer(PageDrawerParameters parameters, PDFont font) throws IOException
    {
        super(parameters);
        this.font = font;
    }

    @Override
    public PDGraphicsState getGraphicsState()
    {
        PDGraphicsState gs = super.getGraphicsState();
        gs.getTextState().setFont(this.font);
        return gs;
    }       
}