【问题标题】:Attempt to apply redactions results in exception尝试应用编辑会导致异常
【发布时间】:2016-06-08 21:20:01
【问题描述】:

我已按照步骤创建注释并使用 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 页面,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。

【问题讨论】:

  • 如果您需要 PDF 示例,请告诉我。 - 是的,请提供示例以重现该问题。这通常通过在 Dropbox 或 googledrive 上公开共享文档并在此处发布 URL 来完成。
  • 我添加了一个指向示例 PDF 的链接。

标签: itextsharp redaction


【解决方案1】:

这里有两个问题,一个在 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 中的问题(夏普)

PdfCleanUpProcessor 有一个成员字典 clippingRects,Redact 注释区域通过其页面 Annots 数组中的索引添加到其中:

private IList<PdfCleanUpLocation> ExtractLocationsFromRedactAnnot(int page, int annotIndex, PdfDictionary annotDict) {
    ...
    clippingRects.Add(annotIndex, markedRectangles); 
    ...
}

如果一个文档在多个页面上的 Redact 注释在它们各自的页面 Annots 数组中具有相同的索引,因此,此方法在不同的调用中会尝试将多个条目添加到成员clippingRects 使用相同的密钥。 .Net Dictionary 类不允许这样做并引发异常。

因此,Redact 注释的 iTextSharp 编辑仅适用于只有 Redact 注释的文档,如果只有一个页面被如此注释!

这个特性的最初开发是在Java中进行的,在Java中clippingRects是一个HashMap,它允许覆盖条目,所以这里不会抛出异常。此外,由于clippingRects 的内容仅在特殊情况下使用(在 Redact 条目中使用 RO 或 OverlayText),错误的条目通常不会造成任何伤害,因此可能还没有被重复观察到。

【讨论】:

  • 感谢@mkl,我同意创建清理位置并使用备用构造函数是我的应用程序的方法。但是,结果是另一个例外:无法从具有索引像素格式的图像创建 Graphics 对象。
  • 不幸的是,iTextSharp 不理解 PDF 中的所有位图格式,但对于编校,它需要了解编校区域中图像的所有图像格式。 iTextSharp 代码可能应该针对此类问题进行一些强化......
  • 对我之前的异常的跟进。异常发生在与我包含的示例文档不符合相同基本格式的文档上。在处理正确格式的 PDF 文件时,如示例中所示,此解决方案运行良好。谢谢@mkI!
猜你喜欢
  • 2023-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-04
  • 1970-01-01
  • 2014-02-17
  • 1970-01-01
相关资源
最近更新 更多