pdfbox:...在此字体的编码中不可用

时间:2016-08-05 10:38:08

标签: pdf fonts pdfbox

我在使用pdfbox 2.0.2从先前阅读的文档(https://www.dropbox.com/s/ttxiv0dq3abh5kj/Test.pdf?dl=0)的元素编写pdf文档时遇到问题。一切正常,除非我在PDPa​​geContentStream上调用showText,我之前使用out.setFont(textState.getFont(), textState.getFontSize())设置了字体(参见信息日志),字体是ComicSansMS或ArialBlack。 textState是(克隆自)先前读取的文档中的状态。使用Helvetica或Times-Roman编写文本可以正常工作。

INFORMATION: set font PDTrueTypeFont RXNQOL+ComicSansMS,Bold/18.0 embedded    
SEVERE: error writing <w>U+0077 is not available in this font's encoding: built-in (TTF)

我认为问题可能是由字体名称中缺少连字符或空白引起的,但不知道如何解决此问题。

这是完整的代码

import java.awt.Point;
import java.awt.geom.Point2D;
import java.io.File;
import java.io.IOException;
import org.apache.pdfbox.contentstream.PDFGraphicsStreamEngine;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.graphics.image.PDImage;
import org.apache.pdfbox.pdmodel.graphics.state.PDTextState;
import org.apache.pdfbox.util.Matrix;
import org.apache.pdfbox.util.Vector;

public class Test extends PDFGraphicsStreamEngine {

public static void main(String[] args) throws IOException {
    test();
}

public static void test() throws IOException {
    PDDocument document = PDDocument.load(new File("Test.pdf"));
    PDPage pageIn = document.getPage(0);
    PDDocument saveDoc = new PDDocument();
    PDPage savePage = new PDPage(pageIn.getMediaBox());
    saveDoc.addPage(savePage);
    try (PDPageContentStream out = new PDPageContentStream(saveDoc, savePage)) {
        Test test = new Test(pageIn, out);
        test.processPage(pageIn);
    }
}

private final PDPageContentStream out;

public Test(PDPage pageIn, PDPageContentStream out) {
    super(pageIn);
    this.out = out;
}

@Override
public void appendRectangle(Point2D p0, Point2D p1, Point2D p2, Point2D p3) throws IOException {
}

@Override
public void clip(int windingRule) throws IOException {
}

@Override
public void closePath() throws IOException {
}

@Override
public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) throws IOException {
}

@Override
public void drawImage(PDImage pdImage) throws IOException {
}

@Override
public void endPath() throws IOException {
}

@Override
public void fillAndStrokePath(int windingRule) throws IOException {
}

@Override
public void fillPath(int windingRule) throws IOException {
}

@Override
public Point2D getCurrentPoint() {
    return new Point(0, 0);
}

@Override
public void lineTo(float x, float y) throws IOException {
}

@Override
public void moveTo(float x, float y) throws IOException {
}

@Override
public void shadingFill(COSName shadingName) throws IOException {
}

@Override
protected void showGlyph(Matrix textRenderingMatrix, PDFont font, int code, String unicode, Vector displacement) throws IOException {
    super.showGlyph(textRenderingMatrix, font, code, unicode, displacement);
    PDTextState textState = getGraphicsState().getTextState();
    out.beginText();
    out.setTextMatrix(getTextMatrix());
    out.setFont(textState.getFont(), textState.getFontSize());
    out.showText(unicode);
    out.endText();
}

@Override
public void strokePath() throws IOException {
}

}

有什么建议吗?

谢谢, 尔根

1 个答案:

答案 0 :(得分:4)

tl; dr:该字体不支持编码。

问题的原因是你的Comic Sans子集化字体确实有一个&#34; post&#34; (postscript)表,但其glyphNames表为null。即您的字体没有字形名称。对于A-Z,a-z,名称就像这些字符;对于&#34;(&#34;字形名称为&#34; parenleft&#34;。由于缺少这些名称,PDFBox会从字形ID创建伪名称,如&#34; 90&#34;(而不是& #34; w&#34;)&#34; w&#34;在PDTrueType.readEncodingFromFont()的第二部分。

enter image description here

但是,在编码时,PDFBox使用Adobe Glyphlist,因为字体没有编码条目。如果您使用PDFDebugger查看其他字体,例如R18,你会发现&#34;编码:WinAnsiEncoding&#34;:

enter image description here

您显然正在做的是创建一个仅包含文本的新页面。另一种方法是分析内容流并简单地删除绘制与文本不同的东西的所有标记。首先,看一下源代码下载中的RemoveAllText示例,然后下载PDF 32000规范,并查看部分&#34;运算符摘要&#34;小心删除的内容。例如&#34; Do&#34;用于绘制图像和绘制XObject表单,它们也是内容流。

见这里: How can I remove all images/drawings from a PDF file and leave text only in Java?

两种解决方案都是错误的,第一种解决方案只是从脚下拉出所有图像,第二种解决方案是一个良好的开端,但不会检查参数是否是图像。