this is my first time testing out Next.js API, I am also quite new to the whole Next.js/React world so bear with me.
The goal for this API route is to trigger an automatic download of a PDF with a custom watermark generated from API URL query parameters like this: /api/PDFWatermark?id=123&firstname=John&lastname=Doe
In order to create the watermark I am using pdf-lib and I am using a modified version of this code to watermark my PDF. To generate a modified and downloadable version of the original PDF pdfDoc
I have tried to create a blob using the pdfBytes
after the watermarking. After the blob is created I thought I could add it to an anchor attached to the DOM.
When commenting out the blob
and anchor
code, two errors occur:
- ReferenceError: Blob is not defined
- ReferenceError: document is not defined (possibility because there is no DOM to attach the anchor link)
At this point I am only able to print the pdfBytes
as json, I am not able to create and download the actual watermarked PDF file.
Is there a way to auto download the pdfBytes
as a PDF file when the API is called?
UPDATE
Working code below after changing modifyPDF
to return a buffer:
const pdfBytes = await pdfDoc.save();
return Buffer.from(pdfBytes.buffer, 'binary');
And:
export default async function handler(req, res) {
const filename = "test.pdf";
const {id, firstname, lastname} = req.query;
const pdfBuffer = await modifyPDF(firstname, lastname, id);
res.status(200);
res.setHeader('Content-Type', 'application/pdf'); // Displsay
res.setHeader('Content-Disposition', 'attachment; filename=' filename);
res.send(pdfBuffer);
}
WORKING:
import {PDFDocument, rgb, StandardFonts } from 'pdf-lib';
export async function modifyPDF(firstname, lastname, id) {
const order_id = id;
const fullname = firstname " " lastname;
const existingPdfBytes = await fetch("https://pdf-lib.js.org/assets/us_constitution.pdf").then((res) => res.arrayBuffer());
const pdfDoc = await PDFDocument.load(existingPdfBytes);
const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica);
const watermark = fullname " (OrderID: " id ")";
// Set Document Metadata
pdfDoc.setSubject(watermark);
// Get pages
const pages = pdfDoc.getPages();
// Iterate every page, skip first
//pages.slice(1).forEach(page => {
pages.forEach(page => {
// Get the width and height of the page
const {
width,
height
} = page.getSize()
// Watermark the page
page.drawText(watermark, {
x: 70,
y: 8,
size: 10,
font: helveticaFont,
color: rgb(0.95, 0.1, 0.1),
})
})
const pdfBytes = await pdfDoc.save();
return Buffer.from(pdfBytes.buffer, 'binary');
}
export default async function handler(req, res) {
const filename = "test.pdf";
const {id, firstname, lastname} = req.query;
const pdfBuffer = await modifyPDF(firstname, lastname, id);
res.status(200);
res.setHeader('Content-Type', 'application/pdf'); // Displsay
res.setHeader('Content-Disposition', 'attachment; filename=' filename);
res.send(pdfBuffer);
}
CodePudding user response:
Change your modifyPDF
to return a buffer
[...]
const pdfBytes = await pdfDoc.save();
return Buffer.from(pdfBytes.buffer, 'binary');
[...]
Let the API return the PDF to the browser through the handler:
export default async function handler(req, res) {
const {id, firstname, lastname} = req.query;
const pdfBuffer = await modifyPDF(firstname, lastname, id);
res.status(200);
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Disposition', 'attachment; filename=' filename);
// Edited as the linked example reports:
// res.type('pdf'); // and might not work
res.send(pdfBuffer);
}
Untested but you should get the gist.