即使FormFlattening属性为false,Itextsharp形式也会变平

时间:2015-07-19 23:46:31

标签: c# pdf itextsharp

我有以下方法应该在给定坐标处的pdf文件上标记图像,并返回它仍然分开的图层,即不展平,我设置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进行测试。

1 个答案:

答案 0 :(得分:4)

看起来您在iText(夏普)中发现了一个错误。但是你的代码也有一个额外的弱点。

错误

PdfStamperImpstamper.Writer的类)派生自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);

RegisterLayerPdfWriter

中定义
documentOCG[layer] = null;

在特定情况下。

因此,new PdfLayer(layername, stamper.Writer)之后documentOCG.Count //Don't delete otherwise the stamper flattens the layers var layers = stamper.GetPdfLayers(); 大于0会阻止延迟层初始化,因此在标记过程中会有效地删除重要层信息,除非之前已经进行过初始化。 < / p>

解决方法

PdfLayer

在调用RegisterLayer构造函数之前,基本上强制执行初始化。

可以通过覆盖PdfStamperImp中的return (ms.GetBuffer()); 来修复此错误(当然,它必须是虚拟的);覆盖必须首先触发延迟初始化本身。实际上,延迟初始化应使用独立标志,并将字典计数检查为完整性检查。

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

代码中的问题

你回来了

return (ms.ToArray());

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

ContainerView

代替。

误会

在您的问题和代码中,您认为问题是形式展平并尝试进行干预。但是,表格展平与你的问题无关。形状展平是关于扁平化(合并到内容中)AcroForm形式字段值,例如,文本字段或复选框。