本文介紹了添加了無法為Acrobat加載正確的pdfbox的字體的處理方法,對(duì)大家解決問題具有一定的參考價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧!
問題描述
我正在嘗試使用以下代碼嵌入字體,
基于Stackoverflow和PDFBOX-2661:
作為Helvetica的替代字體嵌入的字體為DejaVuSans。
// given: PDDocument document, PDAcroForm acroForm
InputStream font_file = ClassLoader.getSystemResourceAsStream("DejaVuSans.ttf");
font = PDType0Font.load(document, font_file);
if (font_file != null) {
font_file.close();
}
System.err.println("Embedded font 'DejaVuSans.ttf' loaded.");
PDResources resources = acroForm.getDefaultResources();
if (resources == null) {
resources = new PDResources();
}
resources.put(COSName.getPDFName("Helv"), font);
resources.put(COSName.getPDFName("Helvetica"), font);
// Also use "DejaVuSans.ttf" for "HeBo", "HelveticaBold" and "Helvetica-Bold" in a similar way, but this is left out to keep this short.
acroForm.setDefaultResources(resources);
// let pdfbox handle refreshing the values, now that all the fonts should be there.
acroForm.refreshAppearances();
然而,在acroForm.refreshAppearances()
中,它導(dǎo)致了大量的Using fallback font LiberationSans for CID-keyed TrueType font DejaVuSans
。稍加調(diào)試,在org.apache.pdfbox.pdmodel.font.PDCIDFontType2
的findFontOrSubstitute
中,它試圖再次從文件系統(tǒng)加載字體文件&DejaVuSans";,而不是使用提供的資源。由于它是在JAR文件中提供的,而不是從正常的文件系統(tǒng)(系統(tǒng)的字體)中找到的,因此將使用備用字體。
如何使其正確識(shí)別并加載字體?
我已經(jīng)嘗試的內(nèi)容:
我嘗試擴(kuò)展字體加載機(jī)制,但由于所有內(nèi)容都是私有的和/或最終的,我不得不在復(fù)制了大約10個(gè)未更改的原始代碼文件后停止,以便能夠訪問它們;這必須以不同的方式實(shí)現(xiàn)。
直接寫入ContentStream
似乎使用不同的方式(contentStream.setFont(pdfFont, fontSize)
),因此不受影響。
推薦答案
PDFBox中當(dāng)前的AcroForm表單域刷新機(jī)制不能真正與尚未設(shè)置子集的字體結(jié)合使用。
原因是,每當(dāng)使用字體刷新外觀時(shí),都會(huì)從某些資源詞典中檢索到該字體。然而,在這些資源詞典中,沒有您的原始PDType0Font
,而只有支持您的PDType0Font
的PDF對(duì)象的初步版本。但是這些PDF對(duì)象不知道它們支持的是最終將被子集化的字體,所以檢索該字體會(huì)生成一個(gè)新的、不同的PDType0Font
對(duì)象,該對(duì)象聲稱是非嵌入的。因此,它也不會(huì)被告知最終要嵌入的字形。
這也是為什么您使用的PDType0Font.load
方法會(huì)用提示來記錄(JavaDoc注釋)如果您要為AcroForm加載字體,請(qǐng)改用3參數(shù)構(gòu)造函數(shù):
/**
* Loads a TTF to be embedded and subset into a document as a Type 0 font. If you are loading a
* font for AcroForm, then use the 3-parameter constructor instead.
*
* @param doc The PDF document that will hold the embedded font.
* @param input An input stream of a TrueType font. It will be closed before returning.
* @return A Type0 font with a CIDFontType2 descendant.
* @throws IOException If there is an error reading the font stream.
*/
public static PDType0Font load(PDDocument doc, InputStream input) throws IOException
其文檔中的3參數(shù)構(gòu)造函數(shù)告訴您在AcroForm使用時(shí)不要使用字體的子集:
/**
* Loads a TTF to be embedded into a document as a Type 0 font.
*
* @param doc The PDF document that will hold the embedded font.
* @param input An input stream of a TrueType font. It will be closed before returning.
* @param embedSubset True if the font will be subset before embedding. Set this to false when
* creating a font for AcroForm.
* @return A Type0 font with a CIDFontType2 descendant.
* @throws IOException If there is an error reading the font stream.
*/
public static PDType0Font load(PDDocument doc, InputStream input, boolean embedSubset)
throws IOException
但是,即使在設(shè)置為時(shí)使用3個(gè)參數(shù)構(gòu)造函數(shù)也不會(huì)呈現(xiàn)良好結(jié)果。乍一看,渲染的字段看起來還不錯(cuò):
但你一點(diǎn)擊它們,就會(huì)發(fā)生一些奇怪的事情:
@Tilman,這里可能仍有需要解決的問題。
子集嵌入字體的潛在問題也可能出現(xiàn)在其他上下文中,例如:
try ( PDDocument pdDocument = new PDDocument();
InputStream font_file = [...] ) {
PDType0Font font = PDType0Font.load(pdDocument, font_file);
PDResources pdResources = new PDResources();
COSName name = pdResources.add(font);
PDPage pdPage = new PDPage();
pdPage.setResources(pdResources);
pdDocument.addPage(pdPage);
try ( PDPageContentStream canvas = new PDPageContentStream(pdDocument, pdPage) ) {
canvas.setFont(pdResources.getFont(name), 12);
canvas.beginText();
canvas.newLineAtOffset(30, 700);
canvas.showText("Some test text.");
canvas.endText();
}
pdDocument.save("sampleOfType0Issue.pdf");
}
(RefreshAppearances測(cè)試testIllustrateType0Issue
)
這篇關(guān)于添加了無法為Acrobat加載正確的pdfbox的字體的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,