【问题标题】:Next.js API: Watermark PDF using query parameters in URLNext.js API:使用 URL 中的查询参数为 PDF 添加水印
【发布时间】:2021-09-25 17:01:54
【问题描述】:

这是我第一次测试 Next.js API,我对整个 Next.js/React 世界也很陌生,所以请多多包涵。

此 API 路由的目标是触发自动下载带有自定义水印的 PDF,该水印由 API URL 查询参数生成,如下所示:/api/PDFWatermark?id=123&firstname=John&lastname=Doe

为了创建水印,我使用pdf-libthis 代码的修改版本来为我的PDF 添加水印。为了生成原始 PDF pdfDoc 的修改和可下载版本,我尝试使用 pdfBytesafter 水印创建一个 blob。创建 Blob 后,我想我可以将其添加到附加到 DOM 的锚点中。

注释掉blobanchor代码时,出现两个错误:

  1. ReferenceError: Blob 未定义
  2. ReferenceError: document is not defined(可能是因为没有 DOM 来附加锚链接)

此时我只能将pdfBytes 打印为 json,我无法创建和下载实际带水印的 PDF 文件。

有没有办法在调用 API 时将pdfBytes 自动下载为 PDF 文件?

更新

更改 modifyPDF 以返回缓冲区后的工作代码如下:

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);
}

工作:

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);
}

【问题讨论】:

    标签: api pdf next.js


    【解决方案1】:

    更改您的 modifyPDF 以返回缓冲区

    [...]
        const pdfBytes = await pdfDoc.save();
        return Buffer.from(pdfBytes.buffer, 'binary');
    [...]
    

    让 API 通过处理程序将 PDF 返回给浏览器:

    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);
    }
    

    未经测试,但您应该了解要点。

    Here's the full example from the library itself

    【讨论】:

    • return Buffer.from(pdfBytes.buffer, 'binary'); 之外添加res.setHeader('Content-Type', 'application/pdf'); res.setHeader('Content-Disposition', 'attachment; filename='+filename); 而不是res.type('pdf'); 感谢您指引我正确的方向!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多