TLDR;Имея ниже проблемы с решением IText, и не нашли «лучший» вариант.
В настоящее время проект находит лучший способ программного заполнения форм из базы данных.После тщательного исследования я нашел несколько решений на основе следующих критериев и создал (несколько работающее) решение:
- В настоящее время мы используем Access, но в ближайшие месяцы переходим на SQL.
- Заполнение нескольких уникальных форм, которые создаются государственными органами на основе введенного пользователем.(поэтому мы не можем просто создавать наши собственные формы.)
- Формы регулярно обновляются агентствами, но необходимые данные остаются неизменными и будут храниться в базе данных.
Чтобы решить эту проблему, я исследовал такие вещи, как IText , который имеет массу инструментов для работы с PDF, одна небольшая часть которого заключается в том, что он может заполнять форму с использованием технологии AcroField.
Я также прочитал ряд ресурсов, в том числе:
- Это описание использования AcroFields и IText для заполнения форм
- Это старое решение с использованием Docotic
Это еще более старое решение с Java
Среди многих других ресурсов.Я обнаружил, что IText лучше всего поддерживается с некоторыми примерами и API, которые помогли мне создать следующее:
//Creates form
public virtual void ManipulatePdf(string src, string dst, DataGridViewRow dataRow)
{
//Initialize PDF document
PdfDocument pdf = new PdfDocument(new PdfReader(src), new PdfWriter(dst));
PdfAcroForm form = PdfAcroForm.GetAcroForm(pdf, true);
//form.RemoveXfaForm();
//form.SetNeedAppearances(true);
IDictionary fields = form.GetFormFields();
PdfFormField toSet;
//visits each field, fills dependant on whether dgv column exists
foreach (string field in fields.Keys)
{
switch (dataGridView1.Columns.Contains(field))
{
case false:
switch (field)
{
case "Date":
fields.TryGetValue(field, out toSet);
toSet.SetValue(dateTime.ToString("MM/dd/yy"));
break;
case "Period_YY":
fields.TryGetValue(field, out toSet);
toSet.SetValue(dateTime.ToString("yy"));
break;
case "Period_YY2":
fields.TryGetValue(field, out toSet);
toSet.SetValue(dateTime.ToString("yy"));
break;
case "Period_Month_Start":
fields.TryGetValue(field, out toSet);
toSet.SetValue(dateTime.AddMonths(-1).ToString("MMMM"));
break;
case "Client_Name2":
fields.TryGetValue(field, out toSet);
toSet.SetValue(dataRow.Cells["Client_Name"].Value.ToString());
break;
default:
fields.TryGetValue(field, out toSet);
toSet.SetValue("0");
//this setting does not commit, issue with hybrid XFA/AcroForm
//.SetBackgroundColor(ColorConstants.YELLOW);
break;
}
break;</p>
<code> case true:
if (dataRow.Cells[field].Value != null && !DBNull.Value.Equals(dataRow.Cells[field].Value))
{
string value = dataRow.Cells[field].Value.ToString();
fields.TryGetValue(field, out toSet);
//this value is sometimes not visable on finished form
toSet.SetValue(value);
}
break;
default:
break;
}
}
//form.RemoveXfaForm();
//pdf.GetCatalog().Remove(PdfName.Perms);
//form.FlattenFields();
pdf.Close();
}
</code>
Это решение заполняет формы, но есть некоторыеочень большие проблемы, которые я не смог решить:
- Изменения не всегда фиксируются в форме (например, .backgroundcolor) / будут отображаться пустыми, пока пользователь не нажмет на поле формы.
- Значение будет напечатано, но при этом будут сформированы такие изменения, как .backgroundcolor.
- Эти формы имеют избыточные поля, и в AcroForm, похоже, есть проблемы с именами родительских / дочерних полей от Adobe.(Например, он будет переименовывать любые подобные поля)
- Не существует API для C # для Itext7, и я не смог решить эти проблемы.
Буду признателен за любую помощь, статьи или понимание, я знаю, что «открытые» вопросы здесь не сильно помогают, но нужно было попробовать.Спасибо.