如何使用 PdfStamper 在 APPEND 模式下将图像添加到 pdf 文件?
How to add an image to a pdf file in APPEND mode using PdfStamper?
我正在使用 iTextSharp 库版本 5.5.6.0。
此文件包含可自定义的文本字段,并且有必要保留交互式文本表单字段:https://yadi.sk/i/yoUvDI9EmtVhc。
但我无法在 PdfTemplate 对象中添加图像。
现阶段c#中的代码为:
string outpath = @"D:\pdf_\output.pdf";
string inpath = @"D:\pdf_\input.pdf";
string stamp = @"D:\pdf_\img.png";
This method does'nt add the image, but the text boxes are active.
public static void onlyInteractive()
{
using (MemoryStream os = new MemoryStream())
using (PdfReader pdfReader = new PdfReader(inpath))
//追加模式
using (PdfStamper stamper = new PdfStamper(pdfReader, os, '[=12=]', true))
{
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(stamp);
image.SetAbsolutePosition(0, 0);
PdfTemplate template = PdfTemplate.CreateTemplate(stamper.Writer, image.Width, image.Height);
template.AddImage(image);
stamper.GetOverContent(1).AddTemplate(template, 150, 200, true);
os.WriteTo(new FileStream(outpath, FileMode.Create, FileAccess.ReadWrite));
}
}
The behavior of this method back to the first.
public static void onlyImage()
{
using (Stream output = new FileStream(outpath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
using (PdfReader reader = new PdfReader(inpath))
using (var stamper = new PdfStamper(reader, output, '[=13=]', true))
{
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(stamp);
image.SetAbsolutePosition(0, 0);
PdfTemplate template = PdfTemplate.CreateTemplate(stamper.Writer, image.Width, image.Height);
template.AddImage(image);
stamper.GetOverContent(1).AddTemplate(template, 150, 200, true);
}
}
仅互动
此代码的问题是您在完成之前获取了输出 PDF:
using (PdfStamper stamper = new PdfStamper(pdfReader, os, '[=10=]', true))
{
[...]
os.WriteTo(new FileStream(outpath, FileMode.Create, FileAccess.ReadWrite));
}
当 stamper
关闭时(这里隐式地在其 using
块的末尾),一些尚未存储的 PDF 对象被写入,内部交叉引用和文件尾部被写入.
你先把os
的内容写入文件。因此,您的结果文档不完整。 Adobe Reader 打开后会对其进行修复,这基本上就是您的原始文档。
仅图片
此代码本身是正确的,它将图像标记到文档上并正确存储。
你的问题是文档本身是 Reader-enabled,即它是用所谓的使用权签名[=72=签名的].此类签名会在打开文件时告诉 Adobe Reader 以提供显示编辑相关文档的其他功能。
但是当使用图像检查文档上的签名时,Adobe Reader 发现文档的更改方式与签名授予的使用权不兼容:图像已被更改添加到页面内容中,这是签名未授予的内容。因此,Adobe Reader 撤销了授予的功能,在您的情况下是表单编辑。
正在删除使用权签名
在这种情况下,一个选择是删除该签名。在这种情况下,不再通过该签名授予表单编辑权限。但是在较新的 Adobe Reader 版本中(如果我没记错的话,从第 XI 版开始)默认情况下所有文档都可以进行表单编辑!在您的情况下,由于签名无效,该功能已被删除!
这可以按如下方式完成:
using (Stream output = new FileStream(outpath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
using (PdfReader reader = new PdfReader(inpath))
using (var stamper = new PdfStamper(reader, output))
{
reader.RemoveUsageRights();
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(stamp);
image.SetAbsolutePosition(0, 0);
PdfTemplate template = PdfTemplate.CreateTemplate(stamper.Writer, image.Width, image.Height);
template.AddImage(image);
stamper.GetOverContent(1).AddTemplate(template, 150, 200, true);
}
您现在可以在较新的 Adobe Readers 中编辑带图像的 PDF。
不幸的是,保存文档时出现错误。我不知道它们是否与源文档部分无效这一事实有关(Adobe Preflight 抱怨了很多问题,最重要的是使用了未定义的编码名称 Win1251Encoding)或者其他东西是否坏了。
正在删除追加模式下的使用权签名
在附加模式下工作,我们必须手动删除使用权限签名。实际上,我们将从 Catalog:
中删除整个 Perms 字典
using (Stream output = new FileStream(outpath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
using (PdfReader reader = new PdfReader(inpath))
using (var stamper = new PdfStamper(reader, output, '[=12=]', true))
{
reader.Catalog.Remove(PdfName.PERMS);
stamper.MarkUsed(reader.Catalog);
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(stamp);
image.SetAbsolutePosition(0, 0);
PdfTemplate template = PdfTemplate.CreateTemplate(stamper.Writer, image.Width, image.Height);
template.AddImage(image);
stamper.GetOverContent(1).AddTemplate(template, 150, 200, true);
}
现在您可以编辑表格并保存文件(至少我可以在 Adobe Reader DC 中)。
PS: 正确坐标
OP 在评论中分享了另一个 PDF 并声明它
for the other file is impossible to place a picture on a page with landscape orientation.
OP 的代码确实有问题:
stamper.GetOverContent(1).AddTemplate(template, 150, 200, true);
固定坐标150, 200
是OP假设左下角为坐标系原点0, 0
的标志。虽然情况经常如此,但这不一定是真的。人们总是必须考虑 CropBox(默认为 MediaBox),即对于 OP 的代码:
Rectangle cropBox = reader.GetCropBox(1);
stamper.GetOverContent(1).AddTemplate(template, cropBox.Left + 150, cropBox.Bottom + 200, true);
the library takes rotation not correctly, but gives 0 degrees.
但这是正确的!您的示例 PDF 有点特殊,因为它使用未旋转的矩形作为横向,使用旋转的矩形作为纵向。
我正在使用 iTextSharp 库版本 5.5.6.0。 此文件包含可自定义的文本字段,并且有必要保留交互式文本表单字段:https://yadi.sk/i/yoUvDI9EmtVhc。 但我无法在 PdfTemplate 对象中添加图像。 现阶段c#中的代码为:
string outpath = @"D:\pdf_\output.pdf";
string inpath = @"D:\pdf_\input.pdf";
string stamp = @"D:\pdf_\img.png";
This method does'nt add the image, but the text boxes are active.
public static void onlyInteractive()
{
using (MemoryStream os = new MemoryStream())
using (PdfReader pdfReader = new PdfReader(inpath))
//追加模式
using (PdfStamper stamper = new PdfStamper(pdfReader, os, '[=12=]', true))
{
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(stamp);
image.SetAbsolutePosition(0, 0);
PdfTemplate template = PdfTemplate.CreateTemplate(stamper.Writer, image.Width, image.Height);
template.AddImage(image);
stamper.GetOverContent(1).AddTemplate(template, 150, 200, true);
os.WriteTo(new FileStream(outpath, FileMode.Create, FileAccess.ReadWrite));
}
}
The behavior of this method back to the first.
public static void onlyImage()
{
using (Stream output = new FileStream(outpath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
using (PdfReader reader = new PdfReader(inpath))
using (var stamper = new PdfStamper(reader, output, '[=13=]', true))
{
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(stamp);
image.SetAbsolutePosition(0, 0);
PdfTemplate template = PdfTemplate.CreateTemplate(stamper.Writer, image.Width, image.Height);
template.AddImage(image);
stamper.GetOverContent(1).AddTemplate(template, 150, 200, true);
}
}
仅互动
此代码的问题是您在完成之前获取了输出 PDF:
using (PdfStamper stamper = new PdfStamper(pdfReader, os, '[=10=]', true))
{
[...]
os.WriteTo(new FileStream(outpath, FileMode.Create, FileAccess.ReadWrite));
}
当 stamper
关闭时(这里隐式地在其 using
块的末尾),一些尚未存储的 PDF 对象被写入,内部交叉引用和文件尾部被写入.
你先把os
的内容写入文件。因此,您的结果文档不完整。 Adobe Reader 打开后会对其进行修复,这基本上就是您的原始文档。
仅图片
此代码本身是正确的,它将图像标记到文档上并正确存储。
你的问题是文档本身是 Reader-enabled,即它是用所谓的使用权签名[=72=签名的].此类签名会在打开文件时告诉 Adobe Reader 以提供显示编辑相关文档的其他功能。
但是当使用图像检查文档上的签名时,Adobe Reader 发现文档的更改方式与签名授予的使用权不兼容:图像已被更改添加到页面内容中,这是签名未授予的内容。因此,Adobe Reader 撤销了授予的功能,在您的情况下是表单编辑。
正在删除使用权签名
在这种情况下,一个选择是删除该签名。在这种情况下,不再通过该签名授予表单编辑权限。但是在较新的 Adobe Reader 版本中(如果我没记错的话,从第 XI 版开始)默认情况下所有文档都可以进行表单编辑!在您的情况下,由于签名无效,该功能已被删除!
这可以按如下方式完成:
using (Stream output = new FileStream(outpath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
using (PdfReader reader = new PdfReader(inpath))
using (var stamper = new PdfStamper(reader, output))
{
reader.RemoveUsageRights();
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(stamp);
image.SetAbsolutePosition(0, 0);
PdfTemplate template = PdfTemplate.CreateTemplate(stamper.Writer, image.Width, image.Height);
template.AddImage(image);
stamper.GetOverContent(1).AddTemplate(template, 150, 200, true);
}
您现在可以在较新的 Adobe Readers 中编辑带图像的 PDF。
不幸的是,保存文档时出现错误。我不知道它们是否与源文档部分无效这一事实有关(Adobe Preflight 抱怨了很多问题,最重要的是使用了未定义的编码名称 Win1251Encoding)或者其他东西是否坏了。
正在删除追加模式下的使用权签名
在附加模式下工作,我们必须手动删除使用权限签名。实际上,我们将从 Catalog:
中删除整个 Perms 字典using (Stream output = new FileStream(outpath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
using (PdfReader reader = new PdfReader(inpath))
using (var stamper = new PdfStamper(reader, output, '[=12=]', true))
{
reader.Catalog.Remove(PdfName.PERMS);
stamper.MarkUsed(reader.Catalog);
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(stamp);
image.SetAbsolutePosition(0, 0);
PdfTemplate template = PdfTemplate.CreateTemplate(stamper.Writer, image.Width, image.Height);
template.AddImage(image);
stamper.GetOverContent(1).AddTemplate(template, 150, 200, true);
}
现在您可以编辑表格并保存文件(至少我可以在 Adobe Reader DC 中)。
PS: 正确坐标
OP 在评论中分享了另一个 PDF 并声明它
for the other file is impossible to place a picture on a page with landscape orientation.
OP 的代码确实有问题:
stamper.GetOverContent(1).AddTemplate(template, 150, 200, true);
固定坐标150, 200
是OP假设左下角为坐标系原点0, 0
的标志。虽然情况经常如此,但这不一定是真的。人们总是必须考虑 CropBox(默认为 MediaBox),即对于 OP 的代码:
Rectangle cropBox = reader.GetCropBox(1);
stamper.GetOverContent(1).AddTemplate(template, cropBox.Left + 150, cropBox.Bottom + 200, true);
the library takes rotation not correctly, but gives 0 degrees.
但这是正确的!您的示例 PDF 有点特殊,因为它使用未旋转的矩形作为横向,使用旋转的矩形作为纵向。