簡體   English   中英

添加字體未為 acroform 加載正確的 pdfbox

[英]Added font not loading correct pdfbox for acroform

我正在嘗試使用以下基於StackoverflowPDFBOX-2661的代碼嵌入 fonts :

作為 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()中,它會導致大量Using fallback font LiberationSans for CID-keyed TrueType font DejaVuSans 稍微調試一下,在createDescendantFont中它嘗試再次從文件系統加載(在org.apache.pdfbox.pdmodel.font.PDCIDFontType2findFontOrSubstitute )字體文件“DejaVuSans”,而不是使用提供的資源。 由於它是在 JAR 文件中提供的,而不是從正常文件系統(系統的字體)中找到的,因此未找到備用字體。

如何讓它正確識別和加載字體?

我已經嘗試過的:

我嘗試擴展字體加載機制,但由於一切都是私有的和/或最終的,在我已經從原始代碼復制了大約 10 個未更改的文件之后,我不得不停下來,以便能夠訪問它們; 這必須以不同的方式實現。

直接寫入ContentStream似乎使用不同的方式( contentStream.setFont(pdfFont, fontSize) ),因此不受影響。

PDFBox 中當前的 AcroForm 表單字段刷新機制並不能真正與 fonts 結合使用,尚未子集化。

原因是每當一種字體用於刷新外觀時,它都是從一些資源字典中檢索的。 但是,在這些資源字典中,沒有您的原始PDType0Font ,而只有支持您的PDType0Font的 PDF 對象的初步版本。 但是這些 PDF 對象不知道它們支持最終將被子集化的字體,因此對該字體的檢索會生成一個新的、不同的PDType0Font object,它聲稱是非嵌入的。 所以它也不會被告知最終嵌入的字形。

這也是為什么您使用的PDType0Font.load方法被記錄(JavaDoc 注釋)並帶有提示的原因如果您正在為 AcroForm 加載字體,那么請改用 3 參數構造函數

/**
 * 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 參數構造函數告訴您不要將子集用於 fonts 用於 AcroForm 用法:

/**
 * 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

但即使使用embedSubset設置為false的 3 參數構造函數也不會產生好的結果。 乍一看,渲染的字段看起來不錯:

截屏

但是一旦你點擊它們,就會發生一些奇怪的事情:

截屏

@Tilman,這里可能還有一些需要修復的地方。


子集嵌入字體的潛在問題也可能發生在其他上下文中,例如:

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測試testIllustrateType0Issue )

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM