即使 FormFlattening 属性 为 false,Itextsharp 表单也会变平

Itextsharp form gets flattened even when the FormFlattening property is false

我有以下方法应该在给定坐标处在 pdf 文件上标记图像,并且 return 它的图层仍然分开,即没有展平,我设置了 FormFlattening 属性 但是没用。

经过一些实验,我发现当我调用getPdfLayers方法时,文件不会被展平,为什么会这样?

public static byte[] StampLayer(System.Drawing.Image image, int x, int y, string layername)
{
    var iImage = iTextSharp.text.Image.GetInstance(image, ImageFormat.Tiff);
    var reader = new PdfReader(_pdfFile);

    using (var ms = new MemoryStream())
    {
        using (var stamper = new PdfStamper(reader, ms))
        {
            //Don't delete otherwise the stamper flattens the layers
            var layers = stamper.GetPdfLayers();

            stamper.FormFlattening = false;

            var logoLayer = new PdfLayer(layername, stamper.Writer);
            PdfContentByte cb = stamper.GetUnderContent(1);
            cb.BeginLayer(logoLayer);

            //300dpi
            iImage.ScalePercent(24f);
            iImage.SetAbsolutePosition(x, y);
            cb.AddImage(iImage);

            cb.EndLayer();
            stamper.Close();

            return (ms.GetBuffer());
        }
    }
}

iTextSharp 版本为:5.5.6

我试过png和jpg图片,结果是一样的。

我正在使用 this file 进行测试。

您似乎在 iText(Sharp) 中发现了错误。但是您的代码也有一个额外的弱点。

错误

PdfStamperImpstamper.Writer 的 class)源自 PdfWriterPdfWriter 保留其写入的 PDF 层的集合:

protected Dictionary<IPdfOCG, object> documentOCG = new Dictionary<IPdfOCG,object>();

PdfStamperImp 仅使用文档的现有层延迟初始化此成员,例如在它的方法中 GetPdfLayers:

virtual public Dictionary<string,PdfLayer> GetPdfLayers()
{
    if (documentOCG.Count == 0)
    {
        ReadOCProperties();
    }
    ...

如您所见,它使用 documentOCG 字典的计数作为初始化是否已经发生的指标。

不幸的是,

var logoLayer = new PdfLayer(layername, stamper.Writer);

打破了这个惰性初始化方案:它执行

writer.RegisterLayer(this);

RegisterLayer定义在PdfWriter

documentOCG[layer] = null;

在给定的情况下。

因此,new PdfLayer(layername, stamper.Writer) 之后 documentOCG.Count 大于 0,这可以防止惰性层初始化,因此在冲压期间有效地删除了重要的层信息,除非之前已经发生了初始化。

您的解决方法

//Don't delete otherwise the stamper flattens the layers
var layers = stamper.GetPdfLayers();

本质上是在 调用 PdfLayer 构造函数之前强制执行初始化。

可以通过覆盖 PdfStamperImp 中的 RegisterLayer 来修复此错误(当然必须将其设为虚拟);覆盖必须首先触发延迟初始化本身。实际上惰性初始化应该使用一个独立的标志并检查字典计数作为完整性检查。

iText 中存在模拟错误,可以使用 StampInLayer.java 重现。

您的代码中的问题

你return

return (ms.GetBuffer());

这是完全错误的:缓冲区通常比实际文件大,即您 return 一个带有长尾垃圾字节的 PDF。使用

return (ms.ToArray());

相反。

误会

在您的问题和您的代码中,您假设您的问题是表单扁平化并试图进行干预。不过,表格扁平化与您的问题无关。表单扁平化是关于扁平化(合并到内容中)AcroForm 表单字段值,例如文本字段或复选框。