如何在iText7中重用另一个pdf中的字体?

时间:2017-08-03 13:28:01

标签: java pdf itext7

我正在尝试在iText7中打开PDF文件,在那里写一些新文本,将原始PDF中的字体应用到它并将其保存在另一个PDF文档中。我正在使用Java 1.8

因此,我需要在原始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

然而,唯一的字体example.pdf是Verdana(它是Adobe Acrobat Pro中的文档属性所说的)。此外,Verdana有两种实现方式:粗体和普通。

所以,我有这些问题:

  1. 为什么这个函数会返回两种字体而不是一种(Verdana)。
  2. 如何生成正常读取良好的字体名称以显示它们 对用户(例如Helvetica而不是Helv)?
  3. 如何将从原始文档中获取的字体应用到 新款?
  4. 提前谢谢!

2 个答案:

答案 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);
    }
}

答案 1 :(得分:0)

您不应该在另一个PDF中重复使用一个PDF中的字体,这就是原因:字体几乎不会完全嵌入到PDF文档中。例如:您使用Verdana字体常规(238 KB)和Verdana粗体字体(207 KB),但是当您创建一个简单的PDF文档,以常规和粗体显示“Hello World”时,文件大小将远小于238 + 207 KB。为什么是这样?因为PDF只包含Verdana字体的子集和Verdana粗体字体的子集

  

您可能已经注意到我正在谈论字体 Verdana常规   和字体 Verdana粗体。这些是两种不同的字体   相同的字体系列。阅读你的问题,我注意到你没有做出这种区分。你谈到 font Verdana   两个实现粗体和正常。这是不正确的。你应该   谈谈字体系列 Verdana和两个字体 Verdana粗体和   Verdana定期。

PDF通常包含不同字体的子集。它甚至可以包含相同字体的两个不同子集。另请参阅What are the extra characters in the font name of my PDF?

您的目标是获取一个PDF的字体并使用另一个PDF的字体。但是,假设您的原始PDF仅包含编写“Hello World”所需的子集,并且您要创建一个名为“Hello Universe”的新PDF。这将永远不会起作用,因为子集将不包含用于呈现字母Univr和{的字形。 {1}}。

  

还要考虑到字体通常是许可的。很多字体   有一个许可证,声明您可以使用字体来创建   文档和嵌入该文档中的字体。但是,有   通常是一条条款,说其他人不被允许   提取到字体以在不同的上下文中使用它。例如:您在购买MS Windows副本时支付了字体费用,但有人支付了费用   收到包含该字体的PDF的人可能没有使用许可   那个字体。见Does one need to have a license for fonts if we are using ttf files in itext?

鉴于与您的问题相关的技术和法律问题,我认为处理代码示例并不合理。你的设计有缺陷。您应该使用许可的字体程序,而不是尝试从现有的PDF中提取字体。这回答问题3:如何将原始文档中的字体应用到新段落?您不能:法律禁止它(请参阅下面的额外信息),如果子集不包含您需要的所有字符,那么技术上可能是不可能的!

此外,您在官方iText网站上找到的样本会查找以形式定义的字体。 s/Helv指的是Helvetica和Zapfdingbats。这是一组14中的两种字体,称为标准类型1字体。这些字体从未嵌入在文档中,因为每个查看者都应该知道如何呈现它们。如果要使用这些字体,则不需要完整的字体程序;字体指标就足够了。例如:iText附带14个包含字体指标的AFM文件(AFM = Adob​​e字体指标)。

你想知道为什么你没有找到Verdana,因为Verdana被用作文档中文本的字体,但是你看错了地方。您要求iText提供用于表单的字体,而不是文本中使用的字体。这个答案问题1:为什么这个函数返回两个字体而不是一个(Verdana)。

至于你的问题2:你正在查看字体的内部名称内部名称可以是任何内容(甚至是ZaDb,{ {1},...)。字体的postscript名称存储在字体字典中。这就是你需要的名字。

额外信息:

我检查了Verdana许可证:

  

Microsoft提供的字体。您可以使用此字体创建,显示和打印Microsoft产品,服务或包含此字体的内容的许可条款或使用条款所允许的内容。您只能(i)将此字体嵌入到此字体中包含的嵌入限制允许的内容中; (ii)暂时将此字体下载到打印机或其他输出设备以帮助打印内容。禁止任何其他用途。

禁止使用您想要的字体。如果您拥有Verdana许可证,则可以将该字体嵌入PDF格式。但是,不允许提取该字体并将其用于其他目的。您需要使用原始字体程序。