通过比较 before 和 after 文件,很明显PdfCleanUpProcessor 出于某种原因错误地丢弃了一般图形状态操作(至少 w、J 和 d)。
在您的 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 中的文本看起来像以前一样。不过,我还没有检查过任何副作用,所以在考虑在生产中使用该变通方法之前,请先使用大量文档进行测试。