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