Home
Put a large, semi-transparent “DRAFT” or “CONFIDENTIAL” across every page of a PDF, or a logo image, with a short script you run with sumatrapdf-tool run.
Available in pre-release 3.7
Save the script below as add-watermark.js and run it on your PDF. At a glance:
  • Run: sumatrapdf-tool run add-watermark.js in.pdf out.pdf [text] [opacity] [image], or Run PDF Script… in SumatraPDF
  • Text: TEXT, FONT and COLOR. FONT_SIZE = 0 sizes it to fit the page.
  • Angle: ANGLE = -1 follows the page diagonal, and 0 is horizontal.
  • Transparency: OPACITY from 0 (invisible) to 1 (solid).
  • Over or under: UNDER = true draws it behind the page content.
  • Logo: IMAGE adds a PNG or JPEG at the center of every page.

Add a text watermark #

In SumatraPDF: Ctrl + K, Run PDF Script…, Example Scripts, Add a text or image watermark to every page. See Run PDF Script.
From the command line:
  1. Save the script as add-watermark.js, or download it.
  2. Change TEXT and the other settings at the top of the script, if you want.
  3. Run it:
sumatrapdf-tool run add-watermark.js in.pdf out.pdf
out.pdf is a copy of in.pdf with the watermark on every page. The optional arguments override TEXT (none for no text), OPACITY and IMAGE, e.g. sumatrapdf-tool run add-watermark.js in.pdf out.pdf CONFIDENTIAL 0.15. SumatraPDF.exe run with the same arguments works the same.
A page with the default DRAFT watermark
// Add a semi-transparent text or image watermark to every page of a PDF.
// Info: Add a text or image watermark to every page.
// Arg: <INPUT> : Input PDF
// Arg: <OUTPUT> : New output PDF
// Arg: DRAFT : Text (none = no text)
// Arg: 0.3 : Opacity: 0 is invisible, 1 is solid
// Arg:  : Image file, PNG or JPEG, drawn at the center (empty = none)
// Usage: sumatrapdf-tool run add-watermark.js in.pdf out.pdf [text] [opacity] [image]

// Settings, used when not given on the command line
var TEXT = "DRAFT"; // "none" for no text
var FONT = "Helvetica-Bold"; // Helvetica, Times-Roman, Courier, Times-Bold, ...
var FONT_SIZE = 0; // in points; 0 fits the text across the page
var COLOR = [1, 0, 0]; // red, green, blue from 0 to 1
var ANGLE = -1; // degrees counter-clockwise; -1 follows the page diagonal
var IMAGE = ""; // path of a PNG or JPEG logo, drawn at the center; "" for none
var IMAGE_WIDTH = 0.4; // image width as a fraction of the page width
var OPACITY = 0.3; // 0 is invisible, 1 is solid
var UNDER = false; // true puts the watermark under the page content

if (!scriptArgs[0] || !scriptArgs[1]) {
  print("usage: sumatrapdf-tool run add-watermark.js in.pdf out.pdf [text] [opacity] [image]");
  quit(1);
}
if (scriptArgs[2]) TEXT = scriptArgs[2];
if (TEXT == "none") TEXT = "";
if (scriptArgs[3]) OPACITY = parseFloat(scriptArgs[3]);
if (scriptArgs[4]) IMAGE = scriptArgs[4];
if (!(OPACITY >= 0 && OPACITY <= 1)) throw new Error("Opacity must be from 0 to 1.");
if (!TEXT && !IMAGE) throw new Error("Give a text or an image.");

var doc = Document.openDocument(scriptArgs[0]);
var font = new Font(FONT);
var fontRef = doc.addSimpleFont(font);
var gsRef = doc.addObject({ Type: "ExtGState", ca: OPACITY, CA: OPACITY });
var image = IMAGE ? new Image(IMAGE) : null;
var imageRef = image ? doc.addImage(image) : null;
var saveState = doc.addStream("q\n");

function num(v) {
  return Math.round(v * 1000) / 1000;
}

function pdfString(s) {
  return "(" + s.replace(/[\\()]/g, "\\$&") + ")";
}

function textWidth(s, size) {
  var w = 0;
  for (var i = 0; i < s.length; i++) w += font.advanceGlyph(font.encodeCharacter(s.charCodeAt(i)), 0);
  return w * size;
}

// add a resource to the page, e.g. addResource(pageObj, "Font", "WmFont", fontRef)
function addResource(pageObj, type, name, ref) {
  var res = pageObj.getInheritable("Resources");
  if (!res) {
    res = doc.newDictionary();
    pageObj.put("Resources", res);
  }
  if (!res.get(type)) res.put(type, doc.newDictionary());
  res.get(type).put(name, ref);
}

for (var i = 0; i < doc.countPages(); i++) {
  var page = doc.loadPage(i);
  var pageObj = page.getObject();
  addResource(pageObj, "ExtGState", "WmGS", gsRef);

  // page size as you see it (crop box, after rotation)
  var b = page.getBounds();
  var w = b[2] - b[0],
    h = b[3] - b[1];

  // map "center of the page as you see it, y up" to the page's own coordinates;
  // handles /Rotate and crop boxes that don't start at 0,0
  var center = Matrix.concat([1, 0, 0, -1, b[0] + w / 2, b[1] + h / 2], Matrix.invert(page.getTransform()));

  var s = "q /WmGS gs\n";
  if (TEXT) {
    addResource(pageObj, "Font", "WmFont", fontRef);
    var angle = ANGLE == -1 ? (Math.atan2(h, w) * 180) / Math.PI : ANGLE;
    var size = FONT_SIZE;
    if (!size) {
      // the biggest size at which the rotated text fits in 80% of the page
      var c = Math.abs(Math.cos((angle * Math.PI) / 180));
      var sn = Math.abs(Math.sin((angle * Math.PI) / 180));
      var tw = textWidth(TEXT, 1),
        th = 0.7; // text height (capitals), at size 1
      size = 0.8 * Math.min(w / (tw * c + th * sn), h / (tw * sn + th * c));
    }
    var m = Matrix.concat(Matrix.rotate(angle), center);
    var x = num(-textWidth(TEXT, size) / 2),
      y = num(-0.35 * size);
    var ops = ["q", m.map(num).join(" "), "cm BT /WmFont", num(size), "Tf", COLOR.join(" "), "rg"];
    s += ops.concat([x, y, "Td", pdfString(TEXT), "Tj ET Q\n"]).join(" ");
  }
  if (image) {
    addResource(pageObj, "XObject", "WmImage", imageRef);
    var iw = IMAGE_WIDTH * w;
    var ih = (iw * image.getHeight()) / image.getWidth();
    var m = Matrix.concat([iw, 0, 0, ih, -iw / 2, -ih / 2], center);
    s += "q " + m.map(num).join(" ") + " cm /WmImage Do Q\n";
  }
  s += "Q\n";

  // new page content: watermark, then the old content, or
  // q, the old content, Q, then watermark
  var contents = doc.newArray();
  if (UNDER) contents.push(doc.addStream(s));
  else contents.push(saveState);
  var old = pageObj.get("Contents");
  if (old && old.isArray())
    old.forEach(function (c) {
      contents.push(c);
    });
  else if (old) contents.push(old);
  if (!UNDER) contents.push(doc.addStream("\nQ " + s));
  pageObj.put("Contents", contents);
}

doc.save(scriptArgs[1], "garbage,compress");
print("Saved " + scriptArgs[1]);
The watermark is centered on the page as you see it, including landscape pages, pages with a rotation (/Rotate) and cropped pages. With FONT_SIZE = 0 the text is as big as fits in 80% of each page, so it scales with the page size.

Change the look #

Edit the settings at the top of the script:
You want Setting
Different text TEXT = "CONFIDENTIAL"
Gray instead of red COLOR = [0.5, 0.5, 0.5]
Lighter OPACITY = 0.15
Horizontal ANGLE = 0
Always 45 degrees ANGLE = 45
Fixed size, e.g. 72 points FONT_SIZE = 72
Serif font FONT = "Times-Bold"
FONT is a standard PDF font: Helvetica, Times-Roman or Courier, or a bold or italic variant such as Helvetica-Bold, Times-Italic, Courier-Oblique. Standard fonts are not embedded, so the file stays small. Use only Latin characters in TEXT.

Put the watermark under the content #

Set UNDER = true. The page’s text and pictures are drawn on top of the watermark, so it never covers anything.
Note: anything opaque on the page hides the watermark under it, e.g. images, colored backgrounds, and the whole page of a scanned document. For scans, keep UNDER = false.

Add a logo or image watermark #

Set IMAGE to the path of a PNG or JPEG file, or pass it as the fifth argument (none as the text gives only the image):
var TEXT = ""               // "" for no text
var IMAGE = "C:\\Pictures\\logo.png"
var IMAGE_WIDTH = 0.4       // image width as a fraction of the page width
  • The image is centered, IMAGE_WIDTH of the page width, with OPACITY applied.
  • Keep TEXT to get both the text and the image.
  • Transparent areas of a PNG stay transparent.
  • Write \\ for each \ in the path, or use /, e.g. "C:/Pictures/logo.png".

Tips #

  • Write to a new file. Saving over the input file fails with cannot remove file.
  • Keep the original. The watermark becomes part of the page content, and there is no easy way to take it out.
  • The watermark text is real text, so it shows up when you search or copy text from the page.
  • Adding a watermark changes the pages, so it breaks existing digital signatures. Add it before you sign.
  • To watermark many files, run the script in a loop. See Batch process PDFs.

See also #