C# 在iText 7.NET/C中为PDF创建图像表单字段#

C# 在iText 7.NET/C中为PDF创建图像表单字段#,c#,pdf,itext,acrofields,C#,Pdf,Itext,Acrofields,我正在尝试在PDF中创建一个表单字段,用户可以在其中插入一个图像文件并保存文档,这样图像就可以持久化(在新的PDF文档中,而不是修改现有文档)。我知道这是可能的,因为我在其他PDF中看到过它,但我不知道在iText 7 for.NET/C#中应该如何实现 我在Google上找到了它,它似乎至少提供了JavaScript和解决方案的概要,但我不知道如何编辑iTextPdfButtonFormField对象的“布局”。我也在iText网站上尝试过,但它是为了添加到现有文档中,我无论如何都无法让它工作

我正在尝试在PDF中创建一个表单字段,用户可以在其中插入一个图像文件并保存文档,这样图像就可以持久化(在新的PDF文档中,而不是修改现有文档)。我知道这是可能的,因为我在其他PDF中看到过它,但我不知道在iText 7 for.NET/C#中应该如何实现

我在Google上找到了它,它似乎至少提供了JavaScript和解决方案的概要,但我不知道如何编辑iText
PdfButtonFormField
对象的“布局”。我也在iText网站上尝试过,但它是为了添加到现有文档中,我无论如何都无法让它工作(一些更难以捉摸的
System.NullReferenceException
错误)

使用创建按钮并替换图像的想法,到目前为止,我已尝试:

PdfWriter writer = new PdfWriter("myfile.pdf");
PdfDocument document = new PdfDocument(writer);
PdfPage pdfPage = document.AddNewPage(PageSize.A4);
PdfCanvas canvas = new PdfCanvas(pdfPage);

PdfAcroForm form = canvas.GetForm();

PdfButtonFormField button = PdfFormField.CreateButton(document, new Rectangle(50, 50), 0);

button.SetAction(PdfAction.CreateJavaScript("event.target.buttonImportIcon();"));

form.AddField(button); // <-- Error on this line

document.Close();
writer.Close();
我还尝试将
CreateButton
替换为
CreateButton
,如下所示:

PdfButtonFormField button = PdfFormField.CreatePushButton(document, new Rectangle(50, 50), "name", "caption");
用它来编译代码,当我点击PDF中的按钮时,我会看到一个“选择图像”对话框,但是按钮仍然是一个灰色的正方形,上面写着“标题”,而不是被选择的图像所取代。但我怀疑需要一个通用按钮,这样您就可以覆盖布局(不知何故)

如果有人知道应该如何做到这一点,无论是使用这个按钮方法还是其他方法,我将非常感谢一些指点。正如我所说,我特别感兴趣的是在新生成的PDF文档中创建这些字段,在C#程序中使用iText 7

但我得到一个System.NullReferenceException:“对象引用未设置为对象的实例。”

这是Acroform#addField方法中的错误。NPE每次获得一个无名字段作为参数时都会被抛出。 为了避免这种情况,只需在添加到表单之前设置字段名(字段#setName)

用它来编译代码,当我点击PDF中的按钮时,我会看到一个“选择图像”对话框,但是按钮仍然是一个灰色的正方形,上面写着“标题”,而不是被选择的图像所取代。但我怀疑需要一个通用按钮,这样您就可以覆盖布局(不知何故)

PdfFormField.CreateButton方法在这里没有任何优势。iText中的方法创建一个空的PdfButtonFormField(外观和行为应由开发人员在创建字段后定义)

另一方面,createbutdown几乎可以满足您的需要。 唯一需要调整的是布局。默认情况下,创建的按钮具有“仅标签”布局

  public void Generate()
    {
        PdfWriter writer = new PdfWriter("myfile.pdf");
        PdfDocument document = new PdfDocument(writer);

        PdfAcroForm form = PdfAcroForm.GetAcroForm(document, true);
        PdfButtonFormField button = PdfFormField.CreatePushButton(document, new Rectangle(20, 500, 50, 50), "btn",
            "load");
        button.SetAction(PdfAction.CreateJavaScript("event.target.buttonImportIcon();"));
//change the layout type.   
PdfDictionary widget = (PdfDictionary) button.GetKids().Get(0).GetIndirectReference().GetRefersTo();
    widget.GetAsDictionary(PdfName.MK).Put(PdfName.TP, new PdfNumber((int) PushButtonLayouts.ICON_ONLY));

        form.AddField(button); // <-- Error on this line

        document.Close();
    }

    enum PushButtonLayouts
    {
        LABEL_ONLY = 0, //No icon; caption only
        ICON_ONLY = 1, //No caption; icon only
        ICON_TOP_LABEL_BOTTOM = 2, // Caption below the icon
        LABEL_TOP_ICON_BOTTOM = 3, // Caption above the icon
        ICON_LEFT_LABEL_RIGHT = 4, //Caption to the right of the icon
        LABEL_LEFT_ICON_RIGHT = 5, //Caption to the left of the icon
        LABEL_OVER = 6 // Caption overlaid directly on the icon
    }
public void Generate()
{
PdfWriter writer=新的PdfWriter(“myfile.pdf”);
PDF文档=新PDF文档(编写器);
PdfAcroForm form=PdfAcroForm.GetAcroForm(文档,true);
PdfButtonFormField button=PdfFormField.CreateButton(文档,新矩形(20500,50,50),“btn”,
“负载”);
SetAction(pdpartion.CreateJavaScript(“event.target.buttonImportIcon();”));
//更改布局类型。
PdfDictionary小部件=(PdfDictionary)按钮.GetKids().Get(0.GetIndirectReference().GetReferesto();
GetAsDictionary(PdfName.MK).Put(PdfName.TP,新的PdfNumber((int)PushButtonLayouts.ICON_));

form.AddField(按钮);//当您点击空引用时,您可以共享堆栈跟踪吗?请将其纳入您的问题中。我已经包含了它,但我不确定它在这里有多大帮助-不幸的是,它是一个非常不透明的堆栈跟踪。至少,对我来说……我总是很有可能遗漏某些内容。您能尝试
form.AddField吗(按钮,pdfPage);
然后看看结果如何。恐怕还是几乎完全相同的堆栈跟踪,只是缺少iText.Forms.PdfAcroForm.AddField(PdfFormField)中的
line。好的,值得一试。恐怕这需要一个itext关注者来解决。这可能与您添加此内容的页面有关,主要是因为该空指针在itext库中被提升。啊,太棒了,谢谢。如果我可以问一个后续问题的话(我不确定StackOverflow上的礼节,因此,如果这是在错误的位置,我深表歉意),您是否知道是否有办法在按钮上设置初始图像,而不仅仅是文本或空白?令人困惑的是,
SetImage
函数只接受一个字符串,我不知道如何接近
SetImageAsForm(PdformXObject表单)
方法(因为我不知道如何将使用ImageData生成的PdfXObject转换为PdformXObject)。实际上,setImage只是通过setValue()方法将Base64编码的图像设置为按钮值。恐怕您在那里找不到我了。
setValue()
与设置图标不同,对吗?您可以将ImageData转换为Base64编码字符串,还是必须使用其他机制?如果您查看PdfButtonFormFIeld类,您可以发现setImage方法在引擎盖下调用setValue(第198行)。
  public void Generate()
    {
        PdfWriter writer = new PdfWriter("myfile.pdf");
        PdfDocument document = new PdfDocument(writer);

        PdfAcroForm form = PdfAcroForm.GetAcroForm(document, true);
        PdfButtonFormField button = PdfFormField.CreatePushButton(document, new Rectangle(20, 500, 50, 50), "btn",
            "load");
        button.SetAction(PdfAction.CreateJavaScript("event.target.buttonImportIcon();"));
//change the layout type.   
PdfDictionary widget = (PdfDictionary) button.GetKids().Get(0).GetIndirectReference().GetRefersTo();
    widget.GetAsDictionary(PdfName.MK).Put(PdfName.TP, new PdfNumber((int) PushButtonLayouts.ICON_ONLY));

        form.AddField(button); // <-- Error on this line

        document.Close();
    }

    enum PushButtonLayouts
    {
        LABEL_ONLY = 0, //No icon; caption only
        ICON_ONLY = 1, //No caption; icon only
        ICON_TOP_LABEL_BOTTOM = 2, // Caption below the icon
        LABEL_TOP_ICON_BOTTOM = 3, // Caption above the icon
        ICON_LEFT_LABEL_RIGHT = 4, //Caption to the right of the icon
        LABEL_LEFT_ICON_RIGHT = 5, //Caption to the left of the icon
        LABEL_OVER = 6 // Caption overlaid directly on the icon
    }