Toolbox add-on code samples
Start using the Toolbox add-on library with code samples. Integrate low-level access to the content of PDF files into your application in Java, .NET, and C.
info
Select a code sample in a specific language and download it. The code samples illustrate how to integrate the SDK into your projects for specific use cases. Each code sample includes a README file that gives instructions on how to run the code sample to process one or multiple files.
tip
Do you miss a specific sample and want us to include it here? Let us know through the Contact page, and we’ll add it to our sample backlog.
Annotations
Add annotations to PDF
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
{
// Create output document
using Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite);
using Document outDoc = Document.Create(outStream, inDoc.Conformance, null);
// Copy document-wide data
CopyDocumentData(inDoc, outDoc);
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Copy first page and add annotations
Page outPage = CopyAndAddAnnotations(outDoc, inDoc.Pages[0], copyOptions);
// Add the page to the output document's page list
outDoc.Pages.Add(outPage);
// Copy the remaining pages and add to the output document's page list
PageList inPages = inDoc.Pages.GetRange(1, inDoc.Pages.Count - 1);
PageList outPages = PageList.Copy(outDoc, inPages, copyOptions);
outDoc.Pages.AddRange(outPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// Copy document-wide data
// Output intent
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// Metadata
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// Viewer settings
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static Page CopyAndAddAnnotations(Document outDoc, Page inPage, PageCopyOptions copyOptions)
{
// Copy page to output document
Page outPage = Page.Copy(outDoc, inPage, copyOptions);
// Make a RGB color space
ColorSpace rgb = ColorSpace.CreateProcessColorSpace(outDoc, ProcessColorSpaceType.Rgb);
// Get the page size for positioning annotations
Size pageSize = outPage.Size;
// Get the output page's list of annotations for adding annotations
AnnotationList annotations = outPage.Annotations;
// Create a sticky note and add to output page's annotations
Paint green = Paint.Create(outDoc, rgb, new double[] { 0, 1, 0 }, null);
Point stickyNoteTopLeft = new Point() { X = 10, Y = pageSize.Height - 10 };
StickyNote stickyNote = StickyNote.Create(outDoc, stickyNoteTopLeft, "Hello world!", green);
annotations.Add(stickyNote);
// Create an ellipse and add to output page's annotations
Paint blue = Paint.Create(outDoc, rgb, new double[] { 0, 0, 1 }, null);
Paint yellow = Paint.Create(outDoc, rgb, new double[] { 1, 1, 0 }, null);
Rectangle ellipseBox = new Rectangle() { Left = 10, Bottom = pageSize.Height - 60, Right = 70, Top = pageSize.Height - 20 };
EllipseAnnotation ellipse = EllipseAnnotation.Create(outDoc, ellipseBox, new Stroke(blue, 1.5), yellow);
annotations.Add(ellipse);
// Create a free text and add to output page's annotations
Paint yellowTransp = Paint.Create(outDoc, rgb, new double[] { 1, 1, 0 }, new Transparency(0.5));
Rectangle freeTextBox = new Rectangle() { Left = 10, Bottom = pageSize.Height - 170, Right = 120, Top = pageSize.Height - 70 };
FreeText freeText = FreeText.Create(outDoc, freeTextBox, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", yellowTransp);
annotations.Add(freeText);
// A highlight and a web-link to be fitted on existing page content elements
Highlight highlight = null;
WebLink webLink = null;
// Extract content elements from the input page
ContentExtractor extractor = new ContentExtractor(inPage.Content);
foreach (ContentElement element in extractor)
{
// Take the first text element
if (highlight == null && element is TextElement textElement)
{
// Get the quadrilaterals of this text element
QuadrilateralList quadrilaterals = new QuadrilateralList();
foreach (TextFragment fragment in textElement.Text)
quadrilaterals.Add(fragment.Transform.TransformRectangle(fragment.BoundingBox));
// Create a highlight and add to output page's annotations
highlight = Highlight.CreateFromQuadrilaterals(outDoc, quadrilaterals, yellow);
annotations.Add(highlight);
}
// Take the first image element
if (webLink == null && element is ImageElement)
{
// Get the quadrilateral of this image
QuadrilateralList quadrilaterals = new QuadrilateralList();
quadrilaterals.Add(element.Transform.TransformRectangle(element.BoundingBox));
// Create a web-link and add to the output page's links
webLink = WebLink.CreateFromQuadrilaterals(outDoc, quadrilaterals, "https://www.pdf-tools.com");
Paint red = Paint.Create(outDoc, rgb, new double[] { 1, 0, 0 }, null);
webLink.BorderStyle = new Stroke(red, 1.5);
outPage.Links.Add(webLink);
}
// Exit loop if highlight and webLink have been created
if (highlight != null && webLink != null)
break;
}
// return the finished page
return outPage;
}
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null);
// Create file stream
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (// Create output document
Document outDoc = Document.create(outStream, inDoc.getConformance(), null)) {
// Copy document-wide data
copyDocumentData(inDoc, outDoc);
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Copy first page and add annotations
Page outPage = copyAndAddAnnotations(outDoc, inDoc.getPages().get(0), copyOptions);
// Add the page to the output document's page list
outDoc.getPages().add(outPage);
// Copy the remaining pages and add to the output document's page list
PageList inPages = inDoc.getPages().subList(1, inDoc.getPages().size());
PageList outPages = PageList.copy(outDoc, inPages, copyOptions);
outDoc.getPages().addAll(outPages);
}
}
private static void copyDocumentData(Document inDoc, Document outDoc) throws ToolboxException, IOException {
// Copy document-wide data
// Output intent
if (inDoc.getOutputIntent() != null)
outDoc.setOutputIntent(IccBasedColorSpace.copy(outDoc, inDoc.getOutputIntent()));
// Metadata
outDoc.setMetadata(Metadata.copy(outDoc, inDoc.getMetadata()));
// Viewer settings
outDoc.setViewerSettings(ViewerSettings.copy(outDoc, inDoc.getViewerSettings()));
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.getAssociatedFiles();
for (FileReference inFileRef : inDoc.getAssociatedFiles())
outAssociatedFiles.add(FileReference.copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.getPlainEmbeddedFiles();
for (FileReference inFileRef : inDoc.getPlainEmbeddedFiles())
outEmbeddedFiles.add(FileReference.copy(outDoc, inFileRef));
}
private static Page copyAndAddAnnotations(Document outDoc, Page inPage, PageCopyOptions copyOptions) throws ConformanceException, CorruptException, IOException, UnsupportedFeatureException {
// Copy page to output document
Page outPage = Page.copy(outDoc, inPage, copyOptions);
// Make a RGB color space
ColorSpace rgb = ColorSpace.createProcessColorSpace(outDoc, ProcessColorSpaceType.RGB);
// Get the page size for positioning annotations
Size pageSize = outPage.getSize();
// Get the output page's list of annotations for adding annotations
AnnotationList annotations = outPage.getAnnotations();
// Create a sticky note and add to output page's annotations
Paint green = Paint.create(outDoc, rgb, new double[] { 0, 1, 0 }, null);
Point stickyNoteTopLeft = new Point(10, pageSize.height - 10 );
StickyNote stickyNote = StickyNote.create(outDoc, stickyNoteTopLeft, "Hello world!", green);
annotations.add(stickyNote);
// Create an ellipse and add to output page's annotations
Paint blue = Paint.create(outDoc, rgb, new double[] { 0, 0, 1 }, null);
Paint yellow = Paint.create(outDoc, rgb, new double[] { 1, 1, 0 }, null);
Rectangle ellipseBox = new Rectangle(10, pageSize.height - 60, 70, pageSize.height - 20);
EllipseAnnotation ellipse = EllipseAnnotation.create(outDoc, ellipseBox, new Stroke(blue, 1.5), yellow);
annotations.add(ellipse);
// Create a free text and add to output page's annotations
Paint yellowTransp = Paint.create(outDoc, rgb, new double[] { 1, 1, 0 }, new Transparency(0.5));
Rectangle freeTextBox = new Rectangle(10, pageSize.height - 170, 120, pageSize.height - 70);
FreeText freeText = FreeText.create(outDoc, freeTextBox, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", yellowTransp);
annotations.add(freeText);
// A highlight and a web-link to be fitted on existing page content elements
Highlight highlight = null;
WebLink webLink = null;
// Extract content elements from the input page
ContentExtractor extractor = new ContentExtractor(inPage.getContent());
for (ContentElement element : extractor) {
// Take the first text element
if (highlight == null && element instanceof TextElement) {
TextElement textElement = (TextElement)element;
// Get the quadrilaterals of this text element
QuadrilateralList quadrilaterals = new QuadrilateralList();
for (TextFragment fragment : textElement.getText())
quadrilaterals.add(fragment.getTransform().transformRectangle(fragment.getBoundingBox()));
// Create a highlight and add to output page's annotations
highlight = Highlight.createFromQuadrilaterals(outDoc, quadrilaterals, yellow);
annotations.add(highlight);
}
// Take the first image element
if (webLink == null && element instanceof ImageElement) {
// Get the quadrilateral of this image
QuadrilateralList quadrilaterals = new QuadrilateralList();
quadrilaterals.add(element.getTransform().transformRectangle(element.getBoundingBox()));
// Create a web-link and add to the output page's links
webLink = WebLink.createFromQuadrilaterals(outDoc, quadrilaterals, "https://www.pdf-tools.com");
Paint red = Paint.create(outDoc, rgb, new double[] { 1, 0, 0 }, null);
webLink.setBorderStyle(new Stroke(red, 1.5));
outPage.getLinks().add(webLink);
}
// Exit loop if highlight and webLink have been created
if (highlight != null && webLink != null)
break;
}
// return the finished page
return outPage;
}
def copy_document_data(in_doc: Document, out_doc: Document):
# Copy document-wide data
# Output intent
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# Metadata
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# Viewer settings
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# Associated files (for PDF/A-3 and PDF 2.0 only)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# Plain embedded files
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def copy_and_add_annotations(out_doc: Document, in_page: Page, copy_options: PageCopyOptions):
# Copy page to output document
out_page = Page.copy(out_doc, in_page, copy_options)
# Make a RGB color space
rgb = ColorSpace.create_process_color_space(out_doc, ProcessColorSpaceType.RGB)
# Get the page size for positioning annotations
page_size = out_page.size
# Get the output page's list of annotations for adding annotations
annotations = out_page.annotations
# Create a sticky note and add to output page's annotations
green = Paint.create(out_doc, rgb, [0.0, 1.0, 0.0], None)
sticky_note_top_left = Point(x=10.0, y=page_size.height - 10.0)
sticky_note = StickyNote.create(out_doc, sticky_note_top_left, "Hello world!", green)
annotations.append(sticky_note)
# Create an ellipse and add to output page's annotations
blue = Paint.create(out_doc, rgb, [0.0, 0.0, 1.0], None)
yellow = Paint.create(out_doc, rgb, [1.0, 1.0, 0.0], None)
ellipse_box = Rectangle(left=10.0, bottom=page_size.height - 60.0, right=70.0, top=page_size.height - 20.0)
ellipse = EllipseAnnotation.create(out_doc, ellipse_box, Stroke(blue, 1.5), yellow)
annotations.append(ellipse)
# Create a free text and add to output page's annotations
yellow_transp = Paint.create(out_doc, rgb, [1.0, 1.0, 0.0], Transparency(0.5))
free_text_box = Rectangle(left=10.0, bottom=page_size.height - 170.0, right=120.0, top=page_size.height - 70.0)
free_text = FreeText.create(out_doc, free_text_box, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", yellow_transp)
annotations.append(free_text)
# A highlight and a web-link to be fitted on existing page content elements
highlight = None
web_link = None
# Extract content elements from the input page
extractor = ContentExtractor(in_page.content)
for element in extractor:
# Take the first text element
if highlight is None and isinstance(element, TextElement):
# Get the quadrilaterals of this text element
quadrilaterals = QuadrilateralList()
for fragment in element.text:
quadrilaterals.append(fragment.transform.transform_rectangle(fragment.bounding_box))
# Create a highlight and add to output page's annotations
highlight = Highlight.create_from_quadrilaterals(out_doc, quadrilaterals, yellow)
annotations.append(highlight)
# Take the first image element
if web_link is None and isinstance(element, ImageElement):
# Get the quadrilateral of this image
quadrilaterals = QuadrilateralList()
quadrilaterals.append(element.transform.transform_rectangle(element.bounding_box))
# Create a web-link and add to the output page's links
web_link = WebLink.create_from_quadrilaterals(out_doc, quadrilaterals, "https://www.pdf-tools.com")
red = Paint.create(out_doc, rgb, [1.0, 0.0, 0.0], None)
web_link.border_style = Stroke(red, 1.5)
out_page.links.append(web_link)
# Exit loop if highlight and web-link have been created
if highlight is not None and web_link is not None:
break
return out_page
# Open input document
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as in_doc:
# Create output document
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, in_doc.conformance, None) as out_doc:
# Copy document-wide data
copy_document_data(in_doc, out_doc)
# Define page copy options
copy_options = PageCopyOptions()
# Copy first page and add annotations
out_page = copy_and_add_annotations(out_doc, in_doc.pages[0], copy_options)
# Add the page to the output document's page list
out_doc.pages.append(out_page)
# Copy the remaining pages and add to the output document's page list
in_pages = in_doc.pages[1:]
out_pages = PageList.copy(out_doc, in_pages, copy_options)
out_doc.pages.extend(out_pages)
Update annotations to PDF
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Stream inFdfStream = new FileStream(inFdfPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.OpenWithFdf(inStream, inFdfStream, null))
{
// Create output document
using var outStream = new FileStream(outPath, FileMode.Create, FileAccess.Write);
using var outFdfStream = new FileStream(outFdfPath, FileMode.Create, FileAccess.Write);
using var outDoc = Document.CreateWithFdf(outStream, outFdfStream, inDoc.Conformance, null);
// Copy document-wide data
CopyDocumentData(inDoc, outDoc);
FilterAnnotations(inDoc, outDoc);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// Copy document-wide data
// Output intent
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// Metadata
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// Viewer settings
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void FilterAnnotations(Document inDoc, Document outDoc)
{
// Define page copy options
var copyOptions = new PageCopyOptions
{
// Remove all annotations: we will add the filtered ones later
Annotations = CopyStrategy.Remove
};
foreach (var inPage in inDoc.Pages)
{
// Copy page to output document
var outPage = Page.Copy(outDoc, inPage, copyOptions);
// Hold the annotations from the input document
var inAnnotations = inPage.Annotations;
// Selectively copy annotations (excluding EllipseAnnotations - like Circle)
foreach (var inAnnotation in inAnnotations)
{
// Skip if the annotation is an EllipseAnnotation
if (inAnnotation is EllipseAnnotation)
{
continue;
}
outPage.Annotations.Add(Annotation.Copy(outDoc, inAnnotation));
}
// Add the page to the output document
outDoc.Pages.Add(outPage);
}
}
def copy_document_data(in_doc: Document, out_doc: Document):
# Copy document-wide data
# Output intent
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# Metadata
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# Viewer settings
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# Associated files (for PDF/A-3 and PDF 2.0 only)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# Plain embedded files
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def filter_annotations(in_doc: Document, out_doc: Document):
"""Filter annotations and remove 'Ellipse' annotations."""
# Define page copy options
copy_options = PageCopyOptions()
# Remove all annotations: we will add the filtered ones later
copy_options.annotations = CopyStrategy.REMOVE
for in_page in in_doc.pages:
# Copy page to the output document
out_page = Page.copy(out_doc, in_page, copy_options)
# Hold the annotations from the input document
in_annotations = in_page.annotations
# Selectively copy annotations (excluding EllipseAnnotations - like Circle)
for in_annotation in in_annotations:
if not isinstance(in_annotation, EllipseAnnotation):
out_page.annotations.append(Annotation.copy(out_doc, in_annotation))
# Add the page to the output document
out_doc.pages.append(out_page)
# Open input PDF and FDF files
with io.FileIO(input_file_path, "rb") as in_stream:
with io.FileIO(input_fdf_path, "rb") as in_fdf_stream:
with Document.open_with_fdf(in_stream, in_fdf_stream, None) as in_doc:
# Create output PDF and FDF files
with io.FileIO(output_file_path, "wb+") as out_stream:
with io.FileIO(output_fdf_path, "wb+") as out_fdf_stream:
with Document.create_with_fdf(out_stream, out_fdf_stream, in_doc.conformance, None) as out_doc:
# Copy document-wide data
copy_document_data(in_doc, out_doc)
# Filter and process annotations
filter_annotations(in_doc, out_doc)
Annotations and form fields
Add form field
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// Create output document
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// Copy document-wide data
CopyDocumentData(inDoc, outDoc);
// Copy all form fields
FieldNodeMap inFormFields = inDoc.FormFields;
FieldNodeMap outFormFields = outDoc.FormFields;
foreach (KeyValuePair<string, FieldNode> inPair in inFormFields)
{
FieldNode outFormFieldNode = FieldNode.Copy(outDoc, inPair.Value);
outFormFields.Add(inPair.Key, outFormFieldNode);
}
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions
{
FormFields = FormFieldCopyStrategy.CopyAndUpdateWidgets,
UnsignedSignatures = CopyStrategy.Remove,
};
// Copy first page
Page inPage = inDoc.Pages[0];
Page outPage = Page.Copy(outDoc, inPage, copyOptions);
// Add different types of form fields to the output page
AddCheckBox(outDoc, "Check Box ID", true, outPage, new Rectangle { Left = 50, Bottom = 300, Right = 70, Top = 320 });
AddComboBox(outDoc, "Combo Box ID", new string[] { "item 1", "item 2" }, "item 1", outPage, new Rectangle { Left = 50, Bottom = 260, Right = 210, Top = 280 });
AddListBox(outDoc, "List Box ID", new string[] { "item 1", "item 2", "item 3" }, new string[] { "item 1", "item 3" }, outPage, new Rectangle { Left = 50, Bottom = 160, Right = 210, Top = 240 });
AddRadioButtonGroup(outDoc, "Radio Button ID", new string[] { "A", "B", "C" }, 0, outPage, new Rectangle { Left = 50, Bottom = 120, Right = 210, Top = 140 });
AddGeneralTextField(outDoc, "Text ID", "Text", outPage, new Rectangle { Left = 50, Bottom = 80, Right = 210, Top = 100 });
// Add page to output document
outDoc.Pages.Add(outPage);
// Copy remaining pages and append to output document
PageList inPageRange = inDoc.Pages.GetRange(1, inDoc.Pages.Count - 1);
PageList copiedPages = PageList.Copy(outDoc, inPageRange, copyOptions);
outDoc.Pages.AddRange(copiedPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// Copy document-wide data
// Output intent
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// Metadata
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// Viewer settings
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void AddCheckBox(Document doc, string id, bool isChecked, Page page, Rectangle rectangle)
{
// Create a check box
CheckBox checkBox = CheckBox.Create(doc);
// Add the check box to the document
doc.FormFields.Add(id, checkBox);
// Set the check box's state
checkBox.Checked = isChecked;
// Create a widget and add it to the page's widgets
page.Widgets.Add(checkBox.AddNewWidget(rectangle));
}
private static void AddComboBox(Document doc, string id, string[] itemNames, string value, Page page, Rectangle rectangle)
{
// Create a combo box
ComboBox comboBox = ComboBox.Create(doc);
// Add the combo box to the document
doc.FormFields.Add(id, comboBox);
// Loop over all given item names
foreach (string itemName in itemNames)
{
// Create a new choice item
ChoiceItem item = comboBox.AddNewItem(itemName);
// Check whether this is the chosen item name
if (value.Equals(itemName))
comboBox.ChosenItem = item;
}
if (comboBox.ChosenItem == null && !string.IsNullOrEmpty(value))
{
// If no item has been chosen then assume we want to set the editable item
comboBox.CanEdit = true;
comboBox.EditableItemName = value;
}
// Create a widget and add it to the page's widgets
page.Widgets.Add(comboBox.AddNewWidget(rectangle));
}
private static void AddListBox(Document doc, string id, string[] itemNames, string[] chosenNames, Page page, Rectangle rectangle)
{
// Create a list box
ListBox listBox = ListBox.Create(doc);
// Add the list box to the document
doc.FormFields.Add(id, listBox);
// Allow multiple selections
listBox.AllowMultiSelect = true;
ChoiceItemList chosenItems = listBox.ChosenItems;
// Loop over all given item names
foreach (string itemName in itemNames)
{
// Create a new choice item
ChoiceItem item = listBox.AddNewItem(itemName);
// Check whether to add to the chosen items
if (chosenNames.Contains(itemName))
chosenItems.Add(item);
}
// Create a widget and add it to the page's widgets
page.Widgets.Add(listBox.AddNewWidget(rectangle));
}
private static void AddRadioButtonGroup(Document doc, string id, string[] buttonNames, int chosen, Page page, Rectangle rectangle)
{
// Create a radio button group
RadioButtonGroup group = RadioButtonGroup.Create(doc);
// Get the page's widgets
WidgetList widgets = page.Widgets;
// Add the radio button group to the document
doc.FormFields.Add(id, group);
// We partition the given rectangle horizontally into sub-rectangles, one for each button
// Compute the width of the sub-rectangles
double buttonWidth = (rectangle.Right - rectangle.Left) / buttonNames.Length;
// Loop over all button names
for (int i = 0; i < buttonNames.Length; i++)
{
// Compute the sub-rectangle for this button
Rectangle buttonRectangle = new Rectangle()
{
Left = rectangle.Left + i * buttonWidth,
Bottom = rectangle.Bottom,
Right = rectangle.Left + (i + 1) * buttonWidth,
Top = rectangle.Top
};
// Create the button and an associated widget
RadioButton button = group.AddNewButton(buttonNames[i]);
Widget widget = button.AddNewWidget(buttonRectangle);
// Check if this is the chosen button
if (i == chosen)
group.ChosenButton = button;
// Add the widget to the page's widgets
widgets.Add(widget);
}
}
private static void AddGeneralTextField(Document doc, string id, string value, Page page, Rectangle rectangle)
{
// Create a general text field
GeneralTextField field = GeneralTextField.Create(doc);
// Add the field to the document
doc.FormFields.Add(id, field);
// Set the text value
field.Text = value;
// Create a widget and add it to the page's widgets
page.Widgets.Add(field.AddNewWidget(rectangle));
}
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null);
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (// Create output document
Document outDoc = Document.create(outStream, inDoc.getConformance(), null)) {
// Copy document-wide data
copyDocumentData(inDoc, outDoc);
// Copy all form fields
FieldNodeMap inFormFields = inDoc.getFormFields();
FieldNodeMap outFormFields = outDoc.getFormFields();
for (Entry<String, FieldNode> entry : inFormFields.entrySet())
outFormFields.put(entry.getKey(), FieldNode.copy(outDoc, entry.getValue()));
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
copyOptions.setFormFields(FormFieldCopyStrategy.COPY_AND_UPDATE_WIDGETS);
copyOptions.setUnsignedSignatures(CopyStrategy.REMOVE);
// Copy first page
Page inPage = inDoc.getPages().get(0);
Page outPage = Page.copy(outDoc, inPage, copyOptions);
// Add different types of form fields to the output page
addCheckBox(outDoc, "Check Box ID", true, outPage, new Rectangle(50, 300, 70, 320));
addComboBox(outDoc, "Combo Box ID", new String[] { "item 1", "item 2" }, "item 1", outPage,
new Rectangle(50, 260, 210, 280));
addListBox(outDoc, "List Box ID", new String[] { "item 1", "item 2", "item 3" },
new String[] { "item 1", "item 3" }, outPage, new Rectangle(50, 160, 210, 240));
addRadioButtonGroup(outDoc, "Radio Button ID", new String[] { "A", "B", "C" }, 0, outPage,
new Rectangle(50, 120, 210, 140));
addGeneralTextField(outDoc, "Text ID", "Text", outPage, new Rectangle(50, 80, 210, 100));
// Add page to output document
outDoc.getPages().add(outPage);
// Copy remaining pages and append to output document
PageList inPageRange = inDoc.getPages().subList(1, inDoc.getPages().size());
PageList copiedPages = PageList.copy(outDoc, inPageRange, copyOptions);
outDoc.getPages().addAll(copiedPages);
}
}
private static void copyDocumentData(Document inDoc, Document outDoc) throws ToolboxException, IOException {
// Copy document-wide data
// Output intent
if (inDoc.getOutputIntent() != null)
outDoc.setOutputIntent(IccBasedColorSpace.copy(outDoc, inDoc.getOutputIntent()));
// Metadata
outDoc.setMetadata(Metadata.copy(outDoc, inDoc.getMetadata()));
// Viewer settings
outDoc.setViewerSettings(ViewerSettings.copy(outDoc, inDoc.getViewerSettings()));
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.getAssociatedFiles();
for (FileReference inFileRef : inDoc.getAssociatedFiles())
outAssociatedFiles.add(FileReference.copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.getPlainEmbeddedFiles();
for (FileReference inFileRef : inDoc.getPlainEmbeddedFiles())
outEmbeddedFiles.add(FileReference.copy(outDoc, inFileRef));
}
private static void addCheckBox(Document doc, String id, boolean isChecked, Page page, Rectangle rectangle)
throws ToolboxException {
// Create a check box
CheckBox checkBox = CheckBox.create(doc);
// Add the check box to the document
doc.getFormFields().put(id, checkBox);
// Set the check box's state
checkBox.setChecked(isChecked);
// Create a widget and add it to the page's widgets
page.getWidgets().add(checkBox.addNewWidget(rectangle));
}
private static void addListBox(Document doc, String id, String[] itemNames, String[] chosenNames, Page page,
Rectangle rectangle) throws ToolboxException {
List<String> chosenNamesList = Arrays.asList(chosenNames);
// Create a list box
ListBox listBox = ListBox.create(doc);
// Add the list box to the document
doc.getFormFields().put(id, listBox);
// Allow multiple selections
listBox.setAllowMultiSelect(true);
// Get the list of chosen items
ChoiceItemList chosenItems = listBox.getChosenItems();
// Loop over all given item names
for (String itemName : itemNames) {
ChoiceItem item = listBox.addNewItem(itemName);
// Check whether to add to the chosen items
if (chosenNamesList.contains(itemName))
chosenItems.add(item);
}
// Create a widget and add it to the page's widgets
page.getWidgets().add(listBox.addNewWidget(rectangle));
}
private static void addComboBox(Document doc, String id, String[] itemNames, String value, Page page,
Rectangle rectangle) throws ToolboxException {
// Create a combo box
ComboBox comboBox = ComboBox.create(doc);
// Add the combo box to the document
doc.getFormFields().put(id, comboBox);
// Loop over all given item names
for (String itemName : itemNames) {
ChoiceItem item = comboBox.addNewItem(itemName);
// Check whether to add to the chosen items
if (value.equals(itemName))
comboBox.setChosenItem(item);
}
if (comboBox.getChosenItem() == null && !(value == null || value.isEmpty())) {
// If no item has been chosen then assume we want to set the editable item
comboBox.setCanEdit(true);
comboBox.setEditableItemName(value);
}
// Create a widget and add it to the page's widgets
page.getWidgets().add(comboBox.addNewWidget(rectangle));
}
private static void addRadioButtonGroup(Document doc, String id, String[] buttonNames, int chosen, Page page,
Rectangle rectangle) throws ToolboxException {
// Create a radio button group
RadioButtonGroup group = RadioButtonGroup.create(doc);
// Add the radio button group to the document
doc.getFormFields().put(id, group);
// We partition the given rectangle horizontally into sub-rectangles, one for
// each button
// Compute the width of the sub-rectangles
double buttonWidth = (rectangle.right - rectangle.left) / buttonNames.length;
// Get the page's widgets
WidgetList widgets = page.getWidgets();
// Loop over all button names
for (int i = 0; i < buttonNames.length; i++) {
// Compute the sub-rectangle for this button
Rectangle buttonRectangle = new Rectangle(rectangle.left + i * buttonWidth, rectangle.bottom,
rectangle.left + (i + 1) * buttonWidth, rectangle.top);
// Create the button and an associated widget
RadioButton button = group.addNewButton(buttonNames[i]);
Widget widget = button.addNewWidget(buttonRectangle);
// Check if this is the chosen button
if (i == chosen)
group.setChosenButton(button);
// Add the widget to the page's widgets
widgets.add(widget);
}
}
private static void addGeneralTextField(Document doc, String id, String value, Page page, Rectangle rectangle)
throws ToolboxException {
// Create a general text field
GeneralTextField field = GeneralTextField.create(doc);
// Add the field to the document
doc.getFormFields().put(id, field);
// Set the check box's state
field.setText(value);
// Create a widget and add it to the page's widgets
page.getWidgets().add(field.addNewWidget(rectangle));
}
def copy_document_data(in_doc: Document, out_doc: Document):
# Copy document-wide data
# Output intent
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# Metadata
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# Viewer settings
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# Associated files (for PDF/A-3 and PDF 2.0 only)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# Plain embedded files
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def add_check_box(doc: Document, field_id: str, is_checked: bool, page: Page, rectangle: Rectangle):
# Create a check box
check_box = CheckBox.create(doc)
# Add the check box to the document
doc.form_fields[field_id] = check_box
# Set the check box's state
check_box.checked = is_checked
# Create a widget and add it to the page's widgets
page.widgets.append(check_box.add_new_widget(rectangle))
def add_combo_box(doc: Document, field_id: str, item_names: list[str], value: str, page: Page, rectangle: Rectangle):
# Create a combo box
combo_box = ComboBox.create(doc)
# Add the combo box to the document
doc.form_fields[field_id] = combo_box
# Loop over all given item names
for item_name in item_names:
# Create a new choice item
item = combo_box.add_new_item(item_name)
# Check whether this is the chosen item name
if value == item_name:
combo_box.chosen_item = item
if combo_box.chosen_item is None and value:
# If no item has been chosen then assume we want to set the editable item
combo_box.can_edit = True
combo_box.editable_item_name = value
# Create a widget and add it to the page's widgets
page.widgets.append(combo_box.add_new_widget(rectangle))
def add_list_box(doc: Document, field_id: str, item_names: list[str], chosen_names: list[str], page: Page, rectangle: Rectangle):
# Create a list box
list_box = ListBox.create(doc)
# Add the list box to the document
doc.form_fields[field_id] = list_box
# Allow multiple selections
list_box.allow_multi_select = True
chosen_items = list_box.chosen_items
# Loop over all given item names
for item_name in item_names:
# Create a new choice item
item = list_box.add_new_item(item_name)
# Check whether to add to the chosen items
if item_name in chosen_names:
chosen_items.append(item)
# Create a widget and add it to the page's widgets
page.widgets.append(list_box.add_new_widget(rectangle))
def add_radio_button_group(doc: Document, field_id: str, button_names: list[str], chosen: int, page: Page, rectangle: Rectangle):
# Create a radio button group
group = RadioButtonGroup.create(doc)
# Get the page's widgets
widgets = page.widgets
# Add the radio button group to the document
doc.form_fields[field_id] = group
# We partition the given rectangle horizontally into sub-rectangles, one for each button
# Compute the width of the sub-rectangles
button_width = (rectangle.right - rectangle.left) / len(button_names)
# Loop over all button names
for i, button_name in enumerate(button_names):
# Compute the sub-rectangle for this button
button_rectangle = Rectangle(
left = rectangle.left + i * button_width,
bottom = rectangle.bottom,
right = rectangle.left + (i + 1) * button_width,
top = rectangle.top
)
# Create the button and associated widget
button = group.add_new_button(button_name)
widget = button.add_new_widget(button_rectangle)
# Check if this is the chosen button
if i == chosen:
group.chosen_button = button
# Add the widget to the page's widgets
widgets.append(widget)
def add_general_text_field(doc: Document, field_id: str, value: str, page: Page, rectangle: Rectangle):
# Create a general text field
text_field = GeneralTextField.create(doc)
# Add the field to the document
doc.form_fields[field_id] = text_field
# Set the text value
text_field.text = value
# Create a widget and add it to the page's widgets
page.widgets.append(text_field.add_new_widget(rectangle))
# Open input document
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as in_doc:
# Create output document
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, in_doc.conformance, None) as out_doc:
# Copy document-wide data
copy_document_data(in_doc, out_doc)
# Copy all form fields
in_form_fields = in_doc.form_fields
out_form_fields = out_doc.form_fields
for in_pair_key, in_pair_node in in_form_fields.items():
out_form_field_node = FieldNode.copy(out_doc, in_pair_node)
out_form_fields[in_pair_key] = out_form_field_node
# Define page copy options
copy_options = PageCopyOptions()
copy_options.form_fields = FormFieldCopyStrategy.COPY_AND_UPDATE_WIDGETS
copy_options.unsigned_signatures = CopyStrategy.REMOVE
# Copy first page
out_page = Page.copy(out_doc, in_doc.pages[0], copy_options)
# Add different types of form fields to the output page
add_check_box(out_doc, "Check Box ID", True, out_page, Rectangle(left=50.0, bottom=300.0, right=70.0, top=320.0))
add_combo_box(out_doc, "Combo Box ID", ["item 1", "item 2"], "item 1", out_page, Rectangle(left=50.0, bottom=260.0, right=210.0, top=280.0))
add_list_box(out_doc, "List Box ID", ["item 1", "item 2", "item 3"], ["item 1", "item 3"], out_page, Rectangle(left=50.0, bottom=160.0, right=210.0, top=240.0))
add_radio_button_group(out_doc, "Radio Button ID", ["A", "B", "C"], 0, out_page, Rectangle(left=50.0, bottom=120.0, right=210.0, top=140.0))
add_general_text_field(out_doc, "Text ID", "Text", out_page, Rectangle(left=50.0, bottom=80.0, right=210.0, top=100.0))
# Add page to output document
out_doc.pages.append(out_page)
# Copy remaining pages and append to output document
in_page_range = in_doc.pages[1:]
copied_pages = PageList.copy(out_doc, in_page_range, copy_options)
out_doc.pages.extend(copied_pages)
Fill form fields
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
// Objects that need releasing or closing
TPtxPdfContent_IccBasedColorSpace* pInOutputIntent = NULL;
TPtxPdfContent_IccBasedColorSpace* pOutOutputIntent = NULL;
TPtxPdf_Metadata* pInMetadata = NULL;
TPtxPdf_Metadata* pOutMetadata = NULL;
TPtxPdfNav_ViewerSettings* pInViewerSettings = NULL;
TPtxPdfNav_ViewerSettings* pOutViewerSettings = NULL;
TPtxPdf_FileReferenceList* pInFileRefList = NULL;
TPtxPdf_FileReferenceList* pOutFileRefList = NULL;
TPtxPdf_FileReference* pInFileRef = NULL;
TPtxPdf_FileReference* pOutFileRef = NULL;
iReturnValue = 0;
// Output intent
pInOutputIntent = PtxPdf_Document_GetOutputIntent(pInDoc);
if (pInOutputIntent != NULL)
{
pOutOutputIntent = PtxPdfContent_IccBasedColorSpace_Copy(pOutDoc, pInOutputIntent);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutOutputIntent,
_T("Failed to copy ICC-based color space. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Document_SetOutputIntent(pOutDoc, pOutOutputIntent),
_T("Failed to set output intent. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
}
else
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get output intent. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
// Metadata
pInMetadata = PtxPdf_Document_GetMetadata(pInDoc);
if (pInMetadata != NULL)
{
pOutMetadata = PtxPdf_Metadata_Copy(pOutDoc, pInMetadata);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutMetadata, _T("Failed to copy metadata. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Document_SetMetadata(pOutDoc, pOutMetadata),
_T("Failed to set metadata. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
}
else
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get metadata. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
// Viewer settings
pInViewerSettings = PtxPdf_Document_GetViewerSettings(pInDoc);
if (pInViewerSettings != NULL)
{
pOutViewerSettings = PtxPdfNav_ViewerSettings_Copy(pOutDoc, pInViewerSettings);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutViewerSettings,
_T("Failed to copy viewer settings. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Document_SetViewerSettings(pOutDoc, pOutViewerSettings),
_T("Failed to set viewer settings. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
}
else
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get viewer settings. %s (ErrorCode: 0x%08x)"), szErrorBuff,
Ptx_GetLastError());
// Associated files (for PDF/A-3 and PDF 2.0 only)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get associated files of input document. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get associated files of output document. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
int nFileRefs = PtxPdf_FileReferenceList_GetCount(pInFileRefList);
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get count of associated files. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
for (int iFileRef = 0; iFileRef < nFileRefs; iFileRef++)
{
pInFileRef = PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInFileRef, _T("Failed to get file reference. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
pOutFileRef = PtxPdf_FileReference_Copy(pOutDoc, pInFileRef);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutFileRef, _T("Failed to copy file reference. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_FileReferenceList_Add(pOutFileRefList, pOutFileRef),
_T("Failed to add file reference. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
Ptx_Release(pInFileRef);
pInFileRef = NULL;
Ptx_Release(pOutFileRef);
pOutFileRef = NULL;
}
Ptx_Release(pInFileRefList);
pInFileRefList = NULL;
Ptx_Release(pOutFileRefList);
pOutFileRefList = NULL;
// Plain embedded files
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(
pInFileRefList, _T("Failed to get plain embedded files of input document %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(
pInFileRefList, _T("Failed to get plain embedded files of output document %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
nFileRefs = PtxPdf_FileReferenceList_GetCount(pInFileRefList);
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get count of plain embedded files. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
for (int iFileRef = 0; iFileRef < nFileRefs; iFileRef++)
{
pInFileRef = PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInFileRef, _T("Failed to get file reference. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
pOutFileRef = PtxPdf_FileReference_Copy(pOutDoc, pInFileRef);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutFileRef, _T("Failed to copy file reference. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_FileReferenceList_Add(pOutFileRefList, pOutFileRef),
_T("Failed to add file reference. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
Ptx_Release(pInFileRef);
pInFileRef = NULL;
Ptx_Release(pOutFileRef);
pOutFileRef = NULL;
}
cleanup:
if (pInOutputIntent != NULL)
Ptx_Release(pInOutputIntent);
if (pOutOutputIntent != NULL)
Ptx_Release(pOutOutputIntent);
if (pInMetadata != NULL)
Ptx_Release(pInMetadata);
if (pOutMetadata != NULL)
Ptx_Release(pOutMetadata);
if (pInViewerSettings != NULL)
Ptx_Release(pInViewerSettings);
if (pOutViewerSettings != NULL)
Ptx_Release(pOutViewerSettings);
if (pInFileRefList != NULL)
Ptx_Release(pInFileRefList);
if (pOutFileRefList != NULL)
Ptx_Release(pOutFileRefList);
if (pInFileRef != NULL)
Ptx_Release(pInFileRef);
if (pOutFileRef != NULL)
Ptx_Release(pOutFileRef);
return iReturnValue;
}
int copyFields(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
// Objects that need releasing or closing
TPtxPdfForms_FieldNodeMap* pInFields = NULL;
TPtxPdfForms_FieldNodeMap* pOutFields = NULL;
TCHAR* szFieldKey = NULL;
TPtxPdfForms_FieldNode* pInFieldNode = NULL;
TPtxPdfForms_FieldNode* pOutFieldNode = NULL;
iReturnValue = 0;
pInFields = PtxPdf_Document_GetFormFields(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInFields,
_T("Failed to get form fields of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutFields = PtxPdf_Document_GetFormFields(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutFields,
_T("Failed to get form fields of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
for (int iField = PtxPdfForms_FieldNodeMap_GetBegin(pInFields);
iField != PtxPdfForms_FieldNodeMap_GetEnd(pInFields);
iField = PtxPdfForms_FieldNodeMap_GetNext(pInFields, iField))
{
if (iField == 0)
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get form field. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
// Get key
size_t nKey = PtxPdfForms_FieldNodeMap_GetKey(pInFields, iField, szFieldKey, 0);
GOTO_CLEANUP_IF_ZERO(nKey, _T("Failed to get form field key\n"));
szFieldKey = (TCHAR*)malloc(nKey * sizeof(TCHAR*));
GOTO_CLEANUP_IF_NULL(szFieldKey, _T("Failed to allocate memory for field key\n"));
if (PtxPdfForms_FieldNodeMap_GetKey(pInFields, iField, szFieldKey, nKey) != nKey)
{
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get form field key. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
}
// Get input field node
pInFieldNode = PtxPdfForms_FieldNodeMap_GetValue(pInFields, iField);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInFieldNode, _T("Failed to get form field. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
// Copy field node to output document
pOutFieldNode = PtxPdfForms_FieldNode_Copy(pOutDoc, pInFieldNode);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutFieldNode, _T("Failed to copy form field. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
// Add copied field node to output fields
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfForms_FieldNodeMap_Set(pOutFields, szFieldKey, pOutFieldNode),
_T("Failed to add form field \"%s\". %s (ErrorCode: 0x%08x)\n"), szFieldKey,
szErrorBuff, Ptx_GetLastError());
// Clean up for next iteration
free(szFieldKey);
szFieldKey = NULL;
Ptx_Release(pOutFieldNode);
pOutFieldNode = NULL;
Ptx_Release(pInFieldNode);
pInFieldNode = NULL;
}
cleanup:
if (pOutFieldNode != NULL)
Ptx_Release(pOutFieldNode);
if (pInFieldNode != NULL)
Ptx_Release(pInFieldNode);
if (szFieldKey != NULL)
free(szFieldKey);
if (pOutFields != NULL)
Ptx_Release(pOutFields);
if (pInFields != NULL)
Ptx_Release(pInFields);
return iReturnValue;
}
int fillFormField(TPtxPdfForms_Field* pField, const TCHAR* szValue)
{
// Objects that need releasing or closing
TPtxPdfForms_RadioButtonList* pButtonList = NULL;
TPtxPdfForms_RadioButton* pButton = NULL;
TPtxPdfForms_ChoiceItemList* pChoiceItemList = NULL;
TPtxPdfForms_ChoiceItem* pItem = NULL;
TCHAR* szName = NULL;
// Other variables
TPtxPdfForms_FieldType iType = 0;
TPtxPdfForms_CheckBox* pCheckBox = NULL;
TPtxPdfForms_RadioButtonGroup* pRadioButtonGroup = NULL;
iReturnValue = 0;
iType = PtxPdfForms_Field_GetType(pField);
if (iType == ePtxPdfForms_FieldType_GeneralTextField || iType == ePtxPdfForms_FieldType_CombTextField)
{
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfForms_TextField_SetText((TPtxPdfForms_TextField*)pField, szValue),
_T("Failed to set text field value. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
}
else if (iType == ePtxPdfForms_FieldType_CheckBox)
{
pCheckBox = (TPtxPdfForms_CheckBox*)pField;
if (_tcscmp(szValue, _T("on")) == 0)
{
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfForms_CheckBox_SetChecked(pCheckBox, TRUE),
_T("Failed to set check box. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
}
else
{
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfForms_CheckBox_SetChecked(pCheckBox, FALSE),
_T("Failed to set check box. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
}
}
else if (iType == ePtxPdfForms_FieldType_RadioButtonGroup)
{
pRadioButtonGroup = (TPtxPdfForms_RadioButtonGroup*)pField;
pButtonList = PtxPdfForms_RadioButtonGroup_GetButtons(pRadioButtonGroup);
for (int iButton = 0; iButton < PtxPdfForms_RadioButtonList_GetCount(pButtonList); iButton++)
{
pButton = PtxPdfForms_RadioButtonList_Get(pButtonList, iButton);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pButton, _T("Failed to get radio button. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError())
size_t nName = PtxPdfForms_RadioButton_GetExportName(pButton, szName, 0);
GOTO_CLEANUP_IF_ZERO(nName, _T("Failed to get radio button name\n"));
szName = (TCHAR*)malloc(nName * sizeof(TCHAR*));
GOTO_CLEANUP_IF_NULL(szName, _T("Failed to allocate memory for radio button name\n"));
if (PtxPdfForms_RadioButton_GetExportName(pButton, szName, nName) != nName)
{
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get radio button name. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
}
if (_tcscmp(szValue, szName) == 0)
{
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxPdfForms_RadioButtonGroup_SetChosenButton(pRadioButtonGroup, pButton),
_T("Failed to set radio button. %s (ErrorCode: 0x%08x)\n"), szErrorBuff, Ptx_GetLastError());
}
free(szName);
szName = NULL;
Ptx_Release(pButton);
pButton = NULL;
}
}
else if (iType == ePtxPdfForms_FieldType_ComboBox || iType == ePtxPdfForms_FieldType_ListBox)
{
pChoiceItemList = PtxPdfForms_ChoiceField_GetItems((TPtxPdfForms_ChoiceField*)pField);
for (int iItem = 0; iItem < PtxPdfForms_ChoiceItemList_GetCount(pChoiceItemList); iItem++)
{
pItem = PtxPdfForms_ChoiceItemList_Get(pChoiceItemList, iItem);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pItem,
_T("Failed to get item from choice field. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
size_t nName = PtxPdfForms_ChoiceItem_GetDisplayName(pItem, szName, 0);
GOTO_CLEANUP_IF_ZERO(nName, _T("Failed to get choice item name\n"));
szName = (TCHAR*)malloc(nName * sizeof(TCHAR*));
GOTO_CLEANUP_IF_NULL(szName, _T("Failed to allocate memory for choice item name\n"));
if (PtxPdfForms_ChoiceItem_GetDisplayName(pItem, szName, nName) != nName)
{
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get choice item name. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
}
if (_tcscmp(szValue, szName) == 0)
{
break;
}
free(szName);
szName = NULL;
Ptx_Release(pItem);
pItem = NULL;
}
if (pItem != NULL)
{
free(szName);
szName = NULL;
if (iType == ePtxPdfForms_FieldType_ComboBox)
{
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxPdfForms_ComboBox_SetChosenItem((TPtxPdfForms_ComboBox*)pField, pItem),
_T("Failed to set choice item for combo box. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
}
else // iType == ePtxPdfForms_FieldType_ListBox
{
Ptx_Release(pChoiceItemList);
pChoiceItemList = PtxPdfForms_ListBox_GetChosenItems((TPtxPdfForms_ListBox*)pField);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(
pChoiceItemList, _T("Failed to get list of chosen items for list box. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxPdfForms_ChoiceItemList_Clear(pChoiceItemList),
_T("Failed to clear list of chosen items for list box. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxPdfForms_ChoiceItemList_Add(pChoiceItemList, pItem),
_T("Failed to add item to list of chosen items for list box. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
}
}
}
cleanup:
if (szName != NULL)
free(szName);
if (pItem == NULL)
Ptx_Release(pItem);
if (pChoiceItemList == NULL)
Ptx_Release(pChoiceItemList);
if (pButton != NULL)
Ptx_Release(pButton);
if (pButtonList != NULL)
Ptx_Release(pButton);
return iReturnValue;
}
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// Create output document
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// Copy document-wide data
CopyDocumentData(inDoc, outDoc);
FieldNodeMap outFields = outDoc.FormFields;
// Copy all form fields
FieldNodeMap inFields = inDoc.FormFields;
foreach (var inPair in inFields)
{
FieldNode inFieldNode = inPair.Value;
FieldNode outFormFieldNode = FieldNode.Copy(outDoc, inFieldNode);
outFields.Add(inPair.Key, outFormFieldNode);
}
// Find the given field, exception thrown if not found
var selectedNode = outFields.Lookup(fieldIdentifier);
if (selectedNode is Field selectedField)
FillFormField(selectedField, fieldValue);
// Configure copying options for updating existing widgets and removing signature fields
PageCopyOptions copyOptions = new PageCopyOptions
{
FormFields = FormFieldCopyStrategy.CopyAndUpdateWidgets,
UnsignedSignatures = CopyStrategy.Remove,
};
// Copy all pages and append to output document
PageList copiedPages = PageList.Copy(outDoc, inDoc.Pages, copyOptions);
outDoc.Pages.AddRange(copiedPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// Copy document-wide data
// Output intent
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// Metadata
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// Viewer settings
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
static void FillFormField(Field formField, string value)
{
// Apply the value, depending on the field type
if (formField is TextField textField)
{
// Set the text
textField.Text = value;
}
else if (formField is CheckBox checkBox)
{
// Check or un-check
checkBox.Checked = "on".Equals(value, StringComparison.CurrentCultureIgnoreCase);
}
else if (formField is RadioButtonGroup group)
{
// Search the buttons for given name
foreach (var button in group.Buttons)
{
if (value.Equals(button.ExportName))
{
// Found: Select this button
group.ChosenButton = button;
break;
}
}
}
else if (formField is ComboBox comboBox)
{
// Search for the given item
foreach (var item in comboBox.Items)
{
if (value.Equals(item.DisplayName))
{
// Found: Select this item.
comboBox.ChosenItem = item;
break;
}
}
}
else if (formField is ListBox listBox)
{
// Search for the given item
foreach (var item in listBox.Items)
{
if (value.Equals(item.DisplayName))
{
// Found: Set this item as the only selected item
var itemList = listBox.ChosenItems;
itemList.Clear();
itemList.Add(item);
break;
}
}
}
}
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null);
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (// Create output document
Document outDoc = Document.create(outStream, inDoc.getConformance(), null)) {
// Copy document-wide data
copyDocumentData(inDoc, outDoc);
// Copy all form fields
FieldNodeMap inFormFields = inDoc.getFormFields();
FieldNodeMap outFormFields = outDoc.getFormFields();
for (Entry<String, FieldNode> entry : inFormFields.entrySet())
outFormFields.put(entry.getKey(), FieldNode.copy(outDoc, entry.getValue()));
// Find the given field, exception thrown if not found
Field selectedField = (Field) outFormFields.lookup(fieldIdentifier);
fillFormField(selectedField, fieldValue);
// Configure copying options for updating existing widgets and removing signature fields
PageCopyOptions copyOptions = new PageCopyOptions();
copyOptions.setFormFields(FormFieldCopyStrategy.COPY_AND_UPDATE_WIDGETS);
copyOptions.setUnsignedSignatures(CopyStrategy.REMOVE);
// Copy all pages and append to output document
PageList copiedPages = PageList.copy(outDoc, inDoc.getPages(), copyOptions);
outDoc.getPages().addAll(copiedPages);
}
}
private static void copyDocumentData(Document inDoc, Document outDoc) throws ToolboxException, IOException {
// Copy document-wide data
// Output intent
if (inDoc.getOutputIntent() != null)
outDoc.setOutputIntent(IccBasedColorSpace.copy(outDoc, inDoc.getOutputIntent()));
// Metadata
outDoc.setMetadata(Metadata.copy(outDoc, inDoc.getMetadata()));
// Viewer settings
outDoc.setViewerSettings(ViewerSettings.copy(outDoc, inDoc.getViewerSettings()));
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.getAssociatedFiles();
for (FileReference inFileRef : inDoc.getAssociatedFiles())
outAssociatedFiles.add(FileReference.copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.getPlainEmbeddedFiles();
for (FileReference inFileRef : inDoc.getPlainEmbeddedFiles())
outEmbeddedFiles.add(FileReference.copy(outDoc, inFileRef));
}
private static void fillFormField(Field formField, String value) throws ToolboxException {
// Apply the value, depending on the field type
if (formField instanceof TextField) {
// Set the text
TextField textField = (TextField) formField;
textField.setText(value);
} else if (formField instanceof CheckBox) {
// Check or un-check
CheckBox checkBox = (CheckBox) formField;
checkBox.setChecked(value.equalsIgnoreCase("on"));
} else if (formField instanceof RadioButtonGroup) {
// Search the buttons for given name
RadioButtonGroup group = (RadioButtonGroup) formField;
for (RadioButton button : group.getButtons()) {
if (value.equals(button.getExportName())) {
// Found: Select this button
group.setChosenButton(button);
break;
}
}
} else if (formField instanceof ComboBox) {
// Search for the given item
ComboBox comboBox = (ComboBox) formField;
for (ChoiceItem item : comboBox.getItems()) {
if (value.equals(item.getDisplayName())) {
// Found: Select this item
comboBox.setChosenItem(item);
break;
}
}
} else if (formField instanceof ListBox) {
// Search for the given item
ListBox listBox = (ListBox) formField;
for (ChoiceItem item : listBox.getItems()) {
if (value.equals(item.getDisplayName())) {
// Found: Set this item as the only selected item
ChoiceItemList itemList = listBox.getChosenItems();
itemList.clear();
itemList.add(item);
break;
}
}
}
}
def copy_document_data(in_doc: Document, out_doc: Document):
# Copy document-wide data
# Output intent
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# Metadata
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# Viewer settings
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# Associated files (for PDF/A-3 and PDF 2.0 only)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# Plain embedded files
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def fill_form_field(form_field: Field, value: str):
"""Set the value of a form field based on its type."""
if isinstance(form_field, TextField):
form_field.text = value
elif isinstance(form_field, CheckBox):
form_field.checked = value.lower() == "on"
elif isinstance(form_field, RadioButtonGroup):
for button in form_field.buttons:
if button.export_name == value:
form_field.chosen_button = button
break
elif isinstance(form_field, ComboBox):
for item in form_field.items:
if item.display_name == value:
form_field.chosen_item = item
break
elif isinstance(form_field, ListBox):
for item in form_field.items:
if item.display_name == value:
form_field.chosen_items.clear()
form_field.chosen_items.append(item)
break
# Open input document
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# Create output document
with io.FileIO(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, in_doc.conformance, None) as out_doc:
# Copy document-wide data
copy_document_data(in_doc, out_doc)
# Copy form fields
in_fields = in_doc.form_fields
out_fields = out_doc.form_fields
for key, in_field_node in in_fields.items():
out_fields[key] = FieldNode.copy(out_doc, in_field_node)
# Find the form field and update its value
selected_field = out_fields.lookup(field_identifier)
if selected_field:
fill_form_field(selected_field, field_value)
# Configure page copy options
copy_options = PageCopyOptions()
copy_options.form_fields = FormFieldCopyStrategy.COPY_AND_UPDATE_WIDGETS
copy_options.unsigned_signatures = CopyStrategy.REMOVE
# Copy all pages
copied_pages = PageList.copy(out_doc, in_doc.pages, copy_options)
out_doc.pages.extend(copied_pages)
Content addition
Add barcode to PDF
// Open input document
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// Create file stream
pFontStream = _tfopen(szFontPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pFontStream, _T("Failed to open font file."));
PtxSysCreateFILEStreamDescriptor(&fontDescriptor, pFontStream, 0);
// Create output document
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
pFont = PtxPdfContent_Font_Create(pOutDoc, &fontDescriptor, TRUE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pFont, _T("Failed to create font. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Copy document-wide data
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Configure copy options
pCopyOptions = PtxPdf_PageCopyOptions_New();
// Get page lists of input and output document
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get the pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get the pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Copy first page
pInPage = PtxPdf_PageList_Get(pInPageList, 0);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPage, _T("Failed to get the first page. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPage = PtxPdf_Page_Copy(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage, _T("Failed to copy page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Add barcode image to copied page
if (addBarcode(pOutDoc, pOutPage, szBarcode, pFont, 50) != 0)
goto cleanup;
// Add page to output document
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_Add(pOutPageList, pOutPage),
_T("Failed to add page to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Get remaining pages from input
pInPageRange = PtxPdf_PageList_GetRange(pInPageList, 1, PtxPdf_PageList_GetCount(pInPageList) - 1);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageRange,
_T("Failed to get page range from input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Copy remaining pages to output
pOutPageRange = PtxPdf_PageList_Copy(pOutDoc, pInPageRange, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageRange,
_T("Failed to copy page range to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Add the copied pages to the output document
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pOutPageRange),
_T("Failed to add page range to output page list. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// Output intent
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// Metadata
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// Viewer settings
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// Associated files (for PDF/A-3 and PDF 2.0 only)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// Plain embedded files
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
int addBarcode(TPtxPdf_Document* pOutDoc, TPtxPdf_Page* pOutPage, TCHAR* szBarcode, TPtxPdfContent_Font* pFont,
double dFontSize)
{
TPtxPdfContent_Content* pContent = NULL;
TPtxPdfContent_ContentGenerator* pGenerator = NULL;
TPtxPdfContent_Text* pBarcodeText = NULL;
TPtxPdfContent_TextGenerator* pTextGenerator = NULL;
pContent = PtxPdf_Page_GetContent(pOutPage);
// Create content generator
pGenerator = PtxPdfContent_ContentGenerator_New(pContent, FALSE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGenerator, _T("Failed to create a content generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Create text object
pBarcodeText = PtxPdfContent_Text_Create(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pBarcodeText, _T("Failed to create a text object. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Create text generator
pTextGenerator = PtxPdfContent_TextGenerator_New(pBarcodeText, pFont, dFontSize, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pTextGenerator, _T("Failed to create a text generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Calculate position
TPtxGeomReal_Size size;
PtxPdf_Page_GetSize(pOutPage, &size);
TPtxGeomReal_Point position;
double dTextWidth = PtxPdfContent_TextGenerator_GetWidth(pTextGenerator, szBarcode);
GOTO_CLEANUP_IF_NEGATIVE_PRINT_ERROR(dTextWidth, _T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
double dFontAscent = PtxPdfContent_Font_GetAscent(pFont);
GOTO_CLEANUP_IF_NEGATIVE_PRINT_ERROR(dFontAscent, _T("%s(ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
double dFontDescent = PtxPdfContent_Font_GetDescent(pFont);
GOTO_CLEANUP_IF_NEGATIVE_PRINT_ERROR(dFontDescent, _T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
position.dX = size.dWidth - (dTextWidth + dBorder);
position.dY = size.dHeight - (dFontSize * (dFontAscent + dFontDescent) + dBorder);
// Move to position
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_MoveTo(pTextGenerator, &position),
_T("Failed to move to position %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Add given barcode string
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_ShowLine(pTextGenerator, szBarcode),
_T("Failed to add barcode string. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Close text generator
if (pTextGenerator != NULL)
PtxPdfContent_TextGenerator_Close(pTextGenerator);
// Paint the positioned barcode text
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_ContentGenerator_PaintText(pGenerator, pBarcodeText),
_T("Failed to paint the positioned barcode text. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
cleanup:
if (pGenerator != NULL)
PtxPdfContent_ContentGenerator_Close(pGenerator);
return iReturnValue;
}
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// Create file stream
using (Stream fontStream = new FileStream(fontPath, FileMode.Open, FileAccess.Read))
// Create output document
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// Copy document-wide data
CopyDocumentData(inDoc, outDoc);
// Create embedded font in output document
Font font = Font.Create(outDoc, fontStream, true);
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Copy first page, add barcode, and append to output document
Page outPage = Page.Copy(outDoc, inDoc.Pages[0], copyOptions);
AddBarcode(outDoc, outPage, barcode, font, 50);
outDoc.Pages.Add(outPage);
// Copy remaining pages and append to output document
PageList inPageRange = inDoc.Pages.GetRange(1, inDoc.Pages.Count - 1);
PageList copiedPages = PageList.Copy(outDoc, inPageRange, copyOptions);
outDoc.Pages.AddRange(copiedPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// Copy document-wide data
// Output intent
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// Metadata
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// Viewer settings
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void AddBarcode(Document outputDoc, Page outPage, string barcode,
Font font, double fontSize)
{
// Create content generator
using ContentGenerator gen = new ContentGenerator(outPage.Content, false);
// Create text object
Text barcodeText = Text.Create(outputDoc);
// Create text generator
using (TextGenerator textGenerator = new TextGenerator(barcodeText, font, fontSize, null))
{
// Calculate position
Point position = new Point
{
X = outPage.Size.Width - (textGenerator.GetWidth(barcode) + Border),
Y = outPage.Size.Height - (fontSize * (font.Ascent + font.Descent) + Border)
};
// Move to position
textGenerator.MoveTo(position);
// Add given barcode string
textGenerator.ShowLine(barcode);
}
// Paint the positioned barcode text
gen.PaintText(barcodeText);
}
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null);
// Create file stream
FileStream fontStream = new FileStream(fontPath, FileStream.Mode.READ_ONLY);
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (// Create output document
Document outDoc = Document.create(outStream, inDoc.getConformance(), null)) {
// Copy document-wide data
copyDocumentData(inDoc, outDoc);
// Create embedded font in output document
Font font = Font.create(outDoc, fontStream, true);
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Copy first page, add barcode, and append to output document
Page outPage = Page.copy(outDoc, inDoc.getPages().get(0), copyOptions);
addBarcode(outDoc, outPage, barcode, font, 50);
outDoc.getPages().add(outPage);
// Copy remaining pages and append to output document
PageList inPageRange = inDoc.getPages().subList(1, inDoc.getPages().size());
PageList copiedPages = PageList.copy(outDoc, inPageRange, copyOptions);
outDoc.getPages().addAll(copiedPages);
}
}
private static void copyDocumentData(Document inDoc, Document outDoc) throws ToolboxException, IOException {
// Copy document-wide data
// Output intent
if (inDoc.getOutputIntent() != null)
outDoc.setOutputIntent(IccBasedColorSpace.copy(outDoc, inDoc.getOutputIntent()));
// Metadata
outDoc.setMetadata(Metadata.copy(outDoc, inDoc.getMetadata()));
// Viewer settings
outDoc.setViewerSettings(ViewerSettings.copy(outDoc, inDoc.getViewerSettings()));
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.getAssociatedFiles();
for (FileReference inFileRef : inDoc.getAssociatedFiles())
outAssociatedFiles.add(FileReference.copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.getPlainEmbeddedFiles();
for (FileReference inFileRef : inDoc.getPlainEmbeddedFiles())
outEmbeddedFiles.add(FileReference.copy(outDoc, inFileRef));
}
private static void addBarcode(Document outputDoc, Page outPage, String barcode, Font font, double fontSize) throws ToolboxException, IOException {
try (// Create content generator
ContentGenerator generator = new ContentGenerator(outPage.getContent(), false)) {
// Create text object
Text barcodeText = Text.create(outputDoc);
// Create a text generator
TextGenerator textgenerator = new TextGenerator(barcodeText, font, fontSize, null);
// Calculate position
Point position = new Point(outPage.getSize().width - (textgenerator.getWidth(barcode) + Border),
outPage.getSize().height - (fontSize * (font.getAscent() + font.getDescent()) + Border));
// Move to position
textgenerator.moveTo(position);
// Add given barcode string
textgenerator.showLine(barcode);
// Close text generator
textgenerator.close();
// Paint the positioned barcode text
generator.paintText(barcodeText);
}
}
def copy_document_data(in_doc: Document, out_doc: Document):
# Copy document-wide data
# Output intent
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# Metadata
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# Viewer settings
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# Associated files (for PDF/A-3 and PDF 2.0 only)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# Plain embedded files
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def add_barcode(out_doc: Document, out_page: Page, barcode: str, font: Font, font_size: float):
# Create content generator
with ContentGenerator(out_page.content, False) as gen:
# Create text object
barcode_text = Text.create(out_doc)
# Create text generator
with TextGenerator(barcode_text, font, font_size, None) as text_generator:
# Calculate position
position = Point(x=out_page.size.width - (text_generator.get_width(barcode) + border),
y=out_page.size.height - (font_size * (font.ascent + font.descent) + border))
# Move to position
text_generator.move_to(position)
# Add given barcode string
text_generator.show_line(barcode)
# Paint the positioned barcode text
gen.paint_text(barcode_text)
# Define border
border = 20
# Open input document
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as in_doc:
# Create font stream
with io.FileIO(font_path, 'rb') as font_stream:
# Create output document
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, in_doc.conformance, None) as out_doc:
# Copy document-wide data
copy_document_data(in_doc, out_doc)
# Create embedded font in output document
font = Font.create(out_doc, font_stream, True)
# Define page copy options
copy_options = PageCopyOptions()
# Copy first page, add barcode, and append to output document
out_page = Page.copy(out_doc, in_doc.pages[0], copy_options)
add_barcode(out_doc, out_page, barcode, font, 50.0)
out_doc.pages.append(out_page)
# Copy remaining pages and append to output document
in_page_range = in_doc.pages[1:]
copied_pages = PageList.copy(out_doc, in_page_range, copy_options)
out_doc.pages.extend(copied_pages)
Add data matrix to PDF
// Open input document
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// Create output document
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// Create embedded font in output document
pFont = PtxPdfContent_Font_CreateFromSystem(pOutDoc, _T("Arial"), _T("Italic"), TRUE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pFont, _T("Failed to create font. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Copy document-wide data
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Configure copy options
pCopyOptions = PtxPdf_PageCopyOptions_New();
// Get page lists of input and output document
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get the pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get the pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Copy first page
pInPage = PtxPdf_PageList_Get(pInPageList, 0);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPage, _T("Failed to get the first page. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPage = PtxPdf_Page_Copy(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage, _T("Failed to copy page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Add datamatrix image to copied page
if (addDataMatrix(pOutDoc, pOutPage, szDatamatrixPath) != 0)
goto cleanup;
// Add page to output document
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_Add(pOutPageList, pOutPage),
_T("Failed to add page to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Get remaining pages from input
pInPageRange = PtxPdf_PageList_GetRange(pInPageList, 1, PtxPdf_PageList_GetCount(pInPageList) - 1);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageRange,
_T("Failed to get page range from input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Copy remaining pages to output
pOutPageRange = PtxPdf_PageList_Copy(pOutDoc, pInPageRange, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageRange,
_T("Failed to copy page range to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Add the copied pages to the output document
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pOutPageRange),
_T("Failed to add page range to output page list. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// Output intent
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// Metadata
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// Viewer settings
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// Associated files (for PDF/A-3 and PDF 2.0 only)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// Plain embedded files
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
int addDataMatrix(TPtxPdf_Document* pOutDoc, TPtxPdf_Page* pOutPage, TCHAR* szDataMatrixPath)
{
TPtxPdfContent_Content* pContent = NULL;
TPtxPdfContent_ContentGenerator* pGenerator = NULL;
TPtxSys_StreamDescriptor datamatrixDescriptor;
FILE* pDatamatrixStream = NULL;
TPtxPdfContent_Image* pDatamatrix = NULL;
pContent = PtxPdf_Page_GetContent(pOutPage);
// Create content generator
pGenerator = PtxPdfContent_ContentGenerator_New(pContent, FALSE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGenerator, _T("Failed to create a content generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Import data matrix
pDatamatrixStream = _tfopen(szDataMatrixPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pDatamatrixStream, _T("Failed to open data matrix file \"%s\".\n"), szDataMatrixPath);
PtxSysCreateFILEStreamDescriptor(&datamatrixDescriptor, pDatamatrixStream, 0);
// Create image object for data matrix
pDatamatrix = PtxPdfContent_Image_Create(pOutDoc, &datamatrixDescriptor);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pDatamatrix, _T("Failed to create image object. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Data matrix size
double dDatamatrixSize = 85.0;
// Calculate Rectangle for data matrix
TPtxGeomReal_Size size;
PtxPdf_Page_GetSize(pOutPage, &size);
TPtxGeomReal_Rectangle rect;
rect.dLeft = dBorder;
rect.dBottom = size.dHeight - (dDatamatrixSize + dBorder);
rect.dRight = dDatamatrixSize + dBorder;
rect.dTop = size.dHeight - dBorder;
// Paint image of data matrix into the specified rectangle
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxPdfContent_ContentGenerator_PaintImage(pGenerator, pDatamatrix, &rect),
_T("Failed to paint data matrix into the specified rectangle. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
cleanup:
if (pGenerator != NULL)
PtxPdfContent_ContentGenerator_Close(pGenerator);
if (pContent != NULL)
Ptx_Release(pContent);
return iReturnValue;
}
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// Create output document
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// Copy document-wide data
CopyDocumentData(inDoc, outDoc);
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Copy first page, add datamatrix image, and append to output document
Page outPage = Page.Copy(outDoc, inDoc.Pages[0], copyOptions);
AddDataMatrix(outDoc, outPage, datamatrixPath);
outDoc.Pages.Add(outPage);
// Copy remaining pages and append to output document
PageList inPageRange = inDoc.Pages.GetRange(1, inDoc.Pages.Count - 1);
PageList copiedPages = PageList.Copy(outDoc, inPageRange, copyOptions);
outDoc.Pages.AddRange(copiedPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// Copy document-wide data
// Output intent
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// Metadata
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// Viewer settings
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void AddDataMatrix(Document document, Page page, string datamatrixPath)
{
// Create content generator
using ContentGenerator generator = new ContentGenerator(page.Content, false);
// Import data matrix
using Stream inMatrix = new FileStream(datamatrixPath, FileMode.Open, FileAccess.Read);
// Create image object for data matrix
Image datamatrix = Image.Create(document, inMatrix);
// Data matrix size
double datamatrixSize = 85;
// Calculate Rectangle for data matrix
Rectangle rect = new Rectangle
{
Left = Border,
Bottom = page.Size.Height - (datamatrixSize + Border),
Right = datamatrixSize + Border,
Top = page.Size.Height - Border
};
// Paint image of data matrix into the specified rectangle
generator.PaintImage(datamatrix, rect);
}
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null);
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (// Create output document
Document outDoc = Document.create(outStream, inDoc.getConformance(), null)) {
// Copy document-wide data
copyDocumentData(inDoc, outDoc);
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Copy first page, add data matrix image, and append to output document
Page outPage = Page.copy(outDoc, inDoc.getPages().get(0), copyOptions);
addDatamatrix(outDoc, outPage, datamatrixPath);
outDoc.getPages().add(outPage);
// Copy remaining pages and append to output document
PageList inPageRange = inDoc.getPages().subList(1, inDoc.getPages().size());
PageList copiedPages = PageList.copy(outDoc, inPageRange, copyOptions);
outDoc.getPages().addAll(copiedPages);
}
}
private static void copyDocumentData(Document inDoc, Document outDoc) throws ToolboxException, IOException {
// Copy document-wide data
// Output intent
if (inDoc.getOutputIntent() != null)
outDoc.setOutputIntent(IccBasedColorSpace.copy(outDoc, inDoc.getOutputIntent()));
// Metadata
outDoc.setMetadata(Metadata.copy(outDoc, inDoc.getMetadata()));
// Viewer settings
outDoc.setViewerSettings(ViewerSettings.copy(outDoc, inDoc.getViewerSettings()));
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.getAssociatedFiles();
for (FileReference inFileRef : inDoc.getAssociatedFiles())
outAssociatedFiles.add(FileReference.copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.getPlainEmbeddedFiles();
for (FileReference inFileRef : inDoc.getPlainEmbeddedFiles())
outEmbeddedFiles.add(FileReference.copy(outDoc, inFileRef));
}
private static void addDatamatrix(Document document, Page page, String datamatrixPath)
throws ToolboxException, IOException {
try (// Create content generator
ContentGenerator generator = new ContentGenerator(page.getContent(), false);
// Import data matrix
FileStream inMatrix = new FileStream(datamatrixPath, FileStream.Mode.READ_ONLY)) {
// Create image object for data matrix
Image datamatrix = Image.create(document, inMatrix);
// Data matrix size
double datamatrixSize = 85;
// Calculate Rectangle for data matrix
Rectangle rect = new Rectangle(Border, page.getSize().height - (datamatrixSize + Border),
datamatrixSize + Border, page.getSize().height - Border);
// Paint image of data matrix into the specified rectangle
generator.paintImage(datamatrix, rect);
}
}
def copy_document_data(in_doc: Document, out_doc: Document):
# Copy document-wide data
# Output intent
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# Metadata
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# Viewer settings
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# Associated files (for PDF/A-3 and PDF 2.0 only)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# Plain embedded files
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def add_data_matrix(document: Document, page: Page, data_matrix_path: str):
# Create content generator
with ContentGenerator(page.content, False) as generator:
# Import data matrix
with io.FileIO(data_matrix_path, 'rb') as in_matrix_stream:
# Create image object for data matrix
data_matrix = Image.create(document, in_matrix_stream)
# Data matrix size
data_matrix_size = 85
# Calculate Rectangle for data matrix
rect = Rectangle(left=border, bottom=page.size.height - (data_matrix_size + border), right=data_matrix_size + border, top=page.size.height - border)
# Paint the positioned barcode text
generator.paint_image(data_matrix, rect)
# Define border
border = 40
# Open input document
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as in_doc:
# Create output document
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, in_doc.conformance, None) as out_doc:
# Copy document-wide data
copy_document_data(in_doc, out_doc)
# Define page copy options
copy_options = PageCopyOptions()
# Copy first page, add datamatrix image, and append to output document
out_page = Page.copy(out_doc, in_doc.pages[0], copy_options)
add_data_matrix(out_doc, out_page, data_matrix_path)
out_doc.pages.append(out_page)
# Copy remaining pages and append to output document
in_page_range = in_doc.pages[1:]
copied_pages = PageList.copy(out_doc, in_page_range, copy_options)
out_doc.pages.extend(copied_pages)
Add image to PDF
// Open input document
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// Create output document
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// Copy document-wide data
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Configure copy options
pCopyOptions = PtxPdf_PageCopyOptions_New();
// Get input and output page lists
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get the pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get the pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Copy pages preceding selected page
pInPageRange = PtxPdf_PageList_GetRange(pInPageList, 0, iPageNumber - 1);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageRange, _T("Failed to get page range. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageRange = PtxPdf_PageList_Copy(pOutDoc, pInPageRange, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageRange, _T("Failed to copy page range. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pOutPageRange),
_T("Failed to add page range. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
Ptx_Release(pInPageRange);
pInPageRange = NULL;
Ptx_Release(pOutPageRange);
pOutPageRange = NULL;
// Copy selected page an add image
pInPage = PtxPdf_PageList_Get(pInPageList, iPageNumber - 1);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPage, _T("Failed to get page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
pOutPage = PtxPdf_Page_Copy(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage, _T("Failed to copy page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
if (addImage(pOutDoc, pOutPage, szImagePath, 150.0, 150.0) != 0)
goto cleanup;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_Add(pOutPageList, pOutPage),
_T("Failed to add page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Copy remaining pages
pInPageRange = PtxPdf_PageList_GetRange(pInPageList, 1, PtxPdf_PageList_GetCount(pInPageList) - 1);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageRange,
_T("Failed to get page range from input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageRange = PtxPdf_PageList_Copy(pOutDoc, pInPageRange, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageRange,
_T("Failed to copy page range to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pOutPageRange),
_T("Failed to add page range to output page list. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// Output intent
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// Metadata
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// Viewer settings
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// Associated files (for PDF/A-3 and PDF 2.0 only)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// Plain embedded files
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
int addImage(TPtxPdf_Document* pOutDoc, TPtxPdf_Page* pOutPage, TCHAR* szImagePath, double x, double y)
{
TPtxPdfContent_Content* pContent = NULL;
TPtxPdfContent_ContentGenerator* pGenerator = NULL;
TPtxSys_StreamDescriptor imageDescriptor;
FILE* pImageStream = NULL;
TPtxPdfContent_Image* pImage = NULL;
pContent = PtxPdf_Page_GetContent(pOutPage);
// Create content generator
pGenerator = PtxPdfContent_ContentGenerator_New(pContent, FALSE);
// Load image from input path
pImageStream = _tfopen(szImagePath, _T("rb"));
PtxSysCreateFILEStreamDescriptor(&imageDescriptor, pImageStream, 0);
// Create image object
pImage = PtxPdfContent_Image_Create(pOutDoc, &imageDescriptor);
double dResolution = 150.0;
TPtxGeomInt_Size size;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_Image_GetSize(pImage, &size),
_T("Failed to get image size. %s(ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Calculate Rectangle for data matrix
TPtxGeomReal_Rectangle rect;
rect.dLeft = x;
rect.dBottom = y;
rect.dRight = x + (double)size.iWidth * 72.0 / dResolution;
rect.dTop = y + (double)size.iHeight * 72.0 / dResolution;
// Paint image into the specified rectangle
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_ContentGenerator_PaintImage(pGenerator, pImage, &rect),
_T("Failed to paint image. %s(ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
cleanup:
if (pGenerator != NULL)
PtxPdfContent_ContentGenerator_Close(pGenerator);
if (pContent != NULL)
Ptx_Release(pContent);
return iReturnValue;
}
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// Create output document
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// Copy document-wide data
CopyDocumentData(inDoc, outDoc);
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Copy pages preceding selected page and append to output document
PageList inPageRange = inDoc.Pages.GetRange(0, pageNumber - 1);
PageList copiedPages = PageList.Copy(outDoc, inPageRange, copyOptions);
outDoc.Pages.AddRange(copiedPages);
// Copy selected page, add image, and append to output document
Page outPage = Page.Copy(outDoc, inDoc.Pages[pageNumber - 1], copyOptions);
AddImage(outDoc, outPage, imagePath, 150, 150);
outDoc.Pages.Add(outPage);
// Copy remaining pages and append to output document
inPageRange = inDoc.Pages.GetRange(pageNumber, inDoc.Pages.Count - pageNumber);
copiedPages = PageList.Copy(outDoc, inPageRange, copyOptions);
outDoc.Pages.AddRange(copiedPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// Copy document-wide data
// Output intent
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// Metadata
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// Viewer settings
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void AddImage(Document document, Page page, string imagePath, double x, double y)
{
// Create content generator
using ContentGenerator generator = new ContentGenerator(page.Content, false);
// Load image from input path
using Stream inImage = new FileStream(imagePath, FileMode.Open, FileAccess.Read);
// Create image object
Image image = Image.Create(document, inImage);
double resolution = 150;
// Calculate rectangle for image
PdfTools.Toolbox.Geometry.Integer.Size size = image.Size;
Rectangle rect = new Rectangle
{
Left = x,
Bottom = y,
Right = x + size.Width * 72 / resolution,
Top = y + size.Height * 72 / resolution
};
// Paint image into the specified rectangle
generator.PaintImage(image, rect);
}
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null);
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (// Create output document
Document outDoc = Document.create(outStream, inDoc.getConformance(), null)) {
// Copy document-wide data
copyDocumentData(inDoc, outDoc);
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Copy pages preceding selected page and append to output document
PageList inPageRange = inDoc.getPages().subList(0, pageNumber - 1);
PageList copiedPages = PageList.copy(outDoc, inPageRange, copyOptions);
outDoc.getPages().addAll(copiedPages);
// Copy selected page, add image, and append to output document
Page outPage = Page.copy(outDoc, inDoc.getPages().get(pageNumber - 1), copyOptions);
addImage(outDoc, outPage, imagePath, 150, 150);
outDoc.getPages().add(outPage);
// Copy remaining pages and append to output document
inPageRange = inDoc.getPages().subList(pageNumber, inDoc.getPages().size());
copiedPages = PageList.copy(outDoc, inPageRange, copyOptions);
outDoc.getPages().addAll(copiedPages);
}
}
private static void copyDocumentData(Document inDoc, Document outDoc) throws ToolboxException, IOException {
// Copy document-wide data
// Output intent
if (inDoc.getOutputIntent() != null)
outDoc.setOutputIntent(IccBasedColorSpace.copy(outDoc, inDoc.getOutputIntent()));
// Metadata
outDoc.setMetadata(Metadata.copy(outDoc, inDoc.getMetadata()));
// Viewer settings
outDoc.setViewerSettings(ViewerSettings.copy(outDoc, inDoc.getViewerSettings()));
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.getAssociatedFiles();
for (FileReference inFileRef : inDoc.getAssociatedFiles())
outAssociatedFiles.add(FileReference.copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.getPlainEmbeddedFiles();
for (FileReference inFileRef : inDoc.getPlainEmbeddedFiles())
outEmbeddedFiles.add(FileReference.copy(outDoc, inFileRef));
}
private static void addImage(Document document, Page outPage, String imagePath, double x, double y)
throws ToolboxException, IOException {
try (// Create content generator
ContentGenerator generator = new ContentGenerator(outPage.getContent(), false);
// Load image from input path
FileStream inImage = new FileStream(imagePath, FileStream.Mode.READ_ONLY)) {
// Create image object
Image image = Image.create(document, inImage);
double resolution = 150;
// Calculate rectangle for image
Size size = image.getSize();
Rectangle rect = new Rectangle(x, y, x + size.getWidth() * 72 / resolution,
y + size.getHeight() * 72 / resolution);
// Paint image into the specified rectangle
generator.paintImage(image, rect);
}
}
def copy_document_data(in_doc: Document, out_doc: Document):
# Copy document-wide data
# Output intent
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# Metadata
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# Viewer settings
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# Associated files (for PDF/A-3 and PDF 2.0 only)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# Plain embedded files
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def add_image(document: Document, page: Page, image_path: str, x: float, y: float):
# Create content generator
with ContentGenerator(page.content, False) as generator:
# Load image from input path
with io.FileIO(image_path, 'rb') as in_image_stream:
# Create image object
image = Image.create(document, in_image_stream)
resolution = 150
# Calculate rectangle for image
size = image.size
rect = Rectangle(
left=x,
bottom=y,
right=x + size.width * 72 / resolution,
top=y + size.height * 72 / resolution
)
# Paint image into the specified rectangle
generator.paint_image(image, rect)
# Open input document
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as in_doc:
# Create output document
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, in_doc.conformance, None) as out_doc:
# Copy document-wide data
copy_document_data(in_doc, out_doc)
# Define page copy options
copy_options = PageCopyOptions()
# Copy pages preceding selected page and append to output document
if page_number > 1:
in_page_range = in_doc.pages[:page_number - 1]
copied_pages = PageList.copy(out_doc, in_page_range, copy_options)
out_doc.pages.extend(copied_pages)
# Copy selected page, add image, and append to output document
out_page = Page.copy(out_doc, in_doc.pages[page_number - 1], copy_options)
add_image(out_doc, out_page, image_path, 150, 150)
out_doc.pages.append(out_page)
# Copy remaining pages and append to output document
in_page_range = in_doc.pages[page_number:]
copied_pages = PageList.copy(out_doc, in_page_range, copy_options)
out_doc.pages.extend(copied_pages)
Add image mask to PDF
// Open input document
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(_T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Create output document
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(_T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Copy document-wide data
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Get the device color space
TPtxPdfContent_ColorSpace* pColorSpace =
PtxPdfContent_ColorSpace_CreateProcessColorSpace(pOutDoc, ePtxPdfContent_ProcessColorSpaceType_Rgb);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pColorSpace, _T("Failed to get the device color space. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Chose the RGB color value
double color[] = {1.0, 0.0, 0.0};
size_t nColor = sizeof(color) / sizeof(double);
// Create paint object
pPaint = PtxPdfContent_Paint_Create(pOutDoc, pColorSpace, color, nColor, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pPaint, _T("Failed to create a transparent paint. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Configure copy options
pCopyOptions = PtxPdf_PageCopyOptions_New();
// Get input and output page lists
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get the pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get the pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Copy first page an add image mask
pInPage = PtxPdf_PageList_Get(pInPageList, 0);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPage, _T("Failed to get page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
pOutPage = PtxPdf_Page_Copy(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage, _T("Failed to copy page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
if (addImageMask(pOutDoc, pOutPage, szImageMaskPath, 250, 150) != 0)
goto cleanup;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_Add(pOutPageList, pOutPage),
_T("Failed to add page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Copy remaining pages
pInPageRange = PtxPdf_PageList_GetRange(pInPageList, 1, PtxPdf_PageList_GetCount(pInPageList) - 1);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageRange,
_T("Failed to get page range from input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageRange = PtxPdf_PageList_Copy(pOutDoc, pInPageRange, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageRange,
_T("Failed to copy page range to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pOutPageRange),
_T("Failed to add page range to output page list. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// Output intent
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// Metadata
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// Viewer settings
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// Associated files (for PDF/A-3 and PDF 2.0 only)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// Plain embedded files
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
int addImageMask(TPtxPdf_Document* pOutDoc, TPtxPdf_Page* pOutPage, TCHAR* szImageMaskPath, double x, double y)
{
TPtxPdfContent_Content* pContent = NULL;
TPtxPdfContent_ContentGenerator* pGenerator = NULL;
FILE* pImageStream = NULL;
TPtxSys_StreamDescriptor imageDescriptor;
TPtxPdfContent_ImageMask* pImageMask = NULL;
pContent = PtxPdf_Page_GetContent(pOutPage);
// Create content generator
pGenerator = PtxPdfContent_ContentGenerator_New(pContent, FALSE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGenerator, _T("Failed to create a content generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Load image from input path
pImageStream = _tfopen(szImageMaskPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pImageStream, _T("Failed to open image mask file \"%s\".\n"), szImageMaskPath);
PtxSysCreateFILEStreamDescriptor(&imageDescriptor, pImageStream, 0);
// Create image mask object
pImageMask = PtxPdfContent_ImageMask_Create(pOutDoc, &imageDescriptor);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pImageMask, _T("Failed to create image mask obejct. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
double dResolution = 150.0;
TPtxGeomInt_Size size;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_ImageMask_GetSize(pImageMask, &size),
_T("Failed to get image mask size. %s(ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Calculate Rectangle for data matrix
TPtxGeomReal_Rectangle rect;
rect.dLeft = x;
rect.dBottom = y;
rect.dRight = x + (double)size.iWidth * 72.0 / dResolution;
rect.dTop = y + (double)size.iHeight * 72.0 / dResolution;
// Paint image mask into the specified rectangle
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxPdfContent_ContentGenerator_PaintImageMask(pGenerator, pImageMask, &rect, pPaint),
_T("Failed to paint image mask. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
cleanup:
if (pGenerator != NULL)
PtxPdfContent_ContentGenerator_Close(pGenerator);
if (pContent != NULL)
Ptx_Release(pContent);
return iReturnValue;
}
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// Create output document
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// Copy document-wide data
CopyDocumentData(inDoc, outDoc);
// Get the device color space
ColorSpace colorSpace = ColorSpace.CreateProcessColorSpace(outDoc, ProcessColorSpaceType.Rgb);
// Create paint object
paint = Paint.Create(outDoc, colorSpace, new double[] { 1.0, 0.0, 0.0 }, null);
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Copy first page, add image mask, and append to output document
Page outPage = Page.Copy(outDoc, inDoc.Pages[0], copyOptions);
AddImageMask(outDoc, outPage, imageMaskPath, 250, 150);
outDoc.Pages.Add(outPage);
// Copy remaining pages and append to output document
PageList inPageRange = inDoc.Pages.GetRange(1, inDoc.Pages.Count - 1);
PageList copiedPages = PageList.Copy(outDoc, inPageRange, copyOptions);
outDoc.Pages.AddRange(copiedPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// Copy document-wide data
// Output intent
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// Metadata
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// Viewer settings
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void AddImageMask(Document document, Page outPage, string imagePath,
double x, double y)
{
// Create content generator
using ContentGenerator generator = new ContentGenerator(outPage.Content, false);
// Load image from input path
using Stream inImage = new FileStream(imagePath, FileMode.Open, FileAccess.Read);
// Create image mask object
ImageMask imageMask = ImageMask.Create(document, inImage);
double resolution = 150;
// Calculate rectangle for image
PdfTools.Toolbox.Geometry.Integer.Size size = imageMask.Size;
Rectangle rect = new Rectangle
{
Left = x,
Bottom = y,
Right = x + size.Width * 72 / resolution,
Top = y + size.Height * 72 / resolution
};
// Paint image mask into the specified rectangle
generator.PaintImageMask(imageMask, rect, paint);
}
}
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null);
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (// Create output document
Document outDoc = Document.create(outStream, inDoc.getConformance(), null)) {
// Copy document-wide data
copyDocumentData(inDoc, outDoc);
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Get the device color space
ColorSpace colorSpace = ColorSpace.createProcessColorSpace(outDoc, ProcessColorSpaceType.RGB);
// Create paint object
paint = Paint.create(outDoc, colorSpace, new double[] { 1.0, 0.0, 0.0 }, null);
// Copy first page, add image mask, and append to output document
Page outPage = Page.copy(outDoc, inDoc.getPages().get(0), copyOptions);
addImageMask(outDoc, outPage, imageMaskPath, 250, 150);
outDoc.getPages().add(outPage);
// Copy remaining pages and append to output document
PageList inPageRange = inDoc.getPages().subList(1, inDoc.getPages().size());
PageList copiedPages = PageList.copy(outDoc, inPageRange, copyOptions);
outDoc.getPages().addAll(copiedPages);
}
}
private static void copyDocumentData(Document inDoc, Document outDoc) throws ToolboxException, IOException {
// Copy document-wide data
// Output intent
if (inDoc.getOutputIntent() != null)
outDoc.setOutputIntent(IccBasedColorSpace.copy(outDoc, inDoc.getOutputIntent()));
// Metadata
outDoc.setMetadata(Metadata.copy(outDoc, inDoc.getMetadata()));
// Viewer settings
outDoc.setViewerSettings(ViewerSettings.copy(outDoc, inDoc.getViewerSettings()));
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.getAssociatedFiles();
for (FileReference inFileRef : inDoc.getAssociatedFiles())
outAssociatedFiles.add(FileReference.copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.getPlainEmbeddedFiles();
for (FileReference inFileRef : inDoc.getPlainEmbeddedFiles())
outEmbeddedFiles.add(FileReference.copy(outDoc, inFileRef));
}
private static void addImageMask(Document document, Page outPage, String imagePath, double x, double y)
throws ToolboxException, IOException {
try (// Create content generator
ContentGenerator generator = new ContentGenerator(outPage.getContent(), false);
// Load image from input path
FileStream inImage = new FileStream(imagePath, FileStream.Mode.READ_ONLY)) {
// Create image mask object
ImageMask imageMask = ImageMask.create(document, inImage);
double resolution = 150;
// Calculate rectangle for image
Size size = imageMask.getSize();
Rectangle rect = new Rectangle(x, y, x + size.getWidth() * 72 / resolution,
y + size.getHeight() * 72 / resolution);
// Paint image mask into the specified rectangle
generator.paintImageMask(imageMask, rect, paint);
}
}
def copy_document_data(in_doc: Document, out_doc: Document):
# Copy document-wide data
# Output intent
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# Metadata
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# Viewer settings
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# Associated files (for PDF/A-3 and PDF 2.0 only)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# Plain embedded files
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def add_image_mask(document: Document, page: Page, image_path: str, x: float, y: float):
# Create content generator
with ContentGenerator(page.content, False) as generator:
# Load image from input path
with io.FileIO(image_path, 'rb') as in_image_stream:
# Create image mask object
image_mask = ImageMask.create(document, in_image_stream)
resolution = 150
# Calculate rectangle for image
size = image_mask.size
rect = Rectangle(
left=x,
bottom=y,
right=x + size.width * 72 / resolution,
top=y + size.height * 72 / resolution
)
# Paint image mask into the specified rectangle
generator.paint_image_mask(image_mask, rect, paint)
# Open input document
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as in_doc:
# Create output document
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, in_doc.conformance, None) as out_doc:
# Copy document-wide data
copy_document_data(in_doc, out_doc)
# Get the device color space
color_space = ColorSpace.create_process_color_space(out_doc, ProcessColorSpaceType.RGB)
# Create paint object
paint = Paint.create(out_doc, color_space, [1.0, 0.0, 0.0], None)
# Define page copy options
copy_options = PageCopyOptions()
# Copy first page, add image mask, and append to output document
out_page = Page.copy(out_doc, in_doc.pages[0], copy_options)
add_image_mask(out_doc, out_page, image_mask_path, 250, 150)
out_doc.pages.append(out_page)
# Copy remaining pages and append to output document
in_page_range = in_doc.pages[1:]
copied_pages = PageList.copy(out_doc, in_page_range, copy_options)
out_doc.pages.extend(copied_pages)
Add line numbers to PDF
// Open input document
using Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read);
using Document inDoc = Document.Open(inStream, null);
// Create output document
using Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite);
using Document outDoc = Document.Create(outStream, inDoc.Conformance, null);
// Copy document-wide data
CopyDocumentData(inDoc, outDoc);
// Create a font for the line numbers
var lineNumberFont = Font.CreateFromSystem(outDoc, "Arial", null, true);
// Define page copy options
PageCopyOptions pageCopyOptions = new();
// Copy all pages from input to output document
var inPages = inDoc.Pages;
var outPages = PageList.Copy(outDoc, inPages, pageCopyOptions);
// Iterate over all input-output page pairs
var pages = inPages.Zip(outPages);
foreach (var pair in pages)
AddLineNumbers(outDoc, lineNumberFont, pair);
// Add the finished pages to the output document's page list
outDoc.Pages.AddRange(outPages);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private static void AddLineNumbers(Document outDoc, Font lineNumberFont, (Page first, Page second) pair)
{
// Add line numbers to all text found in the input page to the output page
// The input and output page
var inPage = pair.first;
var outPage = pair.second;
// Extract all text fragments
var extractor = new ContentExtractor(inPage.Content)
{
Ungrouping = UngroupingSelection.All
};
// The left-most horizontal position of all text fragments
double leftX = inPage.Size.Width;
// A comparison for doubles that considers distances smaller than the font size as equal
var comparison = new Comparison<double>(
(a, b) =>
{
var d = b - a;
if (Math.Abs(d) < fontSize)
return 0;
return Math.Sign(d);
});
// A container to hold the vertical positions of all text fragments, sorted and without duplicates
SortedSet<double> lineYPositions = new(Comparer<double>.Create(comparison));
// Iterate over all content elements of the input page
foreach (var element in extractor)
{
// Process only text elements
if (element is TextElement textElement)
{
// Iterate over all text fragments
foreach (var fragment in textElement.Text)
{
// Get the fragments base line starting point
var point = fragment.Transform.TransformPoint(new Point { X = fragment.BoundingBox.Left, Y = 0 });
// Update the left-most position
leftX = Math.Min(leftX, point.X);
// Add the vertical position
lineYPositions.Add(point.Y);
}
}
}
// If at least text fragment was found: add line numbers
if (lineYPositions.Count > 0)
{
// Create a text object and use a text generator
var text = Text.Create(outDoc);
using (var textGenerator = new TextGenerator(text, lineNumberFont, fontSize, null))
{
// Iterate over all vertical positions found in the input
foreach (var y in lineYPositions)
{
// The line number string
var lineNumberString = string.Format("{0}", ++lineNumber);
// The width of the line number string when shown on the page
var width = textGenerator.GetWidth(lineNumberString);
// Position line numbers right aligned
// with a given distance to the right-most horizontal position
// and at the vertical position of the current text fragment
textGenerator.MoveTo(new Point { X = leftX - width - distance, Y = y });
// Show the line number string
textGenerator.Show(lineNumberString);
}
}
// Use a content generator to paint the text onto the page
using var contentGenerator = new ContentGenerator(outPage.Content, false);
contentGenerator.PaintText(text);
}
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// Copy document-wide data
// Output intent
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// Metadata
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// Viewer settings
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null);
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (Document outDoc = Document.create(outStream, inDoc.getConformance(), null)) {
// Copy document-wide data
copyDocumentData(inDoc, outDoc);
// Create embedded font in output document
Font font = Font.createFromSystem(outDoc, "Arial", null, true);
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Copy all pages from input to output document
PageList inPages = inDoc.getPages();
PageList outPages = PageList.copy(outDoc, inPages, copyOptions);
// Iterate over all input-output page pairs and add line numbers
for (int i = 0; i < inPages.size(); ++i) {
addLineNumbers(outDoc, font, new SimpleEntry<>(inPages.get(i), outPages.get(i)));
}
// Add the finished pages to the output document's page list
outDoc.getPages().addAll(outPages);
}
}
private static void addLineNumbers(Document outDoc, Font lineNumberFont, Entry<Page, Page> pair) throws IOException, ToolboxException {
// Add line numbers to all text found in the input page to the output page
// The input and output page
Page inPage = pair.getKey();
Page outPage = pair.getValue();
// Extract all text fragments
ContentExtractor extractor = new ContentExtractor(inPage.getContent());
extractor.setUngrouping(UngroupingSelection.ALL);
// The left-most horizontal position of all text fragments
double leftX = inPage.getSize().getWidth();
Comparator<Double> comparator = new Comparator<Double>() {
@Override
public int compare(Double d1, Double d2) {
Double diff = d2 - d1;
if (Math.abs(diff) < fontSize)
return 0;
return (int) Math.signum(diff);
}
};
SortedSet<Double> lineYPositions = new TreeSet<>(comparator);
for (ContentElement element : extractor) {
// Process only text elements
if (element instanceof TextElement) {
TextElement textElement = (TextElement) element;
// Iterate over all text fragments
for (TextFragment fragment : textElement.getText()) {
// Get the fragments base line starting point
Point point = fragment.getTransform().transformPoint(new Point(fragment.getBoundingBox().left, 0));
// Update the left-most position
leftX = Math.min(leftX, point.x);
// Add the vertical position
lineYPositions.add(point.y);
}
}
}
// If at least one text fragment was found: add line numbers
if (lineYPositions.size() > 0) {
// Create a text object and use a text generator
Text text = Text.create(outDoc);
try (TextGenerator textGenerator = new TextGenerator(text, lineNumberFont, fontSize, null)) {
// Iterate over all vertical positions found in the input
for(double y : lineYPositions) {
// The line number string
String lineNumberString = String.valueOf(++lineNumber);
// The width of the line number string when shown on the page
double width = textGenerator.getWidth(lineNumberString);
// Position line numbers right aligned
// with a given distance to the right-most horizontal position
// and at the vertical position of the current text fragment
textGenerator.moveTo(new Point (leftX - width - distance, y));
// Show the line number string
textGenerator.show(lineNumberString);
}
}
try (ContentGenerator contentGenerator = new ContentGenerator(outPage.getContent(), false)) {
// Use a content generator to paint the text onto the page
contentGenerator.paintText(text);
}
}
}
private static void copyDocumentData(Document inDoc, Document outDoc) throws ToolboxException, IOException {
// Copy document-wide data
// Output intent
if (inDoc.getOutputIntent() != null)
outDoc.setOutputIntent(IccBasedColorSpace.copy(outDoc, inDoc.getOutputIntent()));
// Metadata
outDoc.setMetadata(Metadata.copy(outDoc, inDoc.getMetadata()));
// Viewer settings
outDoc.setViewerSettings(ViewerSettings.copy(outDoc, inDoc.getViewerSettings()));
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.getAssociatedFiles();
for (FileReference inFileRef : inDoc.getAssociatedFiles())
outAssociatedFiles.add(FileReference.copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.getPlainEmbeddedFiles();
for (FileReference inFileRef : inDoc.getPlainEmbeddedFiles())
outEmbeddedFiles.add(FileReference.copy(outDoc, inFileRef));
}
def copy_document_data(in_doc: Document, out_doc: Document):
# Copy document-wide data
# Output intent
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# Metadata
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# Viewer settings
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# Associated files (for PDF/A-3 and PDF 2.0 only)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# Plain embedded files
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
class TolerantSortedSet:
def add(self, value: float):
for existing in self.data:
if abs(existing - value) < self.tolerance:
return # Do not add duplicate-like value
self.data.append(value)
self.data.sort(reverse=self.sort_reverse)
def iterator(self):
return iter(self.data)
def display(self):
return str(self.data)
def create_tolerant_sorted_set(tolerance: float, sort_reverse: bool):
tolerant_sorted_set = TolerantSortedSet()
tolerant_sorted_set.tolerance = tolerance
tolerant_sorted_set.sort_reverse = sort_reverse
tolerant_sorted_set.data = []
return tolerant_sorted_set
def add_line_numbers(out_doc: Document, line_number_font: Font, pair: tuple):
global line_number
# Add line numbers to all text found in the input page to the output page
# The input and output page
in_page, out_page = pair
# Extract all text fragments
extractor = ContentExtractor(in_page.content)
extractor.ungrouping = UngroupingSelection.ALL
# The left-most horizontal position of all text fragments
left_x = in_page.size.width
# A comparison for doubles that considers distances smaller than the font size as equal
def comparison(a, b):
d = b - a
if abs(d) < font_size:
return 0
return (d > 0) - (d < 0) # return 1 if d > 0, -1 if d < 0, 0 otherwise
# A sorted set to hold the vertical positions of all text fragments
# Keep the data sorted in reverse order as the coordinates are reverse in a PDF
line_y_positions = create_tolerant_sorted_set(tolerance=font_size, sort_reverse=True)
# Iterate over all content elements of the input page
for element in extractor:
# Process only text elements
if isinstance(element, TextElement):
# Iterate over all text fragments
for fragment in element.text:
# Get the fragment's baseline starting point
point = fragment.transform.transform_point(
Point(fragment.bounding_box.left, 0)
)
# Update the left-most position
left_x = min(left_x, point.x)
# Add the vertical position
line_y_positions.add(point.y)
# If at least one text fragment was found, add line numbers
if line_y_positions:
# Create a text object and use a text generator
text = Text.create(out_doc)
with TextGenerator(text, line_number_font, font_size, None) as text_generator:
# Iterate over all vertical positions found in the input
for y in line_y_positions.iterator():
# The line number string
line_number += 1
line_number_string = str(line_number)
# The width of the line number string when shown on the page
width = text_generator.get_width(line_number_string)
# Position line numbers right-aligned
# with a given distance to the right-most horizontal position
# and at the vertical position of the current text fragment
text_generator.move_to(Point(left_x - width - distance, y))
# Show the line number string
text_generator.show(line_number_string)
# Use a content generator to paint the text onto the page
with ContentGenerator(out_page.content, False) as content_generator:
content_generator.paint_text(text)
# Define global variables
distance = 10
font_size = 8.0
line_number = 0
# Open input document
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as in_doc:
# Create output document
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, in_doc.conformance, None) as out_doc:
# Copy document-wide data
copy_document_data(in_doc, out_doc)
# Create a font for the line numbers
lineNumberFont = Font.create_from_system(out_doc, "Arial", None, True)
# Define page copy options
copy_options = PageCopyOptions()
# Copy all pages from input to output document
in_pages = in_doc.pages
out_pages = PageList.copy(out_doc, in_pages, copy_options)
# Iterate over all input-output page pairs
pages = zip(in_pages, out_pages)
for pair in pages:
add_line_numbers(out_doc, lineNumberFont, pair)
out_doc.pages.extend(out_pages)
Add stamp to PDF
// Open input document
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&inDescriptor, pInStream, FALSE);
pInDoc = PtxPdf_Document_Open(&inDescriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// Create output document
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file %s.\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file %s cannot be closed. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// Create embedded font in output document
pFont = PtxPdfContent_Font_CreateFromSystem(pOutDoc, _T("Arial"), _T("Italic"), TRUE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pFont, _T("Embedded font cannot be created. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Copy document-wide data
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Get the color space
TPtxPdfContent_ColorSpace* pColorSpace =
PtxPdfContent_ColorSpace_CreateProcessColorSpace(pOutDoc, ePtxPdfContent_ProcessColorSpaceType_Rgb);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pColorSpace, _T("Failed to get the color space. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Chose the RGB color values
double color[] = {1.0, 0.0, 0.0};
size_t nColor = sizeof(color) / sizeof(double);
pTransparency = PtxPdfContent_Transparency_New(dAlpha);
// Create paint object
pPaint = PtxPdfContent_Paint_Create(pOutDoc, pColorSpace, color, nColor, pTransparency);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pPaint, _T("Failed to create a transparent paint. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Configure copy options
pCopyOptions = PtxPdf_PageCopyOptions_New();
// Loop through all pages of input
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get the pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get the pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
for (int i = 0; i < PtxPdf_PageList_GetCount(pInPageList); i++)
{
// Get a list of pages
pInPage = PtxPdf_PageList_Get(pInPageList, i);
// Copy page from input to output
pOutPage = PtxPdf_Page_Copy(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage,
_T("Failed to copy pages from input to output. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Add stamp to page
if (addStamp(pOutDoc, pOutPage, szStampString, pFont, 50) == 1)
{
goto cleanup;
}
// Add page to output document
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_Add(pOutPageList, pOutPage),
_T("Failed to add page to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
if (pOutPage != NULL)
{
Ptx_Release(pOutPage);
pOutPage = NULL;
}
if (pInPage != NULL)
{
Ptx_Release(pInPage);
pInPage = NULL;
}
}
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// Output intent
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// Metadata
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// Viewer settings
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// Associated files (for PDF/A-3 and PDF 2.0 only)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// Plain embedded files
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
int addStamp(TPtxPdf_Document* pOutDoc, TPtxPdf_Page* pOutPage, TCHAR* szStampString, TPtxPdfContent_Font* pFont,
double dFontSize)
{
TPtxPdfContent_ContentGenerator* pGenerator = NULL;
TPtxPdfContent_Text* pText = NULL;
TPtxPdfContent_TextGenerator* pTextGenerator = NULL;
TPtxGeomReal_AffineTransform trans;
TPtxGeomReal_Point rotationCenter;
double dTextWidth;
double dFontAscent;
TPtxPdfContent_Content* pContent = PtxPdf_Page_GetContent(pOutPage);
// Create content generator
pGenerator = PtxPdfContent_ContentGenerator_New(pContent, FALSE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGenerator, _T("Failed to create a content generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Create text object
pText = PtxPdfContent_Text_Create(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pText, _T("Failed to create a text object. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Create a text generator
pTextGenerator = PtxPdfContent_TextGenerator_New(pText, pFont, dFontSize, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pTextGenerator, _T("Failed to create a text generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Get output page size
TPtxGeomReal_Size size;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Page_GetSize(pOutPage, &size),
_T("Failed to read page size. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Calculate point and angle of rotation
rotationCenter.dX = size.dWidth / 2.0;
rotationCenter.dY = size.dHeight / 2.0;
double dRotationAngle = atan2(size.dHeight, size.dWidth) / M_PI * 180.0;
// Rotate textinput around the calculated position
PtxGeomReal_AffineTransform_GetIdentity(&trans);
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxGeomReal_AffineTransform_Rotate(&trans, dRotationAngle, &rotationCenter),
_T("Failed to rotate textinput around the calculated position. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_ContentGenerator_Transform(pGenerator, &trans),
_T("Failed to modify the current transformation. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Calculate position
TPtxGeomReal_Point position;
dTextWidth = PtxPdfContent_TextGenerator_GetWidth(pTextGenerator, szStampString);
GOTO_CLEANUP_IF_ZERO_PRINT_ERROR(dTextWidth, _T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
dFontAscent = PtxPdfContent_Font_GetAscent(pFont);
GOTO_CLEANUP_IF_ZERO_PRINT_ERROR(dFontAscent, _T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
position.dX = (size.dWidth - dTextWidth) / 2.0;
position.dY = (size.dHeight - dFontAscent * dFontSize) / 2.0;
// Move to position
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_MoveTo(pTextGenerator, &position),
_T("Failed to move to position. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Set text rendering
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_SetFill(pTextGenerator, pPaint),
_T("Failed to set fill paint. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Add given stamp string
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_ShowLine(pTextGenerator, szStampString),
_T("Failed to add stamp. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Close text generator
if (pTextGenerator != NULL)
{
PtxPdfContent_TextGenerator_Close(pTextGenerator);
pTextGenerator = NULL;
}
// Paint the positioned text
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_ContentGenerator_PaintText(pGenerator, pText),
_T("Failed to paint the positioned text. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
cleanup:
if (pTextGenerator != NULL)
PtxPdfContent_TextGenerator_Close(pTextGenerator);
if (pText != NULL)
Ptx_Release(pText);
if (pGenerator != NULL)
PtxPdfContent_ContentGenerator_Close(pGenerator);
if (pContent != NULL)
Ptx_Release(pContent);
return iReturnValue;
}
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// Create output document
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// Copy document-wide data
CopyDocumentData(inDoc, outDoc);
font = Font.CreateFromSystem(outDoc, "Arial", "Italic", true);
// Get the color space
ColorSpace colorSpace = ColorSpace.CreateProcessColorSpace(outDoc, ProcessColorSpaceType.Rgb);
// Choose the RGB color value
double[] color = { 1.0, 0.0, 0.0 };
Transparency transparency = new Transparency(alpha);
// Create paint object with the choosen RGB color
paint = Paint.Create(outDoc, colorSpace, color, transparency);
// Define copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Copy all pages from input document
foreach (Page inPage in inDoc.Pages)
{
// Copy page from input to output
Page outPage = Page.Copy(outDoc, inPage, copyOptions);
// Add text to page
AddStamp(outDoc, outPage, stampString);
// Add page to document
outDoc.Pages.Add(outPage);
}
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// Copy document-wide data
// Output intent
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// Metadata
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// Viewer settings
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void AddStamp(Document outputDoc, Page outPage, string stampString)
{
// Create content generator and text object
using ContentGenerator gen = new ContentGenerator(outPage.Content, false);
Text text = Text.Create(outputDoc);
// Create text generator
using (TextGenerator textgenerator = new TextGenerator(text, font, fontSize, null))
{
// Calculate point and angle of rotation
Point rotationCenter = new Point
{
X = outPage.Size.Width / 2.0,
Y = outPage.Size.Height / 2.0
};
double rotationAngle = Math.Atan2(outPage.Size.Height,
outPage.Size.Width) / Math.PI * 180.0;
// Rotate text input around the calculated position
AffineTransform trans = AffineTransform.Identity;
trans.Rotate(rotationAngle, rotationCenter);
gen.Transform(trans);
// Calculate position
Point position = new Point
{
X = (outPage.Size.Width - textgenerator.GetWidth(stampString)) / 2.0,
Y = (outPage.Size.Height - font.Ascent * fontSize) / 2.0
};
// Move to position
textgenerator.MoveTo(position);
// Set text paint
textgenerator.Fill = paint;
// Add given stamp string
textgenerator.ShowLine(stampString);
}
// Paint the positioned text
gen.PaintText(text);
}
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null);
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (// Create output document
Document outDoc = Document.create(outStream, inDoc.getConformance(), null)) {
// Copy document-wide data
copyDocumentData(inDoc, outDoc);
// Create embedded font in output document
font = Font.createFromSystem(outDoc, "Arial", "Italic", true);
// Get the color space
ColorSpace colorSpace = ColorSpace.createProcessColorSpace(outDoc, ProcessColorSpaceType.RGB);
// Choose the RGB color value
double[] color = { 1.0, 0.0, 0.0 };
Transparency transparency = new Transparency(alpha);
// Create paint object
paint = Paint.create(outDoc, colorSpace, color, transparency);
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Loop throw all pages of input
for (Page inPage : inDoc.getPages()) {
// Copy page from input to output
Page outPage = Page.copy(outDoc, inPage, copyOptions);
// Add text to page
addStamp(outDoc, outPage, stampString);
// Add page to document
outDoc.getPages().add(outPage);
}
}
}
private static void copyDocumentData(Document inDoc, Document outDoc) throws ToolboxException, IOException {
// Copy document-wide data
// Output intent
if (inDoc.getOutputIntent() != null)
outDoc.setOutputIntent(IccBasedColorSpace.copy(outDoc, inDoc.getOutputIntent()));
// Metadata
outDoc.setMetadata(Metadata.copy(outDoc, inDoc.getMetadata()));
// Viewer settings
outDoc.setViewerSettings(ViewerSettings.copy(outDoc, inDoc.getViewerSettings()));
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.getAssociatedFiles();
for (FileReference inFileRef : inDoc.getAssociatedFiles())
outAssociatedFiles.add(FileReference.copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.getPlainEmbeddedFiles();
for (FileReference inFileRef : inDoc.getPlainEmbeddedFiles())
outEmbeddedFiles.add(FileReference.copy(outDoc, inFileRef));
}
private static void addStamp(Document outputDoc, Page outPage, String stampString)
throws ToolboxException, IOException {
try (// Create content generator
ContentGenerator generator = new ContentGenerator(outPage.getContent(), false)) {
// Create text object
Text text = Text.create(outputDoc);
try (// Create text generator
TextGenerator textgenerator = new TextGenerator(text, font, fontSize, null)) {
// Calculate point and angle of rotation
Point rotationCenter = new Point(outPage.getSize().width / 2.0, outPage.getSize().height / 2.0);
// Calculate rotation angle
double rotationAngle = Math.atan2(outPage.getSize().height, outPage.getSize().width) / Math.PI * 180.0;
// Rotate text input around the calculated position
AffineTransform trans = AffineTransform.getIdentity();
trans.rotate(rotationAngle, rotationCenter);
generator.transform(trans);
// Calculate position
Point position = new Point((outPage.getSize().width - textgenerator.getWidth(stampString)) / 2.0,
(outPage.getSize().height - font.getAscent() * fontSize) / 2.0);
// Move to position
textgenerator.moveTo(position);
// Set text paint
textgenerator.setFill(paint);
// Add given stamp string
textgenerator.showLine(stampString);
}
// Paint the positioned text
generator.paintText(text);
}
}
def copy_document_data(in_doc: Document, out_doc: Document):
# Copy document-wide data
# Output intent
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# Metadata
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# Viewer settings
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# Associated files (for PDF/A-3 and PDF 2.0 only)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# Plain embedded files
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def add_stamp(output_doc: Document, out_page: Page, stamp_string: str):
# Create content generator and text object
with ContentGenerator(out_page.content, False) as gen:
text = Text.create(output_doc)
# Create text generator
with TextGenerator(text, font, font_size, None) as text_generator:
# Calculate point and angle of rotation
rotation_center = Point(
x=out_page.size.width / 2.0,
y=out_page.size.height / 2.0
)
rotation_angle = math.atan2(out_page.size.height, out_page.size.width) / math.pi * 180.0
# Rotate text input around the calculated position
trans = AffineTransform.get_identity()
trans.rotate(rotation_angle, rotation_center)
gen.transform(trans)
# Calculate position
position = Point(
x=(out_page.size.width - text_generator.get_width(stamp_string)) / 2.0,
y=(out_page.size.height - font.ascent * font_size) / 2.0
)
# Move to position
text_generator.move_to(position)
# Set text paint
text_generator.fill = paint
# Add given stamp string
text_generator.show_line(stamp_string)
# Paint the positioned text
gen.paint_text(text)
# Define global variables
font_size = 50.0
# Open input document
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as in_doc:
# Create output document
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, in_doc.conformance, None) as out_doc:
# Copy document-wide data
copy_document_data(in_doc, out_doc)
# Create font
font = Font.create_from_system(out_doc, "Arial", "Italic", True)
# Get the color space
color_space = ColorSpace.create_process_color_space(out_doc, ProcessColorSpaceType.RGB)
# Choose the RGB color value and transparency
color = [1.0, 0.0, 0.0]
transparency = Transparency(alpha)
# Create paint object with the chosen RGB color
paint = Paint.create(out_doc, color_space, color, transparency)
# Define copy options
copy_options = PageCopyOptions()
# Copy all pages from input document
for in_page in in_doc.pages:
# Copy page from input to output
out_page = Page.copy(out_doc, in_page, copy_options)
# Add text to page
add_stamp(out_doc, out_page, stamp_string)
# Add page to document
out_doc.pages.append(out_page)
Add text to PDF
// Open input document
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// Create output document
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// Create embedded font in output document
pFont = PtxPdfContent_Font_CreateFromSystem(pOutDoc, _T("Arial"), _T("Italic"), TRUE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pFont, _T("Failed to create font. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Copy document-wide data
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Configure copy options
pCopyOptions = PtxPdf_PageCopyOptions_New();
// Get page lists of input and output document
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get the pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get the pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Copy first page
pInPage = PtxPdf_PageList_Get(pInPageList, 0);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPage, _T("Failed to get the first page. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPage = PtxPdf_Page_Copy(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage, _T("Failed to copy page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Add text to copied page
if (addText(pOutDoc, pOutPage, szTextString, pFont, 15) != 0)
goto cleanup;
// Add page to output document
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_Add(pOutPageList, pOutPage),
_T("Failed to add page to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Get remaining pages from input
pInPageRange = PtxPdf_PageList_GetRange(pInPageList, 1, PtxPdf_PageList_GetCount(pInPageList) - 1);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageRange,
_T("Failed to get page range from input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Copy remaining pages to output
pOutPageRange = PtxPdf_PageList_Copy(pOutDoc, pInPageRange, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageRange,
_T("Failed to copy page range to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Add the copied pages to the output document
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pOutPageRange),
_T("Failed to add page range to output page list. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// Output intent
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// Metadata
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// Viewer settings
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// Associated files (for PDF/A-3 and PDF 2.0 only)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// Plain embedded files
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
int addText(TPtxPdf_Document* pOutDoc, TPtxPdf_Page* pOutPage, TCHAR* szTextString, TPtxPdfContent_Font* pFont,
double dFontSize)
{
TPtxPdfContent_Content* pContent = NULL;
TPtxPdfContent_ContentGenerator* pGenerator = NULL;
TPtxPdfContent_Text* pText = NULL;
TPtxPdfContent_TextGenerator* pTextGenerator = NULL;
TPtxGeomReal_Size size;
TPtxGeomReal_Point position;
double dFontAscent;
pContent = PtxPdf_Page_GetContent(pOutPage);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pContent, _T("Failed to get content of output file. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Create content generator
pGenerator = PtxPdfContent_ContentGenerator_New(pContent, FALSE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGenerator, _T("Failed to create a content generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Create text object
pText = PtxPdfContent_Text_Create(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pText, _T("Failed to create text object. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Create a text generator
pTextGenerator = PtxPdfContent_TextGenerator_New(pText, pFont, dFontSize, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pTextGenerator, _T("Failed to create a text generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Get output page size
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Page_GetSize(pOutPage, &size),
_T("Failed to read page size. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
dFontAscent = PtxPdfContent_Font_GetAscent(pFont);
GOTO_CLEANUP_IF_ZERO_PRINT_ERROR(dFontAscent, _T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
// Calculate position
position.dX = dBorder;
position.dY = size.dHeight - dBorder - dFontSize * dFontAscent;
// Move to position
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_MoveTo(pTextGenerator, &position),
_T("Failed to move to position. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Add given text string
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_ShowLine(pTextGenerator, szTextString),
_T("Failed to add text string. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Close text generator
PtxPdfContent_TextGenerator_Close(pTextGenerator);
pTextGenerator = NULL;
// Paint the positioned text
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_ContentGenerator_PaintText(pGenerator, pText),
_T("Failed to paint the positioned text. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
cleanup:
if (pTextGenerator != NULL)
PtxPdfContent_TextGenerator_Close(pTextGenerator);
if (pText != NULL)
Ptx_Release(pText);
if (pGenerator != NULL)
PtxPdfContent_ContentGenerator_Close(pGenerator);
if (pContent != NULL)
Ptx_Release(pContent);
return iReturnValue;
}
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// Create output document
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// Copy document-wide data
CopyDocumentData(inDoc, outDoc);
// Create a font
font = Font.CreateFromSystem(outDoc, "Arial", "Italic", true);
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Copy first page, add text, and append to output document
Page outPage = Page.Copy(outDoc, inDoc.Pages[0], copyOptions);
AddText(outDoc, outPage, textString);
outDoc.Pages.Add(outPage);
// Copy remaining pages and append to output document
PageList inPageRange = inDoc.Pages.GetRange(1, inDoc.Pages.Count - 1);
PageList copiedPages = PageList.Copy(outDoc, inPageRange, copyOptions);
outDoc.Pages.AddRange(copiedPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// Copy document-wide data
// Output intent
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// Metadata
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// Viewer settings
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void AddText(Document outputDoc, Page outPage, string textString)
{
// Create content generator and text object
using ContentGenerator gen = new ContentGenerator(outPage.Content, false);
Text text = Text.Create(outputDoc);
// Create text generator
using (TextGenerator textGenerator = new TextGenerator(text, font, fontSize, null))
{
// Calculate position
Point position = new Point
{
X = border,
Y = outPage.Size.Height - border - fontSize * font.Ascent
};
// Move to position
textGenerator.MoveTo(position);
// Add given text string
textGenerator.ShowLine(textString);
}
// Paint the positioned text
gen.PaintText(text);
}
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null);
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (// Create output document
Document outDoc = Document.create(outStream, inDoc.getConformance(), null)) {
// Copy document-wide data
copyDocumentData(inDoc, outDoc);
// Create embedded font in output document
font = Font.createFromSystem(outDoc, "Arial", "Italic", true);
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Copy first page, add text, and append to output document
Page outPage = Page.copy(outDoc, inDoc.getPages().get(0), copyOptions);
addText(outDoc, outPage, textString);
outDoc.getPages().add(outPage);
// Copy remaining pages and append to output document
PageList inPageRange = inDoc.getPages().subList(1, inDoc.getPages().size());
PageList copiedPages = PageList.copy(outDoc, inPageRange, copyOptions);
outDoc.getPages().addAll(copiedPages);
}
}
private static void copyDocumentData(Document inDoc, Document outDoc) throws ToolboxException, IOException {
// Copy document-wide data (excluding metadata)
// Output intent
if (inDoc.getOutputIntent() != null)
outDoc.setOutputIntent(IccBasedColorSpace.copy(outDoc, inDoc.getOutputIntent()));
// Viewer settings
outDoc.setViewerSettings(ViewerSettings.copy(outDoc, inDoc.getViewerSettings()));
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.getAssociatedFiles();
for (FileReference inFileRef : inDoc.getAssociatedFiles())
outAssociatedFiles.add(FileReference.copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.getPlainEmbeddedFiles();
for (FileReference inFileRef : inDoc.getPlainEmbeddedFiles())
outEmbeddedFiles.add(FileReference.copy(outDoc, inFileRef));
}
private static void addText(Document outputDoc, Page outPage, String textString)
throws ToolboxException, IOException {
try (// Create content generator
ContentGenerator generator = new ContentGenerator(outPage.getContent(), false)) {
// Create text object
Text text = Text.create(outputDoc);
try (// Create a text generator
TextGenerator textgenerator = new TextGenerator(text, font, fontSize, null)) {
// Calculate position
Point position = new Point(border, outPage.getSize().height - border - fontSize * font.getAscent());
// Move to position
textgenerator.moveTo(position);
// Add given text string
textgenerator.showLine(textString);
}
// Paint the positioned text
generator.paintText(text);
}
}
def copy_document_data(in_doc: Document, out_doc: Document):
# Copy document-wide data
# Output intent
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# Metadata
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# Viewer settings
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# Associated files (for PDF/A-3 and PDF 2.0 only)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# Plain embedded files
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def add_text(output_doc: Document, output_page: Page, text_string: str):
# Create content generator and text object
with ContentGenerator(output_page.content, False) as gen:
text = Text.create(output_doc)
# Create text generator
with TextGenerator(text, font, font_size, None) as textGenerator:
# Calculate position
position = Point(border, output_page.size.height - border - font_size * font.ascent)
# Move to position
textGenerator.move_to(position)
# Add given text string
textGenerator.show_line(text_string)
# Paint the positioned text
gen.paint_text(text)
# Define global variables
border = 40.0
font_size = 15.0
# Open input document
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as input_document:
# Create output document
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, input_document.conformance, None) as output_document:
# Copy document-wide data
copy_document_data(input_document, output_document)
# Create a font
font = Font.create_from_system(output_document, "Arial", "Italic", True)
# Define page copy options
copy_options = PageCopyOptions()
# Copy first page, add text, and append to output document
out_page = Page.copy(output_document, input_document.pages[0], copy_options)
add_text(output_document, out_page, text_string)
output_document.pages.append(out_page)
# Copy remaining pages and append to output document
inPageRange = input_document.pages[1:]
copied_pages = PageList.copy(output_document, inPageRange, copy_options)
output_document.pages.extend(copied_pages)
Add vector graphic to PDF
// Open input document
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// Create output document
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// Copy document-wide data
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Configure copy options
pCopyOptions = PtxPdf_PageCopyOptions_New();
// Loop through all pages of input
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get the pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get the pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
for (int iPage = 1; iPage <= PtxPdf_PageList_GetCount(pInPageList); iPage++)
{
pInPage = PtxPdf_PageList_Get(pInPageList, iPage - 1);
// Copy page from input to output
pOutPage = PtxPdf_Page_Copy(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage,
_T("Failed to copy pages from input to output. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
PtxPdf_Page_GetSize(pOutPage, &size);
// Add text on first page
if (addLine(pOutDoc, pOutPage) == 1)
{
goto cleanup;
}
// Add page to output document
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_Add(pOutPageList, pOutPage),
_T("Failed to add page to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
if (pOutPage != NULL)
{
Ptx_Release(pOutPage);
pOutPage = NULL;
}
if (pInPage != NULL)
{
Ptx_Release(pInPage);
pInPage = NULL;
}
}
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// Output intent
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// Metadata
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// Viewer settings
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// Associated files (for PDF/A-3 and PDF 2.0 only)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// Plain embedded files
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
int addLine(TPtxPdf_Document* pOutDoc, TPtxPdf_Page* pOutPage)
{
TPtxPdfContent_Content* pContent = NULL;
TPtxPdfContent_ContentGenerator* pGenerator = NULL;
TPtxPdfContent_Path* pPath = NULL;
TPtxPdfContent_PathGenerator* pPathGenerator = NULL;
TPtxPdfContent_ColorSpace* pDeviceRgbColorSpace = NULL;
double aColor[3];
TPtxPdfContent_Paint* pPaint = NULL;
TPtxPdfContent_Stroke* pStroke;
TPtxGeomReal_Size pageSize;
TPtxGeomReal_Point point;
pContent = PtxPdf_Page_GetContent(pOutPage);
PtxPdf_Page_GetSize(pOutPage, &pageSize);
// Create content generator
pGenerator = PtxPdfContent_ContentGenerator_New(pContent, FALSE);
GOTO_CLEANUP_IF_NULL(pGenerator, szErrorBuff, Ptx_GetLastError());
// Create a path
pPath = PtxPdfContent_Path_New();
GOTO_CLEANUP_IF_NULL(pPath, szErrorBuff, Ptx_GetLastError());
// Create a path generator
pPathGenerator = PtxPdfContent_PathGenerator_New(pPath);
GOTO_CLEANUP_IF_NULL(pPathGenerator, szErrorBuff, Ptx_GetLastError());
// Draw a line diagonally across the page
point.dX = 10.0;
point.dY = 10.0;
GOTO_CLEANUP_IF_FALSE(PtxPdfContent_PathGenerator_MoveTo(pPathGenerator, &point), szErrorBuff, Ptx_GetLastError());
point.dX = pageSize.dWidth - 10.0;
point.dY = pageSize.dHeight - 10.0;
GOTO_CLEANUP_IF_FALSE(PtxPdfContent_PathGenerator_LineTo(pPathGenerator, &point), szErrorBuff, Ptx_GetLastError());
// Close the path generator in order to finish the path
PtxPdfContent_PathGenerator_Close(pPathGenerator);
pPathGenerator = NULL;
// Create a RGB color space
pDeviceRgbColorSpace =
PtxPdfContent_ColorSpace_CreateProcessColorSpace(pOutDoc, ePtxPdfContent_ProcessColorSpaceType_Rgb);
GOTO_CLEANUP_IF_NULL(pDeviceRgbColorSpace, szErrorBuff, Ptx_GetLastError());
// Initialize a red color
aColor[0] = 1.0;
aColor[1] = 0.0;
aColor[2] = 0.0;
// Create a paint
pPaint =
PtxPdfContent_Paint_Create(pOutDoc, pDeviceRgbColorSpace, aColor, sizeof(aColor) / sizeof(aColor[0]), NULL);
GOTO_CLEANUP_IF_NULL(pPaint, szErrorBuff, Ptx_GetLastError());
// Setup stroking parameters with given paint and line width
pStroke = PtxPdfContent_Stroke_New(pPaint, 10.0);
GOTO_CLEANUP_IF_NULL(pStroke, szErrorBuff, Ptx_GetLastError());
// Draw the path onto the page
GOTO_CLEANUP_IF_FALSE(PtxPdfContent_ContentGenerator_PaintPath(pGenerator, pPath, NULL, pStroke), szErrorBuff,
Ptx_GetLastError());
cleanup:
if (pPathGenerator != NULL)
PtxPdfContent_PathGenerator_Close(pPathGenerator);
if (pGenerator != NULL)
PtxPdfContent_ContentGenerator_Close(pGenerator);
if (pContent != NULL)
Ptx_Release(pContent);
return iReturnValue;
}
// Open input document
using (System.IO.Stream inStream = new System.IO.FileStream(inPath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// Create output document
using (System.IO.Stream outStream = new System.IO.FileStream(outPath, System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// Copy document-wide data
CopyDocumentData(inDoc, outDoc);
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Copy all pages from input document
foreach (Page inPage in inDoc.Pages)
{
Page outPage = Page.Copy(outDoc, inPage, copyOptions);
// Add a line
AddLine(outDoc, outPage);
// Add page to output document
outDoc.Pages.Add(outPage);
}
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// Copy document-wide data
// Output intent
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// Metadata
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// Viewer settings
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void AddLine(Document document, Page page)
{
// Create content generator
using ContentGenerator generator = new ContentGenerator(page.Content, false);
// Create a path
Path path = new Path();
using (PathGenerator pathGenerator = new PathGenerator(path))
{
// Draw a line diagonally across the page
Size pageSize = page.Size;
pathGenerator.MoveTo(new Point() { X = 10.0, Y = 10.0 });
pathGenerator.LineTo(new Point() { X = pageSize.Width - 10.0, Y = pageSize.Height - 10.0 });
}
// Create a RGB color space
ColorSpace deviceRgbColorSpace = ColorSpace.CreateProcessColorSpace(document, ProcessColorSpaceType.Rgb);
// Create a red color
double[] color = new double[] { 1.0, 0.0, 0.0 };
// Create a paint
Paint paint = Paint.Create(document, deviceRgbColorSpace, color, null);
// Create stroking parameters with given paint and line width
Stroke stroke = new Stroke(paint, 10.0);
// Draw the path onto the page
generator.PaintPath(path, null, stroke);
}
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null);
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (// Create output document
Document outDoc = Document.create(outStream, inDoc.getConformance(), null)) {
// Copy document-wide data
copyDocumentData(inDoc, outDoc);
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Copy all pages
for (Page inPage : inDoc.getPages()) {
// Copy page from input to output
Page outPage = Page.copy(outDoc, inPage, copyOptions);
// Add a line
addLine(outDoc, outPage);
// Add page to output document
outDoc.getPages().add(outPage);
}
}
}
private static void copyDocumentData(Document inDoc, Document outDoc) throws ToolboxException, IOException {
// Copy document-wide data
// Output intent
if (inDoc.getOutputIntent() != null)
outDoc.setOutputIntent(IccBasedColorSpace.copy(outDoc, inDoc.getOutputIntent()));
// Metadata
outDoc.setMetadata(Metadata.copy(outDoc, inDoc.getMetadata()));
// Viewer settings
outDoc.setViewerSettings(ViewerSettings.copy(outDoc, inDoc.getViewerSettings()));
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.getAssociatedFiles();
for (FileReference inFileRef : inDoc.getAssociatedFiles())
outAssociatedFiles.add(FileReference.copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.getPlainEmbeddedFiles();
for (FileReference inFileRef : inDoc.getPlainEmbeddedFiles())
outEmbeddedFiles.add(FileReference.copy(outDoc, inFileRef));
}
private static void addLine(Document document, Page outPage)
throws ToolboxException, IOException {
try (// Create content generator
ContentGenerator generator = new ContentGenerator(outPage.getContent(), false)) {
// Create a path
Path path = new Path();
try (// Create a path generator
PathGenerator pathGenerator = new PathGenerator(path)) {
// Draw a line diagonally across the page
Size pageSize = outPage.getSize();
pathGenerator.moveTo(new Point(10.0, 10.0));
pathGenerator.lineTo(new Point(pageSize.width - 10.0, pageSize.height - 10.0));
}
// Create a RGB color space
ColorSpace deviceRgbColorSpace = ColorSpace.createProcessColorSpace(document, ProcessColorSpaceType.RGB);
// Create a red color
double[] color = new double[] { 1.0, 0.0, 0.0 };
// Create a paint
Paint paint = Paint.create(document, deviceRgbColorSpace, color, null);
// Create stroking parameters with given paint and line width
Stroke stroke = new Stroke(paint, 10.0);
// Draw the path onto the page
generator.paintPath(path, null, stroke);
}
}
def copy_document_data(in_doc: Document, out_doc: Document):
# Copy document-wide data
# Output intent
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# Metadata
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# Viewer settings
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# Associated files (for PDF/A-3 and PDF 2.0 only)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# Plain embedded files
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def add_line(out_doc: Document, page: Page):
# Extract content generator
with ContentGenerator(page.content, False) as generator:
# Create a path
path = Path()
with PathGenerator(path) as path_generator:
# Draw a line diagonally across the page
page_size = page.size
path_generator.move_to(Point(x = 10.0, y = 10.0))
path_generator.line_to(Point(x = page_size.width - 10.0, y=page_size.height - 10.0))
# Create a RGB color space
device_rgb_color_space = ColorSpace.create_process_color_space(out_doc, ProcessColorSpaceType.RGB)
# Create a red color
red = [1.0, 0.0, 0.0]
# Create a paint
paint = Paint.create(out_doc, device_rgb_color_space, red, None)
# Create stroking parameters with given paint and line width
stroke = Stroke(paint, 10.0)
# Draw the path onto the page
generator.paint_path(path, None, stroke)
# Open input document
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as in_doc:
# Create output document
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, in_doc.conformance, None) as out_doc:
# Copy document-wide data
copy_document_data(in_doc, out_doc)
# Define page copy options
copy_options = PageCopyOptions()
# Copy all pages from input document
for in_page in in_doc.pages:
out_page = Page.copy(out_doc, in_page, copy_options)
# Add a line
add_line(out_doc, out_page)
# Add page to output document
out_doc.pages.append(out_page)
Layout text on PDF page
// Create output document
using (Stream outStream = new FileStream(outPath, FileMode.CreateNew, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, null, null))
{
Font font = Font.CreateFromSystem(outDoc, "Arial", "Italic", true);
// Create page
Page outPage = Page.Create(outDoc, PageSize);
// Add text as justified text
LayoutText(outDoc, outPage, textPath, font, 20);
// Add page to document
outDoc.Pages.Add(outPage);
}
private static void LayoutText(Document outputDoc, Page outPage, string textPath, Font font,
double fontSize)
{
// Create content generator
using ContentGenerator gen = new ContentGenerator(outPage.Content, false);
// Create text object
Text text = Text.Create(outputDoc);
// Create text generator
using TextGenerator textGenerator = new TextGenerator(text, font, fontSize, null);
// Calculate position
Point position = new Point
{
X = Border,
Y = outPage.Size.Height - Border
};
// Move to position
textGenerator.MoveTo(position);
// Loop through all lines of the textinput
string[] lines = File.ReadAllLines(textPath, Encoding.Default);
foreach (string line in lines)
{
// Split string in substrings
string[] substrings = line.Split(new char[] { ' ' }, StringSplitOptions.None);
string currentLine = null;
double maxWidth = outPage.Size.Width - Border * 2;
int wordcount = 0;
// Loop through all words of input strings
foreach (string word in substrings)
{
string tempLine;
// Concatenate substrings to line
if (currentLine != null)
tempLine = currentLine + " " + word;
else
tempLine = word;
// Calculate the current width of line
double width = textGenerator.GetWidth(currentLine);
if (textGenerator.GetWidth(tempLine) > maxWidth)
{
// Calculate the word spacing
textGenerator.WordSpacing = (maxWidth - width) / (wordcount - 1);
// Paint on new line
textGenerator.ShowLine(currentLine);
textGenerator.WordSpacing = 0;
currentLine = word;
wordcount = 1;
}
else
{
currentLine = tempLine;
wordcount++;
}
}
textGenerator.WordSpacing = 0;
// Add given stamp string
textGenerator.ShowLine(currentLine);
}
// Paint the positioned text
gen.PaintText(text);
}
try (
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (// Create output document
Document outDoc = Document.create(outStream, null, null)) {
// Create embedded font in output document
Font font = Font.createFromSystem(outDoc, "Arial", "Italic", true);
// Create page
Page outPage = Page.create(outDoc, new Size(595, 842));
// Add text to document
layoutText(outDoc, outPage, textPath, font, 20);
// Add page to output document
outDoc.getPages().add(outPage);
}
}
private static void layoutText(Document outputDoc, Page outPage, String textPath, Font font, double fontSize)
throws ToolboxException, IOException {
try (// Create content generator
ContentGenerator generator = new ContentGenerator(outPage.getContent(), false)) {
// Create text object
Text text = Text.create(outputDoc);
try (// Create a text generator
TextGenerator textGenerator = new TextGenerator(text, font, fontSize, null)) {
// Calculate position
Point position = new Point(Border, outPage.getSize().height - Border);
// Move to position
textGenerator.moveTo(position);
// Loop throw all lines of the textinput
List<String> lines = Files.readAllLines(Paths.get(textPath), Charset.defaultCharset());
for (String line : lines) {
// Split string in substrings
String[] substrings = line.split(" ");
String currentLine = null;
double maxWidth = outPage.getSize().width - (Border * 2);
int wordCount = 0;
// Loop throw all words of input strings
for (String word : substrings) {
String tempLine;
// Concatenate substrings to line
if (currentLine != null) {
tempLine = currentLine + " " + word;
} else {
tempLine = word;
}
// Calculate the current width of line
double width = textGenerator.getWidth(currentLine);
if ((textGenerator.getWidth(tempLine) > maxWidth)) {
// Calculate the word spacing
textGenerator.setWordSpacing((maxWidth - width) / (double) (wordCount - 1));
// Paint on new line
textGenerator.showLine(currentLine);
textGenerator.setWordSpacing(0);
currentLine = word;
wordCount = 1;
} else {
currentLine = tempLine;
wordCount++;
}
}
textGenerator.setWordSpacing(0);
// Add given stamp string
textGenerator.showLine(currentLine);
}
}
// Paint the positioned text
generator.paintText(text);
}
}
def layout_text(output_doc: Document, out_page: Page, text_path: str, font: Font, font_size: float):
"""
Layout and justify text on the PDF page.
"""
# Create content generator
with ContentGenerator(out_page.content, False) as generator:
# Create text object
text = Text.create(output_doc)
# Create text generator
with TextGenerator(text, font, font_size, None) as text_generator:
# Calculate starting position
position = Point(x=BORDER, y=out_page.size.height - BORDER)
# Move to position
text_generator.move_to(position)
with open(text_path, "r", encoding="utf-8") as file:
lines = file.readlines()
# Loop through all lines of the textinput
for line in lines:
# Split string in substrings
substrings = line.split(" ")
current_line = ""
max_width = out_page.size.width - BORDER * 2
word_count = 0
# Loop through all words of input strings
for word in substrings:
# Concatenate substrings to line
temp_line = f"{current_line} {word}".strip()
# Calculate the current width of line
current_width = text_generator.get_width(current_line)
if text_generator.get_width(temp_line) > max_width:
# Calculate the word spacing
text_generator.word_spacing = (max_width - current_width) / (word_count - 1) if word_count > 1 else 0
text_generator.show_line(current_line)
text_generator.word_spacing = 0
current_line = word
word_count = 1
else:
current_line = temp_line
word_count += 1
text_generator.word_spacing = 0
# Add given stamp string
text_generator.show_line(current_line)
# Paint the positioned text
generator.paint_text(text)
# Define global variables
BORDER = 50
PAGE_SIZE = Size(width=595, height=842) # A4 page size in points
# Create output document
with io.FileIO(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, None, None) as out_doc:
font = Font.create_from_system(out_doc, "Arial", "Italic", True)
# Create page
out_page = Page.create(out_doc, PAGE_SIZE)
# Add text as justified text
layout_text(out_doc, out_page, input_text_path, font, font_size=20)
# Add page to document
out_doc.pages.append(out_page)
Stamp page number to PDF
// Open input document
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// Create output document
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// Create embedded font in output document
pFont = PtxPdfContent_Font_CreateFromSystem(pOutDoc, _T("Arial"), _T(""), TRUE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pFont, _T("Failed to create font. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Copy document-wide data
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Configure copy options
pCopyOptions = PtxPdf_PageCopyOptions_New();
// Copy all pages
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get the pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get the pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
for (int iPage = 0; iPage < PtxPdf_PageList_GetCount(pInPageList); iPage++)
{
pInPage = PtxPdf_PageList_Get(pInPageList, iPage);
// Copy page from input to output
pOutPage = PtxPdf_Page_Copy(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage,
_T("Failed to copy pages from input to output. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Page_GetSize(pOutPage, &size),
_T("Failed to get size. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Stamp page number on current page of output document
if (addPageNumber(pOutDoc, pOutPage, pFont, iPage + 1) == 1)
{
goto cleanup;
}
// Add page to output document
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_Add(pOutPageList, pOutPage),
_T("Failed to add page to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
if (pOutPage != NULL)
{
Ptx_Release(pOutPage);
pOutPage = NULL;
}
if (pInPage != NULL)
{
Ptx_Release(pInPage);
pInPage = NULL;
}
}
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// Output intent
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// Metadata
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// Viewer settings
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// Associated files (for PDF/A-3 and PDF 2.0 only)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// Plain embedded files
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
int addPageNumber(TPtxPdf_Document* pOutDoc, TPtxPdf_Page* pOutPage, TPtxPdfContent_Font* pFont, int nPageNumber)
{
TPtxPdfContent_Content* pContent = NULL;
TPtxPdfContent_ContentGenerator* pGenerator = NULL;
TPtxPdfContent_Text* pText = NULL;
TPtxPdfContent_TextGenerator* pTextGenerator = NULL;
pContent = PtxPdf_Page_GetContent(pOutPage);
// Create content generator
pGenerator = PtxPdfContent_ContentGenerator_New(pContent, FALSE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGenerator, _T("Failed to create a content generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Create text object
pText = PtxPdfContent_Text_Create(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pText, _T("Failed to create a text object. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Create a text generator with the given font, size and position
pTextGenerator = PtxPdfContent_TextGenerator_New(pText, pFont, 8, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pTextGenerator, _T("Failed to create a text generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Generate string to be stamped as page number
char szStampBuffer[50];
snprintf(szStampBuffer, sizeof(szStampBuffer), _T("Page %d"), nPageNumber);
TCHAR* szStampText = szStampBuffer;
double dTextWidth = PtxPdfContent_TextGenerator_GetWidth(pTextGenerator, szStampText);
GOTO_CLEANUP_IF_ZERO_PRINT_ERROR(dTextWidth, _T("Failed to get text width. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Calculate position
TPtxGeomReal_Point position;
position.dX = (size.dWidth / 2) - (dTextWidth / 2);
position.dY = 10;
// Move to position
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_MoveTo(pTextGenerator, &position),
_T("Failed to move to position. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Add given text string
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_ShowLine(pTextGenerator, szStampText),
_T("Failed to add given text string. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Close text generator
PtxPdfContent_TextGenerator_Close(pTextGenerator);
pTextGenerator = NULL;
// Paint the positioned text
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_ContentGenerator_PaintText(pGenerator, pText),
_T("Failed to paint the positioned text. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
cleanup:
if (pTextGenerator != NULL)
PtxPdfContent_TextGenerator_Close(pTextGenerator);
if (pGenerator != NULL)
PtxPdfContent_ContentGenerator_Close(pGenerator);
if (pText != NULL)
Ptx_Release(pText);
if (pContent != NULL)
Ptx_Release(pContent);
return iReturnValue;
}
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// Create output document
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// Copy document-wide data
CopyDocumentData(inDoc, outDoc);
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Create embedded font in output document
Font font = Font.CreateFromSystem(outDoc, "Arial", string.Empty, true);
// Copy all pages from input document
int currentPageNumber = 1;
foreach (Page inPage in inDoc.Pages)
{
// Copy page from input to output
Page outPage = Page.Copy(outDoc, inPage, copyOptions);
// Stamp page number on current page of output document
AddPageNumber(outDoc, outPage, font, currentPageNumber++);
// Add page to output document
outDoc.Pages.Add(outPage);
}
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// Copy document-wide data
// Output intent
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// Metadata
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// Viewer settings
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void AddPageNumber(Document outDoc, Page outPage, Font font, int pageNumber)
{
// Create content generator
using ContentGenerator generator = new ContentGenerator(outPage.Content, false);
// Create text object
Text text = Text.Create(outDoc);
// Create a text generator with the given font, size and position
using (TextGenerator textgenerator = new TextGenerator(text, font, 8, null))
{
// Generate string to be stamped as page number
string stampText = string.Format("Page {0}", pageNumber);
// Calculate position for centering text at bottom of page
Point position = new Point
{
X = (outPage.Size.Width / 2) - (textgenerator.GetWidth(stampText) / 2),
Y = 10
};
// Position the text
textgenerator.MoveTo(position);
// Add page number
textgenerator.Show(stampText);
}
// Paint the positioned text
generator.PaintText(text);
}
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null);
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (// Create output document
Document outDoc = Document.create(outStream, inDoc.getConformance(), null)) {
// Copy document-wide data
copyDocumentData(inDoc, outDoc);
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Copy pages from input to output
int pageNo = 1;
// Create embedded font in output document
Font font = Font.createFromSystem(outDoc, "Arial", "", true);
// Loop through all pages of input
for (Page inPage : inDoc.getPages()) {
// Copy page from input to output
Page outPage = Page.copy(outDoc, inPage, copyOptions);
// Stamp page number on current page of output document
applyStamps(outDoc, outPage, font, pageNo++);
// Add page to output document
outDoc.getPages().add(outPage);
}
}
}
private static void copyDocumentData(Document inDoc, Document outDoc) throws ToolboxException, IOException {
// Copy document-wide data
// Output intent
if (inDoc.getOutputIntent() != null)
outDoc.setOutputIntent(IccBasedColorSpace.copy(outDoc, inDoc.getOutputIntent()));
// Metadata
outDoc.setMetadata(Metadata.copy(outDoc, inDoc.getMetadata()));
// Viewer settings
outDoc.setViewerSettings(ViewerSettings.copy(outDoc, inDoc.getViewerSettings()));
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.getAssociatedFiles();
for (FileReference inFileRef : inDoc.getAssociatedFiles())
outAssociatedFiles.add(FileReference.copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.getPlainEmbeddedFiles();
for (FileReference inFileRef : inDoc.getPlainEmbeddedFiles())
outEmbeddedFiles.add(FileReference.copy(outDoc, inFileRef));
}
private static void applyStamps(Document doc, Page page, Font font, int pageNo) throws ToolboxException, IOException {
try (// Create content generator
ContentGenerator generator = new ContentGenerator(page.getContent(), false)) {
// Create text object
Text text = Text.create(doc);
try (// Create a text generator with the given font, size and position
TextGenerator textgenerator = new TextGenerator(text, font, 8, null)) {
// Generate string to be stamped as page number
String stampText = String.format("Page %d", pageNo);
// Calculate position for centering text at bottom of page
Point position = new Point((page.getSize().width / 2) - (textgenerator.getWidth(stampText) / 2), 10);
// Position the text
textgenerator.moveTo(position);
// Add page number
textgenerator.show(stampText);
}
// Paint the positioned text
generator.paintText(text);
}
}
def copy_document_data(in_doc: Document, out_doc: Document):
# Copy document-wide data
# Output intent
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# Metadata
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# Viewer settings
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# Associated files (for PDF/A-3 and PDF 2.0 only)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# Plain embedded files
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def add_page_number(out_doc, out_page, font, page_number):
"""Stamp the page number on the specified page."""
# Create content generator
with ContentGenerator(out_page.content, False) as generator:
# Create text object
text = Text.create(out_doc)
# Create a text generator with the given font, size, and position
with TextGenerator(text, font, 8, None) as text_generator:
# Generate string to be stamped as the page number
stamp_text = f"Page {page_number}"
# Calculate position for centering text at the bottom of the page
position = Point(
x=(out_page.size.width / 2) - (text_generator.get_width(stamp_text) / 2),
y=10
)
# Position the text
text_generator.move_to(position)
# Add page number
text_generator.show(stamp_text)
# Paint the positioned text
generator.paint_text(text)
# Open input document
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# Create output document
with io.FileIO(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, in_doc.conformance, None) as out_doc:
# Copy document-wide data
copy_document_data(in_doc, out_doc)
# Define page copy options
page_copy_options = PageCopyOptions()
# Create embedded font in the output document
font = Font.create_from_system(out_doc, "Arial", None, True)
# Copy all pages from input document
for page_number, in_page in enumerate(in_doc.pages, start=1):
# Copy page from input to output
out_page = Page.copy(out_doc, in_page, page_copy_options)
# Stamp page number on current page of output document
add_page_number(out_doc, out_page, font, page_number)
# Add page to output document
out_doc.pages.append(out_page)
Content modification
Remove glyphs
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// Create output document
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// Copy document-wide data
CopyDocumentData(inDoc, outDoc);
// Process each page
foreach (var inPage in inDoc.Pages)
{
// Create empty output page
Page outPage = Page.Create(outDoc, inPage.Size);
// Copy page content from input to output and remove glyphs
CopyContentAndRemoveGlyphs(inPage.Content, outPage.Content, outDoc);
// Add the new page to the output document's page list
outDoc.Pages.Add(outPage);
}
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// Copy document-wide data
// Output intent
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// Metadata
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// Viewer settings
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void CopyContentAndRemoveGlyphs(Content inContent, Content outContent, Document outDoc)
{
// Use a content extractor and a content generator to copy content
ContentExtractor extractor = new ContentExtractor(inContent);
using ContentGenerator generator = new ContentGenerator(outContent, false);
// Iterate over all content elements
foreach (ContentElement inElement in extractor)
{
ContentElement outElement;
// Special treatment for group elements
if (inElement is GroupElement inGroupElement)
{
// Create empty output group element
GroupElement outGroupElement = GroupElement.CopyWithoutContent(outDoc, inGroupElement);
outElement = outGroupElement;
// Call CopyContentAndRemoveGlyphs() recursively for the group element's content
CopyContentAndRemoveGlyphs(inGroupElement.Group.Content, outGroupElement.Group.Content, outDoc);
}
else
{
// Copy the content element to the output document
outElement = ContentElement.Copy(outDoc, inElement);
if (outElement is TextElement outTextElement)
{
// Special treatment for text element
Text text = outTextElement.Text;
// Remove the first two glyphs from each text fragment
foreach (var fragment in text)
{
// Ensure that the fragment has more than two glyphs
if (fragment.Count > 2)
{
// Call RemoveAt twice
fragment.RemoveAt(0);
fragment.RemoveAt(0);
}
}
}
}
// Append the finished output element to the content generator
generator.AppendContentElement(outElement);
}
}
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null);
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (// Create output document
Document outDoc = Document.create(outStream, inDoc.getConformance(), null)) {
// Copy document-wide data
copyDocumentData(inDoc, outDoc);
// Process each page
for (Page inPage : inDoc.getPages()) {
// Create empty output page
Page outPage = Page.create(outDoc, inPage.getSize());
// Copy page content from input to output and remove glyphs
copyContentAndRemoveGlyphs(inPage.getContent(), outPage.getContent(), outDoc);
// Add the new page to the output document's page list
outDoc.getPages().add(outPage);
}
}
}
private static void copyDocumentData(Document inDoc, Document outDoc) throws ToolboxException, IOException {
// Copy document-wide data
// Output intent
if (inDoc.getOutputIntent() != null)
outDoc.setOutputIntent(IccBasedColorSpace.copy(outDoc, inDoc.getOutputIntent()));
// Metadata
outDoc.setMetadata(Metadata.copy(outDoc, inDoc.getMetadata()));
// Viewer settings
outDoc.setViewerSettings(ViewerSettings.copy(outDoc, inDoc.getViewerSettings()));
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.getAssociatedFiles();
for (FileReference inFileRef : inDoc.getAssociatedFiles())
outAssociatedFiles.add(FileReference.copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.getPlainEmbeddedFiles();
for (FileReference inFileRef : inDoc.getPlainEmbeddedFiles())
outEmbeddedFiles.add(FileReference.copy(outDoc, inFileRef));
}
private static void copyContentAndRemoveGlyphs(Content inContent, Content outContent, Document outDoc) throws ToolboxException, IOException {
// Use a content extractor and a content generator to copy content
ContentExtractor extractor = new ContentExtractor(inContent);
try (ContentGenerator generator = new ContentGenerator(outContent, false)) {
// Iterate over all content elements
for (ContentElement inElement : extractor) {
ContentElement outElement = null;
// Special treatment for group elements
if (inElement instanceof GroupElement) {
GroupElement inGroupElement = (GroupElement)inElement;
// Create empty output group element
GroupElement outGroupElement = GroupElement.copyWithoutContent(outDoc, inGroupElement);
outElement = outGroupElement;
// Call copyContentAndRemoveGlyphs() recursively for the group element's content
copyContentAndRemoveGlyphs(inGroupElement.getGroup().getContent(), outGroupElement.getGroup().getContent(), outDoc);
} else {
// Copy the content element to the output document
outElement = ContentElement.copy(outDoc, inElement);
if (outElement instanceof TextElement) {
// Special treatment for text element
TextElement outTextElement = (TextElement)outElement;
Text text = outTextElement.getText();
// Remove the first two glyphs from each text fragment
for (int iFragment = 0; iFragment < text.size(); ++iFragment) {
// Ensure that the fragment has more than two glyphs
if (text.get(iFragment).size() > 2) {
// Call remove twice
text.get(iFragment).remove(0);
text.get(iFragment).remove(0);
}
}
}
}
// Append the finished output element to the content generator
generator.appendContentElement(outElement);
}
}
}
def copy_document_data(in_doc: Document, out_doc: Document):
# Copy document-wide data
# Output intent
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# Metadata
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# Viewer settings
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# Associated files (for PDF/A-3 and PDF 2.0 only)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# Plain embedded files
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def copy_content_and_remove_glyphs(in_content: Content, out_content: Content, out_doc: Document):
"""Process content to remove the first two glyphs from text fragments."""
# Use a content extractor and a content generator to copy content
extractor = ContentExtractor(in_content)
with ContentGenerator(out_content, False) as generator:
# Iterate over all content elements
for in_element in extractor:
# Special treatment for group elements
if isinstance(in_element, GroupElement):
# Create empty output group element
out_group_element = GroupElement.copy_without_content(out_doc, in_element)
out_element = out_group_element
copy_content_and_remove_glyphs(in_element.group.content, out_group_element.group.content, out_doc)
else:
# Copy the content element to the output document
out_element = ContentElement.copy(out_doc, in_element)
if isinstance(out_element, TextElement):
# Special treatment for text element
text = out_element.text
# Remove the first two glyphs from each text fragment
for fragment in text:
# Ensure that the fragment has more than two glyphs
if len(fragment) > 2:
# Call RemoveAt twice
fragment.remove(0)
fragment.remove(0)
# Append the finished output element to the content generator
generator.append_content_element(out_element)
# Open input and create output documents
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# Create output document
with io.FileIO(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, in_doc.conformance, None) as out_doc:
# Copy document-wide data
copy_document_data(in_doc, out_doc)
# Process each page
for in_page in in_doc.pages:
# Create empty output page
out_page = Page.create(out_doc, in_page.size)
# Copy page content from input to output and remove glyphs
copy_content_and_remove_glyphs(in_page.content, out_page.content, out_doc)
# Add the new page to the output document's page list
out_doc.pages.append(out_page)
Remove white text from PDF
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// Create output document
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// Copy document-wide data
CopyDocumentData(inDoc, outDoc);
// Process each page
foreach (var inPage in inDoc.Pages)
{
// Create empty output page
Page outPage = Page.Create(outDoc, inPage.Size);
// Copy page content from input to output
CopyContent(inPage.Content, outPage.Content, outDoc);
// Add the new page to the output document's page list
outDoc.Pages.Add(outPage);
}
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// Copy document-wide data
// Output intent
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// Metadata
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// Viewer settings
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void CopyContent(Content inContent, Content outContent, Document outDoc)
{
// Use a content extractor and a content generator to copy content
ContentExtractor extractor = new ContentExtractor(inContent);
using ContentGenerator generator = new ContentGenerator(outContent, false);
// Iterate over all content elements
foreach (ContentElement inElement in extractor)
{
ContentElement outElement;
// Special treatment for group elements
if (inElement is GroupElement inGroupElement)
{
// Create empty output group element
GroupElement outGroupElement = GroupElement.CopyWithoutContent(outDoc, inGroupElement);
outElement = outGroupElement;
// Call CopyContent() recursively for the group element's content
CopyContent(inGroupElement.Group.Content, outGroupElement.Group.Content, outDoc);
}
else
{
// Copy the content element to the output document
outElement = ContentElement.Copy(outDoc, inElement);
if (outElement is TextElement outTextElement)
{
// Special treatment for text element
Text text = outTextElement.Text;
// Remove all those text fragments whose fill and stroke paint is white
for (int iFragment = text.Count - 1; iFragment >= 0; iFragment--)
{
TextFragment fragment = text[iFragment];
if ((fragment.Fill == null || IsWhite(fragment.Fill.Paint)) &&
(fragment.Stroke == null || IsWhite(fragment.Stroke.Paint)))
text.RemoveAt(iFragment);
}
// Prevent appending an empty text element
if (text.Count == 0)
outElement = null;
}
}
// Append the finished output element to the content generator
if (outElement != null)
generator.AppendContentElement(outElement);
}
}
private static bool IsWhite(Paint paint)
{
ColorSpace colorSpace = paint.ColorSpace;
if (colorSpace is DeviceGrayColorSpace || colorSpace is CalibratedGrayColorSpace ||
colorSpace is DeviceRgbColorSpace || colorSpace is CalibratedRgbColorSpace)
{
// These color spaces are additive: white is 1.0
return paint.Color.Min() == 1.0;
}
if (colorSpace is DeviceCmykColorSpace)
{
// This color space is subtractive: white is 0.0
return paint.Color.Max() == 0.0;
}
return false;
}
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null);
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (// Create output document
Document outDoc = Document.create(outStream, inDoc.getConformance(), null)) {
// Copy document-wide data
copyDocumentData(inDoc, outDoc);
// Process each page
for (Page inPage : inDoc.getPages()) {
// Create empty output page
Page outPage = Page.create(outDoc, inPage.getSize());
// Copy page content from input to output
copyContent(inPage.getContent(), outPage.getContent(), outDoc);
// Add page to output document
outDoc.getPages().add(outPage);
}
}
}
private static void copyDocumentData(Document inDoc, Document outDoc) throws ToolboxException, IOException {
// Copy document-wide data
// Output intent
if (inDoc.getOutputIntent() != null)
outDoc.setOutputIntent(IccBasedColorSpace.copy(outDoc, inDoc.getOutputIntent()));
// Metadata
outDoc.setMetadata(Metadata.copy(outDoc, inDoc.getMetadata()));
// Viewer settings
outDoc.setViewerSettings(ViewerSettings.copy(outDoc, inDoc.getViewerSettings()));
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.getAssociatedFiles();
for (FileReference inFileRef : inDoc.getAssociatedFiles())
outAssociatedFiles.add(FileReference.copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.getPlainEmbeddedFiles();
for (FileReference inFileRef : inDoc.getPlainEmbeddedFiles())
outEmbeddedFiles.add(FileReference.copy(outDoc, inFileRef));
}
private static void copyContent(Content inContent, Content outContent, Document outDoc) throws ToolboxException, IOException {
// Use a content extractor and a content generator to copy content
ContentExtractor extractor = new ContentExtractor(inContent);
try (ContentGenerator generator = new ContentGenerator(outContent, false)) {
// Iterate over all content elements
for (ContentElement inElement : extractor) {
ContentElement outElement = null;
// Special treatment for group elements
if (inElement instanceof GroupElement) {
GroupElement inGroupElement = (GroupElement)inElement;
// Create empty output group element
GroupElement outGroupElement = GroupElement.copyWithoutContent(outDoc, inGroupElement);
outElement = outGroupElement;
// Call copyContent() recursively for the group element's content
copyContent(inGroupElement.getGroup().getContent(), outGroupElement.getGroup().getContent(), outDoc);
} else {
// Copy the content element to the output document
outElement = ContentElement.copy(outDoc, inElement);
if (outElement instanceof TextElement) {
// Special treatment for text element
TextElement outTextElement = (TextElement)outElement;
Text text = outTextElement.getText();
// Remove all those text fragments whose fill and stroke paint is white
for (int iFragment = text.size() - 1; iFragment >= 0; iFragment--) {
TextFragment fragment = text.get(iFragment);
if ((fragment.getFill() == null || isWhite(fragment.getFill().getPaint())) &&
(fragment.getStroke() == null || isWhite(fragment.getStroke().getPaint())))
text.remove(iFragment);
}
// Prevent appending an empty text element
if (text.size() == 0)
outElement = null;
}
}
// Append the finished output element to the content generator
if (outElement != null)
generator.appendContentElement(outElement);
}
}
}
private static boolean isWhite(Paint paint) {
double[] color = paint.getColor();
ColorSpace colorSpace = paint.getColorSpace();
if (colorSpace instanceof DeviceGrayColorSpace || colorSpace instanceof CalibratedGrayColorSpace ||
colorSpace instanceof DeviceRgbColorSpace || colorSpace instanceof CalibratedRgbColorSpace) {
// These color spaces are additive: white is 1.0
for (double value : color)
if (value != 1.0)
return false;
return true;
}
if (colorSpace instanceof DeviceCmykColorSpace) {
// This color space is subtractive: white is 0.0
for (double value : color)
if (value != 0.0)
return false;
return true;
}
return false;
}
def copy_document_data(in_doc: Document, out_doc: Document):
# Copy document-wide data
# Output intent
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# Metadata
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# Viewer settings
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# Associated files (for PDF/A-3 and PDF 2.0 only)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# Plain embedded files
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def is_white(paint: Paint) -> bool:
"""Determine if a paint is white based on its color space."""
color_space = paint.color_space
color = paint.color
if isinstance(color_space, (DeviceGrayColorSpace, CalibratedGrayColorSpace, DeviceRgbColorSpace, CalibratedRgbColorSpace)):
# These color spaces are additive: white is 1.0
return min(color) == 1.0
if isinstance(color_space, DeviceCmykColorSpace):
# This color space is subtractive: white is 0.0
return max(color) == 0.0
return False
def copy_content_and_remove_white_text(in_content: Content, out_content: Content, out_doc: Document):
"""Process content to remove white text fragments."""
# Use a content extractor and a content generator to copy content
extractor = ContentExtractor(in_content)
with ContentGenerator(out_content, False) as generator:
# Iterate over all content elements
for in_element in extractor:
# Special treatment for group elements
if isinstance(in_element, GroupElement):
# Create empty output group element
out_group_element = GroupElement.copy_without_content(out_doc, in_element)
out_element = out_group_element
copy_content_and_remove_white_text(in_element.group.content, out_group_element.group.content, out_doc)
else:
# Copy the content element to the output document
out_element = ContentElement.copy(out_doc, in_element)
if isinstance(out_element, TextElement):
text = out_element.text
# Remove all those text fragments whose fill and stroke paint is white
for i_fragment in range(len(text) - 1, -1, -1):
fragment = text[i_fragment]
if ((fragment.fill is None or is_white(fragment.fill.paint)) and
(fragment.stroke is None or is_white(fragment.stroke.paint))):
text.remove(i_fragment)
# Prevent appending an empty text element
if len(text) == 0:
out_element = None
# Append the finished output element to the content generator
if out_element:
generator.append_content_element(out_element)
# Open input and create output documents
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# Create output document
with io.FileIO(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, in_doc.conformance, None) as out_doc:
# Copy document-wide data
copy_document_data(in_doc, out_doc)
# Process each page
for in_page in in_doc.pages:
# Create empty output page
out_page = Page.create(out_doc, in_page.size)
# Copy page content from input to output and remove white text
copy_content_and_remove_white_text(in_page.content, out_page.content, out_doc)
# Add the new page to the output document's page list
out_doc.pages.append(out_page)
Replace text fragment in PDF
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// Create output document
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// Copy document-wide data
CopyDocumentData(inDoc, outDoc);
// Process each page
foreach (var inPage in inDoc.Pages)
{
// Create empty output page
Page outPage = Page.Create(outDoc, inPage.Size);
// Copy page content from input to output and search for string
CopyContent(inPage.Content, outPage.Content, outDoc, searchString);
// If the text was found and deleted, add the replacement text
if (fragment != null)
AddText(outDoc, outPage, replString);
// Add the new page to the output document's page list
outDoc.Pages.Add(outPage);
}
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// Copy document-wide data
// Output intent
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// Metadata
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// Viewer settings
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void CopyContent(Content inContent, Content outContent, Document outDoc, string searchString)
{
// Use a content extractor and a content generator to copy content
ContentExtractor extractor = new ContentExtractor(inContent);
using ContentGenerator generator = new ContentGenerator(outContent, false);
// Iterate over all content elements
foreach (ContentElement inElement in extractor)
{
ContentElement outElement;
// Special treatment for group elements
if (inElement is GroupElement inGroupElement)
{
// Create empty output group element
GroupElement outGroupElement = GroupElement.CopyWithoutContent(outDoc, inGroupElement);
outElement = outGroupElement;
// Save transform for later restore
AffineTransform currentTransform = overallTransform;
// Update the transform
overallTransform.Concatenate(inGroupElement.Transform);
// Call CopyContent() recursively for the group element's content
CopyContent(inGroupElement.Group.Content, outGroupElement.Group.Content, outDoc, searchString);
// Restore the transform
overallTransform = currentTransform;
}
else
{
// Copy the content element to the output document
outElement = ContentElement.Copy(outDoc, inElement);
if (fragment == null && outElement is TextElement outTextElement)
{
// Special treatment for text element
Text text = outTextElement.Text;
// Find text fragment with string to replace
for (int iFragment = text.Count - 1; iFragment >= 0; iFragment--)
{
// In this sample, the fragment text must match in its entirety
if (text[iFragment].Text == searchString)
{
// Keep the found fragment for later use
fragment = text[iFragment];
// Update the transform
overallTransform.Concatenate(fragment.Transform);
// Remove the found text fragment from the output
text.RemoveAt(iFragment);
break;
}
}
// Prevent appending an empty text element
if (text.Count == 0)
outElement = null;
}
}
// Append the finished output element to the content generator
if (outElement != null)
generator.AppendContentElement(outElement);
}
}
private static void AddText(Document doc, Page page, string replString)
{
// Create a new text object
Text text = Text.Create(doc);
// Heuristic to map the extracted font base name to a font name and font family
string[] parts = fragment.Font.BaseFont.Split('-');
string family = parts[0];
string style = parts.Length > 1 ? parts[1] : null;
// Create a new font object
Font font = Font.CreateFromSystem(doc, family, style, true);
// Create a text generator and set the original fragment's properties
using (TextGenerator textGenerator = new TextGenerator(text, font, fragment.FontSize, null))
{
textGenerator.CharacterSpacing = fragment.CharacterSpacing;
textGenerator.WordSpacing = fragment.WordSpacing;
textGenerator.HorizontalScaling = fragment.HorizontalScaling;
textGenerator.Rise = fragment.Rise;
textGenerator.Show(replString);
}
// Create a content generator
using ContentGenerator contentGenerator = new ContentGenerator(page.Content, false);
// Apply the computed transform
contentGenerator.Transform(overallTransform);
// Paint the new text
contentGenerator.PaintText(text);
}
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null);
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (// Create output document
Document outDoc = Document.create(outStream, inDoc.getConformance(), null)) {
// Copy document-wide data
copyDocumentData(inDoc, outDoc);
// Process each page
for (Page inPage : inDoc.getPages()) {
// Create empty output page
Page outPage = Page.create(outDoc, inPage.getSize());
// Copy page content from input to output and search for string
copyContent(inPage.getContent(), outPage.getContent(), outDoc, searchString);
// If the text was found and deleted, add the replacement text
if (fragment != null)
addText(outDoc, outPage, replString);
// Add page to output document
outDoc.getPages().add(outPage);
}
}
}
private static void copyDocumentData(Document inDoc, Document outDoc) throws ToolboxException, IOException {
// Copy document-wide data
// Output intent
if (inDoc.getOutputIntent() != null)
outDoc.setOutputIntent(IccBasedColorSpace.copy(outDoc, inDoc.getOutputIntent()));
// Metadata
outDoc.setMetadata(Metadata.copy(outDoc, inDoc.getMetadata()));
// Viewer settings
outDoc.setViewerSettings(ViewerSettings.copy(outDoc, inDoc.getViewerSettings()));
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.getAssociatedFiles();
for (FileReference inFileRef : inDoc.getAssociatedFiles())
outAssociatedFiles.add(FileReference.copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.getPlainEmbeddedFiles();
for (FileReference inFileRef : inDoc.getPlainEmbeddedFiles())
outEmbeddedFiles.add(FileReference.copy(outDoc, inFileRef));
}
private static void copyContent(Content inContent, Content outContent, Document outDoc, String searchString) throws ToolboxException, IOException {
// Use a content extractor and a content generator to copy content
ContentExtractor extractor = new ContentExtractor(inContent);
try (ContentGenerator generator = new ContentGenerator(outContent, false)) {
// Iterate over all content elements
for (ContentElement inElement : extractor) {
ContentElement outElement = null;
// Special treatment for group elements
if (inElement instanceof GroupElement) {
GroupElement inGroupElement = (GroupElement)inElement;
// Create empty output group element
GroupElement outGroupElement = GroupElement.copyWithoutContent(outDoc, inGroupElement);
outElement = outGroupElement;
// Save transform for later restor
AffineTransform currentTransform = overallTransform;
// Update the transform
overallTransform.concatenate(inGroupElement.getTransform());
// Call copyContent() recursively for the group element's content
copyContent(inGroupElement.getGroup().getContent(), outGroupElement.getGroup().getContent(), outDoc, searchString);
// Restor the transform
overallTransform = currentTransform;
} else {
// Copy the content element to the output document
outElement = ContentElement.copy(outDoc, inElement);
if (fragment == null && outElement instanceof TextElement) {
// Special treatment for text element
TextElement outTextElement = (TextElement)outElement;
Text text = outTextElement.getText();
// Find text fragment with string to replace
for (int iFragment = text.size() - 1; iFragment >= 0; iFragment--) {
// In this sample, the fragment text must match in its entirety
if (text.get(iFragment).getText().equals(searchString)) {
// Keep the found fragment for later use
fragment = text.get(iFragment);
// Update the transform
overallTransform.concatenate(fragment.getTransform());
// Remove the found text fragment from the output
text.remove(iFragment);
break;
}
}
// Prevent appending an empty text element
if (text.size() == 0)
outElement = null;
}
}
// Append the finished output element to the content generator
if (outElement != null)
generator.appendContentElement(outElement);
}
}
}
private static void addText(Document doc, Page page, String replString) throws CorruptException, ToolboxException, IOException {
// Create a new text object
Text text = Text.create(doc);
// Heuristic to map the extracted fon base name to a font family and font style
String[] parts = fragment.getFont().getBaseFont().split("-");
String family = parts[0];
String style = parts.length > 1 ? parts[1] : null;
// Create a new font object
Font font = Font.createFromSystem(doc, family, style, true);
// Create a text generator and set the original fragment's properties
try (TextGenerator textGenerator = new TextGenerator(text, font, fragment.getFontSize(), null)) {
textGenerator.setCharacterSpacing(fragment.getCharacterSpacing());
textGenerator.setWordSpacing(fragment.getWordSpacing());
textGenerator.setHorizontalScaling(fragment.getHorizontalScaling());
textGenerator.setRise(fragment.getRise());
textGenerator.show(replString);
}
// Create a content generator
try (ContentGenerator contentGenerator = new ContentGenerator(page.getContent(), false)) {
// Apply the computed transform
contentGenerator.transform(overallTransform);
// Paint the new text
contentGenerator.paintText(text);
}
}
def copy_document_data(in_doc: Document, out_doc: Document):
# Copy document-wide data
# Output intent
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# Metadata
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# Viewer settings
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# Associated files (for PDF/A-3 and PDF 2.0 only)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# Plain embedded files
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def copy_content_and_remove_text(in_content: Content, out_content: Content, out_doc: Document, search_text: str):
"""Process content to find and remove a specific text fragment."""
global overall_transform, fragment
# Use a content extractor and a content generator to copy content
extractor = ContentExtractor(in_content)
with ContentGenerator(out_content, False) as generator:
# Iterate over all content elements
for in_element in extractor:
# Special treatment for group elements
if isinstance(in_element, GroupElement):
out_group_element = GroupElement.copy_without_content(out_doc, in_element)
out_element = out_group_element
# Save transform for later restore
current_transform = overall_transform
# Update the transform
copy_content_and_remove_text(in_element.group.content, out_group_element.group.content, out_doc, search_text)
# Restore the transform
overall_transform = current_transform
else:
# Copy the content element to the output document
out_element = ContentElement.copy(out_doc, in_element)
if isinstance(out_element, TextElement) and fragment is None:
# Special treatment for text element
text = out_element.text
# Find text fragment with string to replace
for index_fragment in range(len(text) - 1, -1, -1):
# In this sample, the fragment text must match in its entirety (Text might contain null characters)
if text[index_fragment].text.replace("\x00", "") == search_text:
# Keep the found fragment for later use
fragment = text[index_fragment]
# Update the transform
overall_transform.concatenate(fragment.transform)
# Remove the fragment from the text element
text.remove(index_fragment)
# Prevent appending an empty text element
if len(text) == 0:
out_element = None
# Append the finished output element to the content generator
if out_element:
generator.append_content_element(out_element)
def add_text(out_doc: Document, page, replacement_text):
"""Add the replacement text at the location of the removed fragment."""
# Create a new text object
text = Text.create(out_doc)
# Heuristic to map the extracted font base name to a font name and font family
font_parts = fragment.font.base_font.split("-")
font_family = font_parts[0]
font_style = font_parts[1] if len(font_parts) > 1 else None
# Create a new font object
font = Font.create_from_system(out_doc, font_family, font_style, True)
# Create a text generator and set the original fragment's properties
with TextGenerator(text, font, fragment.font_size, None) as text_gen:
text_gen.character_spacing = fragment.character_spacing
text_gen.word_spacing = fragment.word_spacing
text_gen.horizontal_scaling = fragment.horizontal_scaling
text_gen.rise = fragment.rise
text_gen.show(replacement_text)
# Create a content generator
with ContentGenerator(page.content, False) as content_gen:
# Apply the computed transform
content_gen.transform(overall_transform)
# Paint the new text
content_gen.paint_text(text)
# Define global variables
overall_transform = AffineTransform.get_identity()
fragment = None
search_string = "Muster Company AG"
replacement_string = "Replacement String"
# Open input document
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# Create output document
with io.FileIO(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, in_doc.conformance, None) as out_doc:
# Copy document-wide data
copy_document_data(in_doc, out_doc)
# Process each page
for in_page in in_doc.pages:
# Create empty output page
out_page = Page.create(out_doc, in_page.size)
# Copy page content from input to output and search for string
copy_content_and_remove_text(in_page.content, out_page.content, out_doc, search_string)
# If the text was found and deleted, add the replacement text
if fragment:
add_text(out_doc, out_page, replacement_string)
# Add the new page to the output document's page list
out_doc.pages.append(out_page)
Custom validation
Validate custom properties of a PDF file
var iniFile = new IniFile(args[1]);
var password = args.Length == 3 ? args[2] : null;
var documentValidator = new DocumentValidator(iniFile, args[0], password);
try
{
if (documentValidator.ValidateDocument())
Console.WriteLine("\nThe document does conform the specified properties.");
else
Console.WriteLine("\nThe document does not conform the specified properties.");
}
catch (Exception ex)
{
Console.WriteLine("The document could not be validated. The following error happened: " + ex.Message);
return;
}
public class IniFile
{
private Dictionary<string, Dictionary<string, string>> _data;
public IniFile(string path)
{
_data = new Dictionary<string, Dictionary<string, string>>();
Load(path);
}
private void Load(string path)
{
var lines = File.ReadAllLines(path);
var currentSection = "";
foreach (var line in lines)
{
var trimmedLine = line.Trim();
if (string.IsNullOrEmpty(trimmedLine) || trimmedLine.StartsWith(";") || trimmedLine.StartsWith("#"))
{
continue; // Skip empty lines and comments
}
if (trimmedLine.StartsWith("[") && trimmedLine.EndsWith("]"))
{
currentSection = trimmedLine.Substring(1, trimmedLine.Length - 2).Trim();
if (!_data.ContainsKey(currentSection))
{
_data[currentSection] = new Dictionary<string, string>();
}
else
{
throw new FormatException("Duplicate section: " + currentSection);
}
}
else if (currentSection != null)
{
var keyValuePair = trimmedLine.Split(new[] { '=' });
if (keyValuePair.Length == 2)
{
var key = keyValuePair[0].Trim();
var value = keyValuePair[1].Trim();
_data[currentSection][key] = value;
}
}
}
}
public string? GetValue(string section, string key, string? defaultValue = null)
{
if (_data.TryGetValue(section, out var sectionData))
{
if (sectionData.TryGetValue(key, out var value))
{
return value;
}
}
return defaultValue;
}
public List<string> GetKeysMatchingPattern(string section, string pattern)
{
var matchingKeys = new List<string>();
if (_data.TryGetValue(section, out var sectionData))
{
foreach (var key in sectionData.Keys)
{
if (Regex.IsMatch(key, pattern, RegexOptions.IgnoreCase))
{
matchingKeys.Add(sectionData[key]);
}
}
}
return matchingKeys;
}
}
public class DocumentValidator
{
private readonly IniFile _iniFile;
private readonly string _inputPath;
private readonly string? _pdfPassword;
// Tolerance used for size comparison: default 3pt
private string _sizeTolerance = "3.0";
private string? _iniMaxPageSize;
private string? _iniMaxPdfVersionStr;
private string? _iniEncryption;
private string? _iniFileSize;
private string? _iniEmbedding;
private readonly List<string> _embeddingExceptionFonts;
public DocumentValidator(IniFile iniFile, string inputPath, string? pdfPassword = null)
{
_iniFile = iniFile;
_inputPath = inputPath;
_pdfPassword = pdfPassword;
// Extract values from INI file
string? iniSizeTolerance = iniFile.GetValue("Pages", "SizeTolerance");
_sizeTolerance = !string.IsNullOrEmpty(iniSizeTolerance) ? iniSizeTolerance : _sizeTolerance;
_iniMaxPageSize = _iniFile.GetValue("Pages", "MaxPageSize");
_iniMaxPdfVersionStr = _iniFile.GetValue("File", "MaxPdfVersion");
_iniEncryption = _iniFile.GetValue("File", "Encryption");
_iniFileSize = _iniFile.GetValue("File", "FileSize");
_iniEmbedding = _iniFile.GetValue("Fonts", "Embedding");
_embeddingExceptionFonts = _iniFile.GetKeysMatchingPattern("Fonts", @"EmbeddingExcFont\d+");
}
public bool ValidateDocument()
{
var isValid = ValidateFileSize();
try
{
using var inpath = File.OpenRead(_inputPath);
using var inDoc = Document.Open(inpath, _pdfPassword);
isValid &= ValidateConformance(inDoc.Conformance);
isValid &= ValidateEncryption(inDoc.Permissions);
isValid &= ValidatePagesSize(inDoc);
isValid &= ValidateFonts(inDoc);
}
catch (PasswordException)
{
if (_pdfPassword == null)
Console.WriteLine("The content of the document could not be validated as it is password protected. Please provide a password.");
else
Console.WriteLine("The content of the document could not be validated as the password provided is not correct.");
return false;
}
return isValid;
}
private bool ValidateFileSize()
{
var fileInfo = new FileInfo(_inputPath);
var fileSizeInMB = fileInfo.Length / (1024.0 * 1024.0);
if (_iniFileSize != null)
{
var iniFileSizeInMB = Convert.ToDouble(_iniFileSize);
if (fileSizeInMB <= iniFileSizeInMB)
{
Console.WriteLine("The PDF file size does not exceed the specified custom limit.");
return true;
}
else
{
Console.WriteLine("The PDF file size exceeds the specified custom limit.");
return false;
}
}
return true;
}
private bool ValidateConformance(Conformance currentConformance)
{
if (_iniMaxPdfVersionStr != null)
{
if (ConformanceValidator.ValidateConformance(_iniMaxPdfVersionStr, currentConformance))
{
Console.WriteLine("The PDF version does not exceed the specified custom maximum version.");
return true;
}
else
{
Console.WriteLine("The PDF version exceeds the specified custom maximum version.");
return false;
}
}
return true;
}
private bool ValidateEncryption(Permission? permissions)
{
if (_iniEncryption != null)
{
if (_iniEncryption.ToLower() == "true" && permissions == null)
{
Console.WriteLine("Encryption not conform: the PDF file is not encrypted. The custom encryption value specifies that the PDF file should be encrypted.");
return false;
}
else if (_iniEncryption.ToLower() == "false" && permissions != null)
{
Console.WriteLine("Encryption not conform: the PDF file is encrypted. The custom encryption value specifies that the PDF file should not be encrypted.");
return false;
}
else
{
Console.WriteLine("The PDF encryption is conform to the specified custom value.");
return true;
}
}
return true;
}
private bool ValidatePagesSize(Document inDoc)
{
var isValid = true;
if (_iniMaxPageSize != null)
{
var pageNumber = 0;
foreach (var page in inDoc.Pages)
{
pageNumber++;
var sizeWithInt = new Size { Width = (int)page.Size.Width, Height = (int)page.Size.Height };
isValid &= ValidatePageSize(pageNumber, sizeWithInt);
}
}
return isValid;
}
private bool ValidatePageSize(int pageNumber, Size pageSize)
{
if (_iniMaxPageSize != null)
{
var validator = new PageSizeValidator(_iniMaxPageSize, _sizeTolerance);
if (validator.ValidatePageSize(pageNumber, pageSize))
{
Console.WriteLine("The size of page " + pageNumber + " is within the specified custom maximum page size value.");
return true;
}
else
{
Console.WriteLine("The size of page " + pageNumber + " exceeds the specified custom maximum page size value.");
return false;
}
}
return true;
}
private bool ValidateFonts(Document inDoc)
{
var isValid = true;
if (_iniEmbedding != null)
{
var embeddingRequired = _iniEmbedding.ToLower() == "true";
var pageNumber = 0;
foreach (var page in inDoc.Pages)
{
pageNumber++;
var extractor = new ContentExtractor(page.Content)
{
Ungrouping = UngroupingSelection.SafelyUngroupable
};
foreach (ContentElement element in extractor)
{
if (element is TextElement textElement)
{
foreach (var fragment in textElement.Text)
{
var fontName = fragment.Font.BaseFont;
var isEmbedded = fragment.Font.IsEmbedded;
// Check if the font is in the exception list
var isCurrentFontAnException = _embeddingExceptionFonts.Exists(exception => Regex.IsMatch(fontName, exception.Replace("*", ".*"), RegexOptions.IgnoreCase));
// Validate based on the embedding setting
// _iniEmbedding = true => The font has to be embedded or it should appear in the exception list
// _iniEmbedding = false => The font cannot be embedded or it should appear in the exception list
if ((embeddingRequired && !isEmbedded && !isCurrentFontAnException) || (!embeddingRequired && isEmbedded && !isCurrentFontAnException))
{
isValid = false;
var statusText = embeddingRequired ? "be embedded" : "not be embedded";
Console.WriteLine("The font '" + fontName + "' on page " + pageNumber + " should " + statusText + " as specified by the property 'Embedding' or it should be added to the list of exceptions.");
}
else
{
var statusText = embeddingRequired != isEmbedded ? "in the exception list" : isEmbedded ? "embedded" : "not embedded";
Console.WriteLine("The font '" + fontName + "' on page " + pageNumber + " is conform to the 'Embedding' property as it is " + statusText + ".");
}
}
}
}
}
}
return isValid;
}
}
public class PageSizeValidator
{
private readonly Size maxSize;
private readonly double sizeTolerance;
// Named page sizes like "Letter", "A4", etc.
private static readonly Dictionary<string, Size> NamedPageSizes = new Dictionary<string, Size>(StringComparer.OrdinalIgnoreCase)
{
{ "Letter", new Size { Width = 612, Height = 792 } }, // 8.5 x 11 inches in points
{ "A0", new Size { Width = 2384, Height = 3370 } },
{ "A1", new Size { Width = 1684, Height = 2384 } },
{ "A2", new Size { Width = 1191, Height = 1684 } },
{ "A3", new Size { Width = 842, Height = 1191 } },
{ "A4", new Size { Width = 595, Height = 842 } }, // 210 x 297 mm in points
{ "A5", new Size { Width = 420, Height = 595 } },
{ "A6", new Size { Width = 298, Height = 420 } },
{ "A7", new Size { Width = 210, Height = 298 } },
{ "A8", new Size { Width = 147, Height = 210 } },
{ "A9", new Size { Width = 105, Height = 147 } },
{ "A10", new Size { Width = 74, Height = 105 } },
{ "DL", new Size { Width = 283, Height = 595 } } // 99 x 210 mm in points
};
public PageSizeValidator(string maxPageSizeStr, string sizeToleranceStr)
{
maxSize = ParsePageSize(maxPageSizeStr);
sizeTolerance = ParseSizeTolerance(sizeToleranceStr);
}
private Size ParsePageSize(string maxPageSize)
{
// First, check if it's a named size
if (NamedPageSizes.TryGetValue(maxPageSize, out var namedSize))
{
return namedSize;
}
// If not a named size, try to parse it as a custom size
var match = Regex.Match(maxPageSize, @"(\d+(\.\d+)?)\s*x\s*(\d+(\.\d+)?)(\s*(pt|in|cm|mm))?", RegexOptions.IgnoreCase);
if (!match.Success) throw new ArgumentException("Invalid MaxPageSize format: " + maxPageSize);
double width = double.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture);
double height = double.Parse(match.Groups[3].Value, CultureInfo.InvariantCulture);
string unit = match.Groups[6].Value.ToLower();
return unit switch
{
"in" => new Size { Width = (int)(width * 72), Height = (int)(height * 72) },
"cm" => new Size { Width = (int)(width * 28.3465), Height = (int)(height * 28.3465) },
"mm" => new Size { Width = (int)(width * 2.83465), Height = (int)(height * 2.83465) },
"pt" or "" => new Size { Width = (int)width, Height = (int)height },
_ => throw new ArgumentException("Unsupported unit: " + unit),
};
}
private double ParseSizeTolerance(string sizeToleranceStr)
{
if (string.IsNullOrEmpty(sizeToleranceStr)) return 3; // Default tolerance in points
var match = Regex.Match(sizeToleranceStr, @"(\d+(\.\d+)?)\s*(%)?", RegexOptions.IgnoreCase);
if (!match.Success) throw new ArgumentException("Invalid SizeTolerance format: " + sizeToleranceStr);
double value = double.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture);
return match.Groups[3].Success ? value / 100.0 : value; // Percentage tolerance or direct value
}
public bool ValidatePageSize(int pageNumber, Size actualSize)
{
// Check both portrait and landscape orientations
bool isValid = (actualSize.Width <= maxSize.Width + sizeTolerance && actualSize.Height <= maxSize.Height + sizeTolerance) ||
(actualSize.Height <= maxSize.Width + sizeTolerance && actualSize.Width <= maxSize.Height + sizeTolerance);
return isValid;
}
}
public class ConformanceValidator
{
private static readonly Dictionary<string, Conformance> VersionMap = new Dictionary<string, Conformance>(StringComparer.OrdinalIgnoreCase)
{
{ "1.0", Conformance.Pdf10 },
{ "1.1", Conformance.Pdf11 },
{ "1.2", Conformance.Pdf12 },
{ "1.3", Conformance.Pdf13 },
{ "1.4", Conformance.Pdf14 },
{ "1.5", Conformance.Pdf15 },
{ "1.6", Conformance.Pdf16 },
{ "1.7", Conformance.Pdf17 },
{ "2.0", Conformance.Pdf20 }
};
public static Conformance ParseVersionString(string version)
{
// Split the version string into parts based on the '.' delimiter
string[] versionParts = version.Split('.');
// Ensure there are only two parts (major and minor)
if (versionParts.Length == 2)
{
// Construct the major.minor version string (e.g., "1.7")
string majorMinorVersion = versionParts[0] + "." + versionParts[1];
// Try to get the corresponding Conformance enum value from the dictionary
if (VersionMap.TryGetValue(majorMinorVersion, out Conformance conformance))
{
return conformance;
}
}
// If the version is not supported, throw an exception
throw new ArgumentException("Unsupported version or conformance level: " + version);
}
public static bool ValidateConformance(string maxPdfVersionStr, Conformance currentConformance)
{
var maxPdfConformance = ParseVersionString(maxPdfVersionStr);
// Convert the current conformance level to the corresponding PDF version (Major.Minor) as it can be based on the PDF/A version
var currentConformanceVersion = GetVersionFromConformance(currentConformance);
return (int)currentConformanceVersion <= (int)maxPdfConformance;
}
public static Conformance GetVersionFromConformance(Conformance conformance)
{
if (VersionMap.ContainsValue(conformance))
{
return conformance;
}
switch (conformance)
{
case Conformance.PdfA1A:
case Conformance.PdfA1B:
return Conformance.Pdf14; // PDF/A-1 is based on PDF 1.4
case Conformance.PdfA2A:
case Conformance.PdfA2B:
case Conformance.PdfA2U:
case Conformance.PdfA3A:
case Conformance.PdfA3B:
case Conformance.PdfA3U:
return Conformance.Pdf17; // PDF/A-2 and PDF/A-3 are based on PDF 1.7
default:
throw new ArgumentException("Unsupported conformance level: " + conformance.ToString());
}
}
}
String pdfPath = args[0];
String iniPath = args[1];
String password = null;
if (args.length == 3)
password = args[2];
IniFile iniFile = new IniFile(iniPath);
DocumentValidator documentValidator = new DocumentValidator(iniFile, pdfPath, password);
try {
if (documentValidator.validateDocument())
System.out.println("\nThe document does conform the specified properties.");
else
System.out.println("\nThe document does not conform the specified properties.");
}
catch(Exception e) {
System.out.println("The document could not be validated. The following error happened: " + e.getMessage());
System.exit(-1);
}
public static class IniFile {
private final Map<String, Map<String, String>> sections = new LinkedHashMap<>();
public IniFile(String path) throws IOException {
load(path);
}
private void load(String path) throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
String currentSection = null;
String line;
while ((line = reader.readLine()) != null) {
line = line.trim();
if (line.isEmpty() || line.startsWith(";") || line.startsWith("#")) {
// Skip empty lines and comments
continue;
}
if (line.startsWith("[") && line.endsWith("]")) {
// New section
currentSection = line.substring(1, line.length() - 1).trim();
sections.putIfAbsent(currentSection, new LinkedHashMap<>());
} else if (currentSection != null) {
// Key-value pair within a section
String[] keyValue = line.split("=", 2);
if (keyValue.length == 2) {
sections.get(currentSection).put(keyValue[0].trim(), keyValue[1].trim());
}
}
}
}
}
public String getValue(String section, String key, String defaultValue) {
Map<String, String> sectionData = sections.get(section);
if (sectionData != null) {
return sectionData.getOrDefault(key, defaultValue);
}
return defaultValue;
}
public String getValue(String section, String key) {
return getValue(section, key, null);
}
public List<String> getKeysMatchingPattern(String section, String pattern) {
List<String> matchingKeys = new ArrayList<>();
Map<String, String> sectionData = sections.get(section);
if (sectionData != null) {
Pattern regexPattern = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
for (String key : sectionData.keySet()) {
Matcher matcher = regexPattern.matcher(key);
if (matcher.find()) {
matchingKeys.add(sectionData.get(key));
}
}
}
return matchingKeys;
}
}
public static class DocumentValidator {
private final String inputPath;
private String pdfPassword;
// Tolerance used for size comparison: default 3pt
private String sizeTolerance = "3.0";
private String iniMaxPageSize;
private String iniMaxPdfVersionStr;
private String iniEncryption;
private String iniFileSize;
private String iniEmbedding;
private final List<String> embeddingExceptionFonts;
public DocumentValidator(IniFile iniFile, String inputPath, String pdfPassword) {
this.inputPath = inputPath;
this.pdfPassword = pdfPassword;
// Extract values from INI file
String iniSizeTolerance = iniFile.getValue("Pages", "SizeTolerance");
this.sizeTolerance = (iniSizeTolerance != null && !iniSizeTolerance.isEmpty()) ? iniSizeTolerance : this.sizeTolerance;
this.iniMaxPageSize = iniFile.getValue("Pages", "MaxPageSize");
this.iniMaxPdfVersionStr = iniFile.getValue("File", "MaxPdfVersion");
this.iniEncryption = iniFile.getValue("File", "Encryption");
this.iniFileSize = iniFile.getValue("File", "FileSize");
this.iniEmbedding = iniFile.getValue("Fonts", "Embedding");
this.embeddingExceptionFonts = iniFile.getKeysMatchingPattern("Fonts", "EmbeddingExcFont\\d+");
}
public boolean validateDocument() throws IOException, CorruptException, ConformanceException, UnsupportedFeatureException, ToolboxException {
boolean isValid = validateFileSize(inputPath);
try (FileStream inStream = new FileStream(inputPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, pdfPassword)) {
isValid &= validateConformance(inDoc.getConformance());
isValid &= validateEncryption(inDoc.getPermissions());
isValid &= validatePagesSize(inDoc);
isValid &= validateFonts(inDoc);
}
catch(PasswordException e) {
if (pdfPassword == null)
System.out.println("The content of the document could not be validated as it is password protected. Please provide a password.");
else
System.out.println("The content of the document could not be validated as the password provided is not correct.");
return false;
}
return isValid;
}
private boolean validateFileSize(String inputPath) {
File file = new File(inputPath);
double fileSizeInMB = file.length() / (1024.0 * 1024.0);
if (iniFileSize != null) {
double iniFileSizeInMB = Double.parseDouble(iniFileSize);
if (fileSizeInMB <= iniFileSizeInMB) {
System.out.println("The PDF file size does not exceed the specified custom limit.");
return true;
} else {
System.out.println("The PDF file size exceeds the specified custom limit.");
return false;
}
}
return true;
}
private boolean validateConformance(Conformance currentConformance) {
if (iniMaxPdfVersionStr != null) {
if (ConformanceValidator.validateConformance(iniMaxPdfVersionStr, currentConformance)) {
System.out.println("The PDF version does not exceed the specified custom maximum version.");
return true;
} else {
System.out.println("The PDF version exceeds the specified custom maximum version.");
return false;
}
}
return true;
}
private boolean validateEncryption(EnumSet<Permission> enumSet) {
if (iniEncryption != null) {
boolean isEncrypted = enumSet != null;
if ("true".equalsIgnoreCase(iniEncryption) && !isEncrypted) {
System.out.println("Encryption not conform: the PDF file is not encrypted. The custom encryption value specifies that the PDF file should be encrypted.");
return false;
} else if ("false".equalsIgnoreCase(iniEncryption) && isEncrypted) {
System.out.println("Encryption not conform: the PDF file is encrypted. The custom encryption value specifies that the PDF file should not be encrypted.");
return false;
} else {
System.out.println("The PDF encryption is conform to the specified custom value.");
return true;
}
}
return true;
}
private boolean validatePagesSize(Document inDoc) {
boolean isValid = true;
if (iniMaxPageSize != null) {
int pageNumber = 0;
for (Page page : inDoc.getPages()) {
pageNumber++;
com.pdftools.toolbox.geometry.real.Size pageSize = page.getSize();
isValid &= validatePageSize(pageNumber, pageSize);
}
}
return isValid;
}
private boolean validatePageSize(int pageNumber, com.pdftools.toolbox.geometry.real.Size pageSize) {
if (iniMaxPageSize != null) {
PageSizeValidator validator = new PageSizeValidator(iniMaxPageSize, sizeTolerance);
if (validator.validatePageSize(pageSize.getWidth(), pageSize.getHeight())) {
System.out.println(String.format("The size of page %d is within the specified custom maximum page size value.", pageNumber));
return true;
} else {
System.out.println(String.format("The size of page %d exceeds the specified custom maximum page size value.", pageNumber));
return false;
}
}
return true;
}
public boolean validateFonts(Document inDoc) throws CorruptException, IOException {
boolean isValid = true;
if (iniEmbedding != null)
{
boolean embeddingRequired = "true".equalsIgnoreCase(iniEmbedding);
int pageNumber = 0;
for (Page page : inDoc.getPages()) {
pageNumber++;
ContentExtractor extractor = new ContentExtractor(page.getContent());
extractor.setUngrouping(UngroupingSelection.ALL);
for (ContentElement element : extractor) {
if (element instanceof TextElement) {
TextElement textElement = (TextElement) element;
Text text = textElement.getText();
for (int iFragment = 0; iFragment < text.size(); iFragment++) {
TextFragment currFragment = text.get(iFragment);
String fontName = currFragment.getFont().getBaseFont();
boolean isEmbedded = currFragment.getFont().getIsEmbedded();
// Check if the font is in the exception list
boolean isCurrentFontAnException = embeddingExceptionFonts.stream()
.anyMatch(exception -> Pattern.compile(exception.replace("*", ".*"), Pattern.CASE_INSENSITIVE).matcher(fontName).matches());
// Validate based on the embedding setting
// _iniEmbedding = true => The font has to be embedded or it should appear in the exception list
// _iniEmbedding = false => The font cannot be embedded or it should appear in the exception list
if ((embeddingRequired && !isEmbedded && !isCurrentFontAnException) || (!embeddingRequired && isEmbedded && !isCurrentFontAnException)) {
isValid = false;
String statusText = embeddingRequired ? "be embedded" : "not be embedded";
System.out.println("The font '" + fontName + "' on page " + pageNumber + " should " + statusText + " as specified by the property 'Embedding' or it should be added to the list of exceptions.");
}
else {
String statusText = embeddingRequired != isEmbedded ? "in the exception list" : isEmbedded ? "embedded" : "not embedded";
System.out.println("The font '" + fontName + "' on page " + pageNumber + " is conform to the 'Embedding' property as it is " + statusText + ".");
}
}
}
}
}
}
return isValid;
}
}
public static class ConformanceValidator {
private static final Map<String, Conformance> versionMap = new HashMap<>();
static {
versionMap.put("1.0", Conformance.PDF10);
versionMap.put("1.1", Conformance.PDF11);
versionMap.put("1.2", Conformance.PDF12);
versionMap.put("1.3", Conformance.PDF13);
versionMap.put("1.4", Conformance.PDF14);
versionMap.put("1.5", Conformance.PDF15);
versionMap.put("1.6", Conformance.PDF16);
versionMap.put("1.7", Conformance.PDF17);
versionMap.put("2.0", Conformance.PDF20);
}
public static Conformance parseVersionString(String version) {
// Extract the major and minor version numbers (e.g., "1.7")
String[] versionParts = version.split("\\.");
if (versionParts.length == 2) {
String majorMinorVersion = versionParts[0] + "." + versionParts[1];
Conformance conformance = versionMap.get(majorMinorVersion);
if (conformance != null) {
return conformance;
}
}
throw new IllegalArgumentException("Unsupported version or conformance level: " + version);
}
public static boolean validateConformance(String maxPdfVersionStr, Conformance currentConformance) {
Conformance maxPdfConformance = parseVersionString(maxPdfVersionStr);
// Convert the current conformance level to the corresponding PDF version (Major.Minor) as it can be based on the PDF/A version
Conformance currentConformanceVersion = getVersionFromConformance(currentConformance);
return currentConformanceVersion.ordinal() <= maxPdfConformance.ordinal();
}
public static Conformance getVersionFromConformance(Conformance conformance) {
if (versionMap.containsValue(conformance)) {
return conformance;
}
switch (conformance) {
case PDF_A1_A:
case PDF_A1_B:
return Conformance.PDF14; // PDF/A-1 is based on PDF 1.4
case PDF_A2_A:
case PDF_A2_B:
case PDF_A2_U:
case PDF_A3_A:
case PDF_A3_B:
case PDF_A3_U:
return Conformance.PDF17; // PDF/A-2 and PDF/A-3 are based on PDF 1.7
default:
throw new IllegalArgumentException("Unsupported conformance level: " + conformance);
}
}
}
public static class PageSizeValidator {
private final double maxWidth;
private final double maxHeight;
private final double sizeTolerance;
// Named page sizes like "Letter", "A4", etc.
private static final Map<String, double[]> NAMED_PAGE_SIZES = new HashMap<>();
static {
NAMED_PAGE_SIZES.put("Letter", new double[]{612, 792}); // 8.5 x 11 inches in points
NAMED_PAGE_SIZES.put("A0", new double[]{2384, 3370});
NAMED_PAGE_SIZES.put("A1", new double[]{1684, 2384});
NAMED_PAGE_SIZES.put("A2", new double[]{1191, 1684});
NAMED_PAGE_SIZES.put("A3", new double[]{842, 1191});
NAMED_PAGE_SIZES.put("A4", new double[]{595, 842}); // 210 x 297 mm in points
NAMED_PAGE_SIZES.put("A5", new double[]{420, 595});
NAMED_PAGE_SIZES.put("A6", new double[]{298, 420});
NAMED_PAGE_SIZES.put("A7", new double[]{210, 298});
NAMED_PAGE_SIZES.put("A8", new double[]{147, 210});
NAMED_PAGE_SIZES.put("A9", new double[]{105, 147});
NAMED_PAGE_SIZES.put("A10", new double[]{74, 105});
NAMED_PAGE_SIZES.put("DL", new double[]{283, 595}); // 99 x 210 mm in points
}
public PageSizeValidator(String maxPageSize, String sizeToleranceStr) {
double[] size = parsePageSize(maxPageSize);
this.maxWidth = size[0];
this.maxHeight = size[1];
this.sizeTolerance = parseSizeTolerance(sizeToleranceStr);
}
private double[] parsePageSize(String maxPageSize) {
if (maxPageSize == null || maxPageSize.isEmpty()) {
throw new IllegalArgumentException("MaxPageSize cannot be null or empty");
}
// First, check if it's a named size
if (NAMED_PAGE_SIZES.containsKey(maxPageSize)) {
return NAMED_PAGE_SIZES.get(maxPageSize);
}
// If not a named size, try to parse it as a custom size
Pattern pattern = Pattern.compile("(\\d+(\\.\\d+)?)\\s*x\\s*(\\d+(\\.\\d+)?)(\\s*(pt|in|cm|mm))?", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(maxPageSize);
if (!matcher.matches()) {
throw new IllegalArgumentException("Invalid MaxPageSize format: " + maxPageSize);
}
double width = Double.parseDouble(matcher.group(1));
double height = Double.parseDouble(matcher.group(3));
String unit = matcher.group(6).toLowerCase();
switch (unit) {
case "in":
return new double[]{width * 72, height * 72};
case "cm":
return new double[]{width * 28.3465, height * 28.3465};
case "mm":
return new double[]{width * 2.83465, height * 2.83465};
case "pt":
default:
return new double[]{width, height};
}
}
private double parseSizeTolerance(String sizeToleranceStr) {
if (sizeToleranceStr == null || sizeToleranceStr.isEmpty()) {
return 3; // Default tolerance in points
}
Pattern pattern = Pattern.compile("(\\d+(\\.\\d+)?)\\s*(%)?", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(sizeToleranceStr);
if (!matcher.matches()) {
throw new IllegalArgumentException("Invalid SizeTolerance format: " + sizeToleranceStr);
}
double value = Double.parseDouble(matcher.group(1));
return matcher.group(3) != null ? value / 100.0 : value; // Percentage tolerance or direct value
}
public boolean validatePageSize(double actualWidth, double actualHeight) {
// Check both portrait and landscape orientations
boolean isValid = (actualWidth <= maxWidth + sizeTolerance && actualHeight <= maxHeight + sizeTolerance) ||
(actualHeight <= maxWidth + sizeTolerance && actualWidth <= maxHeight + sizeTolerance);
return isValid;
}
}
class IniFile:
def get_value(self, section: str, key: str, default_value: str = None) -> str:
return self.config.get(section, key, fallback=default_value)
def get_keys_matching_pattern(self, section: str, pattern: str) -> list:
matching_keys = []
if section in self.config:
for key in self.config[section]:
if re.match(pattern, key, re.IGNORECASE):
matching_keys.append(self.config[section][key])
return matching_keys
def open_ini_file(path: str) -> IniFile:
ini_file = IniFile()
ini_file.config = configparser.ConfigParser()
ini_file.config.read(path)
return ini_file
class DocumentValidator:
def validate_document(self) -> bool:
is_valid = self.validate_file_size()
with open(self.input_path, "rb") as in_stream:
with Document.open(in_stream, self.pdf_password) as in_doc:
is_valid &= self.validate_conformance(in_doc.conformance)
is_valid &= self.validate_encryption(in_doc.permissions)
is_valid &= self.validate_pages_size(in_doc)
is_valid &= self.validate_fonts(in_doc)
return is_valid
def validate_file_size(self) -> bool:
file_size_in_mb = os.path.getsize(self.input_path) / (1024 * 1024)
if self.ini_file_size:
ini_file_size_in_mb = float(self.ini_file_size)
if file_size_in_mb > ini_file_size_in_mb:
print("The PDF file size exceeds the specified custom limit.")
return False
else:
print("The PDF file size does not exceed the specified custom limit.")
return True
return True
def validate_conformance(self, current_conformance: Conformance) -> bool:
if self.ini_max_pdf_version_str:
if ConformanceValidator.validate_conformance(self.ini_max_pdf_version_str, current_conformance):
print("The PDF version does not exceed the specified custom maximum version.")
return True
else:
print("The PDF version exceeds the specified custom maximum version.")
return False
return True
def validate_encryption(self, permissions: Permission) -> bool:
if self.ini_encryption:
encryption_required = self.ini_encryption.lower() == "true"
if encryption_required and not permissions:
print("Encryption not conform: the PDF file is not encrypted. The custom encryption value specifies that the PDF file should be encrypted.")
return False
elif not encryption_required and permissions:
print("Encryption not conform: the PDF file is encrypted. The custom encryption value specifies that the PDF file should not be encrypted.")
return False
else:
print("The PDF encryption is conform to the specified custom value.")
return True
return True
def validate_pages_size(self, in_doc: Document) -> bool:
is_valid = True
if self.ini_max_page_size is not None:
page_number = 0
for page in in_doc.pages:
page_number += 1
size_with_int = Size(
width=int(page.size.width), height=int(page.size.height)
)
is_valid &= self.validate_page_size(page_number, size_with_int)
return is_valid
def validate_page_size(self, page_number: int, page_size: Size) -> bool:
if self.ini_max_page_size is not None:
validator = create_page_size_validator(self.ini_max_page_size, self.size_tolerance)
if validator.validate_page_size(page_size):
print(
f"The size of page {page_number} is within the specified custom maximum page size value."
)
return True
else:
print(
f"The size of page {page_number} exceeds the specified custom maximum page size value."
)
return False
return True
def validate_fonts(self, in_doc: Document) -> bool:
is_valid = True
if self.ini_embedding:
embedding_required = self.ini_embedding.lower() == "true"
for page_number in range(len(in_doc.pages)):
page_number += 1
page = in_doc.pages[page_number-1]
extractor = ContentExtractor(page.content)
extractor.ungrouping = UngroupingSelection.ALL
for element in extractor:
if isinstance(element, TextElement):
for fragment in element.text:
font_name = fragment.font.base_font
is_embedded = fragment.font.is_embedded
# Check if the font is in the exception list
is_current_font_an_exception = any(
re.match(exc.replace("*", ".*"), font_name, re.IGNORECASE)
for exc in self.embedding_exception_fonts
)
# Validate based on the embedding setting
if (embedding_required and not is_embedded and not is_current_font_an_exception) or (
not embedding_required and is_embedded and not is_current_font_an_exception
):
is_valid = False
status_text = "be embedded" if embedding_required else "not be embedded"
print(
f"The font '{font_name}' on page {page_number} should {status_text} as specified by the property 'Embedding' or it should be added to the list of exceptions."
)
else:
status_text = (
"in the exception list" if embedding_required != is_embedded
else "embedded" if is_embedded
else "not be embedded"
)
print(
f"The font '{font_name}' on page {page_number} is conform to the 'Embedding' property as it is {status_text}."
)
return is_valid
def create_document_validator(ini_file: IniFile, input_path: str, pdf_password: str = None) -> DocumentValidator:
document_validator = DocumentValidator()
document_validator.ini_file = ini_file
document_validator.input_path = input_path
document_validator.pdf_password = pdf_password
# Extract values from INI file
document_validator.size_tolerance = ini_file.get_value("Pages", "SizeTolerance", "3.0")
document_validator.ini_max_page_size = ini_file.get_value("Pages", "MaxPageSize")
document_validator.ini_max_pdf_version_str = ini_file.get_value("File", "MaxPdfVersion")
document_validator.ini_encryption = ini_file.get_value("File", "Encryption")
document_validator.ini_file_size = ini_file.get_value("File", "FileSize")
document_validator.ini_embedding = ini_file.get_value("Fonts", "Embedding")
document_validator.embedding_exception_fonts = ini_file.get_keys_matching_pattern("Fonts", r"EmbeddingExcFont\d+")
return document_validator
class PageSizeValidator:
named_page_sizes = {
"Letter": Size(width=612, height=792),
"A0": Size(width=2384, height=3370),
"A1": Size(width=1684, height=2384),
"A2": Size(width=1191, height=1684),
"A3": Size(width=842, height=1191),
"A4": Size(width=595, height=842),
"A5": Size(width=420, height=595),
"A6": Size(width=298, height=420),
"A7": Size(width=210, height=298),
"A8": Size(width=147, height=210),
"A9": Size(width=105, height=147),
"A10": Size(width=74, height=105),
"DL": Size(width=283, height=595),
}
def parse_page_size(self, max_page_size: str) -> Size:
named_size = self.named_page_sizes.get(max_page_size)
if named_size:
return named_size
match = re.match(
r"(\d+(\.\d+)?)\s*x\s*(\d+(\.\d+)?)(\s*(pt|in|cm|mm))?", max_page_size, re.IGNORECASE
)
if not match:
raise ValueError(f"Invalid MaxPageSize format: {max_page_size}")
width = float(match.group(1))
height = float(match.group(3))
unit = match.group(6).lower() if match.group(6) else "pt"
if unit == "in":
return Size(width=int(width * 72), height=int(height * 72))
elif unit == "cm":
return Size(width=int(width * 28.3465), height=int(height * 28.3465))
elif unit == "mm":
return Size(width=int(width * 2.83465), height=int(height * 2.83465))
elif unit in ["pt", ""]:
return Size(width=int(width), height=int(height))
else:
raise ValueError(f"Unsupported unit: {unit}")
def parse_size_tolerance(self, size_tolerance_str: str) -> float:
if not size_tolerance_str:
return 3.0
match = re.match(r"(\d+(\.\d+)?)\s*(%)?", size_tolerance_str, re.IGNORECASE)
if not match:
raise ValueError(f"Invalid SizeTolerance format: {size_tolerance_str}")
value = float(match.group(1))
return value / 100.0 if match.group(3) else value
def validate_page_size(self, page_size: Size) -> bool:
is_valid = (
(page_size.width <= self.max_size.width + self.size_tolerance
and page_size.height <= self.max_size.height + self.size_tolerance
) or
(page_size.height <= self.max_size.width + self.size_tolerance
and page_size.width <= self.max_size.height + self.size_tolerance)
)
return is_valid
def create_page_size_validator(max_page_size_str: str, size_tolerance_str: str) -> PageSizeValidator:
page_size_validator = PageSizeValidator()
page_size_validator.max_size = page_size_validator.parse_page_size(max_page_size_str)
page_size_validator.size_tolerance = page_size_validator.parse_size_tolerance(size_tolerance_str)
return page_size_validator
class ConformanceValidator:
version_map = {
"1.0": Conformance.PDF10,
"1.1": Conformance.PDF11,
"1.2": Conformance.PDF12,
"1.3": Conformance.PDF13,
"1.4": Conformance.PDF14,
"1.5": Conformance.PDF15,
"1.6": Conformance.PDF16,
"1.7": Conformance.PDF17,
"2.0": Conformance.PDF20,
}
@staticmethod
def parse_version_string(version: str) -> Conformance:
version_parts = version.split(".")
if len(version_parts) == 2:
major_minor_version = f"{version_parts[0]}.{version_parts[1]}"
conformance = ConformanceValidator.version_map.get(major_minor_version)
if conformance:
return conformance
raise ValueError(f"Unsupported version or conformance level: {version}")
@staticmethod
def validate_conformance(max_pdf_version_str: str, current_conformance: Conformance) -> bool:
max_pdf_conformance = ConformanceValidator.parse_version_string(max_pdf_version_str)
current_conformance_version = ConformanceValidator.get_version_from_conformance(current_conformance)
return current_conformance_version.value <= max_pdf_conformance.value
@staticmethod
def get_version_from_conformance(conformance: Conformance) -> Conformance:
if conformance in ConformanceValidator.version_map.values():
return conformance
if conformance in {Conformance.PDF_A1_A, Conformance.PDF_A1_B}:
return Conformance.PDF14
if conformance in {
Conformance.PDF_A2_A,
Conformance.PDF_A2_B,
Conformance.PDF_A2_U,
Conformance.PDF_A3_A,
Conformance.PDF_A3_B,
Conformance.PDF_A3_U,
}:
return Conformance.PDF17
raise ValueError(f"Unsupported conformance level: {conformance}")
ini_file = open_ini_file(ini_path)
document_validator = create_document_validator(ini_file, input_file_path, pdf_password)
if document_validator.validate_document():
print("\nThe document does conform the specified properties.")
else:
print("\nThe document does not conform the specified properties.")
Document setup
Add metadata to PDF
// Open input document
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// Create output document
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// Copy document-wide data
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Configure copy options
pCopyOptions = PtxPdf_PageCopyOptions_New();
// Copy all pages
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pCopiedPages = PtxPdf_PageList_Copy(pOutDoc, pInPageList, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pCopiedPages, _T("Failed to copy pages. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Add copied pages to output
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pCopiedPages),
_T("Failed to add copied pages to output. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
if (argc == 4)
{
// Add metadata from a input file
pMdataStream = _tfopen(szMdatafile, _T("rb"));
GOTO_CLEANUP_IF_NULL(pMdataStream, _T("Failed to open metadata file \"%s\".\n"), szMdatafile);
PtxSysCreateFILEStreamDescriptor(&mdataDescriptor, pMdataStream, 0);
// Get file extension
TCHAR* szExt = _tcsrchr(szMdatafile, '.');
_tcscpy(szExtension, szExt);
if (_tcscmp(szExtension, _T(".pdf")) == 0)
{
// Use the metadata of another PDF file
TPtxPdf_Document* pMetaDoc = PtxPdf_Document_Open(&mdataDescriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pMetaDoc, _T("Failed to open metadata file. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
TPtxPdf_Metadata* pMetadata = PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pMetaDoc));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pMetadata, _T("Failed to copy metadata. %s (ErrorCode: 0x%08x)."),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Document_SetMetadata(pOutDoc, pMetadata),
_T("Failed to set metadata. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
}
else
{
// Use the content of an XMP metadata file
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Create(pOutDoc, &mdataDescriptor)),
_T("Failed to set metadata. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
}
}
else
{
// Set some metadata properties
TPtxPdf_Metadata* pMetadata = PtxPdf_Document_GetMetadata(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pMetadata, _T("Failed to get metadata. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Metadata_SetAuthor(pMetadata, _T("Your Author")),
_T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Metadata_SetTitle(pMetadata, _T("Your Title")),
_T("%s(ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Metadata_SetSubject(pMetadata, _T("Your Subject")),
_T("%s(ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Metadata_SetCreator(pMetadata, _T("Your Creator")),
_T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
}
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
// Copy document-wide data (excluding metadata)
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// Output intent
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// Viewer settings
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// Associated files (for PDF/A-3 and PDF 2.0 only)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// Plain embedded files
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// Create output document
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// Copy document-wide data
CopyDocumentData(inDoc, outDoc);
// Set Metadata
if (args.Length == 3)
{
Metadata mdata;
// Add metadata from a input file
using FileStream metaStream = File.OpenRead(mdatafile);
if (mdatafile.EndsWith(".pdf"))
{
// Use the metadata of another PDF file
using Document metaDoc = Document.Open(metaStream, "");
mdata = Metadata.Copy(outDoc, metaDoc.Metadata);
}
else
{
// Use the content of an XMP metadata file
mdata = Metadata.Create(outDoc, metaStream);
}
outDoc.Metadata = mdata;
}
else
{
// Set some metadata properties
Metadata metadata = outDoc.Metadata;
metadata.Author = "Your Author";
metadata.Title = "Your Title";
metadata.Subject = "Your Subject";
metadata.Creator = "Your Creator";
}
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Copy all pages and append to output document
PageList copiedPages = PageList.Copy(outDoc, inDoc.Pages, copyOptions);
outDoc.Pages.AddRange(copiedPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// Copy document-wide data (except metadata)
// Output intent
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// Viewer settings
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null);
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (// Create output document
Document outDoc = Document.create(outStream, inDoc.getConformance(), null)) {
// Copy document-wide data
copyDocumentData(inDoc, outDoc);
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Copy all pages and append to output document
PageList copiedPages = PageList.copy(outDoc, inDoc.getPages(), copyOptions);
outDoc.getPages().addAll(copiedPages);
if (args.length == 3) {
Metadata mdata;
// Add metadata from a input file
try (
FileStream metaStream = new FileStream(mdatafile, FileStream.Mode.READ_ONLY)) {
if (mdatafile.toLowerCase().endsWith(".pdf")) {
// Use the metadata of another PDF file
try (
Document metaDoc = Document.open(metaStream, null)) {
mdata = Metadata.copy(outDoc, metaDoc.getMetadata());
}
} else {
// Use the content of an XMP metadata file
mdata = Metadata.create(outDoc, metaStream);
}
}
outDoc.setMetadata(mdata);
} else {
// Set some metadata properties
Metadata metadata = outDoc.getMetadata();
metadata.setAuthor("Your Author");
metadata.setTitle("Your Title");
metadata.setSubject("Your Subject");
metadata.setCreator("Your Creator");
}
}
}
private static void copyDocumentData(Document inDoc, Document outDoc) throws ToolboxException, IOException {
// Copy document-wide data (excluding metadata)
// Output intent
if (inDoc.getOutputIntent() != null)
outDoc.setOutputIntent(IccBasedColorSpace.copy(outDoc, inDoc.getOutputIntent()));
// Viewer settings
outDoc.setViewerSettings(ViewerSettings.copy(outDoc, inDoc.getViewerSettings()));
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.getAssociatedFiles();
for (FileReference inFileRef : inDoc.getAssociatedFiles())
outAssociatedFiles.add(FileReference.copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.getPlainEmbeddedFiles();
for (FileReference inFileRef : inDoc.getPlainEmbeddedFiles())
outEmbeddedFiles.add(FileReference.copy(outDoc, inFileRef));
}
def copy_document_data(in_doc: Document, out_doc: Document):
# Copy document-wide data (excluding metadata)
# Output intent
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# Viewer settings
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# Associated files (for PDF/A-3 and PDF 2.0 only)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# Plain embedded files
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
# Open input document
with io.FileIO(input_file_path, 'rb') as content_pdf_stream:
with Document.open(content_pdf_stream, None) as content_pdf_document:
# Create output document
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, content_pdf_document.conformance, None) as output_document:
# Copy document-wide data
copy_document_data(content_pdf_document, output_document)
# Set Metadata
if metadata_file_path is not None:
with io.FileIO(metadata_file_path, 'rb') as metadata_stream:
if metadata_file_path.endswith(".pdf"):
# Use the metadata of another PDF file
with Document.open(metadata_stream, "") as meta_doc:
mdata = Metadata.copy(output_document, meta_doc.metadata)
else:
# Use the content of an XMP metadata file
mdata = Metadata.create(output_document, metadata_stream)
else:
mdata = output_document.metadata
mdata.author = "Your Author"
mdata.title = "Your Title"
mdata.subject = "Your Subject"
mdata.creator = "Your Creator"
output_document.metadata = mdata
# Define page copy options
copy_options = PageCopyOptions()
# Copy all pages and append to output document
copied_pages = PageList.copy(output_document, content_pdf_document.pages, copy_options)
output_document.pages.extend(copied_pages)
Encrypt PDF
// Open input document
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
pEncryption =
PtxPdf_Encryption_New(szUserPwd, szOwnerPwd, ePtxPdf_Permission_Print | ePtxPdf_Permission_DigitalPrint);
// Create output document
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, pEncryption);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// Copy document-wide data
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Configure copy options
pCopyOptions = PtxPdf_PageCopyOptions_New();
// Copy all pages
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pCopiedPages = PtxPdf_PageList_Copy(pOutDoc, pInPageList, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pCopiedPages, _T("Failed to copy pages. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Add copied pages to output
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pCopiedPages),
_T("Failed to add copied pages to output. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// Output intent
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// Metadata
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// Viewer settings
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// Associated files (for PDF/A-3 and PDF 2.0 only)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// Plain embedded files
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
// Create encryption parameters
Encryption encryptionParams = new Encryption(UserPwd, OwnerPwd, Permission.Print |
Permission.DigitalPrint);
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// Create output document and set a user and owner password
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, encryptionParams))
{
// Copy document-wide data
CopyDocumentData(inDoc, outDoc);
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Copy all pages and append to output document
PageList copiedPages = PageList.Copy(outDoc, inDoc.Pages, copyOptions);
outDoc.Pages.AddRange(copiedPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// Copy document-wide data
// Output intent
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// Metadata
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// Viewer settings
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
// Create encryption parameters
Encryption encryptionParams = new Encryption(userPwd, ownerPwd,
EnumSet.of(Permission.PRINT, Permission.DIGITAL_PRINT));
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null);
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (// Create output document and set a user and owner password
Document outDoc = Document.create(outStream, inDoc.getConformance(), encryptionParams)) {
// Copy document-wide data
copyDocumentData(inDoc, outDoc);
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Copy all pages and append to output document
PageList copiedPages = PageList.copy(outDoc, inDoc.getPages(), copyOptions);
outDoc.getPages().addAll(copiedPages);
}
}
private static void copyDocumentData(Document inDoc, Document outDoc) throws ToolboxException, IOException {
// Copy document-wide data
// Output intent
if (inDoc.getOutputIntent() != null)
outDoc.setOutputIntent(IccBasedColorSpace.copy(outDoc, inDoc.getOutputIntent()));
// Metadata
outDoc.setMetadata(Metadata.copy(outDoc, inDoc.getMetadata()));
// Viewer settings
outDoc.setViewerSettings(ViewerSettings.copy(outDoc, inDoc.getViewerSettings()));
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.getAssociatedFiles();
for (FileReference inFileRef : inDoc.getAssociatedFiles())
outAssociatedFiles.add(FileReference.copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.getPlainEmbeddedFiles();
for (FileReference inFileRef : inDoc.getPlainEmbeddedFiles())
outEmbeddedFiles.add(FileReference.copy(outDoc, inFileRef));
}
def copy_document_data(in_doc: Document, out_doc: Document):
# Copy document-wide data
# Output intent
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# Metadata
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# Viewer settings
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# Associated files (for PDF/A-3 and PDF 2.0 only)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# Plain embedded files
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
# Open input document
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# Create encryption parameters
encryption_params = Encryption(
user_pwd,
owner_pwd,
Permission.PRINT | Permission.DIGITAL_PRINT,
)
# Create output document and set a user and owner password
with io.FileIO(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, in_doc.conformance, encryption_params) as out_doc:
# Copy document-wide data
copy_document_data(in_doc, out_doc)
# Define page copy options
copy_options = PageCopyOptions()
# Copy all pages and append to output document
copied_pages = PageList.copy(out_doc, in_doc.pages, copy_options)
out_doc.pages.extend(copied_pages)
Flatten form fields in PDF
// Open input document
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// Create output document
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// Copy document-wide data
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Configure copy options: enable form field flattening
pCopyOptions = PtxPdf_PageCopyOptions_New();
PtxPdf_PageCopyOptions_SetFormFields(pCopyOptions, ePtxPdfForms_FormFieldCopyStrategy_Flatten);
// Copy all pages
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pCopiedPages = PtxPdf_PageList_Copy(pOutDoc, pInPageList, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pCopiedPages, _T("Failed to copy pages. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Add copied pages to output
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pCopiedPages),
_T("Failed to add copied pages to output. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// Output intent
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// Metadata
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// Viewer settings
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// Associated files (for PDF/A-3 and PDF 2.0 only)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// Plain embedded files
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// Create output document
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// Copy document-wide data
CopyDocumentData(inDoc, outDoc);
// Define copy options including form field flattening
PageCopyOptions copyOptions = new PageCopyOptions();
copyOptions.FormFields = FormFieldCopyStrategy.Flatten;
// Copy all pages and append to output document
PageList copiedPages = PageList.Copy(outDoc, inDoc.Pages, copyOptions);
outDoc.Pages.AddRange(copiedPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// Copy document-wide data
// Output intent
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// Metadata
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// Viewer settings
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null);
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (// Create output document
Document outDoc = Document.create(outStream, inDoc.getConformance(), null)) {
// Copy document-wide data
copyDocumentData(inDoc, outDoc);
// Define copy options including form field flattening
PageCopyOptions copyOptions = new PageCopyOptions();
copyOptions.setFormFields(FormFieldCopyStrategy.FLATTEN);
// Copy all pages and append to output document
PageList copiedPages = PageList.copy(outDoc, inDoc.getPages(), copyOptions);
outDoc.getPages().addAll(copiedPages);
}
}
private static void copyDocumentData(Document inDoc, Document outDoc) throws ToolboxException, IOException {
// Copy document-wide data
// Output intent
if (inDoc.getOutputIntent() != null)
outDoc.setOutputIntent(IccBasedColorSpace.copy(outDoc, inDoc.getOutputIntent()));
// Metadata
outDoc.setMetadata(Metadata.copy(outDoc, inDoc.getMetadata()));
// Viewer settings
outDoc.setViewerSettings(ViewerSettings.copy(outDoc, inDoc.getViewerSettings()));
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.getAssociatedFiles();
for (FileReference inFileRef : inDoc.getAssociatedFiles())
outAssociatedFiles.add(FileReference.copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.getPlainEmbeddedFiles();
for (FileReference inFileRef : inDoc.getPlainEmbeddedFiles())
outEmbeddedFiles.add(FileReference.copy(outDoc, inFileRef));
}
def copy_document_data(in_doc: Document, out_doc: Document):
# Copy document-wide data
# Output intent
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# Metadata
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# Viewer settings
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# Associated files (for PDF/A-3 and PDF 2.0 only)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# Plain embedded files
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
# Open input document
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# Create output document
with io.FileIO(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, in_doc.conformance, None) as out_doc:
# Copy document-wide data
copy_document_data(in_doc, out_doc)
# Set form field flattening options
copy_options = PageCopyOptions()
copy_options.form_fields = FormFieldCopyStrategy.FLATTEN
# Copy all pages with flattening options
copied_pages = PageList.copy(out_doc, in_doc.pages, copy_options)
out_doc.pages.extend(copied_pages)
Merge multiple PDFs and create a table of contents page
// Create output document
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, null, null))
{
// Create embedded font in output document
Font font = Font.CreateFromSystem(outDoc, "Arial", string.Empty, true);
// Define page copy options
PageCopyOptions pageCopyOptions = new PageCopyOptions();
var copiedPageLists = new List<Tuple<string, PageList>>(inPaths.Length);
// A page number counter
int pageNumber = 2;
// Copy all input documents pages
foreach (string inPath in inPaths)
{
// Open input document
using Stream inFs = new FileStream(inPath, FileMode.Open, FileAccess.Read);
using Document inDoc = Document.Open(inFs, null);
// Copy all pages and append to output document
PageList copiedPages = PageList.Copy(outDoc, inDoc.Pages, pageCopyOptions);
// Add page numbers to copied pages
foreach (var copiedPage in copiedPages)
{
AddPageNumber(outDoc, copiedPage, font, pageNumber++);
}
// Create outline item
string title = inDoc.Metadata.Title ?? System.IO.Path.GetFileNameWithoutExtension(inPath);
copiedPageLists.Add(new Tuple<string, PageList>(title, copiedPages));
}
// Create table of contents page
var contentsPage = CreateTableOfContents(outDoc, copiedPageLists);
AddPageNumber(outDoc, contentsPage, font, 1);
// Add pages to the output document
PageList outPages = outDoc.Pages;
outPages.Add(contentsPage);
foreach (var tuple in copiedPageLists)
{
outPages.AddRange(tuple.Item2);
}
private static void AddPageNumber(Document outDoc, Page copiedPage, Font font, int pageNumber)
{
// Create content generator
using ContentGenerator generator = new ContentGenerator(copiedPage.Content, false);
// Create text object
Text text = Text.Create(outDoc);
// Create a text generator with the given font, size and position
using (TextGenerator textgenerator = new TextGenerator(text, font, 8, null))
{
// Generate string to be stamped as page number
string stampText = string.Format("Page {0}", pageNumber);
// Calculate position for centering text at bottom of page
Point position = new Point
{
X = (copiedPage.Size.Width / 2) - (textgenerator.GetWidth(stampText) / 2),
Y = 10
};
// Position the text
textgenerator.MoveTo(position);
// Add page number
textgenerator.Show(stampText);
}
// Paint the positioned text
generator.PaintText(text);
}
private static Page CreateTableOfContents(Document outDoc, List<Tuple<string, PageList>> copiedPageLists)
{
// Create a new page with size equal to the first page copied
var page = Page.Create(outDoc, copiedPageLists[0].Item2[0].Size);
// Create a font
var font = Font.CreateFromSystem(outDoc, "Arial", null, true);
// Parameters for layout computation
double border = 30;
double textWidth = page.Size.Width - 2 * border;
double chapterTitleSize = 24;
double titleSize = 12;
// The current text location
var location = new Point() { X = border, Y = page.Size.Height - border - chapterTitleSize };
// The page number of the current item in the table of content
int pageNumber = 2;
// Create a content generator for the table of contents page
using (var contentGenerator = new ContentGenerator(page.Content, false))
{
// Create a text object
var text = Text.Create(outDoc);
// Create a text generator to generate the table of contents. Initially, use the chapter title font size
using (var textGenerator = new TextGenerator(text, font, chapterTitleSize, location))
{
// Show a chapter title
textGenerator.ShowLine("Table of Contents");
// Advance the vertical position
location.Y -= 1.7 * chapterTitleSize;
// Select the font size for an entry in the table of contents
textGenerator.FontSize = titleSize;
// Iterate over all copied page ranges
foreach (var tuple in copiedPageLists)
{
// The title string for the current entry
string title = tuple.Item1;
// The page number string of the target page for this entry
string pageNumberString = string.Format("{0}", pageNumber);
// The width of the page number string
double pageNumberWidth = textGenerator.GetWidth(pageNumberString);
// Compute the number of filler dots to be displayed between the entry title and the page number
int numberOfDots = (int)Math.Floor((textWidth - textGenerator.GetWidth(title) - pageNumberWidth) / textGenerator.GetWidth("."));
// Move to the current location and show the entry's title and the filler dots
textGenerator.MoveTo(location);
textGenerator.Show(title + new string('.', numberOfDots));
// Show the page number
textGenerator.MoveTo(new Point() { X = page.Size.Width - border - pageNumberWidth, Y = location.Y });
textGenerator.Show(pageNumberString);
// Compute the rectangle for the link
var linkRectangle = new Rectangle()
{
Left = border,
Bottom = location.Y + font.Descent * titleSize,
Right = border + textWidth,
Top = location.Y + font.Ascent * titleSize
};
// Create a destination to the first page of the current page range and create a link for this destination
var pageList = tuple.Item2;
var targetPage = pageList[0];
var destination = LocationZoomDestination.Create(outDoc, targetPage, 0, targetPage.Size.Height, null);
var link = InternalLink.Create(outDoc, linkRectangle, destination);
// Add the link to the table of contents page
page.Links.Add(link);
// Advance the location for the next entry
location.Y -= 1.8 * titleSize;
pageNumber += pageList.Count;
}
}
// Paint the generated text
contentGenerator.PaintText(text);
}
// Return the finished table-of-contents page
return page;
}