2017-08-03 90 views
1

我試圖在iText7中打開PDF文件,在那裏寫一些新的文本,從原始PDF應用字體到它並保存在另一個PDF文檔中。我正在使用Java 1.8如何在iText7中從另一個pdf中重用字體?

因此,我需要一組用於原始pdf的字體名稱,用戶將從中選擇一個字體名稱,並將其應用於新的段落。 而且我還需要以某種方式應用此字體。

現在我有這樣的一段代碼,我已經從here採取:

public static void main(String[] args) throws IOException { 
     PdfDocument pdf = new PdfDocument(new PdfReader("example.pdf")); 
     Set<PdfName> fonts = listAllUsedFonts(pdf); 
     fonts.stream().forEach(System.out::println); 
} 

public static Set<PdfName> listAllUsedFonts(PdfDocument pdfDoc) throws IOException { 
     PdfDictionary acroForm = pdfDoc.getCatalog().getPdfObject().getAsDictionary(PdfName.AcroForm); 
     if (acroForm == null) { 
      return null; 
     } 
     PdfDictionary dr = acroForm.getAsDictionary(PdfName.DR); 
     if (dr == null) { 
      return null; 
     } 
     PdfDictionary font = dr.getAsDictionary(PdfName.Font); 
     if (font == null) { 
      return null; 
     } 
     return font.keySet(); 
    } 

它返回的輸出:

/Helv 
/ZaDb 

不過,唯一的字體爲例.pdf已經是Verdana(這是Adobe Acrobat Pro中的文檔屬性)。而且,Verdana有兩種實現方式:粗體和正常。

所以,我有以下問題:

  1. 爲什麼這個函數返回兩種字體,而不是一個(宋體)。
  2. 我怎樣才能生成正常的閱讀良好的字體名稱,以將它們顯示給用戶(例如Helvetica而不是Helv) ?
  3. 我該如何申請從原始文件中獲得的字體到 新款?

提前致謝!

回答

0

您不應該在另一個PDF中重複使用某個PDF中的字體,原因如下:字體幾乎不會完全嵌入PDF文檔中。例如:您使用字體Verdana(238 KB)和字體Verdana(207 KB),但是當您以普通和粗體創建一個簡單的PDF文檔「Hello World」時,文件大小將遠小於238 + 207 KB。爲什麼是這樣?由於PDF將只包含字體Verdana Regular的子集和字體Verdana bold的子集

你可能已經注意到,我說的字體宋體定期 和字體宋體加粗。這些是兩種不同的字體相同的字體家族。讀你的問題,我注意到你沒有這樣的區別。你談談字體 Verdana與 兩個實現加粗和正常。這是不正確的。你應該 談論字體家族 Verdana和字體 Verdana bold和 Verdana regular。

PDF通常包含不同字體的子集。它甚至可以包含兩個不同的子集。另請參見What are the extra characters in the font name of my PDF?

你的目標是把一個PDF的字體,並使用另一個PDF的該字體。但是,假設您的原始PDF僅包含編寫「Hello World」所需的子集,並且您希望創建一個名爲「Hello Universe」的新PDF。這將永遠不會工作,因爲子集將不包含字形以呈現字母U,n,i,v,rs

還考慮到,字體通常是授權的帳戶。許多字體 有規定,您可以使用字體來創建文檔 和嵌入,該文件中的字體的許可證。然而,有 往往是說,其他人不準 提取到字體在不同的上下文中使用的條款。例如:您在購買MS Windows的副本時支付了字體,但收到包含該字體的PDF的某人 可能沒有使用 該字體的許可證。請參閱Does one need to have a license for fonts if we are using ttf files in itext?

鑑於與您的問題相關的技術和法律問題,我認爲在代碼示例上工作並不合理。你的設計有缺陷。您應該使用許可的字體程序,而不是嘗試從現有PDF中提取字體。這回答了問題3:如何將原始文檔中的字體應用於新段落?您不能:法律禁止它(請參閱下面的其他信息),如果子集不包含您需要的所有字符,則可能在技術上是不可能的!

此外,您在官方iText網站上找到的示例將查找表格中定義的字體。 /HelvZaDb指Helvetica和Zapfdingbats。這些字體是一組14個被稱爲標準類型1字體的兩種字體。這些字體是從未在文檔中嵌入,因爲每個瀏覽者都應該知道如何呈現它們。如果您想使用這些字體,則不需要完整的字體程序;字體度量就足夠了。例如:iText附帶14個包含字體指標的AFM文件(AFM = Adob​​e Font Metrics)。

你想知道爲什麼你沒有找到Verdana,因爲Verdana被用作文檔中字體的字體,但是你看錯了位置。您正在向iText詢問用於表單的字體,而不是文本中使用的字體。這個答案問題1:爲什麼這個函數返回兩個字體而不是一個(Verdana)。

至於你的問題2:您正在尋找在內部名稱的字體,而內部名稱可以是任何東西(甚至/F1/F2,...)。字體的postscript名稱存儲在字體字典中。這是你需要的名字。

額外的信息:

我查了宋體許可證:

微軟提供的字體。根據許可條款或使用條款,Microsoft產品,服務或包含此字體的內容的許可,您可以使用此字體創建,顯示和打印內容。您只可以(i)將此字體嵌入到內容中,如該字體中包含的嵌入限制所允許的; (ii)將該字體暫時下載到打印機或其他輸出設備以幫助打印內容。禁止任何其他用途。

禁止使用你想要的字體。如果您擁有Verdana許可證,則可以將該字體嵌入到PDF中。但是,不允許提取該字體並將其用於其他目的。您需要使用原始字體程序。

+0

非常感謝您對您的一致和準確的答案。在理解字體使用的法律問題和字體術語方面,你幫了我很多忙。我將重新分配我的代碼,使其在法律上合適,並在技術上可執行。 –

1

如果你只是想顯示的字體的名稱中使用(你是法律允許這樣做),你可以使用下面的代碼:

public void go() throws IOException { 

    final Set<String> usedFontNames = new HashSet<>(); 
    IEventListener fontNameExtractionStrategy = new IEventListener() { 
     @Override 
     public void eventOccurred(IEventData iEventData, EventType eventType) { 
      if(iEventData instanceof TextRenderInfo) 
      { 
       TextRenderInfo tri = (TextRenderInfo) iEventData; 
       String fontName = tri.getFont().getFontProgram().getFontNames().getFontName(); 
       usedFontNames.add(fontName); 
      } 
     } 
     @Override 
     public Set<EventType> getSupportedEvents() { 
      return null; 
     } 
    }; 

    PdfCanvasProcessor parser = new PdfCanvasProcessor(fontNameExtractionStrategy); 

    File inputFile = new File("YOUR_INPUT_FILE_HERE.pdf"); 
    PdfDocument pdfDocument = new PdfDocument(new PdfReader(inputFile)); 
    for(int i=1;i<=pdfDocument.getNumberOfPages();i++) 
    { 
     parser.processPageContent(pdfDocument.getPage(i)); 
    } 
    pdfDocument.close(); 

    for(String fontName : usedFontNames) 
    { 
     System.out.println(fontName); 
    } 
} 
+0

非常感謝您的回答。我現在可以顯示用戶使用的字體的名稱。 –

相關問題