我有以下方法应该在给定坐标处的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进行测试。
答案 0 :(得分:4)
看起来您在iText(夏普)中发现了一个错误。但是你的代码也有一个额外的弱点。
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);
和RegisterLayer
在PdfWriter
做
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形式字段值,例如,文本字段或复选框。