尝试应用密文会导致异常
Attempt to apply redactions results in exception
我已按照步骤创建注释并使用 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 构造时收到以下异常:
Object reference not set to an instance of an object.
at
iTextSharp.xtra.iTextSharp.text.pdf.pdfcleanup.PdfCleanUpProcessor.ExtractLocationsFromRedactAnnots(Int32 page, PdfDictionary pageDict)
at
iTextSharp.xtra.iTextSharp.text.pdf.pdfcleanup.PdfCleanUpProcessor.ExtractLocationsFromRedactAnnots()
at
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.
这里有两个问题,一个在 OP 的代码中,一个在 iText(Sharp) 中。
OP 代码中的问题
需要注意的是,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)
iText 中的问题 (Sharp)
PdfCleanUpProcessor
有一个成员字典 clippingRects
,其中 Redact 注释区域通过它们在页面 Annots[ 中的索引添加=56=]数组:
private IList<PdfCleanUpLocation> ExtractLocationsFromRedactAnnot(int page, int annotIndex, PdfDictionary annotDict) {
...
clippingRects.Add(annotIndex, markedRectangles);
...
}
如果多个页面上的文档在各自的页面 Annots 数组中具有具有相同索引的 Redact 注释,因此,此方法在不同的调用尝试使用相同的密钥向成员 clippingRects
添加多个条目。 .Net Dictionary
class 不允许这样做并抛出异常。
因此,通过 Redact 注释进行的 iTextSharp 修订仅适用于只有 Redact 注释的文档,如果只有一页被如此注释!
此功能的最初开发发生在Java,而在Java clippingRects
是一个允许覆盖条目的HashMap
,因此此处不会抛出异常.此外,由于 clippingRects
的内容仅在特殊情况下使用(RO 或 OverlayText 在 Redact 个条目),错误的条目通常不会造成任何伤害,因此可能尚未被重复观察到。
我已按照步骤创建注释并使用 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 构造时收到以下异常:
Object reference not set to an instance of an object. at iTextSharp.xtra.iTextSharp.text.pdf.pdfcleanup.PdfCleanUpProcessor.ExtractLocationsFromRedactAnnots(Int32 page, PdfDictionary pageDict) at iTextSharp.xtra.iTextSharp.text.pdf.pdfcleanup.PdfCleanUpProcessor.ExtractLocationsFromRedactAnnots() at 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.
这里有两个问题,一个在 OP 的代码中,一个在 iText(Sharp) 中。
OP 代码中的问题
需要注意的是,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)
iText 中的问题 (Sharp)
PdfCleanUpProcessor
有一个成员字典 clippingRects
,其中 Redact 注释区域通过它们在页面 Annots[ 中的索引添加=56=]数组:
private IList<PdfCleanUpLocation> ExtractLocationsFromRedactAnnot(int page, int annotIndex, PdfDictionary annotDict) {
...
clippingRects.Add(annotIndex, markedRectangles);
...
}
如果多个页面上的文档在各自的页面 Annots 数组中具有具有相同索引的 Redact 注释,因此,此方法在不同的调用尝试使用相同的密钥向成员 clippingRects
添加多个条目。 .Net Dictionary
class 不允许这样做并抛出异常。
因此,通过 Redact 注释进行的 iTextSharp 修订仅适用于只有 Redact 注释的文档,如果只有一页被如此注释!
此功能的最初开发发生在Java,而在Java clippingRects
是一个允许覆盖条目的HashMap
,因此此处不会抛出异常.此外,由于 clippingRects
的内容仅在特殊情况下使用(RO 或 OverlayText 在 Redact 个条目),错误的条目通常不会造成任何伤害,因此可能尚未被重复观察到。