【问题标题】:C# iTextSharp - Copy Image from One Image Field to AnotherC# iTextSharp - 将图像从一个图像字段复制到另一个
【发布时间】:2018-12-05 11:15:19
【问题描述】:

我创建了 2 个可填写表格的 pdf,一个用作客户订单,另一个用作内部生产表。每个 pdf 都有相同的字段(每个字段的名称和类型相同)。我编写了一个应用程序(除其他几项外),它使用 iTextSharp 读取给定客户订单中的所有字段,创建一个新的生产表,并填写订单中的所有数据。这一切都适用于文本和日期字段(字符串数据)。但是,每个 pdf 上都有一个图像字段,我需要从订单上的图像字段中获取图像并将其复制到生产表上的图像字段。这就是我要挂断电话的地方。

我可以使用pr.Acrofields.GetFieldItem("imageFieldName"); 将图像作为Acrofields.item 对象获取,但我似乎无法让iTextSharp 让我使用PdfStamper.Acrofields.SetField() 方法将其放入图像字段中,因为它会只取一个字符串。

是否有办法获取该图像数据并将其存储为临时 .jpg 或 .bmp 文件,然后将其插入生产工作表的图像字段?还是我做错了?

【问题讨论】:

  • pdf格式没有图片字段。一些 pdf 设计者允许使用例如 emulate 他们。一个按钮加上一些javascript。但由于该字段只是模拟,因此没有图像价值。尽管如此,复制图像数据是可能的。您可以分享示例 pdf 以检查实现吗?
  • 这是我正在使用的 2 个 pdf 文件的链接:drive.google.com/open?id=1QAbCoMcMsYoZDbqvuaxaLYZ4nrqmXnkc
  • 我认为将 pdf 转换为位图会更容易,然后您可以从图像中剪切特定坐标并使用它们。 “.net pdf to bmp”虽然有点泥潭,但旁边写着很多带有 Free* 的库:P
  • @DerekGlissman 我无权访问这些文件。
  • @mkl 对不起;我只在内部共享它。现已公开。

标签: c# .net image pdf itext


【解决方案1】:

正如评论中所说,pdf 格式没有任何图像字段。一些 pdf 设计器允许使用例如模拟它们。一个按钮加上一些javascript。但是由于该字段只是模拟的,因此没有图像值。这确实是您的两个文档的情况。

因此,要从源表单按钮中检索图像,我们不能获取按钮,而是必须从按钮外观中提取图像。我们使用 itext 解析器命名空间类和一个自定义的 ImageRenderListener 渲染侦听器类来收集位图图像。

要将图像设置为目标表单按钮,此外,我们也不能简单地设置按钮,而必须设置按钮外观。我们使用 iText AcroFields 方法 GetNewPushbuttonFromFieldReplacePushbuttonField 来做到这一点。

ImageRenderListener 渲染监听器类

这个渲染监听器所做的只是收集位图图像:

public class ImageRenderListener : IRenderListener
{
    public List<System.Drawing.Image> Images = new List<System.Drawing.Image>();

    public void BeginTextBlock()
    { }

    public void EndTextBlock()
    { }

    public void RenderText(TextRenderInfo renderInfo)
    { }

    public void RenderImage(ImageRenderInfo renderInfo)
    {
        PdfImageObject imageObject = renderInfo.GetImage();
        if (imageObject == null)
        {
            Console.WriteLine("Image {0} could not be read.", renderInfo.GetRef().Number);
        }
        else
        {
            Images.Add(imageObject.GetDrawingImage());
        }
    }
}

图片的Copy方法

此方法从源阅读器表单元素中检索第一张图像并将其添加到目标压模表单元素:

void Copy(PdfReader source, string sourceButton, PdfStamper target, string targetButton)
{
    PdfStream xObject = (PdfStream) PdfReader.GetPdfObjectRelease(source.AcroFields.GetNormalAppearance(sourceButton));

    PdfDictionary resources = xObject.GetAsDict(PdfName.RESOURCES);
    ImageRenderListener strategy = new ImageRenderListener();
    PdfContentStreamProcessor processor = new PdfContentStreamProcessor(strategy);
    processor.ProcessContent(ContentByteUtils.GetContentBytesFromContentObject(xObject), resources);
    System.Drawing.Image drawingImage = strategy.Images.First();
    Image image = Image.GetInstance(drawingImage, drawingImage.RawFormat);

    PushbuttonField button = target.AcroFields.GetNewPushbuttonFromField(targetButton);
    button.Image = image;
    target.AcroFields.ReplacePushbuttonField(targetButton, button.Field);
}

一个例子

我使用 Adob​​e Acrobat Reader 将图像填充到源文档中

并将此文档保存为Customer Order Form-Willi.pdf

然后我应用了上面的复制方法:

String source = @"Customer Order Form-Willi.pdf";
String dest = @"Production Sheet.pdf";
String target = @"Production Sheet-withImage.pdf";

using (PdfReader sourceReader = new PdfReader(source))
using (PdfReader destReader = new PdfReader(dest))
using (PdfStamper targetStamper = new PdfStamper(destReader, File.Create(target), (char)0, true))
{
    Copy(sourceReader, "proofImage", targetStamper, "proofImage");
}

Production Sheet-withImage.pdf中的结果:

一些警告

上面的代码非常乐观,不包含任何合理性检查。对于生产,您应该明确地使其更具防御性并检查null 值、空列表等。

【讨论】:

  • 太棒了!感谢您提供令人难以置信的彻底答案。这将有很大帮助,并帮助我了解有关 pdf 和 iTextSharp 工作原理的几件事。
猜你喜欢
  • 1970-01-01
  • 2015-08-10
  • 1970-01-01
  • 2010-11-06
  • 1970-01-01
  • 2016-07-14
  • 2012-03-25
  • 2018-08-31
  • 2021-02-24
相关资源
最近更新 更多