Itextsharp iTexterFieldBug?

Itextsharp iTexterFieldBug?,itextsharp,itext,Itextsharp,Itext,我试图重命名子类化的复选框。假设复选框的名称为MyForm.Check1.page0。当我跑步时: reader.AcroField.RenameField("MyForm.Check1.page0", "MyForm.Check1.newName"); 复选框重命名为“newName”。子类信息将被删除。我从文档中得知,子类不能更改,但这是出乎意料的 根据文件: “重命名字段。只能重命名名称的最后一部分。对于 例如,如果原始字段为“ab.cd.ef”,则只能选择“ef”部分 重新命名。” 这

我试图重命名子类化的复选框。假设复选框的名称为MyForm.Check1.page0。当我跑步时:

reader.AcroField.RenameField("MyForm.Check1.page0", "MyForm.Check1.newName");
复选框重命名为“newName”。子类信息将被删除。我从文档中得知,子类不能更改,但这是出乎意料的

根据文件:

“重命名字段。只能重命名名称的最后一部分。对于 例如,如果原始字段为“ab.cd.ef”,则只能选择“ef”部分 重新命名。”

这是漫长的一天,但我认为这意味着你可以将一个字段的子类“ab.cd.ef”重命名为“ab.cd.yz”,而不是如果你将“ab.cd.ef”重命名为“ab.cd.yz”,你就会得到一个名为“yz”的字段

在GitHub上,我觉得这是一个bug。来自GitHub:

 public bool RenameField(String oldName, String newName) {
            int idx1 = oldName.LastIndexOf('.') + 1;
            int idx2 = newName.LastIndexOf('.') + 1;
            <snip>
            Item item = fields[oldName];
            newName = newName.Substring(idx2);
public bool重命名字段(字符串oldName,字符串newName){
int idx1=oldName.LastIndexOf('.')+1;
int idx2=newName.LastIndexOf('.')+1;
项目=字段[旧名称];
newName=newName.Substring(idx2);
我想问题是最后一行。如果这是设计的,我觉得很奇怪。我想我可以解决它,但它只是看起来很奇怪

编辑:

我已经复制并清理了代码,并做了一个演示。你只需要下载一个副本并更改PDF的路径。这都来自一个更大的应用程序,所以作为一个测试应用程序,它有点臃肿,但它比试图重写所有内容都要快。一些代码有点草率,因为它是一个prog中的工作我还遗漏了一些与此问题无关的代码(即我插入的JavaScript代码)

如果您更喜欢DropBox以外的交付机制,请告诉我

我还在粘贴下面的.cs文件的详细信息。您应该可以将其粘贴到C#项目中,它应该可以工作。您需要一个PDF,其中包含一个名为“TableStartPosition”的文本字段,或者调整FillCoverPage方法中的fieldPositions对象,并更新硬编码路径

运行应用程序时,会添加一些复选框,这些复选框的名称为“InkSaver.chk2.pageX”(其中X是一个数字)。但是在运行结束时,这些复选框的名称仅为“pageX”。您可以在RenameFields()方法中查看代码

使用系统;
使用System.Collections.Generic;
使用System.IO;
使用System.Linq;
使用iTextSharp.text;
使用iTextSharp.text.pdf;
命名空间重命名字段测试
{
班级计划
{
Stream _pdfTemplateStream;
MemoryStream\pdfResultStream;
PdfReader_pdfTemplateReader;
PDFSTAMPERPDFRESULTSTAMPER;
静态void Main(字符串[]参数)
{
程序p=新程序();
尝试
{
p、 RunTest();
}
捕获(例外f)
{
控制台写入线(f.Message);
Console.ReadLine();
}
}
内部无效运行测试()
{
FileStream fs=File.OpenRead(@“C:\temp\a\RenameFieldTest\RenameFieldTest\Library\CoverPage.pdf”);
_pdfTemplateStream=fs;
_pdfResultStream=newmemoryStream();
//PDFTemplateStream=newfilestream(_templatePath,FileMode.Open);
_pdfTemplateReader=新的PdfReader(_pdfTemplateStream);
_pdfResultStamper=新的PdfStamper(_pdfTemplateReader,_pdfResultStream);
#区域设置对象
列表类别=新列表();
CustomCategory c1=新CustomCategory();
c1.CategorySizeSinus.Add(CustomCategory.AvailableSizes[1]);
c1.categorysizesinus.Add(CustomCategory.AvailableSizes[2]);
增加(c1);
CustomCategory c2=新CustomCategory();
c2.CategorySizeSinus.Add(CustomCategory.AvailableSizes[0]);
c2.CategorySizeSinus.Add(CustomCategory.AvailableSizes[1]);
增加(c2);
列表项=新列表();
CustomObject co1=新的CustomObject();
co1.类别=c1;
co1.Title=“对象1”;
添加项目(co1);
CustomObject co2=新的CustomObject();
二氧化碳。类别=c2;
co2.Title=“对象2”;
增加(二氧化碳);
#端区
填写封面(项目);
_pdfResultStamper.Close();
_pdfTemplateReader.Close();
List pdfStreams=新列表();
添加(新内存流(pdfResultStream.ToArray());
合并pdf(@“C:\temp\a\RenameFieldTest\RenameFieldTest\Library\Outfile.pdf”,pdfStreams);
_pdfResultStream.Dispose();
_pdfTemplateStream.Dispose();
}
内部空白填充封面页(列表项)
{
//在开始之前,我们需要弄清楚从哪里开始添加表
var fieldPositions=pdfResultStamper.AcroFields.GetFieldPositions(“表起始位置”);
if(fieldPositions==null)
{抛出新异常(“找不到TableStartPosition字段。无法确定表的原点!”;}
_pdfResultStamper.AcroFields.RemoveField(“表起始位置”);
变量fieldPosition=fieldPositions[0];
//获取字段的位置
var targetPosition=fieldPosition.position;
//首先,获取所有可用的卡尺寸
List availableSizes=CustomCategory.availableSizes;
//生成一个表,其中设备名称的可用卡尺寸数为+1
PdfPTable table=新的PdfPTable(availableSizes.Count+1);
float[]columnWidth=新的float[availableSizes.Count+1];
对于(int y=0;yusing System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using iTextSharp.text;
using iTextSharp.text.pdf;

namespace RenameFieldTest
{
    class Program
    {
        Stream _pdfTemplateStream;
        MemoryStream _pdfResultStream;

        PdfReader _pdfTemplateReader;
        PdfStamper _pdfResultStamper;

        static void Main(string[] args)
        {
            Program p = new Program();
            try
            {
                p.RunTest();
            }
            catch (Exception f)
            {
                Console.WriteLine(f.Message);
                Console.ReadLine();
            }
        }
        internal void RunTest()
        {
            FileStream fs = File.OpenRead(@"C:\temp\a\RenameFieldTest\RenameFieldTest\Library\CoverPage.pdf");
            _pdfTemplateStream = fs;
            _pdfResultStream = new MemoryStream();
            //PDFTemplateStream = new FileStream(_templatePath, FileMode.Open);
            _pdfTemplateReader = new PdfReader(_pdfTemplateStream);
            _pdfResultStamper = new PdfStamper(_pdfTemplateReader, _pdfResultStream);

            #region setup objects
            List<CustomCategory> Categories = new List<CustomCategory>();
            CustomCategory c1 = new CustomCategory();
            c1.CategorySizesInUse.Add(CustomCategory.AvailableSizes[1]);
            c1.CategorySizesInUse.Add(CustomCategory.AvailableSizes[2]);
            Categories.Add(c1);

            CustomCategory c2 = new CustomCategory();
            c2.CategorySizesInUse.Add(CustomCategory.AvailableSizes[0]);
            c2.CategorySizesInUse.Add(CustomCategory.AvailableSizes[1]);
            Categories.Add(c2);

            List<CustomObject> Items = new List<CustomObject>();
            CustomObject co1 = new CustomObject();
            co1.Category = c1;
            co1.Title = "Object 1";
            Items.Add(co1);

            CustomObject co2 = new CustomObject();
            co2.Category = c2;
            co2.Title = "Object 2";
            Items.Add(co2);

            #endregion

            FillCoverPage(Items);
            _pdfResultStamper.Close();
            _pdfTemplateReader.Close();

            List<MemoryStream> pdfStreams = new List<MemoryStream>();
            pdfStreams.Add(new MemoryStream(_pdfResultStream.ToArray()));

            MergePdfs(@"C:\temp\a\RenameFieldTest\RenameFieldTest\Library\Outfile.pdf", pdfStreams);

            _pdfResultStream.Dispose();
            _pdfTemplateStream.Dispose();
        }
        internal void FillCoverPage(List<CustomObject> Items)
        {

            //Before we start we need to figure out where to start adding the table
            var fieldPositions = _pdfResultStamper.AcroFields.GetFieldPositions("TableStartPosition");
            if (fieldPositions == null)
            { throw new Exception("Could not find the TableStartPosition field. Unable to determine point of origin for the table!"); }

            _pdfResultStamper.AcroFields.RemoveField("TableStartPosition");

            var fieldPosition = fieldPositions[0];
            // Get the position of the field
            var targetPosition = fieldPosition.position;

            //First, get all the available card sizes
            List<string> availableSizes = CustomCategory.AvailableSizes;


            //Generate a table with the number of available card sizes + 1 for the device name
            PdfPTable table = new PdfPTable(availableSizes.Count + 1);
            float[] columnWidth = new float[availableSizes.Count + 1];
            for (int y = 0; y < columnWidth.Length; y++)
            {
                if (y == 0)
                { columnWidth[y] = 320; }
                else
                { columnWidth[y] = 120; }
            }

            table.SetTotalWidth(columnWidth);
            table.WidthPercentage = 100;

            PdfContentByte canvas;

            List<PdfFormField> checkboxes = new List<PdfFormField>();

            //Build the header row
            table.Rows.Add(new PdfPRow(this.GetTableHeaderRow(availableSizes)));

            //Insert the global check boxes
            PdfPCell[] globalRow = new PdfPCell[availableSizes.Count + 1];
            Phrase tPhrase = new Phrase("Select/Unselect All");
            PdfPCell tCell = new PdfPCell();
            tCell.BackgroundColor = BaseColor.LIGHT_GRAY;
            tCell.AddElement(tPhrase);
            globalRow[0] = tCell;

            for (int x = 0; x < availableSizes.Count; x++)
            {
                tCell = new PdfPCell();
                tCell.BackgroundColor = BaseColor.LIGHT_GRAY;
                PdfFormField f = PdfFormField.CreateCheckBox(_pdfResultStamper.Writer);
                string fieldName = string.Format("InkSaver.Global.chk{0}", availableSizes[x].Replace(".", ""));
                //f.FieldName = fieldName;
                string js = string.Format("hideAll(event.target, '{0}');", availableSizes[x].Replace(".", ""));
                f.Action = PdfAction.JavaScript(js, _pdfResultStamper.Writer);
                tCell.CellEvent = new ChildFieldEvent(_pdfResultStamper.Writer, f, fieldName);
                globalRow[x + 1] = tCell;
                checkboxes.Add(f);
            }
            table.Rows.Add(new PdfPRow(globalRow));

            int status = 0;
            int pageNum = 1;

            for (int itemIndex = 0; itemIndex < Items.Count; itemIndex++)
            {
                tCell = new PdfPCell();
                Phrase p = new Phrase(Items[itemIndex].Title);
                tCell.AddElement(p);
                tCell.HorizontalAlignment = Element.ALIGN_LEFT;

                PdfPCell[] cells = new PdfPCell[availableSizes.Count + 1];
                cells[0] = tCell;

                for (int availCardSizeIndex = 0; availCardSizeIndex < availableSizes.Count; availCardSizeIndex++)
                {
                    if (Items[itemIndex].Category.CategorySizesInUse.Contains(availableSizes[availCardSizeIndex]))
                    {
                        string str = availableSizes[availCardSizeIndex];
                        tCell = new PdfPCell();
                        tCell.PaddingLeft = 10f;
                        tCell.PaddingRight = 10f;
                        cells[availCardSizeIndex + 1] = tCell;
                        cells[availCardSizeIndex].HorizontalAlignment = Element.ALIGN_CENTER;

                        PdfFormField f = PdfFormField.CreateCheckBox(_pdfResultStamper.Writer);
                        string fieldName = string.Format("InkSaver.chk{0}.{1}", availableSizes[availCardSizeIndex].Replace(".", ""), itemIndex + 1);
                        //f.FieldName = fieldName; <-- This causes the checkbox to be double-named (i.e. InkSaver.Global.chk0.InkSaver.Global.chk0
                        string js = string.Format("hideCardSize(event.target, {0}, '{1}');", itemIndex + 1, availableSizes[availCardSizeIndex]);
                        f.Action = PdfAction.JavaScript(js, _pdfResultStamper.Writer);
                        tCell.CellEvent = new ChildFieldEvent(_pdfResultStamper.Writer, f, fieldName);

                        checkboxes.Add(f);
                    }
                    else
                    {
                        //Add a blank cell
                        tCell = new PdfPCell();
                        cells[availCardSizeIndex + 1] = tCell;
                    }
                }
                //Test if the column text will fit

                table.Rows.Add(new PdfPRow(cells));

                canvas = _pdfResultStamper.GetUnderContent(pageNum);
                ColumnText ct2 = new ColumnText(canvas);
                ct2.AddElement(new PdfPTable(table));
                ct2.Alignment = Element.ALIGN_LEFT;
                ct2.SetSimpleColumn(targetPosition.Left, 0, targetPosition.Right, targetPosition.Top, 0, 0);
                status = ct2.Go(true);

                if ((status != ColumnText.NO_MORE_TEXT) || (itemIndex == (Items.Count - 1)))
                {
                    ColumnText ct3 = new ColumnText(canvas);
                    ct3.AddElement(table);
                    ct3.Alignment = Element.ALIGN_LEFT;
                    ct3.SetSimpleColumn(targetPosition.Left, 0, targetPosition.Right, targetPosition.Top, 0, 0);
                    ct3.Go();

                    foreach (PdfFormField f in checkboxes)
                    {
                        _pdfResultStamper.AddAnnotation(f, pageNum);
                    }
                    checkboxes.Clear();

                    if (itemIndex < (Items.Count - 1))
                    {
                        pageNum++;
                        _pdfResultStamper.InsertPage(pageNum, _pdfTemplateReader.GetPageSize(1));

                        table = new PdfPTable(availableSizes.Count + 1);
                        table.SetTotalWidth(columnWidth);
                        table.WidthPercentage = 100;
                        table.Rows.Add(new PdfPRow(this.GetTableHeaderRow(availableSizes)));
                    }
                }
            }
        }
        private PdfPCell[] GetTableHeaderRow(List<string> AvailableSizes)
        {
            PdfPCell[] sizeHeaders = new PdfPCell[AvailableSizes.Count + 1];
            Phrase devName = new Phrase("Device Name");
            PdfPCell deviceHeader = new PdfPCell(devName);
            deviceHeader.HorizontalAlignment = Element.ALIGN_CENTER;
            deviceHeader.BackgroundColor = BaseColor.GRAY;
            sizeHeaders[0] = deviceHeader;
            for (int x = 0; x < AvailableSizes.Count; x++)
            {
                PdfPCell hCell = new PdfPCell(new Phrase(AvailableSizes[x]));
                hCell.HorizontalAlignment = Element.ALIGN_CENTER;
                hCell.BackgroundColor = BaseColor.GRAY;
                sizeHeaders[x + 1] = hCell;
            }
            return sizeHeaders;
        }
        public void MergePdfs(string filePath, List<MemoryStream> pdfStreams)
        {
            //Create output stream            
            FileStream outStream = new FileStream(filePath, FileMode.Create);

            if (pdfStreams.Count > 0)
            {
                try
                {
                    int PriceCardCounter = 0;
                    //Create Main reader
                    PdfReader reader = new PdfReader(pdfStreams[0]);

                    //rename fields in the PDF.  This is required because PDF's cannot have more than one field with the same name
                    RenameFields(reader, PriceCardCounter++);

                    //Create main writer
                    PdfCopyFields Writer = new PdfCopyFields(outStream);

                    //Open document for writing
                    ////Add pages
                    Writer.AddDocument(reader);

                    //For each additional pdf after first combine them into main document
                    foreach (var PdfStream in pdfStreams.Skip(1))
                    {
                        PdfReader reader2 = new PdfReader(PdfStream);
                        //rename PDF fields
                        RenameFields(reader2, PriceCardCounter++);
                        // Add content
                        Writer.AddDocument(reader2);
                    }

                    Writer.Close();
                }
                finally
                {
                    foreach (var Strm in pdfStreams)
                    {
                        try { if (null != Strm) Strm.Dispose(); }
                        catch { }
                    }
                    outStream.Close();
                }
            }
        }
        private void RenameFields(PdfReader reader, int PriceCardID)
        {
            int tempPageNum = 1;
            //rename all fields
            foreach (string field in reader.AcroFields.Fields.Keys)
            {
                if (((reader.AcroFields.GetFieldType(field) == 1) || (reader.AcroFields.GetFieldType(field) == 2)) && (field.StartsWith("InkSaver")))
                {
                    //This is a InkSaver button, set the name so its subclassed
                    string classPath;
                    if (reader.AcroFields.GetFieldType(field) == 2)
                    {
                        classPath = field.Substring(0, field.LastIndexOf("."));
                        if (field.StartsWith("InkSaver.chk"))
                        {
                            int a = field.LastIndexOf(".");
                            string sub = field.Substring(a + 1, (field.Length - a - 1));
                            int pageNum = int.Parse(sub);
                            int realPageNum = pageNum + tempPageNum;//PostProcessing.Instance.CoverPageLength;
                            PriceCardID = realPageNum;
                        }
                    }
                    else
                    {
                        classPath = field.Substring(0, field.LastIndexOf("."));
                    }
                    string newID = classPath + ".page" + PriceCardID.ToString();
                    bool ret = reader.AcroFields.RenameField(field, newID);
                }
                else
                {
                    reader.AcroFields.RenameField(field, field + "_" + PriceCardID.ToString());// field + Guid.NewGuid().ToString("N"));
                }
            }
        }
    }
    public class ChildFieldEvent : IPdfPCellEvent
    {
        protected PdfWriter writer;
        protected PdfFormField parent;
        protected string checkBoxName;

        internal ChildFieldEvent(PdfWriter writer, PdfFormField parent, string CheckBoxName)
        {
            this.writer = writer;
            this.parent = parent;
            this.checkBoxName = CheckBoxName;
        }

        public void CellLayout(PdfPCell cell, Rectangle rect, PdfContentByte[] cb)
        {
            createCheckboxField(rect);
        }
        private void createCheckboxField(Rectangle rect)
        {
            RadioCheckField bt = new RadioCheckField(this.writer, rect, this.checkBoxName, "Yes");
            bt.CheckType = RadioCheckField.TYPE_SQUARE;
            bt.Checked = true;
            this.parent.AddKid(bt.CheckField);
        }
    }
}
// snippet from com.itextpdf.text.pdf.AcroFields.renameField
int idx2 = newName.lastIndexOf('.') + 1;
// cut the last part from the original name
newName = newName.substring(idx2);
PdfString ss = new PdfString(newName, PdfObject.TEXT_UNICODE);
// problem: only the last part will be registered, this must 
// be IMO the (original) whole name including the dots
fields.put(newName, item);