【问题标题】:itextpdf font does not embed in Linuxitextpdf 字体不嵌入 Linux
【发布时间】:2014-05-23 11:42:33
【问题描述】:

我有一个简单的 Java 程序,它使用 iTextPDF 创建一个简单的“Hello World”文件,使用的字体不是 iTextPDF 原生的(COOPBL.TTF,直接来自 Windows)。

在 Windows 7-64 上运行,它运行良好并创建了一个 pdf 文件,文件中嵌入了 Cooper Black 字体的子集,反映在文件外观中。

在 Linux 上运行完全相同的类文件(无需重新编译),它不嵌入任何内容并使用 Helvetica。

这是程序:

import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import com.itextpdf.text.FontFactory;
import com.itextpdf.text.Document;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfWriter;

import com.itextpdf.tool.xml.XMLWorkerHelper;


public class iTextTest {
  private void doit(String sOut) {
    Document doc = new Document(PageSize.LETTER);

    try {
      FileOutputStream fOut = new FileOutputStream(sOut);

      // Register a non-native font.
      String sFontDir = ".";
      int iResult = FontFactory.registerDirectory(sFontDir);
      if(iResult == 0) {
        System.out.println("TestPDF(): Could not register font directory " + sFontDir);
      } else {
        System.out.println("TestPDF(): Registered font directory " + sFontDir);
      }
      System.out.println("  Fonts registered:");
      for(String sFont:FontFactory.getRegisteredFonts()) {
        System.out.println("    " + sFont);
      }

      PdfWriter pdfWriter = PdfWriter.getInstance(doc, fOut);

      doc.open();

      XMLWorkerHelper helper = XMLWorkerHelper.getInstance();

      String htmlContent;
      htmlContent  = "<HTML><HEAD></HEAD><BODY>";
      htmlContent += "<P style=\"font-family: cooperblack;\">";
      htmlContent += "Hello World!";
      htmlContent += "</P>";
      htmlContent += "</BODY></HTML>";
      helper.parseXHtml(pdfWriter, doc, new ByteArrayInputStream(htmlContent.getBytes()));

    } catch(IOException e) {
      e.printStackTrace();
    } catch(DocumentException e) {
      e.printStackTrace();
    }

    if(doc != null) {
      doc.close();
    }
  }


  public static void main(String[] args) {
    if(args.length != 1) {
      System.out.println("Usage: iTextTest outfile");
      return;
    }

    iTextTest test = new iTextTest();
    test.doit(args[0]);
  }
}

我正在使用: itextpdf-5.5.0 xmlworker-5.5.0 视窗 Java 1.6.0_21 Linux Java 1.6.0_23

我会包含字体的副本和生成的 pdf,但看不到明显的方法。对于我的测试,我只是将 \Windows\fonts\COOPBL.TTF 复制到测试目录中,用于 Windows 测试和 Linux 测试。

对于它的价值: - 调整字体文件中的保护/属性标志没有区别。 - 我知道这不是公共领域字体。我只是用它来测试。

我对任何 cmets 都很感兴趣!

谢谢, 查克

【问题讨论】:

  • 您定义了String sFontDir = ".";,但与Linux 相比,Windows 上的"." 会有所不同。请将"." 的绝对路径写入System.out,我很确定这不会是您在Linux 上所期望的。您必须将 COOPBL.TTF 文件移动到 Linux 返回的路径。
  • 谢谢,Bruno,我尝试了 getPath、getAbsolutePath 和 getCanonicalPath,并且在两个操作系统上都返回了我从中运行测试的当前目录的预期结果。请注意,我在调用 registerDirectory() 后列出了注册的字体。根据 FontFactory.getRegisteredFonts(),字体文件正在被注册,我正在使用它的一个化身(cooperblack)的确切名称。
  • 这很奇怪。我以前从未见过这个问题。我在 Windows 和 Linux 上运行所有示例。要解决这个问题,我需要能够重现它,但我不能。

标签: linux pdf fonts itext embedding


【解决方案1】:

在 Windows 和 Linux(Windows Ecplise 和控制台 jdb -ack!)上并排调试后,我发现了问题所在。这似乎要么是文档缺陷,要么是我的疏忽。我想我会在这里发布修复,以防其他人遇到类似问题。

问题是,如果我打算使用 XMLWorkerHelper 解析文件,我不应该使用默认的 FontFactory 来注册字体。我在第一个代码示例中使用的 XMLWorkerHelper.parseXHtml() 风格创建了自己的 FontFactoryImp,XMLWorkerFontProvider。该提供程序会忽略默认 FontFactory 执行的任何注册。

修复有两个方面:
1) 创建您自己的 XMLWorkerFontProvider。使用将字体目录作为输入参数的构造函数。
2) 将该提供程序传递给 parseXHtml(),而不是使用更短的调用。

我还使用 FontFactory.setFontImp() 设置了默认的 FontFactory 提供程序。我还没有研究过这个动作的微妙含义,但是跳过这个步骤很容易。

值得一提的是,原始程序在 Windows 中工作的唯一原因是,在我最初对 parseXHtml() 的调用内部提供的默认 XMLWorkerFontProvider 注册了所有系统目录中的所有字体。因为,在 Windows 端,我使用的是已经在 C:/Windows/fonts 中的字体,这是被拾取的字体,而不是本地目录中的文件。如果我使用了未在 Windows 中注册的新字体,Windows 测试也会失败。

这是有效的解决方案。它在 Windows 和 Linux 上生成相同的 pdf 文件:

注意:如果您使用 XMLParser.parse() 而不是 XMLWorkerHelper.parseXHtml(),请查看此代码块之后的其他 cmets。

import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.File;

import com.itextpdf.text.FontFactory;
import com.itextpdf.text.Document;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfWriter;

import com.itextpdf.tool.xml.XMLWorkerHelper;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;


public class iTextTest {
  private void doit(String sOut) {
    Document doc = new Document(PageSize.LETTER);

    try {
      FileOutputStream fOut = new FileOutputStream(sOut);

      // Register non-native fonts in a directory.
      String sFontDir = ".";
      XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(sFontDir, null);
      FontFactory.setFontImp(fontImp);

      System.out.println("  Fonts registered before parsing:");
      for(String sFont:FontFactory.getRegisteredFonts()) {
        System.out.println("    " + sFont);
      }

      PdfWriter pdfWriter = PdfWriter.getInstance(doc, fOut);

      doc.open();

      XMLWorkerHelper helper = XMLWorkerHelper.getInstance();

      String htmlContent;
      htmlContent  = "<HTML><HEAD></HEAD><BODY>";
      htmlContent += "<P style=\"font-family: cooperblack;\">";
      htmlContent += "Hello World!";
      htmlContent += "</P>";
      htmlContent += "</BODY></HTML>";
      helper.parseXHtml(pdfWriter,
                        doc,
                        new ByteArrayInputStream(htmlContent.getBytes()),
                        XMLWorkerHelper.class.getResourceAsStream("/default.css"),
                        null,
                        fontImp);

    } catch(IOException e) {
      e.printStackTrace();
    } catch(DocumentException e) {
      e.printStackTrace();
    }

    if(doc != null) {
      doc.close();
    }
  }


  public static void main(String[] args) {
    if(args.length != 1) {
      System.out.println("Usage: iTextTest outfile");
      return;
    }

    iTextTest test = new iTextTest();
    test.doit(args[0]);
  }
}

在最近的一次更新中,我还必须调整使用 XMLParser 的代码。问题是相似的。默认的 HtmlPipelineContext 创建自己的 XMLWorkerFontProvider。与上述情况一样,这将忽略您使用默认 FontFactory.registerDirectory() 注册的任何字体。同样,解决方案是使用您自己的 XMLWorkerFontProvider,然后将其提供给 HtmlPipelineContext。然后,您需要为自己的 XMLWorker 创建一个新的 CssResolverPipeline,然后将其传递给 XMLParser 构造函数。

这里有一小段代码说明了这一点(使用自定义图像处理程序):

  htmlContext = new HtmlPipelineContext(new CssAppliersImpl(fontImp));
  htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());

  pdfImageProvider = new PDFImageProvider();  // Optional
  htmlContext.setImageProvider(pdfImageProvider);  // Optional

  Pipeline<?> pipeline = new CssResolverPipeline(cssResolver, new HtmlPipeline(htmlContext, new PdfWriterPipeline(doc, pdfWriter)));
  xmlWorker = new XMLWorker(pipeline, true);
  xmlParser = new XMLParser(true, xmlWorker, charsetUTF8);

我希望这可以节省我花费几天时间寻找的人!

【讨论】:

  • 在我的情况下(windows\fonts),它是从系统字体文件夹中挑选出来的,但是当我部署在 linux 上时,找不到 ttf
猜你喜欢
  • 1970-01-01
  • 2016-07-12
  • 2021-10-24
  • 2013-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-19
  • 1970-01-01
相关资源
最近更新 更多