Blog Post

How to Add a Watermark with Next.js

Illustration: How to Add a Watermark with Next.js

Next.js was initially released four years ago, and it has been steadily growing in popularity ever since. Last year, we wrote a tutorial, where we covered the details of integrating the Next.js JavaScript framework into PSPDFKit for Web.

Next.js has grown even more since that post, and it’s been improving with each new version. As a result, we wanted to take another look at it — this time, with an integration example that goes beyond opening and viewing a PDF document. Instead, we’ll showcase a more elaborate example that also highlights how easy it is to build web applications based on React.

The Goal

We’ll start off where the last post finished. That is, we’ll base our example off PSPDFKit’s Next.js example, which is publicly available on GitHub.

But in this post, we’ll implement an additional feature in our PDF viewer: We’ll render a custom watermark on each page that will appear on top of the content but below any annotations.

Setup

To get started, clone the repo, follow the installation instructions found in the repo’s readme.md, and open ./pages/index.js in your favorite editor.

Feel free to run npm run dev in the shell console to enjoy hot reloading while applying changes to the code.

The Code

The original Next.js example consists of a component that loads and renders a PDF document. Let’s take a quick look at it:

import React, { useEffect, useRef } from "react";

export default function() {
  const containerRef = useRef(null);

  useEffect(() => {
    const container = containerRef.current;
    let PSPDFKit;
    (async function() {
      PSPDFKit = await import("pspdfkit");
      await PSPDFKit.load({
        container,
        document: "/example.pdf",
        baseUrl: `${window.location.protocol}//${window.location.host}/`
      });
    })();

    return () => PSPDFKit && PSPDFKit.unload(container);
  }, []);
  return (
    <>
      <div ref={containerRef} style={{ height: "100vh" }} />
      <style global jsx>
        {`
          * {
            margin: 0;
            padding: 0;
          }
        `}
      </style>
    </>
  );
}

Simple enough. You can check the details in the original blog post if you want to see more. Now let’s add some watermark powers in!

PSPDFKit for Web allows us to render individual watermarks for each page. But to do so, we have to provide a callback function to which the library will pass a canvas context where we can draw any content we want.

For this example, we’ll add the text “This is page x” to each page with the current page number, and we’ll do this using PSPDFKit.Instance#renderPageCallback(). Let’s have a look at the callback function’s signature:

type RenderPageCallback(ctx: [CanvasRenderingContext2D][], pageIndex: number, size: [PSPDFKit.Size][])

This callback must be provided through the configuration object passed to PSPDFKit#load(). The drawing context it receives already contains the page’s rendered content.

We’ll draw on top of this drawing context, which is limited only by the drawing context dimensions, which are specified in the provided size argument:

PSPDFKit.load({
  renderPageCallback: function(ctx, pageIndex, pageSize) {
    ctx.beginPath();
    ctx.fillStyle = "red";
    ctx.fillRect(0, 0, pageSize.width, 40);
    ctx.stroke();
    ctx.font = "30px Comic Sans MS";
    ctx.fillStyle = "white";
    ctx.textAlign = "right";
    ctx.fillText(`This is page ${pageIndex + 1}`, pageSize.width, 30);
  }
});

Now we’re ready to integrate the watermarking callback to the original example code in ./pages/index.js, which will now look like this:

import React, { useEffect, useRef } from "react";

export default function() {
  const containerRef = useRef(null);

  useEffect(() => {
    const container = containerRef.current;
    let PSPDFKit;
    (async function() {
      PSPDFKit = await import("pspdfkit");
      await PSPDFKit.load({
        container,
        document: "/example.pdf",
        baseUrl: `${window.location.protocol}//${window.location.host}/`,
        renderPageCallback: function(ctx, pageIndex, pageSize) {
          ctx.beginPath();
          ctx.fillStyle = "red";
          ctx.fillRect(0, 0, pageSize.width, 40);
          ctx.stroke();
          ctx.font = "30px Comic Sans MS";
          ctx.fillStyle = "white";
          ctx.textAlign = "right";
          ctx.fillText(`This is page ${pageIndex + 1}`, pageSize.width, 30);
        }
      });
    })();

    return () => PSPDFKit && PSPDFKit.unload(container);
  }, []);
  return (
    <>
      <div ref={containerRef} style={{ height: "100vh" }} />
      <style global jsx>
        {`
          * {
            margin: 0;
            padding: 0;
          }
        `}
      </style>
    </>
  );
}

And that’s all it takes! If we’re already running npm run dev, we’ll see the view updating in real time, but now with a nice, good-looking (in Comic Sans!) watermark on each page.

Conclusion

As we saw in the previous blog post, building a Next.js application with PDF viewing and annotating capabilities can’t get much easier using PSPDFKit for Web. That’s because our Web SDK is an enterprise-ready PDF solution for web browsers and other platforms, and it features industry-leading first-class support.

That said, our SDK offers many possibilities beyond viewing PDFs. Check out our demo to see PSPDFKit for Web in action. I hope this post encourages you to try and build your own Next.js app with PDF superpowers!

Related Products
Share Post

Related Articles

Explore more
DEVELOPMENT  |  Development • Testing • Android • Web

Why Should You Care about Manual Testing?

DEVELOPMENT  |  Processor • Web • Development

A Brief Tour of Multipart Requests

TUTORIALS  |  Web • Products • How To • JavaScript

Approaches to Undo and Redo