As opposed to filling out the fields and trying to get them to display, I wrote the following to replace the fields with text in a new document. It's easily extensible to use the PdfTextFields as rectangles for images as well by simply testing for other object types in DrawItemForField() and calling gfx.DrawImage().
Code:
class Program
{
static void Main()
{
var document = PdfReader.Open(@"C:/Form.pdf", PdfDocumentOpenMode.Import);
var outputDoc = new PdfDocument();
outputDoc.AddPage(document.Pages[0]);
outputDoc.Version = 14;
var page = outputDoc.Pages[0];
var fields = new List<FormField>();
// Remove all the form fields from the copied page
foreach (var annotation in page.Annotations.ToList().OfType<PdfAnnotation>())
{
var annotParent = annotation.Elements[PdfAcroField.Keys.Parent] as PdfReference;
var title = (annotParent != null)
? ((PdfDictionary)annotParent.Value).Elements[PdfAcroField.Keys.T].ToString()
: annotation.Title;
if (document.AcroForm.Fields.Names.Contains(title))
{
fields.Add(new FormField(title, annotation, page));
page.Annotations.Remove(annotation);
}
}
var gfx = XGraphics.FromPdfPage(page);
foreach (var field in fields)
{
field.Field = document.AcroForm.Fields[field._title];
DrawItemForField(gfx, field, "-" + field._title + "-");
}
const string filename = @"C:/Form2.pdf";
outputDoc.Save(filename);
outputDoc.Close();
document.Dispose();
Process.Start(filename);
}
private static void DrawItemForField(XGraphics gfx, FormField field, object obj)
{
var font = FontFromPdfFont(field._font);
var brush = BrushFromPdfFont(field._font);
var format = XStringFormats.TopLeft;
if (field.Field.Flags != PdfAcroFieldFlags.Multiline)
{
format.LineAlignment = XLineAlignment.Center;
format = AdjustFormat(format, field._alignment);
}
if (obj is string)
{
if (field.Field.Flags == PdfAcroFieldFlags.Multiline)
{
var tf = new XTextFormatter(gfx);
tf.DrawString(obj as string, font, brush, field._rect, XStringFormats.TopLeft);
}
else
gfx.DrawString(obj as string, font, brush, field._rect, format);
}
}
private static XStringFormat AdjustFormat(XStringFormat format, PdfItem alignment)
{
if (alignment is PdfInteger)
{
switch (((PdfInteger)alignment).Value)
{
case 0: format.Alignment = XStringAlignment.Near; break;
case 1: format.Alignment = XStringAlignment.Center; break;
case 2: format.Alignment = XStringAlignment.Far; break;
}
}
return format;
}
private static XFont FontFromPdfFont(PdfString font)
{
const string boldItalic = "Bold,Italic";
const string bold = "Bold";
const string italic = "Italic";
const string fontHelv = "Helvetica";
const string fontTiRo = "Times";
const string fontCour = "Courier New";
const string fontSymb = "Symbol";
var options = new XPdfFontOptions(PdfFontEncoding.WinAnsi, PdfFontEmbedding.Default);
if (font == null) return null;
var pieces = font.Value.Split(' ');
var family = pieces[0].Replace("/", string.Empty);
double size;
if (!double.TryParse(pieces[1], out size))
return new XFont("Arial", 10);
var split = family.Split(',');
var searchfam = split[0];
var modifier = string.Join(",", split.Reverse().Take(split.Count() - 1).Reverse());
switch (family)
{
case "Helv": searchfam = fontHelv; break;
case "HeBO": searchfam = fontHelv; modifier = boldItalic; break;
case "HeBo": searchfam = fontHelv; modifier = bold; break;
case "HeOb": searchfam = fontHelv; modifier = italic; break;
case "TiRo": searchfam = fontTiRo; break;
case "TiBI": searchfam = fontTiRo; modifier = boldItalic; break;
case "TiIt": searchfam = fontTiRo; modifier = italic; break;
case "TiBo": searchfam = fontTiRo; modifier = bold; break;
case "Cour": searchfam = fontCour; break;
case "CoBo": searchfam = fontCour; modifier = bold; break;
case "CoOb": searchfam = fontCour; modifier = italic; break;
case "CoBO": searchfam = fontCour; modifier = boldItalic; break;
case "Symb": searchfam = fontSymb; break;
case "CourierNew": searchfam = fontCour; break;
}
if (!string.IsNullOrEmpty(modifier))
searchfam = string.Join(",", new[] { searchfam, modifier });
try
{
return new XFont(searchfam, size, XFontStyle.Regular, options);
}
catch
{
return new XFont(fontHelv, size, XFontStyle.Regular, options);
}
}
private static XBrush BrushFromPdfFont(PdfString font)
{
if (font != null)
{
var pieces = font.Value.Split(' ');
switch (pieces.Last())
{
case "g": // grayscale
double gray;
if (double.TryParse(pieces[pieces.Count() - 2], out gray))
return new XSolidBrush(XColor.FromGrayScale(gray));
break;
case "rg": // rgb
double red, green, blue;
var success = new bool[3];
if (pieces.Count() < 4) break;
success[0] = double.TryParse(pieces[pieces.Count() - 4], out red);
success[1] = double.TryParse(pieces[pieces.Count() - 3], out green);
success[2] = double.TryParse(pieces[pieces.Count() - 2], out blue);
if (success.All(v => v))
return new XSolidBrush(XColor.FromArgb((int)(255 * red), (int)(255 * green), (int)(255 * blue)));
break;
}
}
return XBrushes.Black;
}
}
class FormField
{
public XRect _rect;
public string _title;
public PdfString _font;
public PdfInteger _alignment;
private PdfAcroField _field;
public PdfAcroField Field
{
get { return _field; }
set
{
_field = value;
if (_field != null)
SetFontAndAlignment(_field);
}
}
public FormField(string title, PdfAnnotation annotation, PdfPage page)
{
_title = title;
var rect = annotation.Rectangle;
_rect = new XRect(rect.X1, rect.Y1, rect.Width, rect.Height);
Console.WriteLine(title + " " + _rect.TopLeft);
_rect.Y = page.Height - _rect.Y - rect.Height;
SetFontAndAlignment(annotation);
}
private void SetFontAndAlignment(PdfDictionary item)
{
if (_font == null)
_font = item.Elements[PdfAcroField.Keys.DA] as PdfString;
if (_alignment == null)
_alignment = item.Elements[PdfAcroField.Keys.Q] as PdfInteger;
}
}