我已按照步骤创建注释并使用iText 5.5.9应用编辑。这是我的代码:
using (var stamper = new PdfStamper(pdfReader, new FileStream(newFilePath, FileMode.Create)))
{
// Redact the values.
var pdfAnot1 = new PdfAnnotation(stamper.Writer, new Rectangle(165f, 685f, 320f, 702f));
pdfAnot1.Title = "First Page";
pdfAnot1.Put(PdfName.SUBTYPE, PdfName.REDACT);
pdfAnot1.Put(PdfName.IC, new PdfArray(new[] { 0f, 0f, 0f }));
pdfAnot1.Put(PdfName.OC, new PdfArray(new[] { 1f, 0f, 0f })); // red outline
stamper.AddAnnotation(pdfAnot1, 1);
for (var i = 1; i <= pdfReader.NumberOfPages; i++)
{
var pdfAnot2 = new PdfAnnotation(stamper.Writer, new Rectangle(220f, 752f, 420f, 768f));
pdfAnot2.Title = "Header";
pdfAnot2.Put(PdfName.SUBTYPE, PdfName.REDACT);
pdfAnot2.Put(PdfName.IC, new PdfArray(new[] { 0f, 0f, 0f }));
pdfAnot2.Put(PdfName.OC, new PdfArray(new[] { 1f, 0f, 0f })); // red outline
stamper.AddAnnotation(pdfAnot2, i);
}
var cleaner = new PdfCleanUpProcessor(stamper);
cleaner.CleanUp();
}
但是,我总是在PdfCleanUpProcessor构造上收到以下异常:
对象引用未设置为对象的实例。 在 iTextSharp.xtra.iTextSharp.text.pdf.pdfcleanup.PdfCleanUpProcessor.ExtractLocationsFromRedactAnnots(Int32 page,PdfDictionary pageDict) 在 iTextSharp.xtra.iTextSharp.text.pdf.pdfcleanup.PdfCleanUpProcessor.ExtractLocationsFromRedactAnnots() 在 iTextSharp.xtra.iTextSharp.text.pdf.pdfcleanup.PdfCleanUpProcessor..ctor(PdfStamper pdfStamper)
在annotDict的赋值中,似乎在extractLocationsFromRedactAnnots中产生了一个空引用,因此下一行抛出异常:
/**
* Extracts locations from the redact annotations contained in the document and applied to the given page.
*/
private IList<PdfCleanUpLocation> ExtractLocationsFromRedactAnnots(int page, PdfDictionary pageDict) {
List<PdfCleanUpLocation> locations = new List<PdfCleanUpLocation>();
if (pageDict.Contains(PdfName.ANNOTS)) {
PdfArray annotsArray = pageDict.GetAsArray(PdfName.ANNOTS);
for (int i = 0; i < annotsArray.Size; ++i) {
PdfIndirectReference annotIndirRef = annotsArray.GetAsIndirectObject(i);
PdfDictionary annotDict = annotsArray.GetAsDict(i);
PdfName annotSubtype = annotDict.GetAsName(PdfName.SUBTYPE);
if (annotSubtype.Equals(PdfName.REDACT)) {
SaveRedactAnnotIndirRef(page, annotIndirRef.ToString());
locations.AddRange(ExtractLocationsFromRedactAnnot(page, i, annotDict));
}
}
}
return locations;
}
知道为什么会这样吗?示例PDF是here。
答案 0 :(得分:1)
这里有两个问题,一个在OP代码中,一个在iText(夏普)。
必须要注意PdfReader
/ PdfStamper
对的体系结构不是内存中的文档的体系结构,只是为了保存到最后。相反,压模的操作通常会尽快写入输出流,而不一定对压模上的其他代码可见。
理由是iText架构(在7.x之前的版本中看起来很疯狂)是为了允许低资源占用的操作而构建的。在可能需要并行处理许多PDF的服务器应用程序中,这非常重要。
在手头的情况下,OP的代码首先添加 Redact 注释,并在同一次运行中尝试使用这些注释进行清理。这不起作用。相反,OP应该在一次通过中添加注释并在一秒内应用清理,即
using (PdfReader pdfReader = new PdfReader(source))
using (var stamper = new PdfStamper(pdfReader, new FileStream(temp, FileMode.Create)))
{
// ... add REDACT annotations
}
using (PdfReader pdfReader = new PdfReader(temp))
using (var stamper = new PdfStamper(pdfReader, new FileStream(dest, FileMode.Create)))
{
var cleaner = new PdfCleanUpProcessor(stamper);
cleaner.CleanUp();
}
或者根本不使用 Redact 注释:毕竟,为什么只添加注释以立即再次删除注释。为此,PdfCleanUpProcessor
有第二个构造函数,直接给出清理位置:
/**
* Creates a {@link com.itextpdf.text.pdf.pdfcleanup.PdfCleanUpProcessor} object based on the
* given {@link java.util.List} of {@link com.itextpdf.text.pdf.pdfcleanup.PdfCleanUpLocation}s
* representing regions to be erased from the document.
*
* @param pdfCleanUpLocations list of locations to be cleaned up {@see PdfCleanUpLocation}
* @param pdfStamper A{@link com.itextpdf.text.pdf.PdfStamper} object representing the document which redaction
* applies to.
*/
public PdfCleanUpProcessor(IList<PdfCleanUpLocation> pdfCleanUpLocations, PdfStamper pdfStamper)
PdfCleanUpProcessor
有一个成员词典clippingRects
, Redact 注释区域的索引在其 Annots 数组中添加了 注释区域:
private IList<PdfCleanUpLocation> ExtractLocationsFromRedactAnnot(int page, int annotIndex, PdfDictionary annotDict) {
...
clippingRects.Add(annotIndex, markedRectangles);
...
}
如果多个网页上的文档在各自的网页 Annots 数组中具有相同索引的 Redact 注释,则不同调用中的此方法会尝试添加多个条目成员clippingRects
使用相同的密钥。 .Net Dictionary
类不允许这样做并抛出异常。
因此,如果只有一个页面被注释,那么 Redact 注释的iTextSharp编辑仅适用于仅包含 Redact 注释的文档!
此功能的原始开发在Java中进行,在Java clippingRects
中是HashMap
,它允许覆盖条目,因此不会抛出任何异常。此外,因为clippingRects
的内容仅用于特殊情况(在 Redact 条目中使用 RO 或 OverlayText ),错误的条目通常不会造成任何伤害,因此可能还没有被重复地观察到。