Sometimes you don't want to change the actual content of a PDF. You simply want to add a colored layer over part or all of the document.
This can be useful for creating branded reports, adding colored backgrounds, highlighting printed copies, producing design mockups, applying watermarked color effects, or preparing documents for presentations.
A PDF Color Overlay Tool makes this possible by placing a semi-transparent color layer over PDF pages while preserving the original text, images, and layout beneath it.
Instead of manually editing every page in graphic design software, users can upload a PDF, choose an overlay color, adjust its transparency, select a blend mode, decide where it should appear, preview the result, and download the updated document.
In this tutorial, you'll build this tool using JavaScript. Users will be able to upload a PDF and perform all the actions just mentioned – all without sending the document to a server.
Table of Contents
A PDF Color Overlay Tool applies a colored layer on top of one or more pages while keeping the original PDF content visible underneath. Unlike a color inverter or grayscale converter, which permanently transform every pixel, a color overlay blends a selected color with the existing page using adjustable transparency and blend modes.
This makes it useful for creating branded documents, adding colored backgrounds, producing presentation-ready PDFs, highlighting sections, creating themed reports, or generating preview versions without modifying the original source document.
In this project, users can upload a PDF, preview every page, choose an overlay color using either a color picker or a hexadecimal value, adjust the overlay opacity, select a blend mode, choose where the overlay should appear, decide which pages should receive the effect, preview the updated document, and download the finished PDF directly from the browser.
Internally, PDF.js renders each page onto an HTML canvas. JavaScript then draws a colored rectangle over the rendered page using the selected transparency and blend mode. Once all selected pages have been processed, PDF-lib assembles the updated pages into a new downloadable PDF.
The overlay color is represented using a hexadecimal value.
const overlay = {
color: "#667eea",
opacity: 0.5
};
When drawing the overlay, JavaScript first sets the transparency level.
context.globalAlpha = overlay.opacity;
Next, the selected color is applied.
context.fillStyle = overlay.color;
Finally, the colored rectangle is drawn over the required area.
context.fillRect(0, 0, canvas.width, canvas.height);
Depending on the selected blend mode, the overlay can either gently tint the document, produce darker colors, create dramatic lighting effects, or generate completely different visual styles while preserving the original page underneath.
Project Setup
Before implementing the overlay functionality, let's create a simple project structure.
We'll build the application using HTML, CSS, and JavaScript, together with PDF.js, the Canvas API, and PDF-lib.
Our project structure looks like this:
pdf-color-overlay/
│── index.html
│── style.css
│── script.js
│── pdf.worker.min.js
│── assets/
Separating the HTML, CSS, and JavaScript keeps the project organized and makes future enhancements easier to implement.
Libraries Used
Our PDF Color Overlay Tool relies on three browser technologies that work together to render PDF pages, apply color overlays, and generate a new downloadable document.
PDF.js renders PDF pages directly inside the browser.
The HTML Canvas API draws the color overlay on top of each rendered page using transparency and blend modes.
PDF-lib generates the final PDF after all selected pages have been processed.
Include the required libraries before loading your application:
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.4.168/pdf.min.js"></script>
<script src="https://unpkg.com/pdf-lib/dist/pdf-lib.min.js"></script>
<script src="script.js"></script>
Configure the PDF.js worker.
pdfjsLib.GlobalWorkerOptions.workerSrc = "pdf.worker.min.js";
Using a worker allows PDF rendering to happen in the background, keeping the interface responsive even when opening large PDF files.
Creating the HTML Layout
The application is divided into four main sections:
Upload area
PDF preview
Overlay settings
Download section
Create the basic layout.
<section id="uploadSection"></section>
<section id="previewSection" hidden></section>
<section id="settingsSection" hidden></section>
<section id="downloadSection" hidden></section>
Initially, only the upload area is visible. The remaining sections appear after a PDF has been successfully loaded.
Selecting the Main Elements
Store references to the elements used throughout the application.
const uploadSection = document.getElementById("uploadSection");
const previewSection = document.getElementById("previewSection");
const settingsSection = document.getElementById("settingsSection");
const pdfCanvas = document.getElementById("pdfCanvas");
These references allow the application to update the interface without repeatedly searching the DOM.
Uploading and Previewing PDFs
The upload area supports both drag-and-drop and manual file selection.
Before loading the document, verify that the selected file is a PDF.
async function uploadPdf(file) {
if (!file || file.type !== "application/pdf") {
alert("Please select a PDF file.");
return;
}
await loadPdf(file);
}
After validation, the PDF is loaded into memory for rendering.
Loading the PDF
Convert the uploaded file into an ArrayBuffer before opening it with PDF.js.
async function loadPdf(file) {
const bytes = await file.arrayBuffer();
pdfDocument = await pdfjsLib.getDocument({
data: bytes
}).promise;
currentPage = 1;
renderPage(currentPage);
}
Once the document has loaded successfully, the first page is rendered automatically.
Rendering PDF Pages
PDF.js renders one page at a time onto an HTML canvas.
Retrieve the selected page.
const page = await pdfDocument.getPage(currentPage);
Create the viewport.
const viewport = page.getViewport({
scale: 1.5
});
Resize the canvas.
pdfCanvas.width = viewport.width;
pdfCanvas.height = viewport.height;
Render the page.
await page.render({
canvasContext: pdfCanvas.getContext("2d"),
viewport
}).promise;
After rendering completes, users can view the current page before applying any overlay effects.
Navigating Between Pages
Most PDF documents contain multiple pages, so the application includes simple navigation controls.
Store the current page.
let currentPage = 1;
let pdfDocument = null;
Move to the previous page.
previousButton.addEventListener("click", async () => {
if (currentPage > 1) {
currentPage--;
await renderPage(currentPage);
}
});
Move to the next page.
nextButton.addEventListener("click", async () => {
if (currentPage < pdfDocument.numPages) {
currentPage++;
await renderPage(currentPage);
}
});
Update the page indicator.
pageCounter.textContent = `Page ${currentPage} of ${pdfDocument.numPages}`;
Users can now browse through the uploaded PDF before deciding how the color overlay should be applied.
Building the Overlay Settings
After the PDF has been uploaded and previewed, users can configure how the color overlay should be applied. The settings panel lets users choose an overlay color, adjust its transparency, select a blend mode, specify where the overlay should appear, and decide which pages should receive the effect before generating the final PDF.
Choosing the Overlay Color
The first setting allows users to choose the color that will be placed over the PDF.
The application supports both a color picker and direct hexadecimal input.
Create the color picker.
<input type="color" id="overlayColor" value="#667eea">
Create the hexadecimal input.
<input type="text" id="hexValue" value="#667eea">
Retrieve the selected color.
const overlayColor = document.getElementById("overlayColor").value;
If users enter a hexadecimal value manually, synchronize it with the color picker.
hexValue.addEventListener("input", () => {
overlayColor.value = hexValue.value;
});
The selected color will later be drawn over the rendered PDF page.
Adjusting the Opacity
Opacity controls how transparent the overlay appears.
Lower values allow more of the original PDF to remain visible, while higher values create a stronger color effect.
Create the opacity slider.
<input type="range" id="opacity" min="0" max="100" value="50">
Retrieve the selected value.
const opacity = Number(document.getElementById("opacity").value) / 100;
This value is later assigned to the canvas transparency before drawing the overlay.
Selecting the Blend Mode
Blend modes determine how the overlay color interacts with the original PDF content.
Create the dropdown.
<select id="blendMode">
<option value="source-over">Normal</option>
<option value="multiply">Multiply</option>
<option value="overlay">Overlay</option>
<option value="soft-light">Soft Light</option>
<option value="hard-light">Hard Light</option>
<option value="difference">Difference</option>
</select>
Retrieve the selected blend mode.
const blendMode = document.getElementById("blendMode").value;
Each blend mode produces a different visual effect while preserving the document beneath the overlay.
Choosing the Overlay Position
The overlay doesn't always need to cover the entire page. Users can apply it only to specific regions if they want.
Create the available options.
<input type="radio" name="position" value="full" checked>
Full Page
<input type="radio" name="position" value="header">
Header Only
<input type="radio" name="position" value="footer">
Footer Only
Retrieve the selected position.
const position = document.querySelector('input[name="position"]:checked').value;
During processing, the application draws the overlay only inside the selected area.
Choosing Which Pages to Process
Users can apply the overlay in several different ways:
Create the page selection controls.
<input type="radio" name="pages" value="current" checked>
Current page only
<input type="radio" name="pages" value="all">
All pages
<input type="radio" name="pages" value="separate">
Separate overlay per page
<input type="radio" name="pages" value="custom">
Specific pages
<input type="text" id="pageRange" placeholder="e.g., 1, 3-5, 10">
Retrieve the selected option.
const pageMode = document.querySelector('input[name="pages"]:checked').value;
Read the custom page range.
const pageRange = document.getElementById("pageRange").value.trim();
This flexibility allows users to apply different overlay strategies depending on the document.
Applying the Overlay
Once all settings have been configured, users can begin processing the PDF.
Create the action button.
<button id="applyOverlay">Apply Overlay</button>
Start the processing workflow.
applyOverlay.addEventListener("click", async () => {
await processOverlay();
});
Starting Over
Users can reset the application at any time and upload another document.
Create the reset button.
<button id="resetTool">Start Over</button>
Reset the tool.
resetTool.addEventListener("click", () => {
location.reload();
});
The upload area becomes visible again, allowing another PDF to be processed without manually clearing every setting.
Applying Color Overlays to PDF Pages
Now we'll build the main feature of the application: adding a colored overlay to PDF pages.
The process begins by rendering each selected PDF page onto an HTML canvas using PDF.js. JavaScript then draws a semi-transparent colored rectangle over the page using the selected blend mode. Once all selected pages have been processed, PDF-lib generates a new downloadable PDF.
Applying the Overlay Color
Before drawing anything, retrieve the selected color.
const overlayColor = document.getElementById("overlayColor").value;
Set the canvas fill color.
context.fillStyle = overlayColor;
This color will be drawn over the selected portion of each PDF page.
Setting the Overlay Transparency
Opacity determines how much of the original page remains visible beneath the overlay.
Apply the selected transparency.
context.globalAlpha = opacity;
A lower opacity produces a subtle tint, while higher values create a stronger visual effect.
Applying the Blend Mode
Canvas supports several compositing modes that determine how the overlay interacts with the existing page.
Assign the selected blend mode.
context.globalCompositeOperation = blendMode;
Some common modes include:
Normal – Places the color directly over the page.
Multiply – Produces a darker appearance.
Overlay – Increases overall contrast.
Soft Light – Creates a gentle lighting effect.
Hard Light – Produces a stronger contrast.
Difference – Generates an inverted-style appearance based on color differences.
Drawing the Overlay
Once the color, opacity, and blend mode have been configured, draw the overlay on the canvas.
For a full-page overlay:
context.fillRect(0, 0, canvas.width, canvas.height);
If users choose Header Only, draw the rectangle across only the top section.
context.fillRect(0, 0, canvas.width, 120);
For Footer Only, draw the overlay near the bottom of the page.
context.fillRect(0, canvas.height - 120, canvas.width, 120);
These options allow different overlay styles without modifying the underlying PDF content.
Processing the Selected Pages
After configuring the overlay, process only the pages chosen by the user.
Loop through the selected pages.
for (let page = startPage; page <= endPage; page++) {
await processPage(page);
}
Each processed page is temporarily stored before creating the final document.
If Current Page Only is selected, only the active page is processed. If All Pages is selected, the overlay is applied to the complete document.
Generating the Final PDF
Create a new PDF document.
const outputPdf = await PDFLib.PDFDocument.create();
Convert the processed canvas into an image.
const imageBytes = await canvasToBytes(pdfCanvas);
Embed the image.
const image = await outputPdf.embedPng(imageBytes);
Create a new page.
const page = outputPdf.addPage([
image.width,
image.height
]);
Draw the processed image.
page.drawImage(image, {
x: 0,
y: 0,
width: image.width,
height: image.height
});
Repeat these steps until every selected page has been added to the new PDF.
Saving the Generated PDF
Once all pages have been processed, save the completed document.
const pdfBytes = await outputPdf.save();
Create a downloadable file.
generatedPdfBlob = new Blob([pdfBytes], {
type: "application/pdf"
});
The new PDF containing the selected color overlays is now ready for preview.
Previewing the Result
Before downloading the processed document, users should be able to review the final output. This makes it easy to verify that the selected color, opacity, blend mode, and page selection have been applied correctly.
Load the generated PDF.
let finalPdf = null;
async function showPreview() {
const bytes = await generatedPdfBlob.arrayBuffer();
finalPdf = await pdfjsLib.getDocument({
data: bytes
}).promise;
renderFinalPage(1);
}
Render the selected page.
async function renderFinalPage(pageNumber) {
const page = await finalPdf.getPage(pageNumber);
const viewport = page.getViewport({
scale: 1.5
});
previewCanvas.width = viewport.width;
previewCanvas.height = viewport.height;
await page.render({
canvasContext: previewCanvas.getContext("2d"),
viewport
}).promise;
}
Users can navigate through the processed PDF before downloading it.
Renaming and Downloading
Before saving the generated PDF, users can customize the output filename.
Create the filename input.
<input type="text" id="outputFilename" value="color-overlay.pdf">
Retrieve the filename.
function getFilename() {
let filename = outputFilename.value.trim();
if (!filename) {
filename = "color-overlay.pdf";
}
if (!filename.toLowerCase().endsWith(".pdf")) {
filename += ".pdf";
}
return filename;
}
Display information about the generated PDF.
pageCount.textContent = `${finalPdf.numPages} Pages`;
fileSize.textContent = formatFileSize(generatedPdfBlob.size);
Download the completed document.
downloadButton.addEventListener("click", () => {
const url = URL.createObjectURL(generatedPdfBlob);
const link = document.createElement("a");
link.href = url;
link.download = getFilename();
link.click();
URL.revokeObjectURL(url);
});
Everything happens locally inside the browser, helping users keep their PDF files private.
Let's walk through the complete workflow.
Step 1: Upload the PDF
Users begin by dragging a PDF into the upload area or clicking Select PDF.
Step 2: Preview the Document
The uploaded PDF is rendered page by page, allowing users to review the document before applying any changes.
Users choose an overlay color, adjust the opacity, select a blend mode, choose the overlay position, and decide which pages should receive the effect.
Step 4: Apply the Overlay
Click Apply Overlay to process the selected pages using the chosen settings.
Step 5: Review the Processed PDF
The completed PDF appears in the preview window so users can verify the applied overlay before downloading.
Step 6: Rename and Download
Finally, users rename the output file if needed, review the page count and file size, and download the generated PDF.
Large PDF files can take longer to process because every selected page must be rendered and updated. Processing only the required pages helps improve performance.
for (const page of selectedPages) {
await processPage(page);
}
After downloading the file, release temporary resources to reduce memory usage.
URL.revokeObjectURL(downloadUrl);
These small optimizations help keep the application responsive when working with large multi-page PDF documents.
Common Mistakes
One common mistake is applying multiple overlays without first restoring the original page. Always render a fresh copy of the PDF page before applying another overlay.
await renderPage(currentPage);
Another issue is forgetting to restore the default canvas state after changing the opacity or blend mode.
context.globalAlpha = 1;
context.globalCompositeOperation = "source-over";
Finally, using a very high opacity can completely hide the original PDF content. Choosing an appropriate transparency level usually produces a more balanced result.
Conclusion
In this tutorial, you built a browser-based PDF Color Overlay Tool using JavaScript.
You learned how to upload PDF documents, render pages with PDF.js, configure overlay colors, adjust opacity, apply blend modes, position overlays, process selected pages, generate a new PDF with PDF-lib, preview the completed document, rename the output file, and download it directly from the browser.
Because the entire workflow runs locally, users can customize PDF documents without uploading sensitive files to an external server.
You can explore the complete workflow using the PDF Color Overlay Tool.
From here, you can extend the project with gradient overlays, custom overlay shapes, image overlays, reusable color presets, watermark templates, or additional PDF editing features for even greater flexibility.