Skip to main content

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

Download code sample
// 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;
}
Download code sample
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;
}
Download code sample
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

Download code sample
// 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);
}
}
Download code sample
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

Download code sample
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));
}
Download code sample
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));
}
Download code sample
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

Download code sample
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;
}
Download code sample
// 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;
}
}
}
}
Download code sample
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;
}
}
}
}
Download code sample
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

Download code sample
// 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;
}
Download code sample
// 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);
}
Download code sample
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);
}
}
Download code sample
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

Download code sample
// 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;
}
Download code sample
// 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);
}
Download code sample
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);
}
}
Download code sample
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

Download code sample
// 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;
}
Download code sample
// 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);
}
Download code sample
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);
}
}
Download code sample
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

Download code sample
// 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;
}
Download code sample
// 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);
}
}
Download code sample
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);
}
}
Download code sample
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

Download code sample
        // 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));
}
Download code sample
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));
}
Download code sample
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

Download code sample
// 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;
}
Download code sample
// 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);
}
Download code sample
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);
}
}
Download code sample
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

Download code sample
// 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;
}
Download code sample
// 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);
}
Download code sample
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);
}
}
Download code sample
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

Download code sample
// 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;
}
Download code sample
// 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);
}
Download code sample
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);
}
}
Download code sample
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

Download code sample
// 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);
}
Download code sample
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);
}
}
Download code sample
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

Download code sample
// 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;
}
Download code sample
// 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);
}
Download code sample
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);
}
}
Download code sample
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

Download code sample
// 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);
}
}
Download code sample
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);
}
}
}
Download code sample
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

Download code sample
// 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;
}
Download code sample
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;
}
Download code sample
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

Download code sample
// 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);
}
Download code sample
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);
}
}
Download code sample
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

Download code sample
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());
}
}
}
Download code sample
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;
}
}
Download code sample
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

Download code sample
// 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;
}
Download code sample
// 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));
}
Download code sample
            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));
}
Download code sample
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

Download code sample
// 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;
}
Download code sample
// 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));
}
Download code sample
// 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));
}
Download code sample
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

Download code sample
// 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;
}
Download code sample
// 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));
}
Download code sample
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));
}
Download code sample
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

Download code sample
// 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;
}
Download code sample
try (
// Open input document
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", "", true);

// Configure page copy options
PageCopyOptions copyOptions = new PageCopyOptions();

Set<Map.Entry<String, PageList>> copiedPageLists = new HashSet<>(inPaths.length);

// A page number counter
int pageNumber = 2;


// Copy all input documents pages
for (String inPath : inPaths) {
try (// Open input document
Stream inFs = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inFs, null)) {

// Copy all pages and append to output document
PageList copiedPages = PageList.copy(outDoc, inDoc.getPages(), copyOptions);

// Add page numbers to copied pages
for ( Page copiedPage : copiedPages)
{
addPageNumber(outDoc, copiedPage, font, pageNumber++);
}

// Hold the file name without extension
if (inPath == null)
continue;
// Get position of last '.'.
int pos = inPath.lastIndexOf(".");
// If there was a '.', hold the file name only
if (pos != -1)
inPath = inPath.substring(0, pos);

// Create outline item
String title = (inDoc.getMetadata().getTitle() == null ? inPath : inDoc.getMetadata().getTitle());
copiedPageLists.add(new AbstractMap.SimpleEntry<String, PageList>(title, copiedPages));
}
}

// Create table of contents page
Page contentsPage = createTableOfContents(outDoc, copiedPageLists);
addPageNumber(outDoc, contentsPage, font, 1);

// Add pages to the output document
PageList outPages = outDoc.getPages();
outPages.add(contentsPage);
for (Map.Entry<String, PageList> entry : copiedPageLists)
{
outPages.addAll(entry.getValue());
}
private static void addPageNumber(Document outDoc, Page copiedPage, Font font, int pageNumber) throws ToolboxException, IOException
{
// Create content generator
try (ContentGenerator generator = new ContentGenerator(copiedPage.getContent(), false)) {
// Create text object
Text text = Text.create(outDoc);

// Create a text generator with the given font, size and position
try (TextGenerator textgenerator = new TextGenerator(text, font, 8, null)) {
// Generate string to be stamped as page number
String stampText = String.format("Page %d", pageNumber);

// Calculate position for centering text at bottom of page
Point position = new Point();
position.x = (copiedPage.getSize().getWidth() / 2) - (textgenerator.getWidth(stampText) / 2);
position.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, Set<Map.Entry<String, PageList>> copiedPageLists) throws IOException, ToolboxException
{
// Create a new page with size equal to the first page copied
Page page = Page.create(outDoc, copiedPageLists.iterator().next().getValue().get(0).getSize());

// Create a font
Font font = Font.createFromSystem(outDoc, "Arial", null, true);

// Parameters for layout computation
double border = 30;
double textWidth = page.getSize().getWidth() - 2 * border;
double chapterTitleSize = 24;
double titleSize = 12;

// The current text location
Point location = new Point();
location.x = border;
location.y = page.getSize().getHeight() - border - chapterTitleSize;

// The page number of the current item in the table of content
int pageNumber = 2;

// Creat a content generator for the table of contents page
try (ContentGenerator contentGenerator = new ContentGenerator(page.getContent(), false)) {
// Create a text object
Text text = Text.create(outDoc);

// Create a text generator to generate the table of contents. Initially, use the chapter title font size
try (TextGenerator 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.setFontSize(titleSize);

// Iterate over all copied page ranges
for (Map.Entry<String, PageList> entry : copiedPageLists)
{
// The title string for the current entry
String title = entry.getKey();

// The page number string of the target page for this entry
String pageNumberString = String.format("%d", 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);
String dots = new String();
for (int i = 0; i < numberOfDots; i++)
{
dots += '.';
}
textGenerator.show(title + dots);

// Show the page number
Point point = new Point();
point.x = page.getSize().getWidth() - border - pageNumberWidth;
point.y = location.y;
textGenerator.moveTo(point);
textGenerator.show(pageNumberString);

// Compute the rectangle for the link
Rectangle linkRectangle = new Rectangle();
linkRectangle.setLeft(border);
linkRectangle.setBottom(location.y + font.getDescent() * titleSize);
linkRectangle.setRight(border + textWidth);
linkRectangle.setTop(location.y + font.getAscent() * titleSize);

// Create a destination to the first page of the current page range and create a link for this destination
PageList pageList = entry.getValue();
Page targetPage = pageList.get(0);
LocationZoomDestination destination = LocationZoomDestination.create(outDoc, targetPage, (double) 0, targetPage.getSize().getHeight(), null);
InternalLink link = InternalLink.create(outDoc, linkRectangle, destination);

// Add the link to the table of contents page
page.getLinks().add(link);

// Advance the location for the next entry
location.y -= 1.8 * titleSize;
pageNumber += pageList.size();
}
}

// Paint the generated text
contentGenerator.paintText(text);
}

// Return the finished table-of-contents page
return page;
}
Download code sample
def add_page_number(out_doc: Document, page: Page, font: Font, page_number: int):
"""Add a page number to the bottom center of a page."""
# Create content generator
with ContentGenerator(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 page number
stamp_text = f"Page {page_number}"

# Calculate position for centering text at bottom of page
position = Point(
x=(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)
def create_table_of_contents(out_doc: Document, toc_entries: tuple, font: Font):
"""Create a table of contents (TOC) page."""
# Create a new page with size equal to the first page copied
page = Page.create(out_doc, toc_entries[0][1][0].size)

# Parameters for layout computation
border = 30
text_width = page.size.width - 2 * border
chapter_title_size = 24
title_size = 12

# The current text location
location = Point(x=border, y=page.size.height - border - chapter_title_size)

# The page number of the current item in the table of content
page_number = 2

# Create a content generator for the table of contents page
with ContentGenerator(page.content, False) as content_generator:
# Create a text object
text = Text.create(out_doc)

# Create a text generator to generate the table of contents. Initially, use the chapter title font size
with TextGenerator(text, font, chapter_title_size, location) as text_gen:
# Show a chapter title
text_gen.show_line("Table of Contents")

# Advance the vertical position
location.y -= 1.7 * chapter_title_size

# Select the font size for an entry in the table of contents
text_gen.font_size = title_size

# Iterate over all copied page ranges
for title, page_list in toc_entries:
# The title string for the current entry
title_text = title

# The page number string of the target page for this entry
page_number_text = f"{page_number}"

# The width of the page number string
page_number_width = text_gen.get_width(page_number_text)

# Compute the number of filler dots to be displayed between the entry title and the page number
filler_dots_count = int(
(text_width - text_gen.get_width(title_text) - page_number_width)
/ text_gen.get_width(".")
)

# Move to the current location and show the entry's title and the filler dots
text_gen.move_to(location)
text_gen.show(title_text + "." * filler_dots_count)

# Show the page number
text_gen.move_to(Point(x=page.size.width - border - page_number_width, y=location.y))
text_gen.show(page_number_text)

# Compute the rectangle for the link
link_rectangle = Rectangle(
left=border,
bottom=location.y + font.descent * title_size,
right=border + text_width,
top=location.y + font.ascent * title_size,
)

# Create a destination to the first page of the current page range and create a link for this destination
target_page = page_list[0]
destination = LocationZoomDestination.create(out_doc, target_page, 0, target_page.size.height, None)
link = InternalLink.create(out_doc, link_rectangle, destination)

# Add the link to the table of contents page
page.links.append(link)

# Advance the location for the next entry
location.y -= 1.8 * title_size
page_number += len(page_list)

# Paint the generated text
content_generator.paint_text(text)

return page
# Create output document
with open(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, None, None) as out_doc:
# Create embedded font in output document
font = Font.create_from_system(out_doc, "Arial", None, True)

# Define page copy options
page_copy_options = PageCopyOptions()

# List of copied pages that will be added to the table of contents
toc_entries = []

# A page number counter
page_number = 2

# Copy all input documents pages
for input_path in input_paths:
# Open input document
with open(input_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:

# Copy all pages and append to output document
copied_pages = PageList.copy(out_doc, in_doc.pages, page_copy_options)

for copied_page in copied_pages:
add_page_number(out_doc, copied_page, font, page_number)
page_number += 1

# Create outline item
title = in_doc.metadata.title or os.path.splitext(os.path.basename(input_path))[0]
toc_entries.append((title, copied_pages))

# Create table of contents page
contents_page = create_table_of_contents(out_doc, toc_entries, font)
add_page_number(out_doc, contents_page, font, 1)

# Add pages to the output document
out_doc.pages.append(contents_page)
for _, pages in toc_entries:
out_doc.pages.extend(pages)

Merge multiple PDFs

Download code sample
// 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);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, NULL, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());

// Configure copy options
pCopyOptions = PtxPdf_PageCopyOptions_New();

// Get output page list
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());

// Merge input documents
for (int i = 1; i < argc - 1; i++)
{
// Open input document
pInStream = _tfopen(szInPath[i], _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath[i]);
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[i], 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());

// Append copied pages
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pCopiedPages),
_T("Failed to add page range. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());

Ptx_Release(pInPageList);
pInPageList = NULL;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Document_Close(pInDoc),
_T("Failed to close input document. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
pInDoc = NULL;
fclose(pInStream);
pInStream = NULL;
Ptx_Release(pCopiedPages);
pCopiedPages = NULL;
}
Download code sample
// Create output document
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, null, null))
{
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();

// Get output pages
PageList outPages = outDoc.Pages;

// Merge input documents
for (int i = 0; i < args.Length - 1; i++)
{
// Open input document
using Stream inFs = new FileStream(inPath[i], 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, copyOptions);
outPages.AddRange(copiedPages);
}
}
Download code sample
try (
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (// Create output document
Document outDoc = Document.create(outStream, null, null)) {

// Configure page copy options
PageCopyOptions copyOptions = new PageCopyOptions();

// Get output pages
PageList outPages = outDoc.getPages();

// Merge input document
for (int i = 0; i < args.length - 1; i++) {
try (// Open input document
FileStream inStream = new FileStream(inPath[i], FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null)) {

// Copy all pages and append to output document
PageList copiedPages = PageList.copy(outDoc, inDoc.getPages(), copyOptions);
outPages.addAll(copiedPages);
}
}
}
}
Download code sample
# Create output document
with open(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, None, None) as out_doc:

# Define page copy options
page_copy_options = PageCopyOptions()

# Get output pages
out_pages = out_doc.pages

# Merge input documents
for input_path in input_paths:
# Open input document
with open(input_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:

# Copy all pages and append to output document
copied_pages = PageList.copy(out_doc, in_doc.pages, page_copy_options)
out_pages.extend(copied_pages)

Merge multiple PDFs with outlines

Download code sample
// Create output document
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, null, null))
{
// Define page copy options, skip outline
PageCopyOptions pageCopyOptions = new PageCopyOptions
{
CopyOutlineItems = false
};

// Define outline copy options
OutlineCopyOptions outlineCopyOptions = new OutlineCopyOptions();

// Get output pages
PageList outPages = outDoc.Pages;

// Merge input documents
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);
outPages.AddRange(copiedPages);

// Create outline item
string title = inDoc.Metadata.Title ?? Path.GetFileName(inPath);
Page firstCopiedPage = copiedPages[0];
Destination destination = LocationZoomDestination.Create(outDoc, firstCopiedPage, 0, firstCopiedPage.Size.Height, null);
OutlineItem outlineItem = OutlineItem.Create(outDoc, title, destination);
outDoc.Outline.Add(outlineItem);

// Add outline items from input document as children
OutlineItemList children = outlineItem.Children;
foreach (OutlineItem inputOutline in inDoc.Outline)
children.Add(OutlineItem.Copy(outDoc, inputOutline, outlineCopyOptions));
}
}
Download code sample
try (
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (// Create output document
Document outDoc = Document.create(outStream, null, null)) {
// Define page copy options, skip outline
PageCopyOptions pageCopyOptions = new PageCopyOptions();
pageCopyOptions.setCopyOutlineItems(false);

// Define outline copy options
OutlineCopyOptions outlineCopyOptions = new OutlineCopyOptions();

// Get output pages
PageList outPages = outDoc.getPages();

// Merge input document
for (String inPath : inPaths) {
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null)) {

// Copy all pages and append to output document
PageList copiedPages = PageList.copy(outDoc, inDoc.getPages(), pageCopyOptions);
outPages.addAll(copiedPages);

// Create outline item
String title = inDoc.getMetadata().getTitle();
if (title == null)
title = Paths.get(inPath).getFileName().toString();
Page firstCopiedPage = copiedPages.get(0);
Destination destination = LocationZoomDestination.create(outDoc, firstCopiedPage, 0.0,
firstCopiedPage.getSize().getHeight(), null);
OutlineItem outlineItem = OutlineItem.create(outDoc, title, destination);
outDoc.getOutline().add(outlineItem);

// Add outline items from input document as children
OutlineItemList children = outlineItem.getChildren();
for (OutlineItem inputOutline : inDoc.getOutline())
children.add(OutlineItem.copy(outDoc, inputOutline, outlineCopyOptions));
}
}
}
}
Download code sample
# Create output document
with open(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, None, None) as out_doc:

# Define page copy options
page_copy_options = PageCopyOptions()
page_copy_options.copy_outline_items = False

# Define outline copy options
outline_copy_options = OutlineCopyOptions()

# Get output pages
out_pages = out_doc.pages

# Merge input documents
for input_path in input_paths:
# Open input document
with open(input_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:

# Copy all pages and append to output document
copied_pages = PageList.copy(out_doc, in_doc.pages, page_copy_options)
out_pages.extend(copied_pages)

# Create outline item
title = in_doc.metadata.title or os.path.basename(input_path)
first_copied_page = copied_pages[0]
destination = LocationZoomDestination.create(out_doc, first_copied_page, 0, first_copied_page.size.height, None)
outline_item = OutlineItem.create(out_doc, title, destination)
out_doc.outline.append(outline_item)

# Add outline items from input document as children
children = outline_item.children
for in_outline_item in in_doc.outline:
children.append(OutlineItem.copy(out_doc, in_outline_item, outline_copy_options))

Overlay color of PDF

Download code sample
// 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 transparency and set blend mode
Transparency transparency = new Transparency(colorAlpha)
{
BlendMode = BlendMode.Multiply
};

// Create colorspace
ColorSpace colorSpace = ColorSpace.CreateProcessColorSpace(outDoc, colorType);

// Create a transparent paint for the given color
Paint paint = Paint.Create(outDoc, colorSpace, color, transparency);
Fill fill = new Fill(paint);

// Get output pages
PageList outPages = outDoc.Pages;

// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();

// Loop through all pages
foreach (Page inPage in inDoc.Pages)
{
// Create a new page
Page outPage = Page.Copy(outDoc, inPage, copyOptions);
Size size = inPage.Size;

// Create a content generator
using (ContentGenerator generator = new ContentGenerator(outPage.Content, false))
{
// Make a rectangular path the same size as the page
PdfTools.Toolbox.Pdf.Content.Path path = new PdfTools.Toolbox.Pdf.Content.Path();
using (PathGenerator pathGenerator = new PathGenerator(path))
{
// Compute Rectangle
Rectangle pathRect = new Rectangle
{
Left = 0,
Bottom = 0,
Right = size.Width,
Top = size.Height
};
pathGenerator.AddRectangle(pathRect);
}
// Paint the path with the transparent paint
generator.PaintPath(path, fill, null);
}
// Add pages to output document
outPages.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));
}
Download code sample
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 transparency and set blend mode
Transparency transparency = new Transparency(colorAlpha);
transparency.setBlendMode(BlendMode.MULTIPLY);

// Create colorspace
ColorSpace colorSpace = ColorSpace.createProcessColorSpace(outDoc, colorType);

// Create a transparent paint for the given color
Paint paint = Paint.create(outDoc, colorSpace, color, transparency);
Fill fill = new Fill(paint);

// Set copy options
PageCopyOptions copyOptions = new PageCopyOptions();

// Loop through all pages
for (Page inPage : inDoc.getPages()) {
// Create a new page
Size size = inPage.getSize();
Page outPage = Page.copy(outDoc, inPage, copyOptions);

try (// Create a content generator
ContentGenerator generator = new ContentGenerator(outPage.getContent(), false)) {
// Calculate rectangle
Rectangle rect = new Rectangle(0, 0, size.width, size.height);

// Make a rectangular path the same size as the page
Path path = new Path();
try (
PathGenerator pathGenerator = new PathGenerator(path)) {
pathGenerator.addRectangle(rect);
}

// Paint the path with the transparent paint
generator.paintPath(path, fill, null);
}

// Add pages 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));
}
Download code sample
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 parse_options(options: str) -> tuple:
"""
Parse the options string to extract color, color type, and alpha.
"""
# Default values
color_type = ProcessColorSpaceType.GRAY
color = [0.9]
alpha = 1.0

if options is None:
return color, color_type, alpha

# Split options into tokens
tokens = options.split()
if not tokens:
return color, color_type, alpha

# Parse options
i = 0
while i < len(tokens):
arg = tokens[i]
if arg.startswith("-"):
if len(arg) != 2:
raise ValueError(f"Invalid option: {arg}")

flag = arg[1]
i += 1 # Move to the next token

if flag == "k": # Grayscale
if len(tokens) - i != 2:
raise ValueError("Invalid arguments for -k. Requires (k) (a).")
color_type = ProcessColorSpaceType.GRAY
color = [float(tokens[i])]
alpha = float(tokens[i + 1])
i += 2
elif flag == "c": # CMYK
if len(tokens) - i != 5:
raise ValueError("Invalid arguments for -c. Requires (c) (m) (y) (k) (a).")
color_type = ProcessColorSpaceType.CMYK
color = [float(tokens[i]), float(tokens[i + 1]), float(tokens[i + 2]), float(tokens[i + 3])]
alpha = float(tokens[i + 4])
i += 5
elif flag == "r": # RGB
if len(tokens) - i != 4:
raise ValueError("Invalid arguments for -r. Requires (r) (g) (b) (a).")
color_type = ProcessColorSpaceType.RGB
color = [float(tokens[i]), float(tokens[i + 1]), float(tokens[i + 2])]
alpha = float(tokens[i + 3])
i += 4
else:
raise ValueError(f"Unsupported option: {flag}")
else:
raise ValueError(f"Unexpected token: {arg}")

# Validate color and alpha values
if not (0 <= alpha <= 1 and all(0 <= c <= 1 for c in color)):
raise ValueError("Color and alpha values must be between 0 and 1.")

return color, color_type, alpha
def apply_overlay_to_pages(in_doc: Document, out_doc: Document, color: list, color_type: ProcessColorSpaceType, color_alpha: float):
"""Apply the overlay color to all pages in the document."""

# Create transparency and set blend mode
transparency = Transparency(color_alpha)
transparency.blend_mode = BlendMode.MULTIPLY

# Create color space
color_space = ColorSpace.create_process_color_space(out_doc, color_type)

# Create a transparent paint for the given color
paint = Paint.create(out_doc, color_space, color, transparency)
fill = Fill(paint)

# Get output pages
out_pages = out_doc.pages

# Define page copy options
copy_options = PageCopyOptions()

# Loop through all pages
for in_page in in_doc.pages:
# Create a new page
out_page = Page.copy(out_doc, in_page, copy_options)

in_page_size = in_page.size

# Create a content generator
with ContentGenerator(out_page.content, False) as generator:

# Make a rectangular path the same size as the page
path = Path()
with PathGenerator(path) as path_generator:
# Compute Rectangle
path_rectangle = Rectangle(
left=0,
bottom=0,
right=in_page_size.width,
top=in_page_size.height,
)

path_generator.add_rectangle(path_rectangle)

# Paint the path with the transparent overlay
generator.paint_path(path, fill, None)

out_pages.append(out_page)
# Parse the color options
color, color_type, color_alpha = parse_options(options)

# Open the input and create the output document
with open(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:

# Create output document
with open(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)

# Apply the overlay
apply_overlay_to_pages(in_doc, out_doc, color, color_type, color_alpha)

Add info entries to PDF

Download code sample
// 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 all pages and append to output document
PageList copiedPages = PageList.Copy(outDoc, inDoc.Pages, copyOptions);
outDoc.Pages.AddRange(copiedPages);

// Set info entry
Metadata metadata = Metadata.Copy(outDoc, inDoc.Metadata);
if (key == "Title")
metadata.Title = value;
else if (key == "Author")
metadata.Author = value;
else if (key == "Subject")
metadata.Subject = value;
else if (key == "Keywords")
metadata.Keywords = value;
else if (key == "CreationDate")
metadata.CreationDate = DateTimeOffset.Parse(value);
else if (key == "ModDate")
throw new Exception("ModDate cannot be set.");
else if (key == "Creator")
metadata.Creator = value;
else if (key == "Producer")
throw new Exception("Producer is set by means of the license key.");
else
metadata.CustomEntries[key] = value;
outDoc.Metadata = metadata;
}
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));
}
Download code sample
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);

// Set info entry
Metadata metadata = Metadata.copy(outDoc, inDoc.getMetadata());
if (key.equals("Title"))
metadata.setTitle(value);
else if (key.equals("Author"))
metadata.setAuthor(value);
else if (key.equals("Subject"))
metadata.setSubject(value);
else if (key.equals("Keywords"))
metadata.setKeywords(value);
else if (key.equals("CreationDate")) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd' 'HH:mm:ssZ");
OffsetDateTime creationDate = OffsetDateTime.parse(value, formatter);
metadata.setCreationDate(creationDate);
} else if (key.equals("ModDate"))
throw new Exception("ModDate cannot be set.");
else if (key.equals("Creator"))
metadata.setCreator(value);
else if (key.equals("Producer"))
throw new Exception("Producer is set by means of the license key.");
else
metadata.getCustomEntries().put(key, value);
outDoc.setMetadata(metadata);
}
}
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));
}
Download code sample
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 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()

# Copy all pages and append to output document
copied_pages = PageList.copy(out_doc, in_doc.pages, page_copy_options)
out_doc.pages.extend(copied_pages)

# Set info entry
metadata = Metadata.copy(out_doc, in_doc.metadata)
if key == "Title":
metadata.title = value
elif key == "Author":
metadata.author = value
elif key == "Subject":
metadata.subject = value
elif key == "Keywords":
metadata.keywords = value
elif key == "CreationDate":
# Use of the ISO 8601 format for the date
date_format = "%Y-%m-%dT%H:%M:%S"
parsed_date = datetime.strptime(value, date_format)
metadata.creation_date = parsed_date
elif key == "ModDate":
raise Exception("ModDate cannot be set.")
elif key == "Creator":
metadata.creator = value
elif key == "Producer":
raise Exception("Producer is set by means of the license key.")
else:
metadata.custom_entries[key] = value

# Assign modified metadata to the output document
out_doc.metadata = metadata

Set the open-destination of a PDF

Download code sample
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
{
if (destinationPageNumber < 1 || destinationPageNumber > inDoc.Pages.Count)
throw new ArgumentOutOfRangeException("Given page number is invalid");

// 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 all pages and append to output document
PageList copiedPages = PageList.Copy(outDoc, inDoc.Pages, copyOptions);
outDoc.Pages.AddRange(copiedPages);

// Add open destination
Page outPage = copiedPages[destinationPageNumber - 1];
outDoc.OpenDestination = LocationZoomDestination.Create(outDoc, outPage, 0, outPage.Size.Height, null);
}
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));
}
Download code sample
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)) {

// Check given page number
if (destinationPageNumber < 1 || destinationPageNumber > inDoc.getPages().size()) {
System.out.println("Given pageNumber is invalid.");
return;
}

// 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);

// Add open destination
Page outPage = outDoc.getPages().get(destinationPageNumber - 1);
LocationZoomDestination destination = LocationZoomDestination.create(outDoc, outPage, 0.0, outPage.getSize().getHeight(), null);
outDoc.setOpenDestination(destination);
}
}
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));
}
Download code sample
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))
destination_page_number = int(page_number)

# Open input document
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:

if destination_page_number < 1 or destination_page_number > len(in_doc.pages):
raise ValueError("Given page number is invalid")

# 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()

# Copy all pages and append to output document
copied_pages = PageList.copy(out_doc, in_doc.pages, page_copy_options)
out_doc.pages.extend(copied_pages)

# Add open destination
out_page = copied_pages[destination_page_number - 1]
out_doc.open_destination = LocationZoomDestination.create(out_doc, out_page, 0, out_page.size.height, None)

Remove pages from PDF

Download code sample
// 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());

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());
int nInPages = PtxPdf_PageList_GetCount(pInPageList);
iStartIndex = MAX(MIN(nInPages - 1, iStartIndex), 0);
nCount = MIN(nInPages - iStartIndex, nCount);
GOTO_CLEANUP_IF_FALSE(nCount > 0, _T("lastPage must be greater or equal to firstPage.\n"));

// 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 page range from input pages
pInPageRange = PtxPdf_PageList_GetRange(pInPageList, iStartIndex, nCount);
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 page range to toutput document
pOutPageRange = PtxPdf_PageList_Copy(pOutDoc, pInPageRange, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageRange, _T("Failed to copy page range. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());

// Get output pages
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());

// Appende page range to output pages
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pOutPageRange),
_T("Failed to append page range. %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;
}
Download code sample
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
{
startIndex = Math.Max(Math.Min(inDoc.Pages.Count - 1, startIndex), 0);
count = Math.Min(inDoc.Pages.Count - startIndex, count);
if (count <= 0)
{
Console.WriteLine("lastPage must be greater or equal to firstPage");
return;
}

// 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();

// Get page range from input pages
PageList inPageRange = inDoc.Pages.GetRange(startIndex, count);

// Copy page range and append to output document
PageList outPageRange = PageList.Copy(outDoc, inPageRange, copyOptions);
outDoc.Pages.AddRange(outPageRange);
}
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));
}
Download code sample
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null)) {
// Get pages from input document
PageList inPages = inDoc.getPages();

// Correct and check page indices
startIndex = Math.max(Math.min(inPages.size() - 1, startIndex), 0);
endIndex = Math.max(Math.min(inPages.size(), endIndex), 0);
if (startIndex >= endIndex) {
System.out.println("lastPage must be greater or equal to firstPage");
return;
}
try (
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 page range from input pages
PageList inPageRange = inPages.subList(startIndex, endIndex);

// Copy page range and append to output document
PageList outPageRange = PageList.copy(outDoc, inPageRange, copyOptions);
outDoc.getPages().addAll(outPageRange);
}
}
}
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 mbedded files
FileReferenceList outEmbeddedFiles = outDoc.getPlainEmbeddedFiles();
for (FileReference inFileRef : inDoc.getPlainEmbeddedFiles())
outEmbeddedFiles.add(FileReference.copy(outDoc, inFileRef));
}
Download code sample
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))
start_index = int(first_page) - 1
last_page = int(last_page)
count = last_page - start_index

# Open input document
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:

# Validate page range
start_index = max(min(len(in_doc.pages) - 1, start_index), 0)
count = min(len(in_doc.pages) - start_index, count)
if count <= 0:
raise ValueError("lastPage must be greater or equal to firstPage")

# 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()

# Get page range from input pages
in_page_range = in_doc.pages[start_index:last_page]

# Copy page range and append to output document
out_page_range = PageList.copy(out_doc, in_page_range, page_copy_options)
out_doc.pages.extend(out_page_range)

Split at Outlines

Download code sample
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
{
// Collect all outline items at the given level
List<OutlineItem> outlines = GetOutlines(inDoc.Outline, level);

// Collect all page ranges corresponding to the given outline items
List<Tuple<PageList, OutlineItem>> parts = GetParts(inDoc.Pages, outlines);

// Iterate over all collected parts
foreach (var part in parts)
{
// Turn the outline item's title into a valid file name
string fileName = part.Item2.Title;
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
fileName = fileName.Replace(c, '_');
}
fileName += ".pdf";
fileName = System.IO.Path.Combine(outDir, fileName);

// Create output document
using Stream outStream = new FileStream(fileName, 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 pageCopyOptions = new PageCopyOptions();
pageCopyOptions.CopyOutlineItems = false;

// Copy the pages and add to the output document's page list
PageList outPages = PageList.Copy(outDoc, part.Item1, pageCopyOptions);
outDoc.Pages.AddRange(outPages);

// Copy child outline items
OutlineCopyOptions outlineCopyOptions = new OutlineCopyOptions();
foreach (var child in part.Item2.Children)
{
outDoc.Outline.Add(OutlineItem.Copy(outDoc, child, outlineCopyOptions));
}
}
}
private static List<OutlineItem> GetOutlines(OutlineItemList currentOutlines, int level, int currentLevel = 1)
{
List<OutlineItem> matchingOutlines = new List<OutlineItem>();
// If the current level matches the specified level add the given outline items
if (level == currentLevel)
{
matchingOutlines.AddRange(currentOutlines);
}
else
{
// Otherwise recurse to next level
foreach (var outline in currentOutlines)
{
matchingOutlines.AddRange(GetOutlines(outline.Children, level, currentLevel + 1));
}
}
return matchingOutlines;
}
private static List<Tuple<PageList, OutlineItem>> GetParts(PageList inPages, List<OutlineItem> outlines)
{
// Construct parts according to the given outlines
List<Tuple<PageList, OutlineItem>> parts = new List<Tuple<PageList, OutlineItem>>();

// No parts to be constructed if no outlines are found
if (outlines.Count == 0)
return parts;

// Keep both the last and the next outline items while iterating
OutlineItem lastOutline = null;
var outlineEnumerator = outlines.GetEnumerator();
outlineEnumerator.MoveNext();
OutlineItem nextOutline = outlineEnumerator.Current;

// Keep both, the last and the current page index while iterating
int lastPageIndex = 0;
for (int pageIndex = 0; pageIndex < inPages.Count; pageIndex++)
{
// Check if this page is the destination's page of the next outline
if (inPages[pageIndex].Equals(nextOutline.Destination.Target.Page))
{
// Create a new part if the last outline item is defined and if the page index has increased at least by 1
if (lastOutline != null && pageIndex - lastPageIndex > 0)
parts.Add(new Tuple<PageList, OutlineItem>(inPages.GetRange(lastPageIndex, pageIndex - lastPageIndex), lastOutline));

// Keep the current page index as the last page index used
lastPageIndex = pageIndex;

// Keep the current outline as the last outline used
lastOutline = nextOutline;

// Iterate to the next outline item and stop if none left
if (outlineEnumerator.MoveNext())
nextOutline = outlineEnumerator.Current;
else
break;
}
}
// Add the last part which is assumed to contain all the pages until the end of the document
parts.Add(new Tuple<PageList, OutlineItem>(inPages.GetRange(lastPageIndex, inPages.Count - lastPageIndex), lastOutline));
return parts;
}
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));
}
Download code sample
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 get_outlines(current_outlines: OutlineItemList, level: int, current_level: int = 1) -> list:
"""Recursively collect outline items at the specified level."""
matching_outlines = []
# If the current level matches the specified level add the given outline items
if level == current_level:
matching_outlines.extend(current_outlines)
else:
# Otherwise recurse to next level
for outline in current_outlines:
matching_outlines.extend(get_outlines(outline.children, level, current_level + 1))

return matching_outlines
def get_parts(in_pages: PageList, outlines: list) -> list:
"""Collect page ranges corresponding to the outlines."""
# Construct parts according to the given outlines
parts = []

# No parts to be constructed if no outlines are found
if not outlines or len(outlines) == 0:
return parts

# Keep both the last and the next outline items while iterating
last_outline = None
last_page_index = 0

for page_index, page in enumerate(in_pages):
# Check if this page is the destination's page of the next outline
if outlines and page == outlines[0].destination.target.page:
# Create a new part if the last outline item is defined and if the page index has increased at least by 1
if last_outline and page_index - last_page_index > 0:
parts.append((in_pages[last_page_index:page_index], last_outline))
last_outline = outlines.pop(0)

# Keep the current page index as the last page index used
last_page_index = page_index

# Add the last part which is assumed to contain all the pages until the end of the document
if last_outline:
parts.append((in_pages[last_page_index:], last_outline))

return parts
# Get the level from the arguments, default to 1 if not provided
level = int(level)
if level < 1:
raise ValueError("The level must be greater than zero.")

# Ensure the output directory exists
os.makedirs(output_dir, exist_ok=True)

# Open input document
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:

# Collect all outline items at the given level
outlines = get_outlines(in_doc.outline, level)

# Collect all page ranges corresponding to the given outline items
parts = get_parts(in_doc.pages, outlines)

# Iterate over all collected parts
for page_list, outline_item in parts:
# Turn the outline item's title into a valid file name
file_name = "".join([c if c.isalnum() or c in "._-" else "_" for c in outline_item.title.replace("\x00", "")]) + ".pdf"
file_path = os.path.join(output_dir, file_name)

# Create output document
with io.FileIO(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()
page_copy_options.copy_outline_items = False

# Copy the pages and add to the output document's page list
out_pages = PageList.copy(out_doc, page_list, page_copy_options)
out_doc.pages.extend(out_pages)

# Copy child outline items
outline_copy_options = OutlineCopyOptions()
for child in outline_item.children:
out_doc.outline.append(OutlineItem.copy(out_doc, child, outline_copy_options))

Document Structure

Create tagged PDF

Download code sample
// Create output document
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, Conformance.Pdf17, null))
{
// Create a font
Font font = CreateFontWithFallbacks(outDoc, ARIAL_AND_FALLBACKS);

outDoc.Language = "en";
outDoc.SetPdfUaConformant();
outDoc.Metadata.Title = "TaggedPDF";
outDoc.ViewerSettings.DisplayDocumentTitle = true;

// Create a page
Size pageSize = new Size { Width = ToPoints(21, "cm"), Height = ToPoints(29.7, "cm") }; // DIN A4
Page outPage = Page.Create(outDoc, pageSize);
CreateAndTagContent(outDoc, outPage, imagePath, font);
outDoc.Pages.Add(outPage);
}
private static void CreateAndTagContent(Document outputDoc, Page outPage, string imagePath, Font font)
{
using (ContentGenerator gen = new ContentGenerator(outPage.Content, false))
{
Tree structTree = new Tree(outputDoc);
Node docNode = structTree.DocumentNode;
Node sectionNode = new Node("Sect", outputDoc, outPage);
docNode.Children.Add(sectionNode);

// Start from the top of the page with margin
double currentY = outPage.Size.Height - MARGIN;

// Create header
NodeAndPosition np = CreateAndTagText(
outputDoc,
outPage,
gen,
sectionNode,
font,
currentY,
"H1",
"This is a properly tagged heading",
24.0
);

// Add padding and create paragraph
currentY = np.position;
currentY -= PADDING;
np = CreateAndTagText(
outputDoc,
outPage,
gen,
sectionNode,
font,
currentY,
"P",
"This is a properly tagged paragraph. Both heading and paragraph belong to a section.",
12.0
);

// Add padding and create image
currentY = np.position;
currentY -= PADDING;
CreateAndTagImage(outputDoc, outPage, gen, imagePath, currentY, np.node);
}
}
/// <summary>
/// Create and tag a text element (header, paragraph, etc.).
/// </summary>
/// <param name="outputDoc">The output document</param>
/// <param name="outPage">The output page</param>
/// <param name="gen">The content generator</param>
/// <param name="sectionNode">The section node to add the text element to</param>
/// <param name="font">The font to use</param>
/// <param name="topY">Y coordinate for the top of this element</param>
/// <param name="tagName">PDF structure tag name (e.g., "H1", "P")</param>
/// <param name="textContent">The text content to display</param>
/// <param name="fontSize">Font size in points</param>
/// <returns>Bottom Y coordinate of this element and created node</returns>
private static NodeAndPosition CreateAndTagText(
Document outputDoc,
Page outPage,
ContentGenerator gen,
Node sectionNode,
Font font,
double topY,
string tagName,
string textContent,
double fontSize)
{
Node textNode = new Node(tagName, outputDoc, outPage);
textNode.ActualText = textContent;
textNode.Language = "en";
gen.TagAs(textNode);
Text text = Text.Create(outputDoc);
sectionNode.Children.Add(textNode);

// Calculate text baseline position
double baselineY = topY - fontSize * font.Ascent;

using (TextGenerator textGen = new TextGenerator(text, font, fontSize, null))
{
Point position = new Point { X = MARGIN, Y = baselineY };
textGen.MoveTo(position);
textGen.ShowLine(textNode.ActualText);
}

gen.PaintText(text);
gen.StopTagging();

// Return bottom coordinate (baseline - descent)
return new NodeAndPosition(baselineY - fontSize * font.Descent, textNode);
}
/// <summary>
/// Create and tag an image element.
/// </summary>
/// <param name="outputDoc">The output document</param>
/// <param name="outPage">The output page</param>
/// <param name="gen">The content generator</param>
/// <param name="imagePath">Path to the image file</param>
/// <param name="topY">Y coordinate for the top of this element</param>
/// <param name="parent">Parent node</param>
/// <returns>Bottom Y coordinate of this element</returns>
private static double CreateAndTagImage(Document outputDoc, Page outPage, ContentGenerator gen,
string imagePath, double topY, Node parent)
{
Node figureNode = new Node("Figure", outputDoc, outPage);
figureNode.AlternateText = "PdfTools AG Logo";
parent.Children.Add(figureNode);

figureNode.Language = "en";

figureNode.SetStringAttribute("O", "Layout");

gen.TagAs(figureNode);

Image image;
try
{
using (Stream inImage = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
{
image = Image.Create(outputDoc, inImage);
}
}
catch (Exception e)
{
throw new InvalidOperationException(
"Failed to create image from file " + imagePath + ": " + e.Message + ". " +
"Please ensure the file is a valid image format (PNG, JPEG, etc.).");
}

double x = MARGIN;
double width = ToPoints(2.0, "cm");
double height = width * image.Size.Height / image.Size.Width; // preserve aspect ratio

Rectangle rect = new Rectangle
{
Left = x, // left
Bottom = topY - height, // bottom (Rectangle coordinates: bottom is lower than top)
Right = x + width, // right
Top = topY // top
};

figureNode.BoundingBox = rect;

gen.PaintImage(image, rect);
gen.StopTagging();

// Return bottom coordinate
return topY - height;
}
/// <summary>
/// Try to create a font using common font names that are likely to be available
/// on Windows, Linux, and Mac systems. Throws an exception if no font can be created.
/// </summary>
private static Font CreateFontWithFallbacks(Document document, string[] fontAndFallbacks)
{
foreach (string fontName in fontAndFallbacks)
{
try
{
Font font = Font.CreateFromSystem(document, fontName, "", true);
if (font != null)
{
return font;
}
}
catch (Exception)
{
// Try next font
}
}

// If we get here, no font worked
throw new InvalidOperationException(
"Unable to create font. Tried the following fonts: " + string.Join(", ", fontAndFallbacks) + ". " +
"Please ensure you have at least one of these fonts installed on your system.");
}
/// <summary>
/// Convert measurement from inches or centimeters to points.
/// </summary>
/// <param name="value">The measurement value</param>
/// <param name="unit">Unit of measurement ("in" for inches, "cm" for centimeters)</param>
/// <returns>Value converted to points (1 inch = 72 points, 1 cm ≈ 28.35 points)</returns>
private static double ToPoints(double value, string unit)
{
if (unit == "in")
{
return value * 72.0; // 1 inch = 72 points
}
else if (unit == "cm")
{
return value * 28.346456693; // 1 cm = 28.346456693 points (72/2.54)
}
else
{
throw new ArgumentException(
"Unsupported unit " + unit + ". Use 'in' for inches or 'cm' for centimeters.", nameof(unit));
}
}
Download code sample
// Create a PDF document
try (FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW);
Document outDoc = Document.create(outStream, Conformance.PDF17, null)) {

// Create a font
Font font = createFontWithFallbacks(outDoc, ARIAL_AND_FALLBACKS);

outDoc.setLanguage("en");
outDoc.setPdfUaConformant();
outDoc.getMetadata().setTitle("TaggedPDF");
outDoc.getViewerSettings().setDisplayDocumentTitle(true);

// Create a page
Size pageSize = new Size(toPoints(21, "cm"), toPoints(29.7, "cm")); // DIN A4
Page outPage = Page.create(outDoc, pageSize);
createAndTagContent(outDoc, outPage, imagePath, font);
outDoc.getPages().add(outPage);
}

private static void createAndTagContent(Document outDoc, Page outPage, String imagePath, Font font) throws Exception {
try (ContentGenerator gen = new ContentGenerator(outPage.getContent(), false)) {
Tree structTree = new Tree(outDoc);
Node docNode = structTree.getDocumentNode();
Node sectionNode = new Node("Sect", outDoc, outPage);
docNode.getChildren().add(sectionNode);

// Start from the top of the page with margin
double currentY = outPage.getSize().getHeight() - MARGIN;

// Create header
NodeAndPosition np = createAndTagText(
outDoc,
outPage,
gen,
sectionNode,
font,
currentY,
"H1",
"This is a properly tagged heading",
24.0
);

// Add padding and create paragraph
currentY = np.position;
currentY -= PADDING;
np = createAndTagText(
outDoc,
outPage,
gen,
sectionNode,
font,
currentY,
"P",
"This is a properly tagged paragraph. Both heading and paragraph belong to a section.",
12.0
);

// Add padding and create image
currentY = np.position;
currentY -= PADDING;
createAndTagImage(outDoc, outPage, gen, imagePath, currentY, np.node);
}
}
/**
* Create and tag a text element (header, paragraph, etc.).
*
* @param outDoc The output document
* @param outPage The output page
* @param gen The content generator
* @param sectionNode The section node to add the text element to
* @param font The font to use
* @param topY Y coordinate for the top of this element
* @param tagName PDF structure tag name (e.g., "H1", "P")
* @param textContent The text content to display
* @param fontSize Font size in points
* @return Bottom Y coordinate of this element and created node
*/
private static NodeAndPosition createAndTagText(
Document outDoc,
Page outPage,
ContentGenerator gen,
Node sectionNode,
Font font,
double topY,
String tagName,
String textContent,
double fontSize) throws Exception {

Node textNode = new Node(tagName, outDoc, outPage);
textNode.setActualText(textContent);
textNode.setLanguage("en");
gen.tagAs(textNode);
Text text = Text.create(outDoc);
sectionNode.getChildren().add(textNode);

// Calculate text baseline position
double baselineY = topY - fontSize * font.getAscent();

try (TextGenerator textGen = new TextGenerator(text, font, fontSize, null)) {
Point position = new Point(MARGIN, baselineY);
textGen.moveTo(position);
textGen.showLine(textNode.getActualText());
}
gen.paintText(text);
gen.stopTagging();

// Return bottom coordinate (baseline - descent)
return new NodeAndPosition(textNode, baselineY - fontSize * font.getDescent());
}
/**
* Create and tag an image element.
*
* @param outDoc The output document
* @param outPage The output page
* @param gen The content generator
* @param imagePath Path to the image file
* @param topY Y coordinate for the top of this element
* @param parent Parent node
* @return Bottom Y coordinate of this element
*/
private static double createAndTagImage(
Document outDoc,
Page outPage,
ContentGenerator gen,
String imagePath,
double topY, Node parent) throws Exception {

Node figureNode = new Node("Figure", outDoc, outPage);
figureNode.setAlternateText("PdfTools AG Logo");
gen.tagAs(figureNode);

figureNode.setLanguage("en");
figureNode.setStringAttribute("O", "Layout");

Image image;
try (FileStream inImage = new FileStream(imagePath, FileStream.Mode.READ_ONLY)) {
image = Image.create(outDoc, inImage);
} catch (Exception e) {
throw new RuntimeException(
String.format("Failed to create image from file '%s': %s. " +
"Please ensure the file is a valid image format (PNG, JPEG, etc.).",
imagePath, e.getMessage())
);
}

double x = MARGIN;
double width = toPoints(2.0, "cm");
double height = width * image.getSize().getHeight() / image.getSize().getWidth(); // preserve aspect ratio

Rectangle rect = new Rectangle(
x, // left
topY - height, // bottom (Rectangle coordinates: bottom is lower than top)
x + width, // right
topY // top
);

figureNode.setBoundingBox(rect);

parent.getChildren().add(figureNode);

gen.paintImage(image, rect);
gen.stopTagging();

// Return bottom coordinate
return topY - height;
}
/**
* Try to create a font using common font names that are likely to be available
* on Windows, Linux, and Mac systems. Throws an exception if no font can be created.
*/
private static Font createFontWithFallbacks(Document document, String[] fontAndFallbacks) {
for (String fontName : fontAndFallbacks) {
try {
Font font = Font.createFromSystem(document, fontName, "", true);
if (font != null) {
return font;
}
} catch (Exception e) {
// Try next font
}
}

// If we get here, no font worked
throw new RuntimeException(
String.format("Unable to create font. Tried the following fonts: %s. " +
"Please ensure you have at least one of these fonts installed on your system.",
String.join(", ", ARIAL_AND_FALLBACKS))
);
}
Download code sample
def to_points(value: float, unit: str = "cm") -> float:
"""
Convert measurement from inches or centimeters to points.

Args:
value: The measurement value
unit: Unit of measurement ("in" for inches, "cm" for centimeters)

Returns:
Value converted to points (1 inch = 72 points, 1 cm ≈ 28.35 points)
"""
if unit == "in":
return value * 72.0 # 1 inch = 72 points
elif unit == "cm":
return value * 28.346456693 # 1 cm = 28.346456693 points (72/2.54)
else:
raise ValueError(
f"Unsupported unit '{unit}'. Use 'in' for inches or 'cm' for centimeters."
)
# Look & Feel
MARGIN = to_points(2.5, "cm")
PADDING = to_points(1, "cm")
ARIAL_AND_FALLBACKS = [
"Arial", # Common on Windows, available on most systems
"Liberation Sans", # Common on Linux
"DejaVu Sans", # Common on Linux
"Helvetica", # Common on macOS
"sans-serif", # Generic fallback
]
def create_font_with_fallbacks(
document: Document, font_and_fallbacks: list[str]
) -> Font:
"""
Try to create a font using common font names that are likely to be available
on Windows, Linux, and Mac systems. Raises an exception if no font can be created.
"""
for font_name in font_and_fallbacks:
try:
font = Font.create_from_system(document, font_name, "", True)
if font is not None:
return font
except Exception:
# Try next font
continue

# If we get here, no font worked
raise RuntimeError(
f"Unable to create font. Tried the following fonts: {', '.join(font_and_fallbacks)}. "
"Please ensure you have at least one of these fonts installed on your system."
)
def create_and_tag_text(
out_doc: Document,
out_page: Page,
gen: ContentGenerator,
section_node: Node,
font: Font,
top_y: float,
tag_name: str,
text_content: str,
font_size: float,
) -> float:
"""
Create and tag a text element (header, paragraph, etc.).

Args:
top_y: Y coordinate for the top of this element
tag_name: PDF structure tag name (e.g., "H1", "P")
text_content: The text content to display
font_size: Font size in points

Returns:
Bottom Y coordinate of this element
"""
text_node = Node(tag_name, out_doc, out_page)
text_node.actual_text = text_content
gen.tag_as(text_node)
text = Text.create(out_doc)
section_node.children.append(text_node)

text_node.language = "en"

# Calculate text baseline position
baseline_y = top_y - font_size * font.ascent

with TextGenerator(text, font, font_size, None) as text_gen:
position = Point(MARGIN, baseline_y)
text_gen.move_to(position)
text_gen.show_line(text_node.actual_text)
gen.paint_text(text)
gen.stop_tagging()

# Return bottom coordinate (baseline - descent)
return text_node, baseline_y - font_size * font.descent
def create_and_tag_image(
out_doc: Document,
out_page: Page,
gen: ContentGenerator,
input_image_path: str,
top_y: float,
parent: Node
) -> float:
"""
Create and tag an image element.

Args:
top_y: Y coordinate for the top of this element

Returns:
Bottom Y coordinate of this element
"""

figure_node = Node("Figure", out_doc, out_page)
figure_node.alternate_text = "PdfTools AG Logo"
figure_node.language = "en"
figure_node.set_string_attribute("O", "Layout")
gen.tag_as(figure_node)

try:
with io.FileIO(input_image_path, "rb") as in_image:
image = Image.create(out_doc, in_image)
except Exception as e:
raise RuntimeError(
f"Failed to create image from file '{input_image_path}': {str(e)}. "
"Please ensure the file is a valid image format (PNG, JPEG, etc.)."
)

x = MARGIN
width = to_points(2.0, "cm")
height = width * image.size.height / image.size.width # preserve aspect ratio

rect = Rectangle(
left=x,
bottom=top_y - height, # Rectangle coordinates: bottom is lower than top
right=x + width,
top=top_y,
)
gen.paint_image(image, rect)
gen.stop_tagging()

figure_node.bounding_box = rect

parent.children.append(figure_node)

# Return bottom coordinate
return top_y - height
def create_and_tag_content(
out_doc: Document,
out_page: Page,
input_image_path: str,
font: Font,
):
with ContentGenerator(out_page.content, False) as gen:
struct_tree = Tree(out_doc)
doc_node = struct_tree.document_node
section_node = Node("Sect", out_doc, out_page)
doc_node.children.append(section_node)

# Start from the top of the page with margin
current_y = out_page.size.height - MARGIN

# Create header
node, current_y = create_and_tag_text(
out_doc,
out_page,
gen,
section_node,
font,
current_y,
"H1",
"This is a properly tagged heading",
24.0,
)

# Add padding and create paragraph
current_y -= PADDING
node, current_y = create_and_tag_text(
out_doc,
out_page,
gen,
section_node,
font,
current_y,
"P",
"This is a properly tagged paragraph. Both heading and paragraph belong to a section.",
12.0,
)

# Add padding and create image
current_y -= PADDING
create_and_tag_image(out_doc, out_page, gen, input_image_path, current_y, node)
# Check if image file exists
if not os.path.isfile(input_image_path):
raise FileNotFoundError(
f"Image file not found: '{input_image_path}'. "
"Please ensure the image file exists and the path is correct."
)
# Create a PDF document
with io.FileIO(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, Conformance.PDF17, None) as out_doc:
# Create a font
font = create_font_with_fallbacks(out_doc, ARIAL_AND_FALLBACKS)

out_doc.language = "en"
out_doc.set_pdf_ua_conformant()
out_doc.metadata.title = "TaggedPDF"
out_doc.viewer_settings.display_document_title = True

# Create a page
page_size = Size(to_points(21, "cm"), to_points(29.7, "cm")) # DIN A4
out_page = Page.create(out_doc, page_size)

create_and_tag_content(out_doc, out_page, input_image_path, font)
out_doc.pages.append(out_page)

Tag existing PDF content

Download code sample
// 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);

outDoc.Language = "en";
outDoc.SetPdfUaConformant();
outDoc.Metadata.Title = "TaggedPDF";
outDoc.ViewerSettings.DisplayDocumentTitle = true;

// Create empty output page
Page inPage = inDoc.Pages[0];
Page outPage = Page.Create(outDoc, inPage.Size);

// We create an output page and copy the content elements from the input page to the output page.
// While copying, we also check if the current element is the one we want to tag.
// If it is, we tag it and update the logical structure accordingly.
// You can easily adapt this sample to fit similar scenarios.
CopyAndTagContent(inPage, outPage, outDoc);
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 CopyAndTagContent(Page inPage, Page outPage, Document outDoc)
{
var structTree = new Tree(outDoc);
var documentNode = structTree.DocumentNode;
var section = new Node("Sect", outDoc, outPage);
documentNode.Children.Add(section);

// Use a content extractor and a content generator to copy content
ContentExtractor extractor = new ContentExtractor(inPage.Content);
using ContentGenerator generator = new ContentGenerator(outPage.Content, false);

Node p = new Node("P", outDoc);

// 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 CopyAndTagContent() recursively for the group element's content
CopyAndTagContent(inPage, outPage, outDoc);
}
else
{
// Copy the content element to the output document
outElement = ContentElement.Copy(outDoc, inElement);
if (outElement is TextElement outTextElement)
{
if (outTextElement.Text[0].Text == "This is a properly tagged heading")
{
CopyAndTagTextElement(outTextElement, section, generator, outPage, outDoc, "H1");
}
else if (outTextElement.Text[0].Text == "This is a properly tagged paragraph. Both heading and paragraph belong to a section.")
{
p = CopyAndTagTextElement(outTextElement, section, generator, outPage, outDoc, "P");
}

}
else if (outElement is ImageElement imageElement)
{
var bbox = imageElement.Transform.TransformRectangle(outElement.BoundingBox);
if (Math.Abs(bbox.BottomLeft.X - 70.86) < 0.5 && Math.Abs(bbox.BottomLeft.Y - 632.65) < 0.5 && Math.Abs(bbox.TopRight.X - 127.559) < 0.5 && Math.Abs(bbox.TopRight.Y - 689.34) < 0.5)
{
CopyAndTagImageElement(imageElement, generator, outPage, outDoc, "PdfTools AG Logo", p);
}
}
else
{
throw new InvalidOperationException("Unexpected content element found.");
}
}
}
}
private static void CopyAndTagImageElement(ImageElement imageElement, ContentGenerator generator, Page outPage, Document outDoc, string alternateText, Node p)
{
Node imgElement = new Node("Figure", outDoc, outPage);

imgElement.AlternateText = alternateText;
imgElement.Language = "en";

var bbox = imageElement.Transform.TransformRectangle(imageElement.BoundingBox);
var rectangle = new Rectangle();
rectangle.Left = bbox.BottomLeft.X;
rectangle.Bottom = bbox.BottomLeft.Y;
rectangle.Right = bbox.TopRight.X;
rectangle.Top = bbox.TopRight.Y;

imgElement.BoundingBox = rectangle;
imgElement.SetStringAttribute("O", "Layout");

p.Children.Add(imgElement);

generator.TagAs(imgElement);

generator.AppendContentElement(imageElement);

generator.StopTagging();
}
private static Node CopyAndTagTextElement(TextElement textElement, Node section, ContentGenerator generator, Page outPage, Document outDoc, string tag)
{
Node element = new Node(tag, outDoc, outPage);
element.ActualText = textElement.Text[0].Text;
element.Language = "en";

section.Children.Add(element);

generator.TagAs(element);

generator.AppendContentElement(textElement);

generator.StopTagging();

return element;
}
Download code sample
try (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);
Document outDoc = Document.create(outStream, inDoc.getConformance(), null)) {

// Copy document-wide data
copyDocumentData(inDoc, outDoc);

outDoc.setLanguage("en");
outDoc.setPdfUaConformant();
outDoc.getMetadata().setTitle("TaggedPDF");
outDoc.getViewerSettings().setDisplayDocumentTitle(true);

// Create empty output page
Page inPage = inDoc.getPages().get(0);
Page outPage = Page.create(outDoc, inPage.getSize());

// We create an output page and copy the content elements from the input page to the output page.
// While copying, we also check if the current element is the one we want to tag.
// If it is, we tag it and update the logical structure accordingly.
// You can easily adapt this sample to fit similar scenarios.
copyAndTagContent(inPage, outPage, outDoc);
outDoc.getPages().add(outPage);
}
private static void copyDocumentData(Document inDoc, Document outDoc) throws Exception {
// Copy output intent
if (inDoc.getOutputIntent() != null)
outDoc.setOutputIntent(IccBasedColorSpace.copy(outDoc, inDoc.getOutputIntent()));

// Copy metadata
outDoc.setMetadata(Metadata.copy(outDoc, inDoc.getMetadata()));

// Copy viewer settings
outDoc.setViewerSettings(ViewerSettings.copy(outDoc, inDoc.getViewerSettings()));

// Copy associated files
FileReferenceList outAssociatedFiles = outDoc.getAssociatedFiles();
for (FileReference inFileRef : inDoc.getAssociatedFiles()) {
outAssociatedFiles.add(FileReference.copy(outDoc, inFileRef));
}

// Copy plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.getPlainEmbeddedFiles();
for (FileReference inFileRef : inDoc.getPlainEmbeddedFiles()) {
outEmbeddedFiles.add(FileReference.copy(outDoc, inFileRef));
}
}
private static void copyAndTagContent(Page inPage, Page outPage, Document outDoc) throws ToolboxException, IOException {
Tree structTree = new Tree(outDoc);
Node documentNode = structTree.getDocumentNode();
Node section = new Node("Sect", outDoc, outPage);
documentNode.getChildren().add(section);

Node p = new Node("P", outDoc, null);

ContentExtractor extractor = new ContentExtractor(inPage.getContent());
try (ContentGenerator generator = new ContentGenerator(outPage.getContent(), false)) {
for (ContentElement inElement : extractor) {
ContentElement outElement;

if (inElement instanceof GroupElement) {
GroupElement inGroup = (GroupElement) inElement;
GroupElement outGroup = GroupElement.copyWithoutContent(outDoc, inGroup);
outElement = outGroup;
// Call CopyAndTagContent() recursively for the group element's content
copyAndTagContent(inPage, outPage, outDoc);
} else {
outElement = ContentElement.copy(outDoc, inElement);

if (outElement instanceof TextElement) {
TextElement text = (TextElement) outElement;
String str = text.getText().get(0).getText();

if ("This is a properly tagged heading".equals(str)) {
copyAndTagTextElement(text, section, generator, outPage, outDoc, "H1");
} else if ("This is a properly tagged paragraph. Both heading and paragraph belong to a section.".equals(str)) {
p = copyAndTagTextElement(text, section, generator, outPage, outDoc, "P");
}else{
throw new RuntimeException("Unexpected content element found.");
}
} else if (outElement instanceof ImageElement) {
ImageElement image = (ImageElement) outElement;
Quadrilateral bbox = image.getTransform().transformRectangle(image.getBoundingBox());

if (Math.abs(bbox.getBottomLeft().getX() - 70.86) < 0.5 &&
Math.abs(bbox.getBottomLeft().getY() - 632.65) < 0.5 &&
Math.abs(bbox.getTopRight().getX() - 127.559) < 0.5 &&
Math.abs(bbox.getTopRight().getY() - 689.34) < 0.5) {

copyAndTagImageElement(image, p, generator, outPage, outDoc, "PdfTools AG Logo");
}else{
throw new RuntimeException("Unexpected content element found.");
}
} else {
throw new RuntimeException("Unexpected content element found.");
}
}
}
}
}
private static void copyAndTagImageElement(ImageElement imageElement, Node parentNode, ContentGenerator generator,
Page outPage, Document outDoc, String altText) throws NotFoundException, UnsupportedFeatureException {
Node figure = new Node("Figure", outDoc, outPage);
figure.setAlternateText(altText);

figure.setLanguage("en");

Quadrilateral bbox = imageElement.getTransform().transformRectangle(imageElement.getBoundingBox());
Rectangle rectangle = new Rectangle();
rectangle.setLeft(bbox.getBottomLeft().getX());
rectangle.setBottom(bbox.getBottomLeft().getY());
rectangle.setRight(bbox.getTopRight().getX());
rectangle.setTop(bbox.getTopRight().getY());

figure.setBoundingBox(rectangle);
figure.setStringAttribute("O", "Layout");

parentNode.getChildren().add(figure);

generator.tagAs(figure);
generator.appendContentElement(imageElement);
generator.stopTagging();
}
private static Node copyAndTagTextElement(TextElement textElement, Node section, ContentGenerator generator,
Page outPage, Document outDoc, String tag) throws NotFoundException, UnsupportedFeatureException {
Node tagNode = new Node(tag, outDoc, outPage);
tagNode.setActualText(textElement.getText().get(0).getText());
section.getChildren().add(tagNode);

tagNode.setLanguage("en");

generator.tagAs(tagNode);
generator.appendContentElement(textElement);
generator.stopTagging();

return tagNode;
}
Download code sample
def copy_document_data(in_doc: Document, out_doc: Document):
if in_doc.output_intent is not None:
out_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)

out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)

out_associated_files = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
out_associated_files.append(FileReference.copy(out_doc, in_file_ref))

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_tag_text_element(text_element: TextElement, section_node: Node, generator: ContentGenerator,
out_page: Page, out_doc: Document, tag: str):
text_node = Node(tag, out_doc, out_page)
text_node.actual_text = text_element.text[0].text
text_node.language = "en"
section_node.children.append(text_node)

generator.tag_as(text_node)
generator.append_content_element(text_element)
generator.stop_tagging()

return text_node
def copy_and_tag_image_element(image_element: ImageElement, parent: Node, generator: ContentGenerator,
out_page: Page, out_doc: Document, alternate_text: str):
image_node = Node("Figure", out_doc, out_page)
image_node.alternate_text = alternate_text
image_node.language = "en"
image_node.set_string_attribute("O", "Layout")

bbox = image_element.transform.transform_rectangle(image_element.bounding_box)
rectangle = Rectangle()
rectangle.left = bbox.bottom_left.x
rectangle.bottom = bbox.bottom_left.y
rectangle.right = bbox.top_right.x
rectangle.top = bbox.top_right.y

image_node.bounding_box = rectangle

parent.children.append(image_node)

generator.tag_as(image_node)
generator.append_content_element(image_element)
generator.stop_tagging()
def copy_and_tag_content(in_page: Page, out_page: Page, out_doc: Document):
struct_tree = Tree(out_doc)
document_node = struct_tree.document_node
section_node = Node("Sect", out_doc, out_page)
document_node.children.append(section_node)

extractor = ContentExtractor(in_page.content)

p = Node("P", out_doc, None)

with ContentGenerator(out_page.content, False) as generator:
for in_element in extractor:
if isinstance(in_element, GroupElement):
out_group = GroupElement.copy_without_content(out_doc, in_element)
copy_and_tag_content(in_page, out_page, out_doc)
else:
out_element = ContentElement.copy(out_doc, in_element)

if isinstance(out_element, TextElement):
text = out_element.text[0].text
if text == "This is a properly tagged heading":
copy_and_tag_text_element(out_element, section_node, generator, out_page, out_doc, "H1")
elif text == "This is a properly tagged paragraph. Both heading and paragraph belong to a section.":
p = copy_and_tag_text_element(out_element, section_node, generator, out_page, out_doc, "P")
else:
raise RuntimeError("Unexpected content element found.")
elif isinstance(out_element, ImageElement):
bbox: Quadrilateral = out_element.transform.transform_rectangle(out_element.bounding_box)
if (
abs(bbox.bottom_left.x - 70.86) < 0.5
and abs(bbox.bottom_left.y - 632.65) < 0.5
and abs(bbox.top_right.x - 127.559) < 0.5
and abs(bbox.top_right.y - 689.34) < 0.5
):
copy_and_tag_image_element(out_element, p, generator, out_page, out_doc, "PdfTools AG Logo")
else:
raise RuntimeError("Unexpected content element found.")
else:
raise RuntimeError("Unexpected content element found.")
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as in_doc:
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)

# Create empty output page
in_page = in_doc.pages[0]
out_page = Page.create(out_doc, in_page.size)

out_doc.language = "en"
out_doc.set_pdf_ua_conformant()
out_doc.metadata.title = "TaggedPDF"
out_doc.viewer_settings.display_document_title = True

# We create an output page and copy the content elements from the input page to the output page.
# While copying, we also check if the current element is the one we want to tag.
# If it is, we tag it and update the logical structure accordingly.
# You can easily adapt this sample to fit similar scenarios.
copy_and_tag_content(in_page, out_page, out_doc)
out_doc.pages.append(out_page)

Traverse the Document Structure

Download code sample

// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
{
var tree = new Tree(inDoc);
foreach (var child in tree.Children)
{
PrintNodeRecursively(child);
}
}
static void PrintProperty(int level, String name, String value)
{
Console.Write($"{new string(' ', level * 2)}");
Console.WriteLine($"{name}: '{value}'");
}
static void PrintNodeRecursively(Node node, int level = 0)
{
PrintProperty(level, "Tag", node.Tag);
PrintProperty(level, "Alternative text", node.AlternateText);
PrintProperty(level, "Actual text", node.ActualText);
PrintProperty(level, "Abbreviation", node.Abbreviation);
PrintProperty(level, "Language", node.Language);

foreach (var child in node.Children)
{
PrintNodeRecursively(child, level + 1);
}
}
Download code sample
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null)) {
Tree tree = new Tree(inDoc);
for (Node node : tree.getChildren()) {
printNodeRecursively(node, 0);
}
}

static void printProperty(int level, String name, String value) {
for (int i = 0; i< level; ++i) {
System.out.print(" ");
}
System.out.println(name + ": " + value);
}
static void printNodeRecursively(Node node, int level) throws NotFoundException {
printProperty(level, "Tag", node.getTag());
printProperty(level, "Alternative text", node.getAlternateText());
printProperty(level, "Actual text", node.getActualText());
printProperty(level, "Abbreviation", node.getAbbreviation());
printProperty(level, "Language", node.getLanguage());
for (Node child : node.getChildren()) {
printNodeRecursively(child, level + 1);
}
}
Download code sample
def print_node_recursive(node: Node, level: int):
print(" " * level, "Tag: ", node.tag)
print(" " * level, "Alternative text: ", node.alternate_text)
print(" " * level, "Actual text: ", node.actual_text)
print(" " * level, "Abbreviation: ", node.abbreviation)
print(" " * level, "Language: ", node.language)

for child in node.children:
print_node_recursive(child, level + 1)
def print_document_structure(in_doc: Document):
tree = Tree(in_doc)
for node in tree.children:
print_node_recursive(node, 0)
# Open the input document
with open(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
print_document_structure(in_doc)

Imposition

Create a booklet from PDF

Download code sample
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 StampPageNumber(TPtxPdf_Document* pDocument, TPtxPdfContent_Font* pFont,
TPtxPdfContent_ContentGenerator* pGenerator, int nPageNo, BOOL bIsLeftPage)
{
// Objects that need releasing or closing
TPtxPdfContent_Text* pText = NULL;
TPtxPdfContent_TextGenerator* pTextGenerator = NULL;

// Create text object
pText = PtxPdfContent_Text_Create(pDocument);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pText, _T("Failed to create text object. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());

// Create text generator
pTextGenerator = PtxPdfContent_TextGenerator_New(pText, pFont, 8.0, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pTextGenerator, _T("Failed to create text generator. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());

TCHAR szStampText[50];
_stprintf(szStampText, _T("Page %d"), nPageNo);

// Get width of stamp text
double dStampWidth = PtxPdfContent_TextGenerator_GetWidth(pTextGenerator, szStampText);
if (dStampWidth == 0.0)
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get text width. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());

// Compute position
TPtxGeomReal_Point point = {
.dX = bIsLeftPage ? dBorder + 0.5 * dCellWidth - dStampWidth / 2
: 2 * dBorder + 1.5 * dCellWidth - dStampWidth / 2,
.dY = dBorder,
};

// Move to position
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_MoveTo(pTextGenerator, &point),
_T("Failed to move to position. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
// Add page number
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_Show(pTextGenerator, szStampText),
_T("Failed to show text. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());

BOOL bClose = PtxPdfContent_TextGenerator_Close(pTextGenerator);
pTextGenerator = NULL;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(bClose, _T("Failed to close text generator. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());

// Paint the positioned text
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_ContentGenerator_PaintText(pGenerator, pText),
_T("Failed to paint text. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());

cleanup:
if (pText != NULL)
Ptx_Release(pText);
if (pTextGenerator != NULL)
PtxPdfContent_TextGenerator_Close(pTextGenerator);
return iReturnValue;
}
void ComputeTargetRect(TPtxGeomReal_Rectangle* pRectangle, const TPtxGeomReal_Size* pBBox, BOOL bIsLeftPage)
{
// Compute factor for fitting page into rectangle
double dScale = MIN(dCellWidth / pBBox->dWidth, dCellHeight / pBBox->dHeight);
double dGroupWidth = pBBox->dWidth * dScale;
double dGroupHeight = pBBox->dHeight * dScale;

// Compute x-value
double dGroupXPos =
bIsLeftPage ? dCellLeft + (dCellWidth - dGroupWidth) / 2 : dCellRight + (dCellWidth - dGroupWidth) / 2;

// Compute y-value
double dGroupYPos = dCellYPos + (dCellHeight - dGroupHeight) / 2;

// Set rectangle
pRectangle->dLeft = dGroupXPos;
pRectangle->dBottom = dGroupYPos;
pRectangle->dRight = dGroupXPos + dGroupWidth;
pRectangle->dTop = dGroupYPos + dGroupHeight;
}
int CreateBooklet(TPtxPdf_PageList* pInDocList, TPtxPdf_Document* pOutDoc, TPtxPdf_PageList* pOutDocList,
int nLeftPageIndex, int nRightPageIndex, TPtxPdfContent_Font* pFont)
{
// Objects that need releasing or closing
TPtxPdf_PageCopyOptions* pCopyOptions = NULL;
TPtxPdf_Page* pOutPage = NULL;
TPtxPdfContent_Content* pContent = NULL;
TPtxPdfContent_ContentGenerator* pGenerator = NULL;
TPtxPdf_Page* pInPage = NULL;
TPtxPdfContent_Group* pGroup = NULL;

// Configure copy options
pCopyOptions = PtxPdf_PageCopyOptions_New();

// Create page object
pOutPage = PtxPdf_Page_Create(pOutDoc, &pageSize);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage, _T("Failed to create page object. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());

// Create content generator
pContent = PtxPdf_Page_GetContent(pOutPage);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pContent, _T("Failed to get content. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
pGenerator = PtxPdfContent_ContentGenerator_New(pContent, FALSE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGenerator, _T("Failed to create content generator. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());

int nPageCount = PtxPdf_PageList_GetCount(pInDocList);
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get page list count. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());

// Left page
if (nLeftPageIndex < nPageCount)
{
// Get the input page
pInPage = PtxPdf_PageList_Get(pInDocList, nLeftPageIndex);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPage, _T("Failed to get page. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());

// Copy page from input to output
pGroup = PtxPdfContent_Group_CopyFromPage(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGroup, _T("Failed to copy page as group. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());

// Compute group location
TPtxGeomReal_Size groupSize;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_Group_GetSize(pGroup, &groupSize),
_T("Failed to get group size. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
TPtxGeomReal_Rectangle targetRect;
ComputeTargetRect(&targetRect, &groupSize, TRUE);

// Paint group at location
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxPdfContent_ContentGenerator_PaintGroup(pGenerator, pGroup, &targetRect, NULL),
_T("Failed to paint group. %s (ErrorCode: 0x%08x)\n"), szErrorBuff, Ptx_GetLastError());

// Add page number to page
if (StampPageNumber(pOutDoc, pFont, pGenerator, nLeftPageIndex + 1, TRUE) != 0)
goto cleanup;

Ptx_Release(pInPage);
pInPage = NULL;
Ptx_Release(pGroup);
pGroup = NULL;
}

// Right page
if (nRightPageIndex < nPageCount)
{
// Get the input Page
pInPage = PtxPdf_PageList_Get(pInDocList, nRightPageIndex);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPage, _T("Failed to get page. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());

// Copy page from input to output
pGroup = PtxPdfContent_Group_CopyFromPage(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGroup, _T("Failed to copy page as group. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());

// Compute group location
TPtxGeomReal_Size groupSize;
PtxPdfContent_Group_GetSize(pGroup, &groupSize);
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_Group_GetSize(pGroup, &groupSize),
_T("Failed to get group size. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
TPtxGeomReal_Rectangle targetRect;
ComputeTargetRect(&targetRect, &groupSize, FALSE);

// Paint group on the Computed rectangle
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxPdfContent_ContentGenerator_PaintGroup(pGenerator, pGroup, &targetRect, NULL),
_T("Failed to paint group. %s (ErrorCode: 0x%08x)\n"), szErrorBuff, Ptx_GetLastError());

// Add page number to page
if (StampPageNumber(pOutDoc, pFont, pGenerator, nRightPageIndex + 1, FALSE) != 0)
goto cleanup;
}

BOOL bClose = PtxPdfContent_ContentGenerator_Close(pGenerator);
pGenerator = NULL;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(bClose, _T("Failed to close content generator. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());

// Add page to output document
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_Add(pOutDocList, pOutPage),
_T("Failed to add page to output document. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());

cleanup:
if (pGenerator != NULL)
PtxPdfContent_ContentGenerator_Close(pGenerator);
if (pCopyOptions != NULL)
Ptx_Release(pCopyOptions);
if (pOutPage != NULL)
Ptx_Release(pOutPage);
if (pContent != NULL)
Ptx_Release(pContent);
if (pInPage != NULL)
Ptx_Release(pInPage);
if (pGroup != NULL)
Ptx_Release(pGroup);
return iReturnValue;
}
Download code sample
// 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 = Font.CreateFromSystem(outDoc, "Arial", "Italic", true);

// Copy pages
PageList inPages = inDoc.Pages;
PageList outPages = outDoc.Pages;
int numberOfSheets = (inPages.Count + 3) / 4;

for (int sheetNumber = 0; sheetNumber < numberOfSheets; ++sheetNumber)
{

// Add on front side
CreateBooklet(inPages, outDoc, outPages, 4 * numberOfSheets - 2 * sheetNumber - 1,
2 * sheetNumber, font);

// Add on back side
CreateBooklet(inPages, outDoc, outPages, 2 * sheetNumber + 1,
4 * numberOfSheets - 2 * sheetNumber - 2, font);
}
}
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 CreateBooklet(PageList inPages, Document outDoc, PageList outPages, int leftPageIndex,
int rightPageIndex, Font font)
{
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();

// Create page object
Page outpage = Page.Create(outDoc, PageSize);

// Create content generator
using (ContentGenerator generator = new ContentGenerator(outpage.Content, false))
{
// Left page
if (leftPageIndex < inPages.Count)
{
// Copy page from input to output
Page leftPage = inPages[leftPageIndex];
Group leftGroup = Group.CopyFromPage(outDoc, leftPage, copyOptions);

// Paint group on the calculated rectangle
generator.PaintGroup(leftGroup, ComputTargetRect(leftGroup.Size, true), null);

// Add page number to page
StampPageNumber(outDoc, font, generator, leftPageIndex + 1, true);
}

// Right page
if (rightPageIndex < inPages.Count)
{
// Copy page from input to output
Page rigthPage = inPages[rightPageIndex];
Group rightGroup = Group.CopyFromPage(outDoc, rigthPage, copyOptions);

// Paint group on the calculated rectangle
generator.PaintGroup(rightGroup, ComputTargetRect(rightGroup.Size, false), null);

// Add page number to page
StampPageNumber(outDoc, font, generator, rightPageIndex + 1, false);
}
}
// Add page to output document
outPages.Add(outpage);
}
private static Rectangle ComputTargetRect(Size bbox, bool isLeftPage)
{
// Calculate factor for fitting page into rectangle
double scale = Math.Min(CellWidth / bbox.Width, CellHeight / bbox.Height);
double groupWidth = bbox.Width * scale;
double groupHeight = bbox.Height * scale;

// Calculate x-value
double groupXPos = isLeftPage ? CellLeft + (CellWidth - groupWidth) / 2 :
CellRight + (CellWidth - groupWidth) / 2;

// Calculate y-value
double groupYPos = CellYPos + (CellHeight - groupHeight) / 2;

// Calculate rectangle
return new Rectangle
{
Left = groupXPos,
Bottom = groupYPos,
Right = groupXPos + groupWidth,
Top = groupYPos + groupHeight
};
}
private static void StampPageNumber(Document document, Font font, ContentGenerator generator,
int PageNo, bool isLeftPage)
{
// Create text object
Text text = Text.Create(document);

// Create text generator
using (TextGenerator textgenerator = new TextGenerator(text, font, 8, null))
{
string stampText = string.Format("Page {0}", PageNo);

// Get width of stamp text
double width = textgenerator.GetWidth(stampText);

// Calculate position
double x = isLeftPage ? Border + 0.5 * CellWidth - width / 2 :
2 * Border + 1.5 * CellWidth - width / 2;
double y = Border;

// Move to position
textgenerator.MoveTo(new Point { X = x, Y = y});

// Add page number
textgenerator.Show(stampText);
}
// Paint the positioned text
generator.PaintText(text);
}
Download code sample
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)) {
Font font = Font.createFromSystem(outDoc, "Arial", "Italic", true);

// Copy document-wide data
copyDocumentData(inDoc, outDoc);

// Copy pages
PageList inPages = inDoc.getPages();
PageList outPages = outDoc.getPages();
int numberOfSheets = (inPages.size() + 3) / 4;

for (int sheetNumber = 0; sheetNumber < numberOfSheets; ++sheetNumber) {
// Add on front side
createBooklet(inPages, outDoc, outPages, 4 * numberOfSheets - 2 * sheetNumber - 1,
2 * sheetNumber, font);

// Add on back side
createBooklet(inPages, outDoc, outPages, 2 * sheetNumber + 1,
4 * numberOfSheets - 2 * sheetNumber - 2, font);
}
}
}
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 createBooklet(PageList inPages, Document outDoc, PageList outPages, int leftPageIndex,
int rightPageIndex, Font font) throws ToolboxException, IOException {
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();

// Create page object
Page outPage = Page.create(outDoc, new Size(PageWidth, PageHeight));

try (// Create content generator
ContentGenerator generator = new ContentGenerator(outPage.getContent(), false)) {

// Left page
if (leftPageIndex < inPages.size()) {
Page leftPage = inPages.get(leftPageIndex);

// Copy page from input to output
Group leftGroup = Group.copyFromPage(outDoc, leftPage, copyOptions);

// Paint group on the calculated rectangle
generator.paintGroup(leftGroup, computeTargetRect(leftGroup.getSize(), true), null);

// Add page number to page
StampPageNumber(outDoc, font, generator, leftPageIndex + 1, true);
}

// Right page
if (rightPageIndex < inPages.size()) {
Page rightPage = inPages.get(rightPageIndex);

// Copy page from input to output
Group rightGroup = Group.copyFromPage(outDoc, rightPage, copyOptions);

// Paint group on the calculated rectangle
generator.paintGroup(rightGroup, computeTargetRect(rightGroup.getSize(), false), null);

// Add page number to page
StampPageNumber(outDoc, font, generator, rightPageIndex + 1, false);
}
}
// Add page to output document
outPages.add(outPage);
}
private static Rectangle computeTargetRect(Size bbox, Boolean isLeftPage) {
// Calculate factor for fitting page into rectangle
double scale = Math.min(CellWidth / bbox.width, CellHeight / bbox.height);
double groupWidth = bbox.width * scale;
double groupHeight = bbox.height * scale;

// Calculate x-value
double groupXPos = isLeftPage ? CellLeft + (CellWidth - groupWidth) / 2 :
CellRight + (CellWidth - groupWidth) / 2;

// Calculate y-value
double groupYPos = CellYPos + (CellHeight - groupHeight) / 2;

// Calculate rectangle
return new Rectangle(groupXPos, groupYPos, groupXPos + groupWidth, groupYPos + groupHeight);
}
private static void StampPageNumber(Document document, Font font, ContentGenerator generator, int pageNo,
boolean isLeftPage) throws ToolboxException, IOException {
// Create text object
Text text = Text.create(document);

try (// Create text generator
TextGenerator textgenerator = new TextGenerator(text, font, 8, null)) {
String stampText = String.format("Page %d", pageNo);

// Get width of stamp text
double width = textgenerator.getWidth(stampText);

// Calculate position
double x = isLeftPage ? Border + 0.5 * CellWidth - width / 2 :
2 * Border + 1.5 * CellWidth - width / 2;
double y = Border;

// Move to position
textgenerator.moveTo(new Point(x, y));

// Add page number
textgenerator.show(stampText);
}

// Paint the positioned text
generator.paintText(text);
}
Download code sample
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 compute_target_rect(bbox: Size, is_left_page: bool) -> Rectangle:
# Calculate factor for fitting page into rectangle
scale = min(cell_width / bbox.width, cell_height / bbox.height)
group_width = bbox.width * scale
group_height = bbox.height * scale

# Calculate x-value
group_x_pos = cell_left + (cell_width - group_width) / 2 if is_left_page else cell_right + (cell_width - group_width) / 2

# Calculate y-value
group_y_pos = cell_y_pos + (cell_height - group_height) / 2

# Calculate rectangle
return Rectangle(
left=group_x_pos,
bottom=group_y_pos,
right=group_x_pos + group_width,
top=group_y_pos + group_height,
)
def stamp_page_number(document: Document, font: Font, generator: ContentGenerator, page_no: int, is_left_page: bool):
# Create text object
text = Text.create(document)

# Create text generator
with TextGenerator(text, font, 8.0, None) as text_generator:
stamp_text = f"Page {page_no}"

# Get width of stamp text
width = text_generator.get_width(stamp_text)

# Calculate position
x = border + 0.5 * cell_width - width / 2 if is_left_page else 2 * border + 1.5 * cell_width - width / 2
y = border

# Move to position
text_generator.move_to(Point(x=x, y=y))

# Add page number
text_generator.show(stamp_text)

# Paint the positioned text
generator.paint_text(text)
def create_booklet(in_pages: PageList, out_doc: Document, out_pages: PageList, left_page_index: int, right_page_index: int, font: Font):
# Define page copy options
copy_options = PageCopyOptions()

# Create page object
out_page = Page.create(out_doc, page_size)

# Create content generator
with ContentGenerator(out_page.content, False) as generator:
# Left page
if left_page_index < len(in_pages):
# Copy page from input to output
left_page = in_pages[left_page_index]
left_group = Group.copy_from_page(out_doc, left_page, copy_options)

# Paint group into target rectangle
generator.paint_group(left_group, compute_target_rect(left_group.size, True), None)

# Add page number to page
stamp_page_number(out_doc, font, generator, left_page_index + 1, True)

# Right page
if right_page_index < len(in_pages):
# Copy page from input to output
right_page = in_pages[right_page_index]
right_group = Group.copy_from_page(out_doc, right_page, copy_options)

# Paint group on the calculated rectangle
generator.paint_group(right_group, compute_target_rect(right_group.size, False), None)

# Add page number to page
stamp_page_number(out_doc, font, generator, right_page_index + 1, False)

# Add page to output document
out_pages.append(out_page)
# Define global variables
page_size = Size(1190.0, 842.0) # A3 portrait
border = 10.0
cell_width = (page_size.width - 3 * border) / 2
cell_height = page_size.height - 2 * border
cell_left = border
cell_right = 2 * border + cell_width
cell_y_pos = border

# 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
font = Font.create_from_system(out_doc, "Arial", "Italic", True)

# Copy pages
in_pages = in_doc.pages
out_pages = out_doc.pages
number_of_sheets = (len(in_pages) + 3) // 4

for sheet_number in range(number_of_sheets):
# Add front side
create_booklet(in_pages, out_doc, out_pages, 4 * number_of_sheets - 2 * sheet_number - 1, 2 * sheet_number, font)
# Add back side
create_booklet(in_pages, out_doc, out_pages, 2 * sheet_number + 1, 4 * number_of_sheets - 2 * sheet_number - 2, font)

Fit pages to specific page format

Download code sample
// 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());
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());
for (int iPage = 0; iPage < PtxPdf_PageList_GetCount(pInPageList); iPage++)
{
TPtxGeomReal_Size pageSize;
TPtxGeomReal_Size rotatedSize;
BOOL bRotate;

pInPage = PtxPdf_PageList_Get(pInPageList, iPage);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPage, _T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());

pOutPage = NULL;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Page_GetSize(pInPage, &pageSize), _T("%s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());

bRotate = bAllowRotate && (pageSize.dHeight >= pageSize.dWidth) != (targetSize.dHeight >= targetSize.dWidth);
if (bRotate)
{
rotatedSize.dWidth = pageSize.dHeight;
rotatedSize.dHeight = pageSize.dHeight;
}
else
{
rotatedSize = pageSize;
}

if (rotatedSize.dWidth == targetSize.dWidth && rotatedSize.dHeight == targetSize.dWidth)
{
// If size is correct, copy page only
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());

if (bRotate)
{
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Page_Rotate(pOutPage, ePtxGeom_Rotation_Clockwise),
_T("Failed to rotate page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
}
}
else
{
TPtxPdfContent_Group* pGroup = NULL;
TPtxPdfContent_Content* pContent = NULL;
TPtxGeomReal_AffineTransform transform;
TPtxGeomReal_Point position;
TPtxGeomReal_Point point;

// Create a new page of correct size and fit existing page onto it
pOutPage = PtxPdf_Page_Create(pOutDoc, &targetSize);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage, _T("Failed to create a new page. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());

// Copy page as group
pGroup = PtxPdfContent_Group_CopyFromPage(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGroup, _T("Failed to copy page as group. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());

// Calculate scaling and position of group
double scale = MIN(targetSize.dWidth / rotatedSize.dWidth, targetSize.dHeight / rotatedSize.dHeight);

// Calculate position
position.dX = (targetSize.dWidth - pageSize.dWidth * scale) / 2;
position.dY = (targetSize.dHeight - pageSize.dHeight * scale) / 2;

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());

// Calculate and apply transformation
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxGeomReal_AffineTransform_GetIdentity(&transform),
_T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxGeomReal_AffineTransform_Translate(&transform, position.dX, position.dY),
_T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxGeomReal_AffineTransform_Scale(&transform, scale, scale),
_T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());

point.dX = pageSize.dWidth / 2.0;
point.dY = pageSize.dHeight / 2.0;

// Rotate input file
if (bRotate)
{
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxGeomReal_AffineTransform_Rotate(&transform, 90, &point),
_T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
}
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_ContentGenerator_Transform(pGenerator, &transform),
_T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());

// Paint form
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_ContentGenerator_PaintGroup(pGenerator, pGroup, NULL, NULL),
_T("Failed to paint the group. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());

PtxPdfContent_ContentGenerator_Close(pGenerator);
pGenerator = NULL;

if (pGenerator != NULL)
Ptx_Release(pGenerator);
if (pGroup != NULL)
Ptx_Release(pGroup);
}

// 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;
}
Download code sample
// 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
foreach (Page inPage in inDoc.Pages)
{
Page outPage = null;
Size pageSize = inPage.Size;

bool rotate = AllowRotate &&
(pageSize.Height >= pageSize.Width) != (TargetSize.Height >= TargetSize.Width);
Size rotatedSize = pageSize;

if (rotate)
rotatedSize = new Size { Width = pageSize.Height, Height = pageSize.Width };

if (rotatedSize.Width == TargetSize.Width && rotatedSize.Height == TargetSize.Width)
{
// If size is correct, copy page only
outPage = Page.Copy(outDoc, inPage, copyOptions);

if (rotate)
outPage.Rotate(Rotation.Clockwise);
}
else
{
// Create new page of correct size and fit existing page onto it
outPage = Page.Create(outDoc, TargetSize);

// Copy page as group
Group group = Group.CopyFromPage(outDoc, inPage, copyOptions);
// Calculate scaling and position of group
double scale = Math.Min(TargetSize.Width / rotatedSize.Width,
TargetSize.Height / rotatedSize.Height);

// Calculate position
Point position = new Point
{
X = (TargetSize.Width - pageSize.Width * scale) / 2,
Y = (TargetSize.Height - pageSize.Height * scale) / 2
};

// Create content generator
using ContentGenerator generator = new ContentGenerator(outPage.Content, false);

// Calculate and apply transformation
AffineTransform transform = AffineTransform.Identity;
transform.Translate(position.X, position.Y);
transform.Scale(scale, scale);

Point point = new Point()
{
X = pageSize.Width / 2.0,
Y = pageSize.Height / 2.0
};

// Rotate input file
if (rotate)
transform.Rotate(90, point);
generator.Transform(transform);

// Paint group
generator.PaintGroup(group, null, null);
}
// 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));
}
Download code sample
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
for (Page inPage : inDoc.getPages()) {
Page outPage = null;
Size pageSize = inPage.getSize();

boolean rotate = AllowRotate &&
(pageSize.height >= pageSize.width) != (TargetHeight >= TargetWidth);
Size rotatedSize = pageSize;

if (rotate)
rotatedSize = new Size(pageSize.height, pageSize.width);

if (rotatedSize.width == TargetWidth && rotatedSize.height == TargetWidth) {
// If size is correct, copy page only
outPage = Page.copy(outDoc, inPage, copyOptions);

if (rotate)
outPage.rotate(Rotation.CLOCKWISE);
} else {
// Create new page of correct size and fit existing page onto it
outPage = Page.create(outDoc, new Size(TargetWidth, TargetHeight));

// Copy page as group
Group group = Group.copyFromPage(outDoc, inPage, copyOptions);
// Calculate scaling and position of group
double scale = Math.min(TargetWidth / rotatedSize.width,
TargetHeight / rotatedSize.height);

// Calculate position
Point position = new Point(
(TargetWidth - pageSize.width * scale) / 2,
(TargetHeight - pageSize.height * scale) / 2);

try(// Create content generator
ContentGenerator generator = new ContentGenerator(outPage.getContent(), false)) {
// Calculate and apply transformation
AffineTransform transform = AffineTransform.getIdentity();
transform.translate(position.x, position.y);
transform.scale(scale, scale);

Point point = new Point(pageSize.width / 2.0, pageSize.height / 2.0);

// Rotate input file
if (rotate)
transform.rotate(90, point);
generator.transform(transform);

// Paint group
generator.paintGroup(group, null, null);
}
}
// 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));
}
Download code sample
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 scale_pages_to_fit(in_doc: Document, out_doc: Document):
copy_options = PageCopyOptions()

# Copy pages
for in_page in in_doc.pages:
page_size = in_page.size
rotate = (
ALLOW_ROTATE
and (page_size.height >= page_size.width) != (TARGET_SIZE.height >= TARGET_SIZE.width)
)

rotated_size = Size(
width=page_size.height, height=page_size.width
) if rotate else page_size

if rotated_size.width == TARGET_SIZE.width and rotated_size.height == TARGET_SIZE.height:
# If size is correct, copy page only
out_page = Page.copy(out_doc, in_page, copy_options)

if rotate:
out_page.rotate(90) # Clockwise rotation
else:
# Create new page of correct size and fit existing page onto it
out_page = Page.create(out_doc, TARGET_SIZE)

# Copy page as group
group = Group.copy_from_page(out_doc, in_page, copy_options)
# Calculate scaling and position of group
scale = min(TARGET_SIZE.width / rotated_size.width, TARGET_SIZE.height / rotated_size.height)

# Calculate position
position = Point(
x=(TARGET_SIZE.width - page_size.width * scale) / 2,
y=(TARGET_SIZE.height - page_size.height * scale) / 2,
)

# Create content generator
with ContentGenerator(out_page.content, False) as generator:

# Calculate and apply transformation
transform = AffineTransform.get_identity()
transform.translate(position.x, position.y)
transform.scale(scale, scale)

# Rotate input file
if rotate:
center_point = Point(x=page_size.width / 2, y=page_size.height / 2)
transform.rotate(90, center_point)

# Paint group
generator.transform(transform)
generator.paint_group(group, None, None)

# Add the page to the output document
out_doc.pages.append(out_page)
# Define global variables
TARGET_SIZE = Size(width=595, height=842) # A4 portrait
ALLOW_ROTATE = True

# 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 and resize pages
scale_pages_to_fit(in_doc, out_doc)

Place multiple pages on one page

Download code sample
// 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 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 pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
int nPageCount = 0;
for (int iPage = 0; iPage < PtxPdf_PageList_GetCount(pInPageList); iPage++)
{
pInPage = PtxPdf_PageList_Get(pInPageList, iPage);

if (nPageCount == nNx * nNy)
{
// Add to output document
PtxPdfContent_ContentGenerator_Close(pGenerator);
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());
Ptx_Release(pOutPage);
pOutPage = NULL;
nPageCount = 0;
}
if (pOutPage == NULL)
{
// Create a new output page
pOutPage = PtxPdf_Page_Create(pOutDoc, &PageSize);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage,
_T("Failed to create a new output page. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
TPtxPdfContent_Content* pContent = PtxPdf_Page_GetContent(pOutPage);
pGenerator = PtxPdfContent_ContentGenerator_New(pContent, FALSE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGenerator,
_T("Failed to create content generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
}

// Get area where group has to be
int x = nPageCount % nNx;
int y = nNy - (nPageCount / nNx) - 1;

// Calculate cell size
TPtxGeomReal_Size cellSize;
cellSize.dWidth = (PageSize.dWidth - ((nNx + 1) * dBorder)) / nNx;
cellSize.dHeight = (PageSize.dHeight - ((nNy + 1) * dBorder)) / nNy;

// Calculate cell position
TPtxGeomReal_Point cellPosition;
cellPosition.dX = dBorder + x * (cellSize.dWidth + dBorder);
cellPosition.dY = dBorder + y * (cellSize.dHeight + dBorder);

// Copy page group from input to output
pGroup = PtxPdfContent_Group_CopyFromPage(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(
pGroup, _T("Failed to copy page group from input to output. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());

// Calculate group position
TPtxGeomReal_Size groupSize;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_Group_GetSize(pGroup, &groupSize),
_T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
double dScale = MIN(cellSize.dWidth / groupSize.dWidth, cellSize.dHeight / groupSize.dHeight);

// Calculate target size
TPtxGeomReal_Size targetSize;
targetSize.dWidth = groupSize.dWidth * dScale;
targetSize.dHeight = groupSize.dHeight * dScale;

// Calculate position
TPtxGeomReal_Point targetPos;
targetPos.dX = cellPosition.dX + ((cellSize.dWidth - targetSize.dWidth) / 2);
targetPos.dY = cellPosition.dY + ((cellSize.dHeight - targetSize.dHeight) / 2);

// Calculate rectangle
TPtxGeomReal_Rectangle targetRect;
targetRect.dLeft = targetPos.dX;
targetRect.dBottom = targetPos.dY;
targetRect.dRight = targetPos.dX + targetSize.dWidth;
targetRect.dTop = targetPos.dY + targetSize.dHeight;

// Add group to page
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxPdfContent_ContentGenerator_PaintGroup(pGenerator, pGroup, &targetRect, NULL),
_T("Failed to paint the group. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());

if (pGroup != NULL)
{
Ptx_Release(pGroup);
pGroup = NULL;
}
if (pInPage != NULL)
{
Ptx_Release(pInPage);
pInPage = NULL;
}

nPageCount++;
}

// Add partially filled page
if (pOutPage != NULL)
{
PtxPdfContent_ContentGenerator_Close(pGenerator);
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());
Ptx_Release(pOutPage);
pOutPage = 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;
}
Download code sample
// 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);
PageList outPages = outDoc.Pages;
int pageCount = 0;
ContentGenerator generator = null;
Page outPage = null;

// Copy document-wide data
CopyDocumentData(inDoc, outDoc);

// Copy all pages from input document
foreach (Page inPage in inDoc.Pages)
{
if (pageCount == Nx * Ny)
{
// Add to output document
generator.Dispose();
outPages.Add(outPage);
outPage = null;
pageCount = 0;
}
if (outPage == null)
{
// Create a new output page
outPage = Page.Create(outDoc, PageSize);
generator = new ContentGenerator(outPage.Content, false);
}

// Get area where group has to be
int x = pageCount % Nx;
int y = Ny - (pageCount / Nx) - 1;

// Compute cell size
Size cellSize = new Size
{
Width = (PageSize.Width - ((Nx + 1) * Border)) / Nx,
Height = (PageSize.Height - ((Ny + 1) * Border)) / Ny
};

// Compute cell position
Point cellPosition = new Point
{
X = Border + x * (cellSize.Width + Border),
Y = Border + y * (cellSize.Height + Border)
};

// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();

// Copy page as group from input to output
Group group = Group.CopyFromPage(outDoc, inPage, copyOptions);

// Compute group position
Size groupSize = group.Size;
double scale = Math.Min(cellSize.Width / groupSize.Width,
cellSize.Height / groupSize.Height);

// Compute target size
Size targetSize = new Size
{
Width = groupSize.Width * scale,
Height = groupSize.Height * scale
};

// Compute position
Point targetPos = new Point
{
X = cellPosition.X + ((cellSize.Width - targetSize.Width) / 2),
Y = cellPosition.Y + ((cellSize.Height - targetSize.Height) / 2)
};

// Compute rectangle
Rectangle targetRect = new Rectangle
{
Left = targetPos.X,
Bottom = targetPos.Y,
Right = targetPos.X + targetSize.Width,
Top = targetPos.Y + targetSize.Height
};

// Add group to page
generator.PaintGroup(group, targetRect, null);
pageCount++;
}
// Add page
if (outPage != null)
{
generator.Dispose();
outPages.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));
}
Download code sample
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null)) {
try (
FileStream outStream = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW)) {
try (// Create output document
Document outDoc = Document.create(outStream, inDoc.getConformance(), null)) {
PageList outPages = outDoc.getPages();
int pageCount = 0;
ContentGenerator generator = null;
Page outPage = null;

// A4 portrait
Size pageSize = new Size(595, 842);

// Copy document-wide data
copyDocumentData(inDoc, outDoc);

// Copy pages
for (Page inPage : inDoc.getPages()) {

if (pageCount == Nx * Ny) {
// Add to output document
generator.close();
outPages.add(outPage);
outPage = null;
pageCount = 0;
}
if (outPage == null) {
// Create a new output page
outPage = Page.create(outDoc, pageSize);
generator = new ContentGenerator(outPage.getContent(), false);
}

// Get area where group has to be
int x = pageCount % Nx;
int y = Ny - (pageCount / Nx) - 1;

// Calculate cell size
Size cellSize = new Size((pageSize.width - ((Nx + 1) * Border)) / Nx,
(pageSize.height - ((Ny + 1) * Border)) / Ny);

// Calculate cell position
Point cellPosition = new Point(Border + x * (cellSize.width + Border),
Border + y * (cellSize.height + Border));

// Set copy option
PageCopyOptions copyOptions = new PageCopyOptions();

// Copy page group from input to output
Group group = Group.copyFromPage(outDoc, inPage, copyOptions);

// Calculate group position
Size groupSize = group.getSize();
double scale = Math.min(cellSize.width / groupSize.width,
cellSize.height / groupSize.height);

// Calculate target size
Size targetSize = new Size(groupSize.width * scale, groupSize.height * scale);

// Calculate position
Point targetPos = new Point(cellPosition.x + ((cellSize.width - targetSize.width) / 2),
cellPosition.y + ((cellSize.height - targetSize.height) / 2));

// Calculate rectangle
Rectangle targetRect = new Rectangle(targetPos.x, targetPos.y,
targetPos.x + targetSize.width, targetPos.y + targetSize.height);

// Add group to page
generator.paintGroup(group, targetRect, null);

pageCount++;
}
// Add page
if (outPage != null) {
generator.close();
outPages.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));
}
Download code sample
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))
# Define global variables
nx = 2
ny = 2
page_size = Size(595.0, 842.0) # A4 portrait
border = 10.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:
out_pages = output_document.pages
page_count = 0
generator = None
out_page = None

# Copy document-wide data
copy_document_data(input_document, output_document)

# Copy all pages from input document
for in_page in input_document.pages:
if page_count == nx * ny:
# Add to output document
generator.__exit__(None, None, None)
out_pages.append(out_page)
out_page = None
page_count = 0
if out_page is None:
# Create a new output page
out_page = Page.create(output_document, page_size)
generator = ContentGenerator(out_page.content, False)

# Get area where group has to be (// calculates the floor of the division)
x = int(page_count % nx)
y = int(ny - (page_count // nx) - 1)

# Compute cell size
cell_width = (page_size.width - ((nx + 1) * border)) / nx
cell_height = (page_size.height - ((ny + 1) * border)) / ny

# Compute cell position
cell_x = border + x * (cell_width + border)
cell_y = border + y * (cell_height + border)

# Define page copy options
copy_options = PageCopyOptions()

# Copy page as group from input to output
group = Group.copy_from_page(output_document, in_page, copy_options)

# Compute group position
group_size = group.size
scale = min(cell_width / group_size.width, cell_height / group_size.height)

# Compute target size
target_width = group_size.width * scale
target_height = group_size.height * scale

# Compute position
target_x = cell_x + ((cell_width - target_width) / 2)
target_y = cell_y + ((cell_height - target_height) / 2)

# Compute rectangle
target_rect = Rectangle()
target_rect.left = target_x
target_rect.bottom = target_y
target_rect.right = target_x + target_width
target_rect.top = target_y + target_height

# Add group to page
generator.paint_group(group, target_rect, None)
page_count += 1

# Add page
if out_page:
generator.__exit__(None, None, None)
out_pages.append(out_page)

Set page orientation

Download code sample
// 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 the 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());

// Rotate given pages by 90 degrees
for (int i = 0; i < ARRAY_SIZE(aPageNumbers); i++)
{
pOutPage = PtxPdf_PageList_Get(pCopiedPages, aPageNumbers[i] - 1);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage, _T("Failed to get copied page. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Page_Rotate(pOutPage, ePtxGeom_Rotation_Clockwise),
_T("Failed to rotate page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
}

// Add pages to output document
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pCopiedPages),
_T("Failed to add copied pages. %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;
}
Download code sample
// 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 outFs = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outFs, inDoc.Conformance, null))
{
// Copy document-wide data
CopyDocumentData(inDoc, outDoc);

// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();

// Copy all pages
PageList copiedPages = PageList.Copy(outDoc, inDoc.Pages, copyOptions);

// Rotate selected pages by 90 degrees
foreach (var pageNumber in pageNumbers)
{
copiedPages[pageNumber - 1].Rotate(Rotation.Clockwise);
}

// Add pages to output document
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));
}
Download code sample
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);

// Set copy options and flatten annotations, form fields and signatures
PageCopyOptions copyOptions = new PageCopyOptions();

// Copy all pages
PageList copiedPages = PageList.copy(outDoc, inDoc.getPages(), copyOptions);

// Rotate selected pages by 90 degrees
for (int pageNumber : pageNumbers) {
copiedPages.get(pageNumber - 1).rotate(Rotation.CLOCKWISE);
}

// Add pages to output document
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));
}
Download code sample
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)

# Define page copy options
page_copy_options = PageCopyOptions()

# Copy all pages
copied_pages = PageList.copy(out_doc, in_doc.pages, page_copy_options)

# Rotate selected pages by 90 degrees
for page_number in page_numbers:
copied_pages[int(page_number) - 1].rotate(Rotation.CLOCKWISE)

# Add pages to output document
out_doc.pages.extend(copied_pages)

Information Extraction

Embed files into a PDF

Download code sample

// Open input document
using (FileStream inStream = new FileStream(input, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))

// Create output document
using (FileStream outStream = new FileStream(output, 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 all pages
PageList inPageRange = inDoc.Pages.GetRange(0, inDoc.Pages.Count);
PageList copiedPages = PageList.Copy(outDoc, inPageRange, copyOptions);
outDoc.Pages.AddRange(copiedPages);

EmbedFile(outDoc, new FileInfo(fileToEmbed), page);
}
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 EmbedFile(Document outputDoc, FileSystemInfo fileToEmbed, int pageNumber)
{
// create file stream to read the file to embed
using (FileStream fileStream = new FileStream(fileToEmbed.FullName, FileMode.Open, FileAccess.Read))
{
// create a file type depending on the file ending (e.g. "application/pdf")
string fileEnding = fileToEmbed.Name.Substring(fileToEmbed.Name.LastIndexOf(".") + 1);
string type = "application/" + fileEnding;

// get the modified date from the file
DateTime dateTime = fileToEmbed.LastWriteTime;

// create a new FileReference
FileReference fr = FileReference.Create(outputDoc, fileStream, fileToEmbed.Name, type, "", dateTime);

// if a page is set, add a FileAttachment annotation to that page
// otherwise, attach the file to the document
if (pageNumber > 0 && pageNumber <= outputDoc.Pages.Count)
{
// get the page to create the annotation on
Page page = outputDoc.Pages[pageNumber - 1];

// Get the color space
ColorSpace colorSpace = ColorSpace.CreateProcessColorSpace(outputDoc, ProcessColorSpaceType.Rgb);

// Choose the RGB color value
double[] color = { 1.0, 0.0, 0.0 };
Transparency transparency = new Transparency(1);

// Create paint object
Paint paint = Paint.Create(outputDoc, colorSpace, color, transparency);

// put the annotation in the center of the page
Point point = new Point
{
X= page.Size.Width / 2,
Y= page.Size.Height / 2
};

// create a FileReference annotation and attach it to a page so the FireReference is visible on that page
FileAttachment fa = FileAttachment.Create(outputDoc, point, fr, paint);

// add FileAttachment annotation to page
page.Annotations.Add(fa);
}
else
{
// attach it to the document
outputDoc.PlainEmbeddedFiles.Add(fr);
}
}
}
Download code sample
try (// Open input document
FileStream inStream = new FileStream(input, Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null);

// Create output document
FileStream outStream = new FileStream(output, Mode.READ_WRITE_NEW);
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
PageList inPageRange = inDoc.getPages().subList(0, inDoc.getPages().size());
PageList copiedPages = PageList.copy(outDoc, inPageRange, copyOptions);
outDoc.getPages().addAll(copiedPages);

embedFile(outDoc, new File(fileToEmbed), page);
}
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 embedFile(Document outputDoc, File fileToEmbed, int pageNumber) throws Exception
{
try(
// create file stream to read the file to embed
FileStream fileStream = new FileStream(fileToEmbed, Mode.READ_ONLY);
)
{
// create a file type depending on the file ending (e.g. "application/pdf")
String fileEnding = fileToEmbed.getName().substring(fileToEmbed.getName().lastIndexOf(".") + 1);
String type = "application/" + fileEnding;

// get the modified date from the file
Instant instant = Instant.ofEpochMilli(fileToEmbed.lastModified());
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, ZoneId.systemDefault());
OffsetDateTime dateTime = OffsetDateTime.from(zonedDateTime);

// create a new FileReference
FileReference fr = FileReference.create(outputDoc, fileStream, fileToEmbed.getName(), type, "", dateTime);

// if a page is set, add a FileAttachment annotation to that page
// otherwise, attach the file to the document
if(pageNumber > 0 && pageNumber <= outputDoc.getPages().size())
{
// get the page to create the annotation on
Page page = outputDoc.getPages().get(pageNumber - 1);

// Get the color space
ColorSpace colorSpace = ColorSpace.createProcessColorSpace(outputDoc, ProcessColorSpaceType.RGB);

// Choose the RGB color value
double[] color = { 1.0, 0.0, 0.0 };
Transparency transparency = new Transparency(1);

// Create paint object
Paint paint = Paint.create(outputDoc, colorSpace, color, transparency);

// put the annotation in the center of the page
Point point = new Point(page.getSize().getWidth() / 2, page.getSize().getHeight() / 2);

// create a FileReference annotation and attach it to a page so the FireReference is visible on that page
FileAttachment fa = FileAttachment.create(outputDoc, point, fr, paint);

// add FileAttachment annotation to the page
page.getAnnotations().add(fa);
}
else
{
// attach it to the document
outputDoc.getPlainEmbeddedFiles().add(fr);
}
}
}
Download code sample
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 embed_file(output_doc: Document, file_to_embed: str, page_number: int | None):
# Create file stream to read the file to embed
with open(file_to_embed, "rb") as file_stream:
# Create a file type depending on the file ending (e.g. "application/pdf")
file_to_embed_name = os.path.basename(file_to_embed)
file_type = "application/" + file_to_embed_name.split(".")[-1]

# Get the modified date from the file
last_modified = datetime.fromtimestamp(os.path.getmtime(file_to_embed))

# Create a new FileReference
file_ref = FileReference.create(output_doc, file_stream, file_to_embed_name, file_type, "", last_modified)

# If a page is set, add a FileAttachment annotation to that page
# otherwise, attach the file to the document
if page_number is not None and page_number > 0 and page_number <= len(output_doc.pages):
# Get the page to create the annotation on
page = output_doc.pages[page_number - 1]

# Get the color space
color_space = ColorSpace.create_process_color_space(output_doc, ProcessColorSpaceType.RGB)

# Choose the RGB color value
color = [1.0, 0.0, 0.0] # Red color
transparency = Transparency(1)

# Create paint object
paint = Paint.create(output_doc, color_space, color, transparency)

# Put the annotation in the center of the page
point = Point(x = page.size.width/2, y = page.size.height/2)

# Create a FileReference annotation and attach it to a page so the FireReference is visible on that page
annotation = FileAttachment.create(output_doc, point, file_ref, paint)

# Add the annotation to the page
page.annotations.append(annotation)
else:
# Attach the file to the document
output_doc.plain_embedded_files.append(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)

# 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)

embed_file(out_doc, file_to_embed, page_number)

Extract files embedded from a PDF

Download code sample

// Open input document
using (FileStream inStream = new FileStream(inputFile, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
{
FileReferenceList frList = inDoc.AllEmbeddedFiles;

foreach(FileReference fr in frList)
{
ExtractFile(fr, outputDir);
}
}
private static void ExtractFile(FileReference fr, String outputDir)
{
using (FileStream outStream = new FileStream(outputDir + "/" + fr.Name, FileMode.Create, FileAccess.ReadWrite))
{
fr.Data.CopyTo(outStream);
}
}
Download code sample
try (// Open input document
FileStream inStream = new FileStream(inputFile, Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null);
)
{
FileReferenceList frList = inDoc.getAllEmbeddedFiles();

for(FileReference fr: frList)
{
extractFile(fr, outputDir);
}
}
private static void extractFile(FileReference fr, String outputDir) throws Exception
{
try(
FileStream outStream = new FileStream(outputDir + "/" + fr.getName(), Mode.READ_WRITE_NEW);
)
{
outStream.copy(fr.getData());
}
}
Download code sample
def copy_to_stream(data: io.IOBase, out_stream: io.IOBase, chunk_size: int = 4096):
"""Copy data from an IO stream to another."""
while chunk := data.read(chunk_size):
out_stream.write(chunk)
def extract_file(file_reference: FileReference, output_dir: str):
# Remove null characters
clean_file_name = file_reference.name.replace(chr(0), "")
output_path = os.path.join(output_dir, clean_file_name)

if file_reference.data is None:
raise ValueError("The file_reference.data stream is None.")
if not file_reference.data.readable():
raise ValueError("The file_reference.data stream is not readable.")

# Ensure the output directory exists
os.makedirs(output_dir, exist_ok=True)

with io.FileIO(output_path, "wb") as out_file:
copy_to_stream(file_reference.data, out_file)
# Open input document
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
file_ref_list = in_doc.all_embedded_files
for file_ref in file_ref_list:
extract_file(file_ref, output_dir)

Extract all images and image masks from a PDF

Download code sample
// 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());

// Loop over all pages and extract images
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());

for (int iPageNo = 0; iPageNo < PtxPdf_PageList_GetCount(pInPageList); iPageNo++)
{
pPage = PtxPdf_PageList_Get(pInPageList, iPageNo);
pContent = PtxPdf_Page_GetContent(pPage);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pContent, _T("Failed to get content from page %d. %s (ErrorCode: 0x%08x).\n"),
iPageNo + 1, szErrorBuff, Ptx_GetLastError());

pExtractor = PtxPdfContent_ContentExtractor_New(pContent);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pExtractor,
_T("Failed to create content extractor. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());

GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(extractImages(pExtractor, iPageNo + 1, szOutputDir),
_T("Error occurred while extracting images. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());

if (pPage != NULL)
{
Ptx_Release(pPage);
pPage = NULL;
}
if (pContent != NULL)
{
Ptx_Release(pContent);
pContent = NULL;
}
}

int extractImages(TPtxPdfContent_ContentExtractor* pExtractor, int iPageNo, const TCHAR* szOutputDir)
{
int iImgCount = 0;
int iImgMaskCount = 0;
TPtxPdfContent_ContentExtractorIterator* pIterator = NULL;
TPtxPdfContent_ContentElement* pContentElement = NULL;
TPtxPdfContent_Image* pImage = NULL;
TPtxPdfContent_ImageMask* pImageMask = NULL;
TCHAR* szExtension = NULL;
FILE* pOutStream = NULL;

pIterator = PtxPdfContent_ContentExtractor_GetIterator(pExtractor);
GOTO_CLEANUP_IF_NULL(pIterator, _T("Failed to get iterator.\n"));
PtxPdfContent_ContentExtractorIterator_MoveNext(pIterator);
while (pContentElement = PtxPdfContent_ContentExtractorIterator_GetValue(pIterator))
{
TPtxPdfContent_ContentElementType iType = PtxPdfContent_ContentElement_GetType(pContentElement);
if (iType == ePtxPdfContent_ContentElementType_ImageElement)
{
iImgCount++;
pImage = PtxPdfContent_ImageElement_GetImage((TPtxPdfContent_ImageElement*)pContentElement);
GOTO_CLEANUP_IF_NULL(pImage, _T("Failed to get image.\n"));

const TPtxPdfContent_ImageType iImageType = PtxPdfContent_Image_GetDefaultImageType(pImage);
if (iImageType == ePtxPdfContent_ImageType_Jpeg)
szExtension = _T(".jpg");
else
szExtension = _T(".tiff");

TCHAR szOutPath[256] = {'\0'};
_stprintf(szOutPath, _T("%s/image_page%d_%d%s"), szOutputDir, iPageNo, iImgCount, szExtension);

pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);

TPtxSys_StreamDescriptor outDescriptor;
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
if (PtxPdfContent_Image_Extract(pImage, &outDescriptor, NULL) == FALSE)
{
if (Ptx_GetLastError() == ePtx_Error_Generic)
{
nBufSize = Ptx_GetLastErrorMessage(NULL, 0);
Ptx_GetLastErrorMessage(szErrorBuff, MIN(ARRAY_SIZE(szErrorBuff), nBufSize));
_tprintf(szErrorBuff);
}
else
return FALSE;
}

if (pImage != NULL)
{
Ptx_Release(pImage);
pImage = NULL;
}
if (pOutStream != NULL)
{
fclose(pOutStream);
pOutStream = NULL;
}
}
else if (iType == ePtxPdfContent_ContentElementType_ImageMaskElement)
{
iImgMaskCount++;
pImageMask = PtxPdfContent_ImageMaskElement_GetImageMask((TPtxPdfContent_ImageMaskElement*)pContentElement);
GOTO_CLEANUP_IF_NULL(pImageMask, _T("Failed to get image.\n"));

szExtension = _T(".tiff");

TCHAR szOutPath[256] = {'\0'};
_stprintf(szOutPath, _T("%s/image_mask_page%d_%d%s"), szOutputDir, iPageNo, iImgMaskCount, szExtension);

pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);

TPtxSys_StreamDescriptor outDescriptor;
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
if (PtxPdfContent_ImageMask_Extract(pImageMask, &outDescriptor, NULL) == FALSE)
{
if (Ptx_GetLastError() == ePtx_Error_Generic)
{
nBufSize = Ptx_GetLastErrorMessage(NULL, 0);
Ptx_GetLastErrorMessage(szErrorBuff, MIN(ARRAY_SIZE(szErrorBuff), nBufSize));
_tprintf(szErrorBuff);
}
else
return FALSE;
}

if (pImageMask != NULL)
{
Ptx_Release(pImageMask);
pImageMask = NULL;
}
if (pOutStream != NULL)
{
fclose(pOutStream);
pOutStream = NULL;
}
}
if (pContentElement != NULL)
{
Ptx_Release(pContentElement);
pContentElement = NULL;
}
PtxPdfContent_ContentExtractorIterator_MoveNext(pIterator);
}

cleanup:
if (pImage != NULL)
Ptx_Release(pImage);
if (pImageMask != NULL)
Ptx_Release(pImageMask);
if (pContentElement != NULL)
Ptx_Release(pContentElement);
if (pIterator != NULL)
Ptx_Release(pIterator);
if (pOutStream != NULL)
fclose(pOutStream);

return iReturnValue == 1 ? FALSE : TRUE;
}
Download code sample
// Open input document
using (Stream stream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document doc = Document.Open(stream, null))
{
// Loop over all pages and extract images
for (int i = 0; i < doc.Pages.Count; i++)
{
ContentExtractor extractor = new ContentExtractor(doc.Pages[i].Content);
ExtractImages(extractor, i + 1, outputDir);
}
}
private static void ExtractImages(ContentExtractor extractor, int pageNo, string outputDir)
{
int imgCount = 0;
int imgMaskCount = 0;
foreach (ContentElement contentElement in extractor)
{
if (contentElement is ImageElement element)
{
imgCount++;
string extension = ".tiff";
switch (element.Image.DefaultImageType)
{
case ImageType.Jpeg:
extension = ".jpg";
break;
case ImageType.Tiff:
extension = ".tiff";
break;
default:
break;
}
string outputPath = System.IO.Path.Combine(outputDir, $"image_page{pageNo}_{imgCount}{extension}");

try
{
using (Stream imageStream = new FileStream(outputPath, FileMode.Create, FileAccess.ReadWrite))
{
element.Image.Extract(imageStream);
}
}
catch (GenericException ex)
{
Console.WriteLine(ex.ToString());
}
}
else if (contentElement is ImageMaskElement maskElement)
{
imgMaskCount++;
string extension = ".tiff";
string outputPath = System.IO.Path.Combine(outputDir, $"image_mask_page{pageNo}_{imgMaskCount}{extension}");
try
{
using (Stream imageStream = new FileStream(outputPath, FileMode.Create, FileAccess.ReadWrite))
{
maskElement.ImageMask.Extract(imageStream);
}
}
catch (GenericException ex)
{
Console.WriteLine(ex.ToString());
}
}
}
}
Download code sample
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null)) {

// Loop over all pages and extract images
for (int i = 0; i < inDoc.getPages().size(); i++) {
ContentExtractor extractor = new ContentExtractor(inDoc.getPages().get(i).getContent());
extractImages(extractor, i + 1, outputDir);
}
}
private static void extractImages(ContentExtractor extractor, int pageNo, String outputDir) throws IOException {
int imgCount = 0;
int imgMaskCount = 0;
for (Object elementObj : extractor) {
if (elementObj instanceof ImageElement) {
ImageElement element = (ImageElement) elementObj;
imgCount++;
String extension = ".tiff";
switch (element.getImage().getDefaultImageType()) {
case JPEG:
extension = ".jpg";
break;
case TIFF:
extension = ".tiff";
break;
default:
break;
}
String outputPath = Paths.get(outputDir, "image_page" + pageNo + "_" + imgCount + extension).toString();
try (FileStream imageStream = new FileStream(outputPath, FileStream.Mode.READ_WRITE_NEW)) {
element.getImage().extract(imageStream);
} catch (GenericException ex) {
System.out.println(ex.toString());
}
}
else if (elementObj instanceof ImageMaskElement) {
ImageMaskElement element = (ImageMaskElement) elementObj;
imgMaskCount++;
String extension = ".tiff";
String outputPath = Paths.get(outputDir, "image_mask_page" + pageNo + "_" + imgMaskCount + extension).toString();
try (FileStream imageStream = new FileStream(outputPath, FileStream.Mode.READ_WRITE_NEW)) {
element.getImageMask().extract(imageStream);
} catch (GenericException ex) {
System.out.println(ex.toString());
}
}
}
}
Download code sample
def extract_image(image_element: ImageElement, output_path: str):
with open(output_path, "wb+") as out_stream:
image_element.image.extract(out_stream)
def extract_image_mask(image_mask_element: ImageMaskElement, output_path: str):
with open(output_path, "wb+") as out_stream:
image_mask_element.image_mask.extract(out_stream)
def process_page_content(page: Page, page_number: int, output_dir: str):
extractor = ContentExtractor(page.content)
img_count = 0
mask_count = 0

for content_element in extractor:
# Extract image elements
if isinstance(content_element, ImageElement):
img_count += 1
image_type = content_element.image.default_image_type

extension = ".jpg" if image_type == ImageType.JPEG else ".tiff"

output_path = os.path.join(output_dir, f"image_page{page_number}_{img_count}{extension}")

extract_image(content_element, output_path)

print(f"Extracted image: {output_path}")

# Extract image masks
elif isinstance(content_element, ImageMaskElement):
mask_count += 1
output_path = os.path.join(output_dir, f"image_mask_page{page_number}_{mask_count}.tiff")
extract_image_mask(content_element, output_path)
print(f"Extracted image mask: {output_path}")
# Ensure the output directory exists
os.makedirs(output_dir, exist_ok=True)

# Open input document
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:

for page_number, page in enumerate(in_doc.pages, start=1):
process_page_content(page, page_number, output_dir)

List bounds of page content

Download code sample
// Open input document
using (Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
using (Document doc = Document.Open(stream, null))
{
// Iterate over all pages
int pageNumber = 1;
foreach (Page page in doc.Pages)
{
// Print page size
Console.WriteLine("Page {0}", pageNumber++);
Size size = page.Size;
Console.WriteLine(" Size:");
Console.WriteLine(" Width: {0}", size.Width);
Console.WriteLine(" Height: {0}", size.Height);

// Compute rectangular bounding box of all content on page
Rectangle contentBox = new Rectangle()
{
Left = double.MaxValue,
Bottom = double.MaxValue,
Right = double.MinValue,
Top = double.MinValue,
};
ContentExtractor extractor = new ContentExtractor(page.Content);
foreach (ContentElement element in extractor)
{
// Enlarge the content box for each content element
AffineTransform tr = element.Transform;
Rectangle box = element.BoundingBox;

// The location on the page is given by the transformed points
Enlarge(ref contentBox, tr.TransformPoint(new Point { X = box.Left, Y = box.Bottom, }));
Enlarge(ref contentBox, tr.TransformPoint(new Point { X = box.Right, Y = box.Bottom, }));
Enlarge(ref contentBox, tr.TransformPoint(new Point { X = box.Right, Y = box.Top, }));
Enlarge(ref contentBox, tr.TransformPoint(new Point { X = box.Left, Y = box.Top, }));
}
Console.WriteLine(" Content bounding box:");
Console.WriteLine(" Left: {0}", contentBox.Left);
Console.WriteLine(" Bottom: {0}", contentBox.Bottom);
Console.WriteLine(" Right: {0}", contentBox.Right);
Console.WriteLine(" Top: {0}", contentBox.Top);
}
}
static void Enlarge(ref Rectangle box, Point point)
{
// Enlarge box if point lies outside of box
if (point.X < box.Left)
box.Left = point.X;
else if (point.X > box.Right)
box.Right = point.X;
if (point.Y < box.Bottom)
box.Bottom = point.Y;
else if (point.Y > box.Top)
box.Top = point.Y;
}
Download code sample
try (// Open input document
FileStream stream = new FileStream(path, FileStream.Mode.READ_ONLY);
Document doc = Document.open(stream, null)) {
// Iterate over all pages
int pageNumber = 1;
for (Page page : doc.getPages()) {
// Print page size
System.out.format("Page %d\n", pageNumber++);
Size size = page.getSize();
System.out.println(" Size:");
System.out.format(" Width: %f\n", size.getWidth());
System.out.format(" Height: %f\n", size.getHeight());

// Compute rectangular bounding box of all content on page
Rectangle contentBox = new Rectangle(Double.MAX_VALUE, Double.MAX_VALUE, Double.MIN_VALUE, Double.MIN_VALUE);
ContentExtractor extractor = new ContentExtractor(page.getContent());
for (ContentElement element : extractor) {
// Enlarge the content box for each content element
AffineTransform tr = element.getTransform();
Rectangle box = element.getBoundingBox();

// The location on the page is given by the transformed points
contentBox = enlarge(contentBox, tr.transformPoint(new Point(box.getLeft(), box.getBottom())));
contentBox = enlarge(contentBox, tr.transformPoint(new Point(box.getRight(), box.getBottom())));
contentBox = enlarge(contentBox, tr.transformPoint(new Point(box.getRight(), box.getTop())));
contentBox = enlarge(contentBox, tr.transformPoint(new Point(box.getLeft(), box.getTop())));
}
System.out.println(" Content bounding box:");
System.out.format(" Left: %f\n", contentBox.getLeft());
System.out.format(" Bottom: %f\n", contentBox.getBottom());
System.out.format(" Right: %f\n", contentBox.getRight());
System.out.format(" Top: %f\n", contentBox.getTop());
}
}
static Rectangle enlarge(Rectangle box, Point point) {
// Enlarge box if point lies outside of box
if (point.getX() < box.getLeft())
box.setLeft(point.getX());
else if (point.getX() > box.getRight())
box.setRight(point.getX());
if (point.getY() < box.getBottom())
box.setBottom(point.getY());
else if (point.getY() > box.getTop())
box.setTop(point.getY());
return box;
}
Download code sample
def enlarge(content_box: Rectangle, point: Point):
"""
Enlarge the bounding box to include the given point.
"""
content_box.left = min(content_box.left, point.x)
content_box.right = max(content_box.right, point.x)
content_box.bottom = min(content_box.bottom, point.y)
content_box.top = max(content_box.top, point.y)
def list_content_bounds(input_doc: Document):
"""
Process the input PDF file to list page size and bounding boxes.
"""
# Iterate over all pages
for page_number, page in enumerate(input_doc.pages, start=1):
print(f"Page {page_number}")

# Print page size
size = page.size
print(" Size:")
print(f" Width: {size.width}")
print(f" Height: {size.height}")

# Compute rectangular bounding box of all content on page
content_box = Rectangle(
left=float("inf"),
bottom=float("inf"),
right=float("-inf"),
top=float("-inf"),
)

# Extract content and compute bounding box
extractor = ContentExtractor(page.content)
for element in extractor:
# Enlarge the content box for each content element
tr = element.transform
box = element.bounding_box

# The location on the page is given by the transformed points
enlarge(content_box, tr.transform_point(Point(x=box.left, y=box.bottom)))
enlarge(content_box, tr.transform_point(Point(x=box.right, y=box.bottom)))
enlarge(content_box, tr.transform_point(Point(x=box.right, y=box.top)))
enlarge(content_box, tr.transform_point(Point(x=box.left, y=box.top)))

print(" Content bounding box:")
print(f" Left: {content_box.left}")
print(f" Bottom: {content_box.bottom}")
print(f" Right: {content_box.right}")
print(f" Top: {content_box.top}")
# Open input document
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# Process the PDF
list_content_bounds(in_doc)

List document information of PDF

Download code sample
// 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, szPassword);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());

// Conformance
TPtxPdf_Conformance conformance = PtxPdf_Document_GetConformance(pInDoc);
if (conformance == 0)
{
GOTO_CLEANUP(szErrorBuff, Ptx_GetLastError());
}
_tprintf(_T("Conformance: "));
switch (conformance)
{
case ePtxPdf_Conformance_Pdf10:
_tprintf(_T("PDF 1.0\n"));
break;
case ePtxPdf_Conformance_Pdf11:
_tprintf(_T("PDF 1.1\n"));
break;
case ePtxPdf_Conformance_Pdf12:
_tprintf(_T("PDF 1.2\n"));
break;
case ePtxPdf_Conformance_Pdf13:
_tprintf(_T("PDF 1.3\n"));
break;
case ePtxPdf_Conformance_Pdf14:
_tprintf(_T("PDF 1.4\n"));
break;
case ePtxPdf_Conformance_Pdf15:
_tprintf(_T("PDF 1.5\n"));
break;
case ePtxPdf_Conformance_Pdf16:
_tprintf(_T("PDF 1.6\n"));
break;
case ePtxPdf_Conformance_Pdf17:
_tprintf(_T("PDF 1.7\n"));
break;
case ePtxPdf_Conformance_Pdf20:
_tprintf(_T("PDF 2.0\n"));
break;
case ePtxPdf_Conformance_PdfA1B:
_tprintf(_T("PDF/A1-b\n"));
break;
case ePtxPdf_Conformance_PdfA1A:
_tprintf(_T("PDF/A1-a\n"));
break;
case ePtxPdf_Conformance_PdfA2B:
_tprintf(_T("PDF/A2-b\n"));
break;
case ePtxPdf_Conformance_PdfA2U:
_tprintf(_T("PDF/A2-u\n"));
break;
case ePtxPdf_Conformance_PdfA2A:
_tprintf(_T("PDF/A2-a\n"));
break;
case ePtxPdf_Conformance_PdfA3B:
_tprintf(_T("PDF/A3-b\n"));
break;
case ePtxPdf_Conformance_PdfA3U:
_tprintf(_T("PDF/A3-u\n"));
break;
case ePtxPdf_Conformance_PdfA3A:
_tprintf(_T("PDF/A3-a\n"));
break;
}

// Encryption information
TPtxPdf_Permission permissions;
BOOL iRet = PtxPdf_Document_GetPermissions(pInDoc, &permissions);
if (iRet == FALSE)
{
if (Ptx_GetLastError() != ePtx_Error_Success)
GOTO_CLEANUP(szErrorBuff, Ptx_GetLastError());
_tprintf(_T("Not encrypted\n"));
}
else
{
_tprintf(_T("Encryption:\n"));
_tprintf(_T(" - Permissions: "));
if (permissions & ePtxPdf_Permission_Print)
_tprintf(_T("Print, "));
if (permissions & ePtxPdf_Permission_Modify)
_tprintf(_T("Modify, "));
if (permissions & ePtxPdf_Permission_Copy)
_tprintf(_T("Copy, "));
if (permissions & ePtxPdf_Permission_Annotate)
_tprintf(_T("Annotate, "));
if (permissions & ePtxPdf_Permission_FillForms)
_tprintf(_T("FillForms, "));
if (permissions & ePtxPdf_Permission_SupportDisabilities)
_tprintf(_T("SupportDisabilities, "));
if (permissions & ePtxPdf_Permission_Assemble)
_tprintf(_T("Assemble, "));
if (permissions & ePtxPdf_Permission_DigitalPrint)
_tprintf(_T("DigitalPrint, "));
_tprintf(_T("\n"));
}

// Get metadata of input PDF
pMetadata = PtxPdf_Document_GetMetadata(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pMetadata, _T("Failed to get metadata. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
_tprintf(_T("Document information:\n"));

// Get title
size_t nTitle = PtxPdf_Metadata_GetTitle(pMetadata, NULL, 0);
if (nTitle != 0)
{
TCHAR* szTitle = (TCHAR*)malloc(nTitle * sizeof(TCHAR));
if (szTitle != NULL)
{
PtxPdf_Metadata_GetTitle(pMetadata, szTitle, nTitle);
_tprintf(_T(" - Title: %s\n"), szTitle);
free(szTitle);
}
}

// Get author
size_t nAuthor = PtxPdf_Metadata_GetAuthor(pMetadata, NULL, 0);
if (nAuthor != 0)
{
TCHAR* szAuthor = (TCHAR*)malloc(nAuthor * sizeof(TCHAR));
if (szAuthor != NULL)
{
PtxPdf_Metadata_GetAuthor(pMetadata, szAuthor, nAuthor);
_tprintf(_T(" - Author: %s\n"), szAuthor);
free(szAuthor);
}
}

// Get creator
size_t nCreator = PtxPdf_Metadata_GetCreator(pMetadata, NULL, 0);
if (nCreator != 0)
{
TCHAR* szCreator = (TCHAR*)malloc(nCreator * sizeof(TCHAR));
if (szCreator != NULL)
{
PtxPdf_Metadata_GetCreator(pMetadata, szCreator, nCreator);
_tprintf(_T(" - Creator: %s\n"), szCreator);
free(szCreator);
}
}

// Get producer
size_t nProducer = PtxPdf_Metadata_GetProducer(pMetadata, NULL, 0);
if (nProducer != 0)
{
TCHAR* szProducer = (TCHAR*)malloc(nProducer * sizeof(TCHAR));
if (szProducer != NULL)
{
PtxPdf_Metadata_GetProducer(pMetadata, szProducer, nProducer);
_tprintf(_T(" - Producer: %s\n"), szProducer);
free(szProducer);
}
}

// Get subject
size_t nSubject = PtxPdf_Metadata_GetSubject(pMetadata, NULL, 0);
if (nSubject != 0)
{
TCHAR* szSubject = (TCHAR*)malloc(nSubject * sizeof(TCHAR));
if (szSubject != NULL)
{
PtxPdf_Metadata_GetSubject(pMetadata, szSubject, nSubject);
_tprintf(_T(" - Subject: %s\n"), szSubject);
free(szSubject);
}
}

// Get keywords
size_t nKeywords = PtxPdf_Metadata_GetKeywords(pMetadata, NULL, 0);
if (nKeywords != 0)
{
TCHAR* szKeywords = (TCHAR*)malloc(nKeywords * sizeof(TCHAR));
if (szKeywords != NULL)
{
PtxPdf_Metadata_GetKeywords(pMetadata, szKeywords, nKeywords);
_tprintf(_T(" - Keywords: %s\n"), szKeywords);
free(szKeywords);
}
}

// Get creation date
if (PtxPdf_Metadata_GetCreationDate(pMetadata, &date) == TRUE)
{
_tprintf(_T(" - Creation Date: %02d-%02d-%d %02d:%02d:%02d%c%02d:%02d\n"), date.iYear, date.iMonth, date.iDay,
date.iHour, date.iMinute, date.iSecond, date.iTZSign >= 0 ? '+' : '-', date.iTZHour, date.iTZMinute);
}

// Get modification date
if (PtxPdf_Metadata_GetModificationDate(pMetadata, &date) == TRUE)
{
_tprintf(_T(" - Modification Date: %02d-%02d-%d %02d:%02d:%02d%c%02d:%02d\n"), date.iYear, date.iMonth,
date.iDay, date.iHour, date.iMinute, date.iSecond, date.iTZSign >= 0 ? '+' : '-', date.iTZHour,
date.iTZMinute);
}

// Get custom entries
_tprintf(_T("Custom entries:\n"));
TPtx_StringMap* pCustomEntries = PtxPdf_Metadata_GetCustomEntries(pMetadata);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pCustomEntries, _T("Failed to get custom entries. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
for (int i = Ptx_StringMap_GetBegin(pCustomEntries), iEnd = Ptx_StringMap_GetEnd(pCustomEntries); i != iEnd;
i = Ptx_StringMap_GetNext(pCustomEntries, i))
{
size_t nKeySize = Ptx_StringMap_GetKey(pCustomEntries, i, NULL, 0);
TCHAR* szKey = (TCHAR*)malloc(nKeySize * sizeof(TCHAR));
nKeySize = Ptx_StringMap_GetKey(pCustomEntries, i, szKey, nKeySize);

size_t nValueSize = Ptx_StringMap_GetValue(pCustomEntries, i, NULL, 0);
TCHAR* szValue = (TCHAR*)malloc(nValueSize * sizeof(TCHAR));
nValueSize = Ptx_StringMap_GetValue(pCustomEntries, i, szValue, nValueSize);

if (szKey && nKeySize && szValue && nValueSize)
_tprintf(_T(" - %s: %s\n"), szKey, szValue);

free(szKey);
free(szValue);
}

Download code sample
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, password))
{
// Conformance
Console.WriteLine("Conformance: {0}", inDoc.Conformance.ToString());

// Encryption information
Permission? permissions = inDoc.Permissions;
if (!permissions.HasValue)
{
Console.WriteLine("Not encrypted");
}
else
{
Console.WriteLine("Encryption:");
Console.Write(" - Permissions: ");
foreach (Enum flag in Enum.GetValues(typeof(Permission)))
if (permissions.Value.HasFlag(flag))
Console.Write("{0}, ", flag.ToString());
Console.WriteLine();
}

// Get metadata
Metadata metadata = inDoc.Metadata;
Console.WriteLine("Document information:");

// Get title
string title = metadata.Title;
if (title != null)
Console.WriteLine(" - Title: {0}", title);

// Get author
string author = metadata.Author;
if (author != null)
Console.WriteLine(" - Author: {0}", author);

// Get subject
string subject = metadata.Subject;
if (subject != null)
Console.WriteLine(" - Subject: {0}", subject);

// Get keywords
string keywords = metadata.Keywords;
if (keywords != null)
Console.WriteLine(" - Keywords: {0}", keywords);

// Get creation date
DateTimeOffset? creationDate = metadata.CreationDate;
if (creationDate != null)
Console.WriteLine(" - Creation Date: {0}", creationDate);

// Get modification date
DateTimeOffset? modificationDate = metadata.ModificationDate;
if (modificationDate != null)
Console.WriteLine(" - Modification Date: {0}", modificationDate);

// Get creator
string creator = metadata.Creator;
if (creator != null)
Console.WriteLine(" - Creator: {0}", creator);

// Get producer
string producer = metadata.Producer;
if (producer != null)
Console.WriteLine(" - Producer: {0}", producer);

// Custom entries
Console.WriteLine("Custom entries:");
foreach (var entry in metadata.CustomEntries)
Console.WriteLine(" - {0}: {1}", entry.Key, entry.Value);
}
Download code sample
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null)) {
// Conformance
System.out.format("Conformance: %s\n", inDoc.getConformance().toString());

// Encryption information
EnumSet<Permission> permissions = inDoc.getPermissions();
if (permissions == null) {
System.out.println("Not encrypted");
} else {
System.out.println("Encryption:");
System.out.print(" - Permissions: ");
for (Permission permission : permissions) {
System.out.format("%s, ", permission.toString());
}
System.out.println();
}

// Get metadata of input PDF
Metadata metadata = inDoc.getMetadata();
System.out.format("Document information:\n");

// Get title
String title = metadata.getTitle();
if (title != null)
System.out.format(" - Title: %s\n", title);

// Get author
String author = metadata.getAuthor();
if (author != null)
System.out.format(" - Author: %s\n", author);

// Get subject
String subject = metadata.getSubject();
if (subject != null)
System.out.format(" - Subject: %s\n", subject);

// Get keywords
String keywords = metadata.getKeywords();
if (keywords != null)
System.out.format(" - Keywords: %s\n", keywords);

// Get creation date
OffsetDateTime creationDate = metadata.getCreationDate();
if (creationDate != null)
System.out.format(" - Creation Date: %s\n", creationDate.toString());

// Get modification date
OffsetDateTime modificationDate = metadata.getModificationDate();
if (modificationDate != null)
System.out.format(" - Modification Date: %s\n", modificationDate.toString());

// Get creator
String creator = metadata.getCreator();
if (creator != null)
System.out.format(" - Creator: %s\n", creator);

// Get producer
String producer = metadata.getProducer();
if (producer != null)
System.out.format(" - Producer: %s\n", producer);

// Custom entries
System.out.format("Custom entries:\n");
for (Map.Entry<String, String> entry : metadata.getCustomEntries().entrySet())
System.out.format(" - %s: %s\n", entry.getKey(), entry.getValue());
}
Download code sample
def display_permissions(permissions: int):
"""Display encryption permissions in a readable format."""
# Display active permission names
active_permissions = [perm.name for perm in Permission if permissions & perm]
for perm in active_permissions:
print(f" - {perm}")
def list_pdf_info(input_doc: Document):
"""
List document information and metadata of the given PDF.
"""
# Conformance
print(f"Conformance: {input_doc.conformance.name}")

# Encryption information
permissions = input_doc.permissions
if permissions is None:
print("Not encrypted")
else:
display_permissions(permissions)

# Get metadata
metadata = input_doc.metadata
print("Document information:")

# Display standard metadata
if metadata.title:
print(f" - Title: {metadata.title}")
if metadata.author:
print(f" - Author: {metadata.author}")
if metadata.subject:
print(f" - Subject: {metadata.subject}")
if metadata.keywords:
print(f" - Keywords: {metadata.keywords}")
if metadata.creation_date:
print(f" - Creation Date: {metadata.creation_date}")
if metadata.modification_date:
print(f" - Modification Date: {metadata.modification_date}")
if metadata.creator:
print(f" - Creator: {metadata.creator}")
if metadata.producer:
print(f" - Producer: {metadata.producer}")

# Display custom entries
print("Custom entries:")
for key, value in metadata.custom_entries.items():
print(f" - {key}: {value}")
# Open input document
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, pdf_password) as in_doc:
# Process the PDF
list_pdf_info(in_doc)

List Signatures in PDF

Download code sample
// 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());

// Get signatures of input PDF
pSignatureFields = PtxPdf_Document_GetSignatureFields(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pSignatureFields,
_T("Failed to get signatures of input PDF. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
_tprintf(_T("Number of signature fields: %d\n"), PtxPdfForms_SignatureFieldList_GetCount(pSignatureFields));

for (int i = 0; i < PtxPdfForms_SignatureFieldList_GetCount(pSignatureFields); i++)
{
pSig = PtxPdfForms_SignatureFieldList_Get(pSignatureFields, i);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pSig, _T("Failed to get signature. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());

TPtxPdfForms_SignatureFieldType iFieldType = PtxPdfForms_SignatureField_GetType(pSig);
if (iFieldType == ePtxPdfForms_SignatureFieldType_Signature ||
iFieldType == ePtxPdfForms_SignatureFieldType_DocMdpSignature ||
iFieldType == ePtxPdfForms_SignatureFieldType_DocumentSignature)
{
// List name
size_t nName = PtxPdfForms_SignedSignatureField_GetName(pSig, NULL, 0);
_tprintf(_T("- %s fields"), PtxPdfForms_SignatureField_IsVisible(pSig) ? _T("Visible") : _T("Invisible"));
if (nName != 0)
{
TCHAR* szName = (TCHAR*)malloc(nName * sizeof(TCHAR));
if (szName != NULL)
{
PtxPdfForms_SignedSignatureField_GetName(pSig, szName, nName);
_tprintf(_T(", signed by: %s"), szName);
free(szName);
}
}
_tprintf(_T("\n"));

// List location
size_t nLocation = PtxPdfForms_Signature_GetLocation(pSig, NULL, 0);
if (nLocation != 0)
{
TCHAR* szLocation = (TCHAR*)malloc(nLocation * sizeof(TCHAR));
if (szLocation != NULL)
{
PtxPdfForms_Signature_GetLocation(pSig, szLocation, nLocation);
_tprintf(_T(" - Location: %s\n"), szLocation);
free(szLocation);
}
}

// List reason
size_t nReason = PtxPdfForms_Signature_GetReason(pSig, NULL, 0);
if (nReason != 0)
{
TCHAR* szReason = (TCHAR*)malloc(nReason * sizeof(TCHAR));
if (szReason != NULL)
{
PtxPdfForms_Signature_GetReason(pSig, szReason, nReason);
_tprintf(_T(" - Reason: %s\n"), szReason);
free(szReason);
}
}

// List contact info
size_t nContactInfo = PtxPdfForms_Signature_GetContactInfo(pSig, NULL, 0);
if (nContactInfo != 0)
{
TCHAR* szContactInfo = (TCHAR*)malloc(nContactInfo * sizeof(TCHAR));
if (szContactInfo != NULL)
{
PtxPdfForms_Signature_GetContactInfo(pSig, szContactInfo, nContactInfo);
_tprintf(_T(" - Contact info: %s\n"), szContactInfo);
free(szContactInfo);
}
}

// List date
if (PtxPdfForms_SignedSignatureField_GetDate(pSig, &date) == TRUE)
{
_tprintf(_T(" - Date: %02d-%02d-%d %02d:%02d:%02d%c%02d:%02d\n"), date.iYear, date.iMonth, date.iDay,
date.iHour, date.iMinute, date.iSecond, date.iTZSign >= 0 ? '+' : '-', date.iTZHour,
date.iTZMinute);
}
}
else
{
_tprintf(_T("- %s field, not signed\n"),
PtxPdfForms_SignatureField_IsVisible(pSig) ? _T("Visible") : _T("Invisible"));
}
}
Download code sample
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
{
SignatureFieldList signatureFields = inDoc.SignatureFields;
Console.WriteLine("Number of signature fields: {0}", signatureFields.Count);
foreach (SignatureField field in signatureFields)
{
if (field is Signature sig)
{
// List name
string name = sig.Name;
Console.WriteLine("- {0} fields, signed by: {1}",
sig.IsVisible ? "Visible" : "Invisible", name ?? "(Unknown name)");

// List location
string location = sig.Location;
if (location != null)
Console.WriteLine(" - Location: {0}", location);

// List reason
string reason = sig.Reason;
if (reason != null)
Console.WriteLine(" - Reason: {0}", reason);

// List contact info
string contactInfo = sig.ContactInfo;
if (contactInfo != null)
Console.WriteLine(" - Contact info: {0}", contactInfo);

// List date
DateTimeOffset? date = sig.Date;
if (date != null)
Console.WriteLine(" - Date: {0}", date.Value);
}
else
Console.WriteLine("- {0} field, not signed", field.IsVisible ? "Visible" : "Invisible");
}
}
Download code sample
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null)) {
SignatureFieldList signatureFields = inDoc.getSignatureFields();
System.out.format("Number of signature fields: %d\n", signatureFields.size());

for (SignatureField field : signatureFields) {
if (field instanceof Signature) {
Signature sig = (Signature)field;
// List name
String name = sig.getName();
System.out.format("- %s field, signed by: %s\n", sig.getIsVisible() ? "Visible" : "Invisible",
name != null ? name : "(Unknown name)");

// List location
String location = sig.getLocation();
if (location != null)
System.out.format(" - Location: %s\n", location);

// List reason
String reason = sig.getReason();
if (reason != null)
System.out.format(" - Reason: %s\n", reason);

// List contact info
String contactInfo = sig.getContactInfo();
if (contactInfo != null)
System.out.format(" - Contact info: %s\n", contactInfo);

// List date
OffsetDateTime date = sig.getDate();
if (date != null)
System.out.format(" - Date: %s\n", date.toString());
} else {
System.out.format("- %s field, not signed\n", field.getIsVisible() ? "Visible" : "Invisible");
}
}
}
Download code sample
def list_signatures(in_doc: Document):
# Retrieve the list of signature fields
signature_fields = in_doc.signature_fields
print(f"Number of signature fields: {len(signature_fields)}")

for field in signature_fields:
if isinstance(field, Signature):
# List name
name = field.name or "(Unknown name)"
print(f"- {'Visible' if field.is_visible else 'Invisible'} field, signed by: {name}")

# List location
if field.location:
print(f" - Location: {field.location}")

# List reason
if field.reason:
print(f" - Reason: {field.reason}")

# List contact info
if field.contact_info:
print(f" - Contact info: {field.contact_info}")

# List date
if field.date:
print(f" - Date: {field.date}")
else:
print(f"- {'Visible' if field.is_visible else 'Invisible'} field, not signed")
# Open input document
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# List all signatures of the PDF document
list_signatures(in_doc)
Download code sample
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
{
PrintOutlineItems(inDoc.Outline, "", inDoc);
}
static void PrintOutlineItem(OutlineItem item, string indentation, Document document)
{
string title = item.Title;
Console.Out.Write("{0}{1}", indentation, title);
Destination dest = item.Destination;
if (dest != null)
{
int pageNumber = document.Pages.IndexOf(dest.Target.Page) + 1;
string dots = new string('.', 78 - indentation.Length - title.Length - pageNumber.ToString().Length);
Console.Out.Write(" {0} {1}", dots, pageNumber);
}
Console.Out.WriteLine();
PrintOutlineItems(item.Children, indentation + " ", document);
}
static void PrintOutlineItems(OutlineItemList outlineItems, string indentation, Document document)
{
foreach (var item in outlineItems)
PrintOutlineItem(item, indentation, document);
}
Download code sample
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null)) {
printOutlineItems(inDoc.getOutline(), "", inDoc);
}
static void printOutlineItem(OutlineItem item, String indentation, Document document) throws ToolboxException {
String title = item.getTitle();
System.out.format("%s%s", indentation, title);
Destination dest = item.getDestination();
if (dest != null) {
int pageNumber = document.getPages().indexOf(dest.getTarget().getPage()) + 1;
char[] dots = new char[78 - indentation.length() - title.length() - Integer.toString(pageNumber).length()];
Arrays.fill(dots, '.');
System.out.format(" %s %d", new String(dots), pageNumber);
}
System.out.println();
printOutlineItems(item.getChildren(), indentation + " ", document);
}
static void printOutlineItems(OutlineItemList outlineItems, String indentation, Document document)
throws ToolboxException {
for (OutlineItem item : outlineItems)
printOutlineItem(item, indentation, document);
}
Download code sample
def print_outline_item(item: OutlineItem, indentation: str, in_doc: Document):
title = item.title
print(f"{indentation}{title}", end="")

dest = item.destination
if dest and dest.target:
page_number = in_doc.pages.index(dest.target.page) + 1
dots_length = max(0, 78 - len(indentation) - len(title) - len(str(page_number)))
dots = "." * dots_length
print(f" {dots} {page_number}", end="")

print() # End the current line
print_outline_items(item.children, indentation + " ", in_doc)
def print_outline_items(items: OutlineItemList, indentation: str, in_doc: Document):
for outline_item in items:
print_outline_item(outline_item, indentation, in_doc)
# Open the input document
with open(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
print_outline_items(in_doc.outline, "", in_doc)

Extract all text from PDF

Download code sample
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
{
int pageNumber = 1;

// Process each page
foreach (var inPage in inDoc.Pages)
{
Console.WriteLine("==========");
Console.WriteLine($"Page: {pageNumber++}");
Console.WriteLine("==========");

ContentExtractor extractor = new ContentExtractor(inPage.Content);
extractor.Ungrouping = UngroupingSelection.All;

// Iterate over all content elements and only process text elements
foreach (ContentElement element in extractor)
if (element is TextElement textElement)
WriteText(textElement.Text);
}
}
private static void WriteText(Text text)
{
string textPart = "";

// Write all text fragments
// Determine heuristically if there is a space between two text fragments
for (int iFragment = 0; iFragment < text.Count; iFragment++)
{

TextFragment currFragment = text[iFragment];
if (iFragment == 0)
textPart += currFragment.Text;
else
{
TextFragment lastFragment = text[iFragment - 1];
if (currFragment.CharacterSpacing != lastFragment.CharacterSpacing ||
currFragment.FontSize != lastFragment.FontSize ||
currFragment.HorizontalScaling != lastFragment.HorizontalScaling ||
currFragment.Rise != lastFragment.Rise ||
currFragment.WordSpacing != lastFragment.WordSpacing)
textPart += $" {currFragment.Text}";
else
{
Point currentBotLeft = currFragment.Transform.TransformRectangle(currFragment.BoundingBox).BottomLeft;
Point beforeBotRight = lastFragment.Transform.TransformRectangle(lastFragment.BoundingBox).BottomRight;

if (beforeBotRight.X < currentBotLeft.X - 0.7 * currFragment.FontSize ||
beforeBotRight.Y < currentBotLeft.Y - 0.1 * currFragment.FontSize ||
currentBotLeft.Y < beforeBotRight.Y - 0.1 * currFragment.FontSize)
textPart += $" {currFragment.Text}";
else
textPart += currFragment.Text;
}
}
}
Console.WriteLine(textPart);
}
Download code sample
try (// Open input document
FileStream inStream = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStream, null)) {
int pageNumber = 1;

// Process each page
for (Page inPage : inDoc.getPages()) {
System.out.println("==========");
System.out.println("Page: " + pageNumber++);
System.out.println("==========");

ContentExtractor extractor = new ContentExtractor(inPage.getContent());
extractor.setUngrouping(UngroupingSelection.ALL);

// Iterate over all content elements and only process text elements
for (ContentElement element : extractor) {
if (element instanceof TextElement)
writeText(((TextElement) element).getText());
}
}
}
private static void writeText(Text text) {
String textPart = "";

// Write all text fragments
// Determine heuristically if there is a space between two text fragments
for (int iFragment = 0; iFragment < text.size(); iFragment++) {
TextFragment currFragment = text.get(iFragment);
if (iFragment == 0)
textPart += currFragment.getText();
else {
TextFragment lastFragment = text.get(iFragment - 1);
if (currFragment.getCharacterSpacing() != lastFragment.getCharacterSpacing() ||
currFragment.getFontSize() != lastFragment.getFontSize() ||
currFragment.getHorizontalScaling() != lastFragment.getHorizontalScaling() ||
currFragment.getRise() != lastFragment.getRise() ||
currFragment.getWordSpacing() != lastFragment.getWordSpacing()) {
textPart += " ";
textPart += currFragment.getText();
}
else {
Point currentBotLeft = currFragment.getTransform().transformRectangle(currFragment.getBoundingBox()).getBottomLeft();
Point beforeBotRight = lastFragment.getTransform().transformRectangle(lastFragment.getBoundingBox()).getBottomRight();

if (beforeBotRight.getX() < currentBotLeft.getX() - 0.7 * currFragment.getFontSize() ||
beforeBotRight.getY() < currentBotLeft.getY() - 0.1 * currFragment.getFontSize() ||
currentBotLeft.getY() < beforeBotRight.getY() - 0.1 * currFragment.getFontSize()) {
textPart += " ";
textPart += currFragment.getText();
}
else
textPart += currFragment.getText();
}
}
}
System.out.println(textPart);
}
Download code sample
def write_text(text: Text):
"""Reconstruct text heuristically from text fragments."""
text_part = []

# Write all text fragments
# Determine heuristically if there is a space between two text fragments
for i_fragment, curr_fragment in enumerate(text):
if i_fragment == 0:
text_part.append(curr_fragment.text)
else:
last_fragment = text[i_fragment - 1]

# Determine if there's a space between fragments
if (curr_fragment.character_spacing != last_fragment.character_spacing or
curr_fragment.font_size != last_fragment.font_size or
curr_fragment.horizontal_scaling != last_fragment.horizontal_scaling or
curr_fragment.rise != last_fragment.rise or
curr_fragment.word_spacing != last_fragment.word_spacing):
text_part.append(f" {curr_fragment.text}")
else:
current_bot_left = curr_fragment.transform.transform_rectangle(curr_fragment.bounding_box).bottom_left
before_bot_right = last_fragment.transform.transform_rectangle(last_fragment.bounding_box).bottom_right

if (before_bot_right.x < current_bot_left.x - 0.7 * curr_fragment.font_size or
before_bot_right.y < current_bot_left.y - 0.1 * curr_fragment.font_size or
current_bot_left.y < before_bot_right.y - 0.1 * curr_fragment.font_size):
text_part.append(f" {curr_fragment.text}")
else:
text_part.append(curr_fragment.text)

print("".join(text_part))
# Open input document
with open(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
page_number = 1

# Process each page
for in_page in in_doc.pages:
print(f"==========\nPage: {page_number}\n==========")

extractor = ContentExtractor(in_page.content)
extractor.ungrouping = UngroupingSelection.ALL

# Iterate over all content elements and only process text elements
for element in extractor:
if isinstance(element, TextElement):
write_text(element.text)
page_number += 1