Editing 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 that 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--

Generated Forms on a page Generated Terms and Conditions

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

Added a cover page

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

Added a watermark on the final page

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.