我想使用Apache PDFBox创建符合PDF / A标准的PDF文件。为了符合PDF / A,必须嵌入所有使用的字体。我可以使用标准字体或从文件加载一个,但我需要调整几个字形的字符宽度。我可以通过加载字体(或使用标准字体)并在之后修改它来完成此操作,如下所示。
doc = new PDDocument();
PDPage page = new PDPage();
doc.addPage( page );
InputStream fontStream = PDFCreator.class.getResourceAsStream("ArialMT.ttf");
PDFont font = PDTrueTypeFont.loadTTF(doc, fontStream);
List<Float> test = font.getWidths();
test.set(101-32, 2000f);
font.setWidths(test);
但是如何嵌入修改后的字体呢?
答案 0 :(得分:1)
如果使用您的被操纵字体,它将被嵌入。如果你是像这样继续你的代码:
PDPageContentStream stream = new PDPageContentStream(doc, page);
stream.setFont(font, 12);
stream.beginText();
stream.moveTextPositionByAmount(30, 600);
stream.drawString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
stream.moveTextPositionByAmount(0, -20);
stream.drawString("abcdefghijklmnopqrstuvwxyz");
stream.moveTextPositionByAmount(0, -20);
stream.drawString("0123456789");
stream.endText();
stream.close();
doc.save("embedFont.pdf");
你使用PDFBox 1.8.8获得这样的PDF:
如您所见,您对'e'宽度的操纵
test.set(101-32, 2000f);
使该字母的空间相当广泛。
如果您查看PDF,您会在字体词典中找到 Widths 数组:
/Widths [278.0 278.0 355.0 556.0 556.0 889.0 667.0 191.0 333.0 333.0
389.0 584.0 278.0 333.0 278.0 278.0 556.0 556.0 556.0 556.0
556.0 556.0 556.0 556.0 556.0 556.0 278.0 278.0 584.0 584.0
584.0 556.0 1015.0 667.0 667.0 722.0 722.0 667.0 611.0 778.0
722.0 278.0 500.0 667.0 556.0 833.0 722.0 778.0 667.0 778.0
722.0 667.0 611.0 722.0 667.0 944.0 667.0 667.0 611.0 278.0
278.0 278.0 469.0 556.0 333.0 556.0 556.0 500.0 556.0 2000.0
...
你的2000
没问题。就PDF而言,您的更改已存储。
不可否认,嵌入式字体程序中“e”的宽度不会改变。如果要更改它,则应预先处理宽度已调整的字体文件:
您可以使用例如谷歌sfntly即时修补字体。在这种情况下,模拟代码可能如下所示:
byte[] fontBytes = null;
try ( InputStream arialMtResource = getClass().getResourceAsStream("ArialMT.ttf");
ByteArrayOutputStream baos = new ByteArrayOutputStream() )
{
patchAdvanceWidth(arialMtResource, baos, 101-29, 2000);
fontBytes = baos.toByteArray();
}
try ( ByteArrayInputStream fontStream = new ByteArrayInputStream(fontBytes); )
{
PDDocument doc = new PDDocument();
PDPage page = new PDPage();
doc.addPage(page);
PDFont font = PDTrueTypeFont.loadTTF(doc, fontStream);
PDPageContentStream stream = new PDPageContentStream(doc, page);
stream.setFont(font, 12);
stream.beginText();
stream.moveTextPositionByAmount(30, 600);
stream.drawString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
stream.moveTextPositionByAmount(0, -20);
stream.drawString("abcdefghijklmnopqrstuvwxyz");
stream.moveTextPositionByAmount(0, -20);
stream.drawString("0123456789");
stream.endText();
stream.close();
doc.save("target/test-outputs/embedPatchedFont.pdf");
}
使用这个辅助方法:
void patchAdvanceWidth(InputStream is, OutputStream os, int entry, int newValue) throws IOException
{
FontFactory fontFactory = FontFactory.getInstance();
Builder[] builders = fontFactory.loadFontsForBuilding(is);
Builder builder = builders[0];
HorizontalMetricsTable.Builder hmtxBuilder = (HorizontalMetricsTable.Builder) builder.getTableBuilder(Tag.hmtx);
WritableFontData hmtxData = hmtxBuilder.data();
int offset = 0 + (entry * 4) + 0;
hmtxData.writeUShort(offset, newValue);
hmtxBuilder.setData(hmtxData);
Font font = builder.build();
fontFactory.serializeFont(font, os);
}