Skip to main content

PDF Operations

Introduction

In this section, we will cover the various actions that can be performed on PDF documents, along with the corresponding query for selecting the relevant data.

PDF Forms

Form Tag

Available from: v20.3

This tag enables the creation of PDF forms. The tag begins with the string ?form, followed by the key containing the data. There are three types of form elements available:

  1. Textboxes
  2. Radio Buttons
  3. Checkboxes

All three types have common fields that must be provided in order to create them.

  • type (required): Indicates which type of form element to be created. Options are text, radio, and checkbox.
  • name (required): Unique ID of a form element.
  • height (optional): User defined height of a form element. If not specified automatically assigned.
  • width (optional): User defined width of a form element. If not specified automatically assigned.
  • value (optional): The default value a certain form element will have.
  • text (optional): A label for certain form elements.
  • selected (optional): Boolean value (true/false) that checks or unchecks radio button elements.

Only form elements fields indicated with required, height and width are common for every element. The remaining elements are discussed in each form elements section below.

Textboxes

To create a textbox form element in a PDF Form, the following fields must be included in the data :

  • type (required)
  • name (required)
  • value (optional)
  • height (optional)
  • width (optional)

Data Source

SELECT
'file1' AS "filename",
CURSOR (
SELECT
CURSOR (
SELECT
'text' AS "type",
'' AS "value",
'first_name' AS "name"
FROM
dual
) AS "first_name",
CURSOR (
SELECT
'text' AS "type",
'Apex R&D' AS "value",
'last_name' AS "name",
'20' AS "height",
'200' AS "width"
FROM
dual
) AS "last_name"
FROM
dual
) AS "data"
FROM
dual;

Template

The template consists of a textbox element with the name first_name and a textbox element with the name last_name, with the form tag represented by

    Name: {?form first_name}   Surname: {?form last_name}

 template.docx  

Output

It will result in two textbox elements in the PDF Form, one with the name first_name and one with the name last_name. The textbox element with the name first_name will be empty with default size, while the textbox element with the name last_name will have the value Apex R&D and will have a height of 20 and a width of 200.

textboxresult

 output.pdf  

Radio Buttons

To create a radio button element, radio type can be used. Extra options for radio type are as follows:

  • type (required)
  • name (required)
  • heigth (optional)
  • width (optional)
  • value (optional)
  • text (optional)
  • selected (optional)

There are two ways to create a radio button element. The first way is to create a single radio button element by Referencing. The second way is to create multiple radio button elements by Looping. Multiple radio buttons or Radiolists are grouped together as a single unit, and only one radio button can be selected at a time.

Looping

This technique is used to create a group of radio buttons that are interconnected to each other. A list of items are expected with options for radio type.

SELECT
'file1' AS "filename",
CURSOR (
SELECT
CURSOR (
SELECT
'radio' AS "type",
'List A' AS "value",
'Radiolist' AS "name",
'List Option A' AS "text"
FROM
dual
UNION ALL
SELECT
'radio' AS "type",
'List B' AS "value",
'Radiolist' AS "name",
'List Option B' AS "text",
true AS "selected"
FROM
dual
) AS "radiolist"
FROM
dual
) AS "data"
FROM
dual;

and template :

Radio List : {#radiolist}
* {?form this} {/radiolist}

Result will look like this:

radiotemplateresult

 template.docx    output.pdf  

Referencing

This technique is used to create a single radio button element. The radio button element is referenced by the name of the radio button element. If multiple radio element are defined, they are not interconnected and will behave as an independent element.

SELECT
'pdf_form' AS "filename",
CURSOR ( SELECT
CURSOR (
SELECT
CURSOR (
SELECT
'radio' AS "type",
'Radio' AS "name",
'A' AS "value",
'Option A' AS "text",
15 AS "height",
100 AS "width"
FROM
dual
) AS "a",
CURSOR (
SELECT
'radio' AS "type",
'Radio' AS "name",
'B' AS "value",
'Option B' AS "text",
15 AS "height",
100 AS "width"
FROM
dual
) AS "b"
FROM
dual
) AS "radio",
FROM
dual
) AS "data" FROM dual;

and template :

    {?form radio[0].a}
{?form radio[0].b}

Result will look like this:

radiotemplateresult

 template.docx    output.pdf  

Checkboxes

The checkbox format generates a from woth checkboxes. It has several other options such as :

  • type (required)
  • name (required)
  • heigth (optional)
  • width (optional)
  • value (optional)
  • text (optional)

In this case, the value field can only accept a boolean value, which sets the default state of the checkbox as either checked or unchecked.

Given the data below:

SELECT
'file1' AS "filename",
CURSOR (
SELECT
CURSOR (
SELECT
'checkbox' AS "type",
1 AS "value",
'Checkbox' AS "name",
'IsChecked' AS "text",
20 AS "height",
200 AS "width"
FROM
dual
) AS "checkbox"
FROM
dual
) AS "data"
FROM
dual;

Template

{?form checkbox}

Output

checkboxresult

 template.docx    output.pdf  

Filling PDF Forms

Available from: v20.2

AOP provides a feature that allows users to fill out forms within PDF files. To use this feature, you need to include an object with the key aop_pdf_form_data in the files array. You can query the available forms by using the form_fields type in the output_type parameter.

There are differeent types of form fields you can fill in :

  • Text Fields : You will need to provide the value you want to fill in the field.
  • Radio Buttons / Checkboxes : You will need to provide a Boolean value to check or uncheck the field.

If you're not sure which form field name corresponds to each actual field, you can find instructions on how to find it here This will fill in each form field with the name of that field.

Example

Data Source

By providing given data source:

SELECT
'file1' AS "filename",
CURSOR (
SELECT
CURSOR (
SELECT
'John' AS "first_name",
'Doe' AS "last_name",
'List A' AS "radiolist",
'A' AS "radio",
'true' AS "Agree"
FROM
dual
) AS "aop_pdf_form_data"
FROM
dual
) AS "data"
FROM
dual;

If you need to specify multiple values in same form field, for example if you have multiple checkboxes with the same name, you can pass it as an array. From AOP 23.2, you can pass it using apex_json prefix in front of the form field name. For example, if you have a checkbox with the name "checkbox1", you can pass it as "apex_json_checkbox1". apex_json prefix parses string values as JSON. For example :

SELECT
'file1' AS "filename",
CURSOR (
SELECT
CURSOR (
SELECT
json_array(1,0,1) AS "apex_json_checkbox"
FROM
dual
) AS "aop_pdf_form_data"
FROM
dual
) AS "data"
FROM
dual;

Specifying Font to be used for filling PDF Forms

Available from: v23.1

AOP provides a feature that allows users to specify the font to be used for filling PDF forms. For that, you need to use g_output_form_fill_font present in aop_api_pkg. The font should be installed in the system where AOP is running. You can query the available fonts by visiting here.

Note

AOP expects font name without whitespaces, if your font name is Arial Black, you should use ArialBlack.

Example

aop_api_pkg.g_output_form_fill_font := 'ArialBlack';
Note

If AOP is unable to find the fontname specified, it will use the fallback font as Arial.

Identifying PDF Form Fields

For filling out forms, or to extract elements that are present in the form fields, you need to know the name of the fields. You can use the identify_form_fields output option to fill in each form field with the name of that field. For that you need to use g_identify_form_fields present in aop_api_pkg.

Example

aop_api_pkg.g_identify_form_fields := 'true';

Read Fields from PDF Forms

AOP provides a feature that allows users to read fields from PDF files. Reading fields from PDF forms returns a json object with the field names and values. For that, in your dynamic action you should select PDF Form Fields (PDF) as your output type.

Form Fields

Parse XFA Forms

AOP provides a feature that allows users to parse XFA forms from PDF files. Parsing XFA forms returns a json object with the field names, values and type of the field.

p_output_type => 'xfa_form_fields',

PDF signing

Signing PDF with Certificate

Available from: v20.2

It is possible to sign the output PDF if the output pdf has a signature field. The certificate (pkcs #12 .p12/.pfx) should be passed in the g_output_sign_certificate of aop_api_pkg. (the format of certificate can be base64, URL, FTP location or a location in the file system.) In your Init PL/SQL section, you should import the certificate. This example assumes that the certificate is stored in the static application files.

Note

Please note that the certificate names and any files that are present in examples might not be the same as in your application. So make sure to

BEGIN
SELECT
apex_web_service.blob2clobbase64(file_content)
INTO aop_api_pkg.g_output_sign_certificate
FROM
apex_application_static_files
WHERE
application_id = v('APP_ID')
AND file_name = 'certificate.p12';

END;

and any PDF as a template, the output PDF will be signed with the certificate provided.

Signing PDF with Password Protected Certificate

Available from: v21.2

It is possible to sign the output PDF if the output pdf has a signature field. The certificate (pkcs #12 .p12/.pfx) should be passed in g_output_sign_certificate in a base64 encoded format (this can also be a URL, FTP location or a location in the file system). Along with the certificate, the password of the certificate should be passed in g_output_sign_certificate_pwd in the INIT PL/SQL section.

BEGIN
SELECT
apex_web_service.blob2clobbase64(file_content)
INTO aop_api_pkg.g_output_sign_certificate
FROM
apex_application_static_files
WHERE
application_id = v('APP_ID')
AND file_name = 'certificate.p12';

aop_api_pkg.g_output_sign_certificate_pwd := 'certificatepassword';
END;

and any PDF as a template, the output PDF will be signed with the certificate provided. The example assumes that the certificate is stored in the static application files.

Signing PDF with Password Protected Certificate and PrivateKey

Available from: v22.2

It is possible to provide private key password if it is different from certificate password. If you are signing with password protected private keys, you should specify g_output_sign_certificate, which can be in base64 encoded format (this can also be a URL, FTP location or a location in the file system.) and g_output_sign_certificate_prp (private key password) in the INIT PL/SQL section.

BEGIN
SELECT
apex_web_service.blob2clobbase64(file_content)
INTO aop_api_pkg.g_output_sign_certificate
FROM
apex_application_static_files
WHERE
application_id = v('APP_ID')
AND file_name = 'certificate.p12';

aop_api_pkg.g_output_sign_certificate_pwd := 'certificatepassword';
aop_api_pkg.g_output_sign_certificate_prp := 'privatekeypassword';
END;

and any PDF as a template, the output PDF will be signed with the certificate provided. The example assumes that the certificate is stored in the static application files.

Signing a Signature Field with Visual Signature

Available from: v22.1

Visual signatures are a type of digital signature that allows you to add a visual representation of your signature to a PDF document. It is possible to create signature fields and create signature with visual representation. We can create multiple signature fields using AOP but can be signed only one at a time. There are various operations that can be done with signature fields. We can add signature field, add signature to signature field and sign existing signature field.

Size of the Signature Field

While creating a signature field or a signature, the size of the field is customizable. For that you can either provide the size as width and height, or if you want predefined size, you can provide size as sm for small, md for medium and lg for large.

i.e. you can provide either of the following:

SELECT
'150' AS "width"
'50' AS "height" FROM dual
// or //
SELECT
'sm' AS "size" FROM dual

If you provide both width and height, and size, size will be given preference.

Creating a Signature Field

To create a new signature field on the template, you should provide the type as signaturefieldunsigned, with name, width and height of the field. In the cursor of the field you want to create signature field, you should provide the following:

SELECT
CURSOR (
SELECT
'signaturefieldunsigned' AS "type",
'text1' AS "name",
150 AS "width",
50 AS "height"
FROM
dual
) AS "text1"

This will create a signature field with name text1 with width 150 and height 50.

Creating a Signature Field and Signing it with Certificate

For creating a signature field and signing it with a certificate, you should provide the type as signaturefieldsigned, with name, value and password of the certificate. In the cursor of the field you want to create signature field, you should provide the following:

SELECT
'signaturefieldsigned' AS "type",
'text2' AS "name",
(
SELECT
apex_web_service.blob2clobbase64(file_content) AS value
FROM
apex_application_static_files
WHERE
file_name = 'kiran_certificate.pfx'
) "value",
(
SELECT
apex_web_service.blob2clobbase64(file_content) AS value
FROM
apex_application_static_files
WHERE
file_name = 'uc_logo.PNG'
AND ROWNUM = 1
) "background_image",
'certificate_password' AS "password",
'md' AS "size"
FROM
dual
) as "text2"

Please note that the content used for the example is only an example of the certificate which is taken from AOP PDF sample application, replace it with your certificates, and source of the certificate. This will add a visual signature to signature field with name text2 with medium size.

Custom Texts in Signature

From AOP 24.1.2 onwards, you can add custom text in any language to the signature field, for that you must pass the text to be added in custom_text property of the signature field.

For example adding the following custom text would result in given signature :

Custom Text Signature

SELECT 
"によるデジタル署名" AS "custom_text"
FROM dual;

Example

Data Source

SELECT
'file1' AS "filename",
CURSOR (
SELECT
CURSOR (
SELECT
'signaturefieldunsigned' AS "type",
'text1' AS "name",
150 AS "width",
50 AS "height"
FROM
dual
) AS "text1",
CURSOR (
SELECT
'signaturefieldsigned' AS "type",
'text2' AS "name",
(
SELECT
apex_web_service.blob2clobbase64(file_content) AS value
FROM
apex_application_static_files
WHERE
file_name = 'kiran_certificate.pfx'
) "value",
(
SELECT
apex_web_service.blob2clobbase64(file_content) AS value
FROM
apex_application_static_files
WHERE
file_name = 'uc_logo.PNG'
AND ROWNUM = 1
) "background_image",
'certificate_password' AS "password",
'md' AS "size"
FROM
dual
) AS "text2",
CURSOR (
SELECT
'signaturefieldunsigned' AS "type",
'text3' AS "name",
150 AS "width",
50 AS "height"
FROM
dual
) AS "text3"
FROM
dual
) AS "data"
FROM
dual;
Note

Please make sure that you change the values for fields value and background_image for the example to function properly in your cases if you're using SQL. Here image are being loaded from the AOP Sample Application. You can use any image of your choice, and provide your digital certificate to sign the PDF.

Template

The template should have 3 signature fields with names text1, text2 and text3. They can be represented as follows in the document

{?sign text1}
{?sign text2}
{?sign text3}

Output

signature_output

If it is unclear which signature field names correspond to which actual field, the output option identify_form_fields can be used to fill in each signature field with the name of that field.

Signing an Existing PDF Signature Field

In some of the cases, we might want to sign an already existing PDF signature field. In this case, we can provide the name of the signature field in the INIT PL/SQL section. you should provide field name in the g_output_sign_certificate_fld, certificate content in the g_output_sign_certificate and password in the g_output_sign_certificate_password variables. Please note that the name of the field might be different in your case.Please note that the template type should be pdf with a signature field for AOP to sign it. If you don't know the name, you can find instructions on how to find the name of the field in the Identifying PDF Form Fields section.

aop_api_pkg.g_output_sign_certificate_fld:= 'text1'
aop_api_pkg.g_output_sign_certificate:= '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\ncDOmnTcCAgQA'
aop_api_pkg.g_output_sign_certificate_img:= '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\n6PtcEfLzGmhyPzXls7zFy1mPJ6WnCiIlFVKFlQnbuGk3snMa0KtXKStIx5I+ggDk\n8VWYkL1VYAz6v1yJlKy52Lr9kIku1MiWj61wU94S5qoVe5GTsQj9upWacRS3Gkpm\njL0xXOM/rasxbFg98nOXYteO4zQLnzXyexhvZ3ocNX1WVydPXb/99q84eOgU3l6y\nBS+9WINOHWhuvIywXPRhPDR11FA+TwraJmShf/9ybN/xLi5f+T5MVxLZe/s+gUHf\n0t7ZcwSzZm9C9z45dKrpS1K7udkxjRyYNCgaT7M3cGA+22EvPvzw0n/wflr0VM2Z\nLeA/6BR+9dXXtM1T0P95+j9RE5j0PSiLPaQqFALrs0XrJFTXbsCuPScfcAmReIif\nJctbV4FTDTRmZAOe7UFwho83A31yoCMouDA2UFRMJWLa12HunD04fDgUrVh6GG/n\n3z+WmvKyMhDpKr+rdtoGvDKkDq0ZibpdbGQml1ufOpIIrGTTwcoqZmDL1p2N+Ww5\nnUn/E4hEiuA0iDlx0nT06cOOGSgwPqDMt0a4BSK3O5nyfpOmbQaWLdtk8lneT5Oe\nCERNKyctIXqHPsHk6k2IiRZoZGoKEBbOMDuS9poOYUxcFp3PKdi+bT9N3teNeXW1\nFWyO966dp1FatJ4NUIiAvxSxwYoQ7wgKjaZCc4EGDZ2MDZsO43M6vMrfHO+nTU6e\nepdNeve7ew+jesp8llmfOBii0/z4vEX0DwvY2Hk0cTkY9FIt1q5huelDipfyPayc\n4mnrIBO4Y+c+FBUvRCB2LOvPiI1+pmYURLpCY0py8AcNqsHGjfspk9AYlZP3w97x\nY+gng8hWQskK61//+m9GGzdQW7sGgwdNo4D0dZ09g+Gnvi3pu1SkN4U9YxHmzN2C\nK1duGKfS5nfytMk2vkzYubM3CM6NGPh8DfzeEvgZjQhI5vsSVbmfTutbY2ejdsZG\nXLp0ywwQKr/l4eT7c5HzHbZeSjdv3cGRwycx9OXp6NG9MgQmAsjjJvBp4vTtrHPn\nCkyaJP/tg0Yg2XJbaspfVw1T7N9/Cq8ML0OPniXstCVmLEyj6NLO8pO6dC0h7zoc\nO3bOjJjb/EpPSk8EIku2MALEju0HMHZMLbxuap3ISYiM1HybLNM73MEc+KJTsX7j\nEXzwwTWT1zayk5/ubbK/K5RfuuQQXhvegKiIiQhqdFjTJlwFNAf5iI4pZBhfhreX\nvYuTJy8aPtJASlbYIud7fg6y5bb3ercFsUimbdSoWWgbz6jNQ0eYWsjtojmmGZLG\n6NJpGlat2oWLF6+a521+kZO3/b/zf1NqVlDD18EXpFwIIo3MR1HjKRqUo92+/STK\ncLvxj5THyvZJ6UeDyFloXW0DqeecO3cFPbumoE1cPvyeSlagmGFoESvDEJ5+wIBB\nU1A3aw2+omNoK9GUn/PeCl7RxYnTHyKQSH8nlqE8tVk4hW+Thw76sBHVWLZ8j4le\nbN6m/Oz9L0HOd9kGt/V9Z897yMiuZYRG+bATREZqUJJaiY2uKGvQkGKUVyxiBwjl\nUbL1ETl56zfbWTTXaPmKLRj6ylS4ojWDkmbSPxl+/1T6o9RO7NR9+pQiI73BRM7y\nq5ym/qfK5ydpIr1MSS+2L9/DaGF67WrERo9CwJeFoK+SJqeCvaCEkUMBXhhYj9Ly\n1Tj1/sXGAb7mCu7krbTjnUOomraYDnMGQ3h9zU9HhIDJ3taK4fLLQ8swdepKY8Lk\neDt5O9MvTc53O+tz5/Y9vHf4NF58aQ41z3RqJEaY7hxj0qQ12refiOGvleDAgdM0\nPZ+b/BaASg/jrd8lV83J2rDhMBK7FJv5VX6CyOWtpBtRZBzt+PgsvreYEdtOfPTR\nx415Ld+fQj8ZRPblQrLmAc+evQaj35iGyIhXqZ7TaW6qDJA8/mL4AjnIyV3Jyh0w\nvcsKU+lhZPmL95dffYu6hrUYOqoMrTzJBJBAlGa+g0VS/XtjS1BRsRg7d75n8qpM\nSspvBfMkAnoS0nudZbB1Dsnt38jNpe84eA6CcoTp12nQUKY5yvsWuvVKx4z6Dbhy\n+dpDtcXDeOuqaPCTT77Ey69ORueu5fQbK+lOsCNTY3vZ+aI8aWjfMROFJTNo1i42\n8ra8fgr9JHOmAuvlutc3noMHz2H0mAYE4vSxUVNUNW1Ug4oVSEjIQN++o3HhwmUz\n2Kc8ViCWn61AU94C59ZtH+C1kcsJyqmICmhedQpV/iS0cr2FNomZePaFKly/cRNf\nf/21ydsc71+TnGVwlu/ixWuorVmChLhhrJMmt+XTlymhds1BeEw+4uhob9584D8c\nYSc/573kZnkfPXoM1ZXzkBhfDE9UKtyRdLC9dAcIJn1TDPePx/r1B/DpZyEH3pl+\nLP0oEOkFtiIShnqTJloVly7Fs/0r4Apkmknz+not9ekPVuK1UXV4++31jZPNrRAe\nVmDLX7wFzps3byMjYxP69J7DHlWNKGPG5KjTafdqbtFUzJq91UylsKPcTv6/JbJl\nsvJT0njXnnePICdzOlrHURv5aNYYMIR7NG2FdY0rRFHpQmzZtq+Rh/LZe1vHprwl\nB31z3LXrAJKTFyCO/pFGy910Acx0Gy87eTAZmTmLsGr1O4aHzSdy8m4J/WQQKX39\n9bf48IPrdORqkNiBCJfD6xpvvum4CaKu3aajrHy5sdMqoM1vC9i0oE7e+rJ+/PgZ\nhvML0a4doz1vuRlj0qT4CE8qOnTNRF7BQoas5xs1l32HTb81suVS/WyDXb16E+vX\n7kbPXtWIjSOIaNq0BCnMk47/CuTitderGXUtpb/zfScRNa2jk7eVx+VL17D07V3o\n1JHRGeVmJswxIjSWIpiCgUMmo6BogflMI3/qp8rvR5sz28h6yaWLN7Fp0zFGGYws\n6KeEe8bivyLfQIQrlVFBIfLyN2D79sON+WzBHlZI/a1nbEVOnvwAS5ZsI+9qmkVG\nFqy8WePlySBYs2jT52DbjoMmrxVuU56/RbJ1t+UN1fl/MCF5Dvo+WwVvgKaGgYlS\nK2qMuLaZGDK00kyv1biXM+/DSP+3MvyO0Zei5qFD8pGYqG9rFZQdI0JPLsIDSQgm\nZOK5F4serCL52uRxmsSWUotAJOZNk2jp0l1ITVtmPjm4PEls4DH4r6g34IvORkK7\nShw6dBHXr98xzzfX0E5+zvuGOavw1lv6Cq51X4U0kZrDnMrelAFfMBvHT36I27fv\nm+edfJ08fuvklInWmGVnL2aYn26msrTSTAQCyRNIRtfu2Vi4aAeuXL1mnrUN3bSu\n9m8l8dZzcjkmV72N4SNqGOBU0ZzRbNKBD/ONR4R/Itp2TkXdjPk4fyE0duTk3VL6\nSSDSi7RCo6x8GUP3WhYqAy75KZ4J1ELj0bFjAQa+WGMWHmpOsQrVEhCJxFufQnJy\nZ6FPX412SwXnkr9GvNMQn5CPnj0r8PEnn5kyiKeTb1P+v2WyMhGdPXsZs2ZtRHR8\nEiPPLDayZiToY2oqO2QW/ZclOHb89A++9DeVnfNvJ+8tW/aisHAhomOrjeOu1S1h\n3nH0uyZQGyVh/MRSHDh4jD7rd82206OoxeZMTC1zOb2XLt3ACDrNZnpHJDWEpm5q\nPRhNzeCXK1FUNK8xny3Yowqn/ytpZPrcuWsYNryGfhCdaH1vc2tlq8LTDDz//BRq\n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',
aop_api_pkg.g_output_sign_certificate_pwd:= 'certificate_password'
Note

Here output_sign_certificate and output_sign_certificate_password are base64 representations of the certificate and password respectively. Please make sure to replace these with your own certificate and password.

Custom Texts in Signature

From AOP 24.1.2 onwards, you can add custom text in any language to the signature field, for that you must pass the text to be added in g_output_sign_certificate_txt property in the init PL/SQL section.

For example adding the following custom text would result in given signature :

aop_api_pkg.g_output_sign_certificate_txt:= 'によるデジタル署名';

Custom Text Signature

 template.pdf    output.pdf  

Removing Last Page From a PDF

Have you ever been in a situation where you have a PDF with a blank last page? If so, you can use the remove_last_page option to remove the last page of a PDF.

For this, in your "output" object, you can add output_remove_last_page as a boolean value. In the INIT PL/SQL section you can provide g_output_remove_last_page as true.

aop_api_pkg.g_output_remove_last_page:= true

and with any template with PDF as output type, the last page will be removed from the output PDF.

 template.docx    output.pdf  

Protecting a PDF with a Password

For protecting a PDF with a password for access and/or modification, you can provide g_output_read_password and/or g_output_modify_password and/or goutput_pwd_protection_flag in the INIT PL/SQL section. It will protect the PDF from read access and/or modification. The g_output_pwd_protection_flag is optional. Click Here for more information on protection flags.

aop_api_pkg.g_output_read_password:= 'read_password';
aop_api_pkg.g_output_modify_password:= 'modify_password';
aop_api_pkg.g_output_pwd_protection_flag:= '4';

and with any template with PDF as output type, the output PDF will be password protected.

 template.docx    output.pdf  

tip

You can use the output_read_password and output_modify_password options together or separately.

Adding Barcodes to PDF

AOP supports overlay of barcodes on PDF. To add barcodes to PDF Templates "output_insert_barcode" should be true. In the INIT PL/SQL section you can provide g_output_insert_barcode as true. The template type should be PDF.

In the data section, data can be provided as normal data for the AOP. The properties that are available for the barcode are:

  • _type : The type of the barcode.
  • _height : The height of the barcode.
  • _width : The width of the barcode.

Example

Template

{|barcode}

Data Source

select 'file1' as "filename",
cursor (
select '1234567890' as "barcode",
'code128' as "barcode_type",
50 as "barcode_height",
50 as "barcode_width"
from dual
) as "data"
from dual;

In the INIT PL/SQL section you should provide g_output_insert_barcode as true.

aop_api_pkg.g_output_insert_barcode:= 1;  -- or true

with a template with PDF as output type, the output PDF will have the barcode.

 template.pdf    output.pdf  

Splitting the PDF into Multiple PDFs

For splitting a PDF into multiple PDFs, you can use the output_split option. For splitting the PDF into multiple PDFs, in INIT PL/SQL section you can provide g_output_split as true.

aop_api_pkg.g_output_split := 'true';

From AOP 24.3 onwards, we can now split pdf by specifying number of pages, or any string present in PDF. For that you should specify g_output_split_by_string in the INIT PL/SQL section.

aop_api_pkg.g_output_split := 'true';
aop_api_pkg.g_output_split_by_page := 3;
aop_api_pkg.g_output_split_by_string := 'Invoice No || Invoice Number' -- You should specify either of the parameter, if you specify both, split by page will be considered.

and a template with PDF as output type, the output PDF will be split into multiple PDFs. The output will be a zip file with each page of the input PDF as a separate PDF file.

 template.docx    output.zip  

Adding Watermark to PDF

Adding a watermark to a PDF can be done using the following options and parameters:

  • Use the output_watermark option in the output object to specify the watermark text as a plain string.
  • To set the color of the watermark text, use output_watermark_color with a plain string. The default color value is black.
  • To customize the font of the watermark text, use output_watermark_font with a plain string. The default font is Arial.
  • Adjust the opacity of the watermark text using output_watermark_opacity, which takes a number representing the opacity in percentage.
  • Specify the size of the watermark text using output_watermark_size with a number representing the size in pixels.

In the INIT PL/SQL section, you have the following options:

  • g_output_watermark: Set this to provide the watermark text.
  • g_output_watermark_color: Use this to define the color of the watermark text.
  • g_output_watermark_font: Set this to customize the font of the watermark text.
  • g_output_watermark_opacity: Use this to adjust the opacity of the watermark text (in percentage).
  • g_output_watermark_size: Set this to specify the size of the watermark text (in pixels).
aop_api_pkg.g_output_watermark:= 'watermark text';
aop_api_pkg.g_output_watermark_color:= 'red';
aop_api_pkg.g_output_watermark_font:= 'Arial';
aop_api_pkg.g_output_watermark_opacity:= 50;
aop_api_pkg.g_output_watermark_size:= 45;

and any template with PDF as output type, the output PDF will have the watermark text in the background. The result will look like this.

watermark_output

 template.docx    output.pdf  

Generating PDF/A Compliant PDF

For generating PDF/A format, we can use the output_convert_to_pdfa option. While converting using openoffice converter, specifying it will create PDF/A format, values can be either 1b or 2b which are the variants of PDF/A specification.

For example, if we want to convert a PDF to PDF/A-1b format, we can provide the value 1b in the output_convert_to_pdfa option. In INIT PL/SQL section you can provide g_output_convert_to_pdfa.

aop_api_pkg.g_output_convert_to_pdfa := '1b';
IMPORTANT NOTE

The PDF/A conversion is only supported by the openoffice converter. While converter handles the conversion, it is the responsibility of the template designer to ensure that the template is accessible.

and any template with PDF as output type, the output PDF will be in PDF/A-1b format.

 template.docx    output.pdf  

Generating PDF/UA standard PDF

For generating PDF/UA format, we can use the output_ua_compliant_pdf option. While converting using openoffice converter, specifying it will create PDF/UA format, values can be either true or false.

In INIT PL/SQL section you can provide g_output_ua_compliant_pdf.

aop_api_pkg.g_output_ua_compliant_pdf := 1;
IMPORTANT NOTE

The PDF/UA conversion is only supported by the openoffice converter. While converter handles the conversion, it is the responsibility of the template designer to ensure that the template is accessible.

 template.docx    output.pdf  

Flattening (Locking) PDF Form Fields

For flattening (locking) PDF form fields, we can use the lock_form option. In the output object we can provide the value true in the lock_form option. In the INIT PL/SQL section you can provide g_output_lock_form as true.

aop_api_pkg.g_output_lock_form := true;

Here's an example of a PDF form before and after it is flattened.

 template.pdf    output.pdf  

Ignoring Signature Fields while Flattening

If you want to ignore signature fields while flattening, you can use the g_lock_form_ignoring_sign option. In the output object we can provide the value true in the lock_form_except_signaturefield option.

aop_api_pkg.g_lock_form_ignoring_sign := true;

Adding Texts to PDF

AOP supports overlay of texts on PDF. For adding texts to PDF, we can define per page text that we want to place on the PDF along with some other properties. The properties supported are : text, x, y, rotation, bold, italic, font, font_color and font_size.

Providing x and y coordinates as percentage

From AOP 24.2.2 onwards, it is possible to specify x and y coordinates as a percentage of the page width and height. For that, you can provide the x and y coordinates as a string with a percentage sign at the end.

SELECT 'file1' AS "filename",
CURSOR (
SELECT CURSOR (
SELECT CURSOR (
SELECT 'First text to be shown in first page' AS "text",
50 AS "x",
600 AS "y",
0 AS "rotation",
'false' AS "bold",
'false' AS "italic",
'Arial' AS "font",
'#FF00FF' AS "font_color"
FROM dual
UNION ALL
SELECT
'Second text to be shown in first page' AS "text",
150 AS "x",
50 AS "y",
60 AS "rotation",
'false' AS "bold",
'false' AS "italic",
'Times new roman' AS "font",
'#00FFFF' AS "font_color",
20 AS "font_size"
FROM
dual
) AS "P1",
CURSOR (
SELECT 'First text to be shown in second page' AS "text",
50 AS "x",
600 AS "y",
0 AS "rotation",
'false' AS "bold",
'false' AS "italic",
'Arial' AS "font",
'#FF00FF' AS "font_color"
FROM dual
) AS "P2",
CURSOR (
SELECT 'Page {currentpage}/{totalpage}' AS "text",
10 AS "x",
10 AS "y",
0 AS "rotation",
'false' AS "bold",
'false' AS "italic",
'Arial' AS "font",
'#000000' AS "font_color",
'15' AS "font_size"
FROM dual
) AS "all"
FROM dual
) AS "aop_pdf_texts"
FROM dual
) AS "data"
FROM dual;

 template.docx    output.pdf  

Adding Images to PDF

We can insert images at any position in the PDF. The image can be scaled and rotated. For adding images to PDF we need to provide source of the image x and y coordinates where we want to place the image on the PDF, width of the image and rotation angle.

SELECT
'file1' AS "filename",
CURSOR (
SELECT
CURSOR (
SELECT
CURSOR (
SELECT
'https://united-codes.com/uc_logos/aop/Branded/logo-apex-office@2x.png' AS "image",
50 AS "x",
400 AS "y",
500 AS "image_width",
- 75 AS "rotation"
FROM
dual
) AS "all"
FROM
dual
) AS "aop_pdf_images"
FROM
dual
) AS "data"
FROM
dual;

with any template whose output is PDF, we can add images to the PDF.

 template.pdf    output.pdf  

Creating Single Page PDF

Some printers can print a document which has unspecified height and tear the paper once the page is finished. These kinds of printers are used for ticketing systems. Since the height is dynamic, it is not possible to create the document in Word. AOP has a feature to create a single page PDF. This allows users to create a template in Word (or any other format) and get their output in a single page.

For that, you need to set Output Type to One Page PDF.

Single Page PDF

Merging Multiple PDFs into Single PDF

You can merge multiple PDFs into a single PDF using AOP. In aop_api_pkg there is a parameter called g_output_merge which can be set to true to merge the output of multiple requests into a single PDF.

aop_api_pkg.g_output_merge := 'true';

Merging Multiple Requests into Single PDF

In some situations when our PDF is too large you can split the PDF into multiple requests, and merge the output of all the requests into a single PDF File.

Suppose you have reports of 5 customers, and you want to merge the output of all the requests into a single PDF. This technique is interesting when you want to generate very big documents. By cutting them in smaller documents and merging them later, might be faster in certain cases.

At first, lets send the request to AOP to generate the PDFs for all the customers and add it to a collection called AOP_MERGE. You will be sending multiple requests using loop.

DECLARE
l_collection_name VARCHAR2(100) := 'AOP_MERGE';
l_binds wwv_flow_plugin_util.t_bind_list;
l_return BLOB;
l_output_filename VARCHAR2(100) := 'output';
l_files_sql VARCHAR2(4000);
-- change the following variables in case you run from PL/SQL
l_app_id NUMBER := :app_id;
l_page_id NUMBER := :app_page_id;
l_username VARCHAR2(200) := :app_user;
l_aop_url VARCHAR2(500) := apex_app_setting.get_value('AOP_URL');
l_api_key VARCHAR2(100) := apex_app_setting.get_value('AOP_API_KEY');
BEGIN
FOR i IN 1..5 LOOP
-- define bind variables
l_binds(1).name := 'p_id';
l_binds(1).value := i;

-- call AOP per document
l_return := aop_api_pkg.plsql_call_to_aop(p_data_type => aop_api_pkg.c_source_type_sql, p_data_source => q'~
SELECT
'file1' AS "filename",
CURSOR (
SELECT
c.cust_first_name AS "cust_first_name",
c.cust_last_name AS "cust_last_name",
c.cust_city AS "cust_city",
CURSOR (
SELECT
o.order_total AS "order_total",
'Order ' || ROWNUM AS "order_name",
CURSOR (
SELECT
p.product_name AS "product_name",
i.quantity AS "quantity",
i.unit_price AS "unit_price",
apex_web_service.blob2clobbase64(p.product_image) AS "image"
FROM
aop_sample_order_items i,
aop_sample_product_info p
WHERE
o.order_id = i.order_id
AND i.product_id = p.product_id
) "product"
FROM
aop_sample_orders o
WHERE
c.customer_id = o.customer_id
) "orders"
FROM
aop_sample_customers c
WHERE
customer_id = :p_id
) AS "data"
FROM
dual
~',
p_template_type => aop_api_pkg.c_source_type_apex, p_template_source => 'aop_template_d01.docx',
p_output_type => 'pdf',
p_output_filename => l_output_filename, p_binds => l_binds, p_aop_url => l_aop_url, p_api_key => l_api_key,
p_app_id => l_app_id,
p_aop_remote_debug => 'No');

-- add to APEX collection
apex_collection.add_member(p_collection_name => l_collection_name, p_blob001 => l_return);
END LOOP;

Now, lets merge the documents stored in the collection into a single PDF, first select all the documents and call the AOP convert API to merge all files and create a single PDF.

-- prepare the SQL for the merge
-- This statement is selecting the 5 documents that have been stored in the collection
l_files_sql := q'~
select 'pdf'||to_char(seq_id) as filename, 'application/pdf' as mime_type, blob001 as file_blob
from apex_collections
where collection_name = 'AOP_MERGE'
order by seq_id
~';

-- call the AOP Convert API to merge all files and create a single PDF

l_return := aop_convert_pkg.convert_files(p_query => l_files_sql, p_output_type => 'pdf', p_output_filename => l_output_filename, p_aop_url => l_aop_url, p_api_key => l_api_key, p_app_id => l_app_id, p_aop_remote_debug => 'No');

-- insert the merged file in a table
INSERT INTO aop_output (
output_blob,
filename,
mime_type,
last_update_date
) VALUES (
l_return,
l_output_filename,
'application/pdf',
sysdate
);

END;

Merging different AOP DA calls

You can combine different DA calls and merge the outputs into a single PDF. Lets take an example which will be combining the output of two different DA calls and merge them into a single PDF.

At first, lets save the response of the two DA calls into a collection. Lets use the collection named SCREEN_CAPTURE. For that we will be sending the output to a procedure called save_collection.

Merging Two DA

Two DA calls generates reports of two different customers. AOP can merge its output by prepending the files present in the collection. For that, place the following SQL in INIT PL/SQL Code section.

aop_api_pkg.g_prepend_files_sql := q'[
select
c001 as filename,
c002 as mime_type,
blob001 as file_blob
from apex_collections
where collection_name = 'SCREEN_CAPTURE'
]';

It will generate a single PDF with the output of both the DA calls.

Merging different PDFs with Page numbers

AOP is able to merge different PDFs and add page numbers to each page. Lets take an example where we will be merging two PDFs and add page numbers to each page. Like before. we'll be combining the output of two DA calls and merge them into a single PDF. We will be using the collection named SCREEN_CAPTURE for this purpose.

At first, lets save the response of the two DA calls into a collection. Lets use the collection named SCREEN_CAPTURE. For that we will be sending the output to a procedure called save_collection.

Merging Two DA

You'll need to create a third Dynamic Action with the following Data Source:

SELECT
'file1' AS "filename",
CURSOR (
SELECT
CURSOR (
SELECT
CURSOR (
SELECT
'Page {currentpage}/{totalpage}' AS "text",
500 AS "x",
10 AS "y",
0 AS "rotation",
'false' AS "bold",
'false' AS "italic",
'Arial' AS "font",
'#000000' AS "font_color"
FROM
dual
) AS "all"
FROM
dual
) AS "aop_pdf_texts"
FROM
dual
) AS "data"
FROM
dual

This is the SQL for insertion of page numbers in each pages, for merging the PDF's we will be using the following SQL in INIT PL/SQL Code section.

aop_api_pkg.g_prepend_files_sql := q'[
select
c001 as filename,
c002 as mime_type,
blob001 as file_blob
from apex_collections
where collection_name = 'SCREEN_CAPTURE'
]';

 template.docx  

Duplicating the PDF into multiple copies

In AOP it is possible to duplicate the PDF into multiple copies. Lets take an example where we will be duplicating the PDF into 3 copies. For that, in the INIT PL/SQL Code section, following SQL needs to be placed.

aop_api_pkg.g_output_copies := 3;

Conversion to PDF from different file formats

In AOP it is possible to convert different file formats to PDF. The possible file formats and their corresponding mime types are listed below.

File FormatMime Type
pdfapplication/pdf
docxapplication/vnd.openxmlformats-officedocument.wordprocessingml.document
docmapplication/vnd.ms-word.document.macroEnabled.12
xlsxapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet
pptxapplication/vnd.openxmlformats-officedocument.presentationml.presentation
pptmapplication/vnd.ms-powerpoint.presentation.macroEnabled.12
htmltext/html
mdtext/markdown
txttext/plain
gifimage/gif
jpegimage/jpeg
jpgimage/jpeg
pngimage/png
svgimage/svg+xml
webpimage/webp
bmpimage/bmp
msbmpimage/x-ms-bmp
docapplication/msword
pptapplication/vnd.ms-powerpoint
xlsapplication/vnd.ms-excel
odtapplication/vnd.oasis.opendocument.text
odsapplication/vnd.oasis.opendocument.spreadsheet
odpapplication/vnd.oasis.opendocument.presentation
emlmessage/rfc822
msgapplication/vnd.ms-outlook
csvtext/csv

Parameters for Specifying the Quality of the PDF (openoffice converter only)

If you are using openoffice converter, AOP provides options to provide the quality of the PDF. The options available are set the resolution of the image i.e. 300dpi, 600dpi, 900dpi or 1200dpi, and jpeg compression factor ranging from 0-100. The quality of the PDF can be set by using the following SQL in INIT PL/SQL Code section.

aop_api_pkg.g_output_image_resolution := "300dpi";
aop_api_pkg.g_output_image_compression := 100;

Changing the Locale used During Conversion (openoffice converter only)

AOP provides the option to change the locale used during conversion. You can use options like en , ne for the locale parameter. The locale can be changed by using the following SQL in INIT PL/SQL Code section.

aop_api_pkg.g_output_locale  := "ne";

Adding Annotations/Comments To PDF

Using AOP you can add annotations to the PDF. The process of adding annotations to PDF is similar to adding texts to PDF. You can define per page annotations that you want to place on the PDF along with some other properties. The properties include x and y coordinates where you want to place the annotation on the PDF, width and height of the annotation. The default height and width of annotations are 200 units and 50 units respectively. You can also set the color of the annotation and text to be displayed in the annotation.

SELECT
'file1' AS "filename",
CURSOR (
SELECT
CURSOR (
SELECT
CURSOR (
SELECT
'First text to be shown in first page' AS "text",
50 AS "x",
50 AS "y",
'#FFE1BD' AS "color",
200 AS "height",
50 AS "width"
FROM
dual
UNION ALL
SELECT
'Second text to be shown in first page' AS "text",
150 AS "x",
50 AS "y",
'#00FFFF' AS "color"
FROM
dual
) AS "P1",
CURSOR (
SELECT
'First text to be shown in second page' AS "text",
50 AS "x",
50 AS "y",
'#f9f9f9' AS "color"
FROM
dual
) AS "P2",
CURSOR (
SELECT
'Page Commenting here' AS "text",
0 AS "x",
0 AS "y",
'#000000' AS "color"
FROM
dual
) AS "all"
FROM
dual
) AS "aop_pdf_comments"
FROM
dual
) AS "data"
FROM
dual

With any Template whose output is PDF, we can add annotations to the PDF.

 template.pdf    output.pdf  

Validating a PDF document

Available from: v24.2.3

In AOP For a PDF template, you can validate if the document is a valid PDF document. For this, you need to set output_type parameter to validate_pdf. The response will be a JSON object with the following keys:

  • valid: A boolean value indicating if the document is a valid PDF document.
  • message: A message indicating the result of the validation.

There might be three possible values for the message key:

  • When a document is a valid PDF document (valid: true), the message will be PDF is valid.
  • When a document is not a valid PDF document (valid: false), the message will start with Error: followed by the exception obtained.
  • When the document is password protected (valid: true) the message will be PDF is password protected.
p_output_type => 'validate_pdf',

For the template, you can use any PDF file. The output will be a JSON object with the following :

//for valid PDF
{
"valid": true,
"message": "PDF is valid"
}
//for password protected PDF
{
"valid": true,
"message": "PDF is password protected"
}
//for invalid PDF
{
"valid": false,
"message": "Error: Header doesn't contain versioninfo"
}

Converting PDF to Images

Available from: v24.3

From AOP v24.3, you can convert a PDF document to images. For this, you need to set output_type parameter to jpeg. In PLSQL you can set the p_output_type parameter to jpeg. Currently PDF to Jpeg conversion is only supported. If the PDF contains only one page, then image will be a single jpeg image. If the PDF contains multiple pages, a zip file will be returned containing all the jpeg images. If you need to generate a zip for one paged PDF too, you can set the output_compression parameter to zip. You can specify name of the zip using output_compression_name parameter (g_output_compression_name on INIT PLSQL)

p_output_type => 'jpeg',