我需要从使用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();
正如这里已经讨论的那样,降级到itext-5.5.4可以解决问题,但是在我的情况下,由于其他原因,已经使用了itext-5.5.11,因此降级不是一种选择。
还有其他解决方案或解决方法吗?
这是清洁前后的pdf文件:之前 - 之后
通过比较文件 之前 和 之后 ,可以清楚地看出,由于某种原因,PdfCleanUpProcessor错误地放弃了常规图形状态操作(至少 w , J 和 d )。
PdfCleanUpProcessor
特别是在您的 之前 文档中, w 操作对于文本非常重要,因为使用了 穷人的粗体 变体,即,使用常规字体代替了实际的粗体字体,并且将文本呈现模式设置为不仅填充字形轮廓并沿其画一条线,使其外观大胆。
使用 w 操作将该行的宽度设置为0.23333 。作为该操作中缺少 后 文件,则使用默认的1宽度值。因此,沿轮廓线的线现在是以前的4倍,导致外观非常胖。
此问题已在提交d5abd23(日期为2015年5月4日)中引入,该提交(除其他事项外)将此区块添加到PdfCleanUpContentOperator.invoke:
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丢弃,同时尝试将更改的值存储在清除策略上下文中。但是,当然==,String在Java中使用进行比较通常是一个非常糟糕的主意,因此,从该版本开始,线型运算符在iText中已被删除。
lineStyleOperators
==
String
实际上,这段代码是从iTextSharp移植过来的,在C#中==,该string类型的工作原理完全不同。尽管如此,即使在iTextSharp版本中,乍一看,似乎仅考虑了这些存储的值,如果笔划了路径,如果文本渲染包括沿轮廓笔划,则没有考虑。
string
稍后在提交9967627中(与上述提交在同一天),内部if..else if..else..已被删除,并带有注释 替换 为包中的PdfCleanUpGraphicsState现有内容,并向后者添加了缺少的参数GraphicsState``itext.pdf.parser,仅disableOutput = true保留了剩余的参数。这(乍看起来)似乎已经解决了iText / Java和iTextSharp / .Net之间的差异,但是,如果文本渲染包括沿轮廓笔划,则仍不考虑线型值。
if..else if..else..
PdfCleanUpGraphicsState
GraphicsState``itext.pdf.parser
disableOutput = true
作为解决方法,请考虑删除行
} else if (lineStyleOperators.contains(operatorStr)) { disableOutput = true;
来自PdfCleanUpContentOperator.invoke。现在,不再删除线型运算符,并且编辑后的PDF中的文本看起来像以前一样。不过,我尚未检查任何副作用,因此,即使考虑在生产中使用该替代方法,也请先测试大量文档。