我已经使用iTextSharp生成PDF表单已经有一段时间了,而且它一直运行良好 . 但是,最近我的组织升级到Adobe Reader XI;从那时起,生成的PDF已经开始在Reader中打开PDF时显示“是否要保存更改”对话框,然后再次关闭它,即使您没有对表单进行任何更改 .
我做了一些研究,显然这是由Adobe Reader在幕后对PDF文件进行某种更改引起的,要么是因为PDF本身已损坏(而Reader会为您修复),要么是出于其他原因 . 进一步的调查揭示了罪魁祸首:我将 AcroForm
的 NeedAppearances
标志设置为 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;
}
}
}