如何将 PDF 合并到单个文件而不需要相同字体的多个副本?

2024-03-13

我创建 PDF 并将它们连接成一个 PDF。

我生成的 PDF 文件大小比我预期的要大得多。

我意识到我的输出 PDF 有大量重复字体,这就是文件大小出乎意料地大的原因。

在这里,我的问题是:

我想创建仅嵌入字体信息的 PDF,因此让它们使用 Windows 系统字体。

当我将它们合并成一个 PDF 时,我插入 PDF 需要的实际字体。

如果可以的话,请让我知道该怎么做。


我已经创建了合并并添加字体 https://kb.itextpdf.com/home/it5kb/examples/fonts-and-merging-documents示例来解释不同的选项。

我们将使用以下代码片段创建 PDF:

public void createPdf(String filename, String text, boolean embedded, boolean subset) throws DocumentException, IOException {
    // step 1
    Document document = new Document();
    // step 2
    PdfWriter.getInstance(document, new FileOutputStream(filename));
    // step 3
    document.open();
    // step 4
    BaseFont bf = BaseFont.createFont(FONT, BaseFont.WINANSI, embedded);
    bf.setSubset(subset);
    Font font = new Font(bf, 12);
    document.add(new Paragraph(text, font));
    // step 5
    document.close();
}

我们使用此代码创建 3 个测试文件 1、2、3,我们将执行 3 次:A、B、C。

第一次,我们使用参数embedded = true and subset = true,产生文件测试A1.pdf https://github.com/itext/i5js-sandbox/raw/master/cmpfiles/fonts/cmp_testA1.pdf有文字"abcdefgh"(3.71 KB),测试A2.pdf https://github.com/itext/i5js-sandbox/raw/master/cmpfiles/fonts/cmp_testA2.pdf有文字"ijklmnopq"(3.49 KB) 和测试A3.pdf https://github.com/itext/i5js-sandbox/raw/master/cmpfiles/fonts/cmp_testA3.pdf有文字"rstuvwxyz"(3.55 KB)。字体是嵌入的,并且文件大小相对较小,因为我们只嵌入了字体的子集。

现在我们使用以下代码合并这些文件,使用smart参数来指示我们是否要使用PdfCopy or PdfSmartCopy:

public void mergeFiles(String[] files, String result, boolean smart) throws IOException, DocumentException {
    Document document = new Document();
    PdfCopy copy;
    if (smart)
        copy = new PdfSmartCopy(document, new FileOutputStream(result));
    else
        copy = new PdfCopy(document, new FileOutputStream(result));
    document.open();
    PdfReader[] reader = new PdfReader[3];
    for (int i = 0; i < files.length; i++) {
        reader[i] = new PdfReader(files[i]);
        copy.addDocument(reader[i]);
    }
    document.close();
    for (int i = 0; i < reader.length; i++) {
        reader[i].close();
    }
}

当我们合并文档时,将其与PdfCopy or PdfSmartCopy,相同字体的不同子集将作为单独的对象复制到生成的 PDF 中testA_merged1.pdf https://github.com/itext/i5js-sandbox/raw/master/cmpfiles/fonts/cmp_testA_merged1.pdf / testA_merged2.pdf https://github.com/itext/i5js-sandbox/raw/master/cmpfiles/fonts/cmp_testA_merged2.pdf(均为 9.75 KB)。

这是您遇到的问题:PdfSmartCopy可以检测并重复使用相同的对象,但同一字体的不同子集不相同,并且 iText 无法将同一字体的不同子集合并为一种字体。

第二次,我们使用参数embedded = true and subset = false,产生文件测试B1.pdf https://raw.githubusercontent.com/itext/i5js-sandbox/master/cmpfiles/fonts/cmp_testB1.pdf(21.38 KB),测试B2.pdf https://raw.githubusercontent.com/itext/i5js-sandbox/master/cmpfiles/fonts/cmp_testB2.pdf(21.38 KB) 和测试A3.pdf https://raw.githubusercontent.com/itext/i5js-sandbox/master/cmpfiles/fonts/cmp_testB.pdf(21.38 KB)。字体是完全嵌入的,并且由于嵌入了完整的字体,单个文件的文件大小比以前大很多。

如果我们使用合并文件PdfCopy,字体会多余地出现在合并后的文档中,导致文件臃肿testB_merged1.pdf https://github.com/itext/i5js-sandbox/raw/master/cmpfiles/fonts/cmp_testB_merged1.pdf(63.16 KB)。这绝对不是你想要的!

但是,如果我们使用PdfSmartCopy,iText 检测到相同的字体流并重用它,导致testB_merged2.pdf https://github.com/itext/i5js-sandbox/raw/master/cmpfiles/fonts/cmp_testB_merged2.pdf(21.95 KB) 比我们使用的小得多PdfCopy。它仍然比带有子集字体的文档大,但如果您要连接大量文件,则嵌入完整字体的结果会更好。

第三次,我们使用参数embedded = false and subset = false,产生文件测试C1.pdf https://github.com/itext/i5js-sandbox/raw/master/cmpfiles/fonts/cmp_testC1.pdf(2.04 KB),测试C2.pdf https://github.com/itext/i5js-sandbox/raw/master/cmpfiles/fonts/cmp_testC2.pdf(2.04 KB) 和测试C3.pdf https://github.com/itext/i5js-sandbox/raw/master/cmpfiles/fonts/cmp_testC3.pdf(2.04 KB)。该字体未嵌入,因此文件大小非常好,但如果与之前的结果之一进行比较,您会发现该字体看起来完全不同。

我们使用合并文件PdfSmartCopy, 导致testC_merged1.pdf https://github.com/itext/i5js-sandbox/raw/master/cmpfiles/fonts/cmp_testC_merged1.pdf(2.6 KB)。同样,我们有一个很好的文件大小,但我们再次遇到字体无法正确显示的问题。

为了解决这个问题,我们需要嵌入字体:

private void embedFont(String merged, String fontfile, String result) throws IOException, DocumentException {
    // the font file
    RandomAccessFile raf = new RandomAccessFile(fontfile, "r");
    byte fontbytes[] = new byte[(int)raf.length()];
    raf.readFully(fontbytes);
    raf.close();
    // create a new stream for the font file
    PdfStream stream = new PdfStream(fontbytes);
    stream.flateCompress();
    stream.put(PdfName.LENGTH1, new PdfNumber(fontbytes.length));
    // create a reader object
    PdfReader reader = new PdfReader(merged);
    int n = reader.getXrefSize();
    PdfObject object;
    PdfDictionary font;
    PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(result));
    PdfName fontname = new PdfName(BaseFont.createFont(fontfile, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED).getPostscriptFontName());
    for (int i = 0; i < n; i++) {
        object = reader.getPdfObject(i);
        if (object == null || !object.isDictionary())
            continue;
        font = (PdfDictionary)object;
        if (PdfName.FONTDESCRIPTOR.equals(font.get(PdfName.TYPE))
            && fontname.equals(font.get(PdfName.FONTNAME))) {
            PdfIndirectObject objref = stamper.getWriter().addToBody(stream);
            font.put(PdfName.FONTFILE2, objref.getIndirectReference());
        }
    }
    stamper.close();
    reader.close();
}

现在,我们有了文件testC_merged2.pdf https://github.com/itext/i5js-sandbox/raw/master/cmpfiles/fonts/cmp_testC_merged2.pdf(22.03 KB) 这实际上是您问题的答案。正如您所看到的,第二个选项比第三个选项更好。

Caveats:此示例使用 Gravitas One 字体作为简单的字体。一旦您使用该字体作为复合字体(您通过选择编码来告诉 iText 将其用作复合字体IDENTITY-H or IDENTITY-V),您无法再选择是否嵌入字体、是否对字体进行子集化。根据 ISO-32000-1 中的定义,iText 将始终嵌入复合字体并始终将其子集化。

这意味着当您需要特殊字体(中文、日文、韩文)时,您不能使用上述解决方案。在这种情况下,您不应嵌入字体,而应使用所谓的 CJK 字体。他们的CJK字体将使用可以通过Adobe Reader下载的字体包。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何将 PDF 合并到单个文件而不需要相同字体的多个副本? 的相关文章

  • 如何使用 Java 将 HTML 内容转换为 PDF 而不丢失格式?

    我有一些 HTML 内容 包括格式化标签 例如strong 图像等 在我的 Java 代码中 我想将此 HTML 内容转换为 PDF 文档 而不丢失 HTML 格式 有没有办法用 Java 来实现 使用 iText 或任何其他库 I use
  • 是否可以“缩小”PdfPtable?

    我目前正在使用 Itextsharp 但在使用 PDfPtables 时遇到一些问题 有时 它们对于一个页面来说太大了 并且当添加到文档中时 它们会被分成多个页面 可悲的是 这种理性的行为对于我的一些上级来说是不可接受的 他们一直坚持认为表
  • 如何将 OTF/TTF 文件转换为 EOT 格式?

    我需要使用 font face 功能 并且我的字体是 OTF TTF 格式 而 Microsoft 浏览器仅支持 EOT 格式 我尝试使用微软工具WEFT 但它不起作用或者我不明白它是如何工作的 还有其他方法可以将我的字体转换为 EOT 格
  • Zend 框架 PDF 问题

    又是我 伙计们 我有一个小问题 Create new PDF pdf new Zend Pdf Add new page to the document page pdf gt newPage Zend Pdf Page SIZE A4 p
  • itextsharp读取表[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我使用 itextsharp 创建了一个带有表格的 pdf 我找到了一个例子http itextsharp sourceforge n
  • 如何向页面添加 HTML 页眉和页脚?

    如何使用 itext 从 html 源添加标题到 pdf 目前 我们已经扩展了 PdfPageEventHelper 并重写了这些方法 工作正常 但当我到达 2 个以上页面时 它会抛出 RuntimeWorkerException Over
  • 使用 ImageMagick 和/或 GhostScript 将多页 PDF 转换为多个 JPG

    我正在尝试将多页 PDF 文件转换为一堆 JPEG PDF 中的每一页一个 我花了几个小时寻找如何做到这一点 最终我发现我需要安装 Ghostscript 所以我就这么做了 来自这个网站 http downloads ghostscript
  • LibreOffice 并行将 .docx 转换为 .pdf 效果不佳

    我有很多 docx 文件需要转换为 pdf 将它们一一转换需要很长时间 所以我编写了一个 python 脚本来并行转换它们 from subprocess import Popen import time import os os chdi
  • 如何向 Rails 应用程序添加自定义字体?

    我想在 RoR 应用程序中使用几种字体 但它们的格式主要是 ttf 和 otf 等 我该如何将这些文件嵌入到我的 Rails 应用程序中 也就是说 一旦我将它们放入我的资产文件夹中 将它们嵌入我的 CSS 和 或 LESS 文件中的语法到底
  • 是否有一个 C++ 库可以从 PDF 文件中提取文本,例如 PDFBox for Java? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 去年 我使用 PDFBox 在 Java 中创建了一个应用程序来获取某些 PDF 文件中的原始文本 现在
  • 将文本叠加在图像背景上并转换为 PDF

    使用 NET 我想以编程方式创建一个 PDF 它仅包含一个背景图像 其上有两个具有不同字体和位置的标签 我已阅读过有关现有 PDF 库的信息 但不知道 如果适用 哪一个对于如此简单的任务来说最简单 有人愿意指导我吗 P D 我不想使用生成的
  • 如何在 WinForms 应用程序中嵌入我自己的字体?

    我想在我的 WinForms 应用程序中嵌入字体 这样我就不必担心它们被安装在计算机上 我在 MSDN 网站上进行了一些搜索 发现了一些有关使用本机 Windows API 调用的提示 例如 Scott Hanselman 链接到的 Mic
  • Windows 如何批量打印 PDF 文档?

    在我的机器上 当在 Windows 资源管理器中选择多个 PDF 文档时 右键单击并选择Print Adobe Acrobat Reader 将最小化打开 所有文档都会静默发送到打印机 我想做Windows一样的事情 但是怎么做呢 我在用P
  • ExceptionConverter:java.io.IOException:文档没有页面。我正在使用 iText

    当我执行下面的代码时 File f new File c sample pdf PdfWriter getInstance document new FileOutputStream f document open System out p
  • 合并两个(或更多)PDF

    背景 我需要为我的销售人员提供每周报告包 该包包含几个 5 10 个水晶报告 Problem 我想允许用户运行所有报告并且只运行单个报告 我想我可以通过创建报告然后执行以下操作来做到这一点 List
  • 如何使用 Ghostscript DLL 将 PDF 转换为 PDF/A

    如何使用 GhostScript DLL 将 PDF 转换为 PDF A 我知道我必须调用 gsdll32 dll 的导出函数 其名称为 gsapi init with args 但如何传递正确的参数 顺便说一句 我正在使用 C 请尝试从命
  • 在chrome中将pdf渲染为iframe

    我正在尝试将 pdf 托管在隐藏的 iframe 中 但在 Chrome 中呈现较小的问题时遇到问题 我必须刷新页面才能正确加载 JSfiddle 在这里https jsfiddle net 464xo40f https jsfiddle
  • 在 iPad 上显示 PDF 文档 - 颜色问题

    我为 iPad 构建了一个 PDF 阅读器 在将预览中的文档与模拟器和设备进行并排比较时 我注意到一些颜色问题 最好的形容就是颜色变得更加浓郁 近距离使用的相似颜色之间的任何差异都会变得更加明显 而所有颜色总体上看起来都更亮 尽管大肆宣传将
  • 在 JSPdf 中嵌入二进制文件

    我在用着JsPDF https www npmjs com package jspdf将 html 内容导出到下载的 PDF 考虑以下示例 该示例获取一些 HTML 内容并将其输出到下载的 PDF 文件 使用JsPdf import Rea
  • 在 Python 中静默打印 PDF

    我正在尝试使用 Python 打印 PDF 而不打开 PDF 查看器应用程序 Adobe Foxit 等 我还需要知道打印何时完成 以删除文件 Here http permalink gmane org gmane comp python

随机推荐