【问题标题】:iText 5.5.11 - bold text looks blurry after using PdfCleanUpProcessoriText 5.5.11 - 使用 PdfCleanUpProcessor 后粗体文本看起来模糊
【发布时间】:2017-06-01 10:11:08
【问题描述】:

我需要从 iText 5.5.11 中使用 Jasper Reports 创建的现有 pdf 中删除一些内容,但在运行 PdfCleanUpProcessor 后,所有粗体文本都变得模糊。

这是我正在使用的代码:

PdfReader reader = new PdfReader("input.pdf");
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("output.pdf"));
List<PdfCleanUpLocation> cleanUpLocations = new ArrayList<PdfCleanUpLocation>();

cleanUpLocations.add(new PdfCleanUpLocation(1, new Rectangle(0f, 0f, 595f, 680f)));

PdfCleanUpProcessor cleaner = new PdfCleanUpProcessor(cleanUpLocations, stamper);
cleaner.cleanUp();

stamper.close();
reader.close();

正如已经讨论过的here,降级到 itext-5.5.4 可以解决问题,但在我的情况下,由于其他原因 itext-5.5.11 已经在使用,因此降级不是一种选择。

是否有其他解决方案或解决方法?

这是清理前后的pdf文件:BEFORE - AFTER

【问题讨论】:

  • 请分享一份 PDF 文件,以便我们重现该问题。
  • @mkl 使用“BEFORE”PDF 重现问题
  • 啊,好的,抱歉,我没有正确阅读您的问题文本,并希望那里只有图像。我去看看。

标签: java pdf itext


【解决方案1】:

通过比较 beforeafter 文件,很明显PdfCleanUpProcessor 出于某种原因错误地丢弃了一般图形状态操作(至少 wJd)。


在您的 before 文档中,尤其是 w 操作对文本很重要,因为使用了 poor man's bold 变体,即代替使用实际的粗体字体,使用普通字体,文本渲染模式设置为不仅填充字形轮廓,还沿着它画一条线,使其具有粗体外观。

使用 w 操作将该线的宽度设置为 0.23333。由于 after 文档中缺少该操作,因此使用默认宽度值 1。因此,现在沿轮廓的线是以前的 4 倍,导致外观非常胖。


此问题已在提交 d5abd23(日期为 2015 年 5 月 4 日)中引入,其中(除其他外)将此块添加到 PdfCleanUpContentOperator.invoke

} else if (lineStyleOperators.contains(operatorStr)) {
    if ("w" == operatorStr) {
        cleanUpStrategy.getContext().setLineWidth(((PdfNumber) operands.get(0)).floatValue());
    } else if ("J" == operatorStr) {
        cleanUpStrategy.getContext().setLineCapStyle(((PdfNumber) operands.get(0)).intValue());
    } else if ("j" == operatorStr) {
        cleanUpStrategy.getContext().setLineJoinStyle(((PdfNumber) operands.get(0)).intValue());
    } else if ("M" == operatorStr) {
        cleanUpStrategy.getContext().setMiterLimit(((PdfNumber) operands.get(0)).floatValue());
    } else if ("d" == operatorStr) {
        cleanUpStrategy.getContext().setLineDashPattern(new LineDashPattern(((PdfArray) operands.get(0)),
                ((PdfNumber) operands.get(1)).floatValue()));
    }

    disableOutput = true;

这会导致所有lineStyleOperators 被删除,同时尝试将更改的值存储在清理策略上下文中。但是当然,在 Java 中使用 == 进行 String 比较通常是一个非常糟糕的主意,所以自从这个版本以来,线条样式运算符在 iText 中被永久删除了。

实际上这段代码是从 iTextSharp 移植过来的,在 C# 中 ==string 类型完全不同;尽管如此,即使在 iTextSharp 版本中,这些存储的值乍一看似乎只是在路径被描边时才考虑在内,而不是在文本渲染包括沿轮廓描边时才考虑在内。

稍后在提交 9967627(与上述提交的同一天)中,内部 if..else if..else.. 已被删除,并带有注释 PdfCleanUpGraphicsState 替换为来自 itext.pdf.parser 包的现有 GraphicsState,添加了缺少的参数进入后者,只剩下disableOutput = true。这(乍一看也是)似乎修复了 iText/Java 和 iTextSharp/.Net 之间的差异,但如果文本渲染包括沿轮廓的描边,则仍然不考虑线条样式值。


作为一种解决方法,请考虑删除这些行

} else if (lineStyleOperators.contains(operatorStr)) {
    disableOutput = true;

来自PdfCleanUpContentOperator.invoke。现在不再删除线型运算符,并且编辑后 PDF 中的文本看起来像以前一样。不过,我还没有检查过任何副作用,所以在考虑在生产中使用该变通方法之前,请先使用大量文档进行测试。

【讨论】:

  • 感谢和抱歉耽搁了。我会尝试建议的解决方法并通知您
  • 您的解释帮助我理解了这个问题的原因。不幸的是,建议的解决方法意味着修改 itext 库,我无法确保将来不会更新自定义版本。最好的选择可能是更改粗体的生成方式。
  • 另外,您可以将清理包中的所有内容复制到您自己的包中并在那里应用修复。不是最优雅的解决方案,但那又怎样!
  • 将页面的一部分复制为图像并将其粘贴到新的 pdf 页面上也可以在我的情况下工作。 iText可以吗? (我知道 iText 不是用来渲染的,但我不需要将图像保存到文件系统)
  • 对于将页面的一部分复制为图像,您需要实际渲染它,而iText(尚未)实现将PDF渲染到图片。
猜你喜欢
  • 1970-01-01
  • 2012-09-20
  • 1970-01-01
  • 2015-11-09
  • 2012-10-28
  • 1970-01-01
  • 2013-08-07
  • 2013-06-24
  • 1970-01-01
相关资源
最近更新 更多