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,FONTandCOLOR.FONT_SIZE = 0sizes it to fit the page. - Angle:
ANGLE = -1follows the page diagonal, and0is horizontal. - Transparency:
OPACITYfrom0(invisible) to1(solid). - Over or under:
UNDER = truedraws it behind the page content. - Logo:
IMAGEadds 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:
- Save the script as
add-watermark.js, or download it. - Change
TEXTand the other settings at the top of the script, if you want. - 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.
// 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_WIDTHof the page width, withOPACITYapplied. - Keep
TEXTto 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 #
- Add page numbers to a PDF: same approach, a number on every page
- Add an image to a PDF: one image on one page
- Batch process PDFs: run the script on many files
- sumatrapdf-tool run: how scripts run
- JavaScript API reference: the objects the script uses