gpt4 book ai didi

java - 调整字符宽度后嵌入 PDFont

转载 作者:太空宇宙 更新时间:2023-11-04 06:11:08 25 4
gpt4 key购买 nike

我想使用 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);

但是如何嵌入修改后的字体呢?

最佳答案

使用修补的宽度字体字典条目嵌入原始字体

如果您使用您所操纵的字体,它将被嵌入。如果你例如像这样继续你的代码:

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:

"embedFont.pdf" screenshot

如您所见,您对“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”的宽度并没有改变。如果你想改变这一点,你应该预处理字体文件并调整宽度:

嵌入修补字体

您可以使用例如Google 的 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);
}

关于java - 调整字符宽度后嵌入 PDFont,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28700696/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com