Edit a Generated PDF
Even once you’ve generated a PDF, you may still want to perform extra operations to finalize your document. Examples of the operations you may want to perform include adding a cover page, adding watermarks, setting page labels, and more. Any operation provided by Processor can be used with PDF Generation. A full range of operations can be found in the Available Operations guide.
This guide will introduce an example to show how PDF Generation and additional operations can be combined in one command to produce your finalized document.
Before you get started, make sure Processor is up and running.
The example will consist of a simple styled form, which can be seen in the following HTML:
<!DOCTYPE html> <html> <head> <style> body { font-size: 16px; line-height: 1.6em; font-family: "Helvetica", Arial, sans-serif; color: #3d434e; } h1 { font-size: 42px; font-weight: normal; color: #142132; margin-block-start: 0.3em; } h2 { font-size: 32px; font-weight: normal; color: #142132; margin-block-start: 0.3em; } h3 { font-size: 12px; font-weight: normal; text-transform: uppercase; letter-spacing: 0.1em; color: #4739e5; } .container { max-width: 500px; margin: 100px auto auto; page-break-after: always; } .grid { display: flex; flex-direction: row; justify-content: space-between; } .column { display: flex; flex-direction: column; } .form-list { list-style: none; padding: 0; } .list-item { margin-bottom: 1.5rem; } .form-border { padding: 15px 10px; border-width: 2px; } .form-text { font-size: 18px; line-height: 1.5; } .full-width { width: 100%; } .expanded-checkbox { width: 30px; height: 30px; } .checkbox-label { display: flex; align-items: center; padding-left: 10px; } .checkbox-list { display: flex; } </style> <title>Data Science Online Course</title> </head> <body> <div class="container"> <h3>Data Science</h3> <h1>Course Signup</h1> <p> Learn how to make informed decisions, create beautiful visualizations, and even try to predict future events through Machine Learning. </p> <form> <ul class="form-list"> <li class="list-item"> <label for="knowledge-level"></label> <select id="knowledge-level" class="full-width form-text form-border" > <option selected>-- Knowledge level --</option> <option value="beginner">Beginner</option> <option value="intermediate">Intermediate</option> <option value="professional">Professional</option> </select> </li> <li class="list-item"> <div class="grid"> <div class="column"> <label for="first-name">First Name</label> <input type="text" id="first-name" class="form-text form-border" /> </div> <div class="column"> <label for="last-name">Last Name</label> <input type="text" id="last-name" class="form-text form-border" /> </div> </div> </li> <li class="list-item"> <div class="column"> <label for="email">Email</label> <input type="text" id="email" class="form-text form-border" /> </div> </li> <li class="list-item"> <div class="column"> <label for="phone-number">Phone Number</label> <input type="text" id="phone-number" class="form-text form-border" /> </div> </li> <li class="checkbox-list"> <input type="checkbox" id="terms" class="expanded-checkbox" /> <label class="checkbox-label" for="terms" >I have read and agreed with the terms and conditions.</label > </li> </ul> </form> </div> <div class="container"> <h2>Terms and Conditions</h2> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. ...</p> </div> </body> </html>
This form includes some text boxes, a select box, and a checkbox. These have all been styled to ensure they display nicely on an A4 page.
In addition to the form, there’s a Terms and Conditions section, which is referenced from the form. To ensure the terms and conditions are generated on a separate page, the container
class defines page-break-after: always;
. This forces a page break when generated.
To generate a PDF with the form and the terms and conditions, send a multipart message like the following, using curl
, to Processor. Note that there are margins defined for the page layout to further style the generated PDF:
curl -X POST http://localhost:5000/process \ -F page.html=@/path/to/page.html \ -F generation='{ "html": "page.html", "layout": { "size": "a4", "margin": { "left": 10, "right": 10, "top": 40, "bottom": 10 } } }' \ -o result.pdf
POST /process HTTP/1.1 Content-Type: multipart/form-data; boundary=customboundary --customboundary Content-Disposition: form-data; name="page.html"; filename="page.html" Content-Type: text/html <HTML data> --customboundary Content-Disposition: form-data; name="generation" Content-Type: application/json { "html": "page.html", "layout": { "size": "a4", "margin": { "left": 10, "right": 10, "top": 40, "bottom": 10 } } } --customboundary--
Adding a Cover Page
To add a cover page to the generated PDF, use the importDocument
operation. Add the operation to the multipart request, along with the PDF that will be used as the cover page. The document
attribute of the operation needs to reference the cover page PDF in the multipart request.
If you’re following along, you can download a sample cover page PDF here:
curl -X POST http://localhost:5000/process \ -F page.html=@/path/to/page.html \ -F cover-page.pdf=@/path/to/cover-page.pdf \ -F generation='{ "html": "page.html", "layout": { "size": "a4", "margin": { "left": 10, "right": 10, "top": 40, "bottom": 10 } } }' \ -F operations='{ "operations": [ { "type": "importDocument", "beforePageIndex": 0, "document": "cover-page.pdf" } ] }' \ -o result.pdf
POST /process HTTP/1.1 Content-Type: multipart/form-data; boundary=customboundary --customboundary Content-Disposition: form-data; name="page.html"; filename="page.html" Content-Type: text/html <HTML data> --customboundary Content-Disposition: form-data; name="cover-page.pdf"; filename="cover-page.pdf" Content-Type: application/pdf <PDF data> --customboundary Content-Disposition: form-data; name="generation" Content-Type: application/json { "html": "page.html", "layout": { "size": "a4", "margin": { "left": 10, "right": 10, "top": 40, "bottom": 10 } } } --customboundary Content-Disposition: form-data; name="operations" Content-Type: application/json { "operations": [ { "type": "importDocument", "beforePageIndex": 0, "document": "cover-page.pdf" } ] } --customboundary--
Adding a Watermark
Lastly, you’ll add a watermark on the terms and conditions page. To do so, add another operation of type watermark
with the annotation desired. Here, an annotation with the text WATERMARK
will be placed at an angle across the page:
curl -X POST http://localhost:5000/process \ -F page.html=@/path/to/page.html \ -F cover-page.pdf=@/path/to/cover-page.pdf \ -F generation='{ "html": "page.html", "layout": { "size": "a4", "margin": { "left": 10, "right": 10, "top": 40, "bottom": 10 } } }' \ -F operations='{ "operations": [ { "type": "importDocument", "beforePageIndex": 0, "document": "cover-page.pdf" }, { "type": "watermark", "pageIndexes": [ 1 ], "annotation": { "v": 1, "type": "pspdfkit/text", "text": "WATERMARK", "fontColor": "#000000", "fontSize": 72, "opacity": 0.5, "rotation": 57, "bbox": [ 0, 0, 595, 842 ], "horizontalAlign": "center", "verticalAlign": "top" } } ] }' \ -o result.pdf
POST /process HTTP/1.1 Content-Type: multipart/form-data; boundary=customboundary --customboundary Content-Disposition: form-data; name="page.html"; filename="page.html" Content-Type: text/html <HTML data> --customboundary Content-Disposition: form-data; name="cover-page.pdf"; filename="cover-page.pdf" Content-Type: application/pdf <PDF data> --customboundary Content-Disposition: form-data; name="generation" Content-Type: application/json { "html": "page.html", "layout": { "size": "a4", "margin": { "left": 10, "right": 10, "top": 40, "bottom": 10 } } } --customboundary Content-Disposition: form-data; name="operations" Content-Type: application/json { "operations": [ { "type": "importDocument", "beforePageIndex": 0, "document": "cover-page.pdf" }, { "type": "watermark", "pageIndexes": [ 1 ], "annotation": { "v": 1, "type": "pspdfkit/text", "text": "WATERMARK", "fontColor": "#000000", "fontSize": 72, "opacity": 0.5, "rotation": 57, "bbox": [ 0, 0, 595, 842 ], "horizontalAlign": "center", "verticalAlign": "top" } } ] } --customboundary--
If you’d like to know more about anything discussed in this guide, check out the Available Operations and Overview guides for more in-depth information.