即使form扁平化属性为false,它也会被扁平化

本文关键字:扁平化 false form 属性 即使 | 更新日期: 2023-09-27 18:03:33

我有以下方法,应该在给定坐标的pdf文件上盖章图像,并返回它与层仍然分开,即不平坦,我设置了formflating属性,但它不起作用。

经过一些实验,我发现当我调用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的图片,结果是一样的。

即使form扁平化属性为false,它也会被扁平化

看起来您在iText(Sharp)中发现了一个bug。但是你的代码中还有一个额外的弱点。

错误

PdfStamperImp (stamper.Writer类)由PdfWriter衍生而来。PdfWriter保存了它写入的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);

RegisterLayerPdfWriter中定义

documentOCG[layer] = null;

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

你的<<p> strong>的变通办法
//Don't delete otherwise the stamper flattens the layers
var layers = stamper.GetPdfLayers();

本质上强制初始化在 PdfLayer构造函数被调用之前发生。

这个bug可以通过在PdfStamperImp中重写RegisterLayer来修复(当然它必须是虚拟的);重写必须首先触发惰性初始化本身。实际上,延迟初始化应该使用一个独立的标志,并检查字典计数作为完整性检查。

iText中存在一个模拟错误,可以使用StampInLayer.java复制。

代码中的问题

你回来

return (ms.GetBuffer());

这是完全错误的:缓冲区通常比实际文件大,也就是说,您返回的PDF具有长尾的垃圾字节。使用

return (ms.ToArray());

误解

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