Attached a project to demonstrate some issues we're seeing that need resolving in order to use the component.
1. When using a font like Tahoma on a form field, the value no longer displays or contains garbled text.
2. Input file is 24KB, output is 2MB!
3. Rotated field lose their rotation after being flattened.
4. Simulate merging with other files, 100 times the file is now 150MB! It's as though it's not re-using the fonts, but keeps adding the same ones.
5. when merging, but not flattening, the form fields are all lost on pages after page 1.
using
System;
using
System.Collections.Generic;
using
System.IO;
using
System.Linq;
using
Telerik.Windows.Documents.Fixed.FormatProviders.Pdf;
using
Telerik.Windows.Documents.Fixed.FormatProviders.Pdf.Streaming;
using
Telerik.Windows.Documents.Fixed.Model;
using
Telerik.Windows.Documents.Fixed.Model.Annotations;
using
Telerik.Windows.Documents.Fixed.Model.Editing;
using
Telerik.Windows.Documents.Fixed.Model.InteractiveForms;
using
Telerik.Windows.Documents.Fixed.Model.Resources;
namespace
FlattenFormFieldsDemo
{
class
Program
{
static
void
Main(
string
[] args)
{
PdfFormatProvider provider =
new
PdfFormatProvider();
RadFixedDocument document = provider.Import(File.ReadAllBytes(
"InteractiveForms.pdf"
));
foreach
(RadFixedPage page
in
document.Pages)
{
foreach
(Annotation annotation
in
page.Annotations)
{
if
(annotation.Type == AnnotationType.Widget)
{
Widget widget = (Widget) annotation;
if
(widget.Field
is
TextBoxField field)
{
field.Value =
"John Doe"
;
}
}
}
}
FlattenFormFields(document);
string
resultFile =
"Flattened.pdf"
;
if
(File.Exists(resultFile))
{
File.Delete(resultFile);
}
File.WriteAllBytes(resultFile, provider.Export(document));
MergeMultipleFiles(resultFile);
}
public
static
void
MergeMultipleFiles(
string
filename)
{
using
(PdfStreamWriter fileWriter =
new
PdfStreamWriter(File.OpenWrite(
"MergedFlattened.pdf"
)))
{
// Iterate through the files you would like to merge
for
(
int
i = 0; i< 100; i++)
{
// Open each of the files
using
(PdfFileSource fileToMerge =
new
PdfFileSource(File.OpenRead(filename)))
{
// Iterate through the pages of the current document
foreach
(PdfPageSource pageToMerge
in
fileToMerge.Pages)
{
// Append the current page to the fileWriter, which holds the stream of the result file
fileWriter.WritePage(pageToMerge);
}
}
}
}
}
public
static
void
FlattenFormFields(RadFixedDocument document)
{
foreach
(RadFixedPage page
in
document.Pages)
{
List<Widget> widgetsToRemove =
new
List<Widget>();
FixedContentEditor pageEditor =
new
FixedContentEditor(page);
foreach
(Annotation annotation
in
page.Annotations)
{
if
(annotation.Type == AnnotationType.Widget)
{
Widget widget = (Widget)annotation;
FlattenWidgetAppearance(pageEditor, widget);
widgetsToRemove.Add(widget);
}
}
foreach
(Widget widget
in
widgetsToRemove)
{
page.Annotations.Remove(widget);
}
}
foreach
(FormField field
in
document.AcroForm.FormFields.ToArray())
{
document.AcroForm.FormFields.Remove(field);
}
}
private
static
void
FlattenWidgetAppearance(FixedContentEditor pageEditor, Widget widget)
{
FormSource widgetAppearance = GetWidgetNormalAppearance(widget);
if
(widgetAppearance ==
null
)
return
;
pageEditor.Position.Translate(widget.Rect.Left, widget.Rect.Top);
pageEditor.DrawForm(widgetAppearance, widget.Rect.Width, widget.Rect.Height);
}
private
static
FormSource GetWidgetNormalAppearance(Widget widget)
{
FormSource widgetAppearance;
switch
(widget.WidgetContentType)
{
case
WidgetContentType.PushButtonContent:
widgetAppearance = ((PushButtonWidget)widget).Content.NormalContentSource;
break
;
case
WidgetContentType.SignatureContent:
widgetAppearance = ((SignatureWidget)widget).Content.NormalContentSource;
break
;
case
WidgetContentType.VariableContent:
widgetAppearance = ((VariableContentWidget)widget).Content.NormalContentSource;
break
;
case
WidgetContentType.TwoStatesContent:
TwoStatesButtonWidget twoStatesWidget = (TwoStatesButtonWidget)widget;
widgetAppearance = GetTwoStatesWidgetNormalAppearance(twoStatesWidget);
break
;
default
:
throw
new
NotSupportedException(
string
.Format(
"Not supported widget content type {0}"
, widget.WidgetContentType));
}
return
widgetAppearance;
}
private
static
FormSource GetTwoStatesWidgetNormalAppearance(TwoStatesButtonWidget twoStatesWidget)
{
FormField field = twoStatesWidget.Field;
bool
isOnState;
switch
(field.FieldType)
{
case
FormFieldType.CheckBox:
CheckBoxField checkBox = (CheckBoxField) field;
isOnState = checkBox.IsChecked;
break
;
case
FormFieldType.RadioButton:
RadioButtonField radio = (RadioButtonField) field;
RadioButtonWidget radioWidget = (RadioButtonWidget) twoStatesWidget;
if
(radio.ShouldUpdateRadiosInUnison)
{
isOnState = radio.Value !=
null
&& radio.Value.Value.Equals(radioWidget.Option.Value);
}
else
{
isOnState = radio.Value == radioWidget.Option;
}
break
;
default
:
throw
new
NotSupportedException(
string
.Format(
"Not supported field type {0} for TwoStateButtonWidget"
, field.FieldType));
}
FormSource widgetAppearance = (isOnState ? twoStatesWidget.OnStateContent : twoStatesWidget.OffStateContent).NormalContentSource;
return
widgetAppearance;
}
}
}