我已经使用iTextSharp生成PDF表单已经有一段时间了,而且它一直运行良好 . 但是,最近我的组织升级到Adobe Reader XI;从那时起,生成的PDF已经开始在Reader中打开PDF时显示“是否要保存更改”对话框,然后再次关闭它,即使您没有对表单进行任何更改 .

我做了一些研究,显然这是由Adobe Reader在幕后对PDF文件进行某种更改引起的,要么是因为PDF本身已损坏(而Reader会为您修复),要么是出于其他原因 . 进一步的调查揭示了罪魁祸首:我将 AcroFormNeedAppearances 标志设置为 true ,这会导致Reader在您打开文件时生成表单字段的外观,然后从文件中删除 NeedAppearances 标志 - 从而修改PDF,并在您关闭时提示您保存"changes" .

删除 NeedAppearances 标志解决了这个问题,但产生了一个新问题来取代它 . 如果没有该标志,iTextSharp将生成表单字段' appearances itself -- but they only apply to the fields' default,unfocused state . 单击(多行文本)字段进行编辑时,Reader定义的外观将接管,从而对字段的文本内容进行可见的更改 .

最明显的变化是内容向下移动了相当数量,但我可以通过使用 TextField.SetExtraMargin() 方法添加上边距来解决这个问题 . 但是,字段's character spacing also changes when it gains focus, becoming slightly narrower. It'只有较小的数量,所以它通常不适合在一条线上,但在间距变窄时确实适合);当发生这种情况时,它会非常明显,因为它会影响它之后的所有线条 .

所以我陷入两难境地 . 如果我将 NeedAppearances 设置为 true ,无论场是否聚焦,我都会得到一致的外观;但如果我没有将 NeedAppearances 设置为 true ,那么当我没有做任何更改时,Reader会停止提示我保存更改 . 我的问题是:我可以立刻获得这两个优势吗?或者我是否必须让自己选择其中一个?

我正在使用iTextSharp 5.5.5,但我尝试升级到最新版本(5.5.8)并没有帮助 .

这是我的示例代码:

using System;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;

namespace MultilineTextFieldDemo
{
    public class PdfCreator
    {
        public static void Main(string[] args)
        {
            string outputDirName = "PdfOutput",
                   outputFilePath = "";
            byte[] buf = null;

            if (!Directory.Exists(outputDirName))
            {
                Directory.CreateDirectory(outputDirName);
            }

            // Create a PDF form with NeedAppearances = true.
            //
            // PRO: The text field will have a consistent appearance, whether it's focused or not.
            // CON: Adobe Reader will prompt you to save changes when you try to close the file,
            //      even if you haven't changed anything.

            buf = CreatePdf(true);
            if (buf != null && buf.Length > 0)
            {
                outputFilePath = Path.Combine(outputDirName, "PdfTest_NeedAppsTrue.pdf");
                File.WriteAllBytes(outputFilePath, buf);
            }

            // Create a PDF form with NeedAppearances = false.
            //
            // PRO: Adobe Reader won't prompt you to save changes when you close the file, unless
            //      you actually changed something.
            // CON: The text field's appearance will change when it gains or loses focus; the characters
            //      will be slightly closer together when focused, and some lines will change their
            //      wrapping positions.

            buf = CreatePdf(false);
            if (buf != null && buf.Length > 0)
            {
                outputFilePath = Path.Combine(outputDirName, "PdfTest_NeedAppsFalse.pdf");
                File.WriteAllBytes(outputFilePath, buf);
            }
        }

        public static byte[] CreatePdf(bool needAppearances)
        {
            byte[] buf = null;
            float marginsH = Utilities.InchesToPoints(0.65f),
                  marginsV = Utilities.InchesToPoints(0.5f);

            using (MemoryStream ms = new MemoryStream())
            {
                using (Document doc = new Document(PageSize.LETTER, marginsH, marginsH, marginsV, marginsV))
                {
                    using (PdfWriter writer = PdfWriter.GetInstance(doc, ms))
                    {
                        if (needAppearances)
                        {
                            writer.AcroForm.NeedAppearances = true;
                        }

                        doc.Open();

                        // Create and add a label for the text field.

                        Phrase label = new Phrase(
                            String.Format("Text Field (NeedAppearances = {0})", needAppearances),
                            FontFactory.GetFont(BaseFont.HELVETICA, 10, Font.BOLD));
                        doc.Add(label);

                        // Calculate the text field's rectangle. It will be the full width of the document, minus a 2-point
                        // margin on the left and right. Its top edge will be directly under the label, and it will be
                        // 4 inches tall.

                        float llx = doc.GetLeft(2),
                              urx = doc.GetRight(2),
                              ury = doc.GetTop(0) - label.Font.CalculatedSize,
                              lly = ury - Utilities.InchesToPoints(4);

                        // Create the text field.

                        TextField textField = new TextField(writer, new Rectangle(llx, lly, urx, ury), "textField");
                        textField.FontSize = 8;
                        textField.Options = BaseField.MULTILINE;
                        textField.Text =
                            "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin ac convallis libero, quis bibendum " +
                            "risus. Vestibulum gravida aliquam tellus, pharetra semper nulla vulputate nec. Nunc eu ornare " +
                            "ligula. Proin pulvinar erat elit, ac elementum ex placerat in. Sed ligula nisl, viverra hendrerit " +
                            "elit ut, lacinia semper diam. Nam in felis fringilla, dignissim metus et, tristique diam. Proin " +
                            "sodales eros non tellus aliquet bibendum. Fusce volutpat, massa at tincidunt porta, dolor justo " +
                            "tincidunt mi, non iaculis justo sem ac erat. Sed dapibus urna vel hendrerit fermentum. Sed rutrum " +
                            "augue sapien, id suscipit nisi porta eu. Morbi vel leo ut tortor faucibus sagittis. Etiam in maximus " +
                            "dui. Quisque et mattis ligula. Integer cursus suscipit semper. Fusce commodo tellus in mattis " +
                            "lobortis. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.";

                        // If NeedAppearances is false, add a vertical margin to compensate for the text shifting downward
                        // when the field gains focus (this still doesn't fix the character spacing issue).

                        if (!needAppearances)
                        {
                            textField.SetExtraMargin(0, 2.8f);
                        }

                        // Get the text field's annotation and add it to the document.

                        PdfFormField annot = textField.GetTextField();
                        writer.AddAnnotation(annot);

                        doc.Close();
                    }
                }

                buf = ms.ToArray();
            }

            return buf;
        }
    }
}