Nodejs 和 pdfKit 和 qr-image

问题描述 投票:0回答:5

我正在开发一个小项目,用于在节点和express中生成pdf,我正在使用pdfkit npm模块,但要生成pdf。我还使用 qr-image npm 模块来生成 QR 码图像,但我很难将生成的 QR 码附加到 pdf 中。这是我用来生成二维码的代码:

var file = "./"+certificationnumber+".png";
var qr_svg = qr.image(file, { type: 'png' });
qr_svg.pipe(require('fs').createWriteStream(file));

这就是我尝试使用 pdfkit npm 模块将其附加到 pdf 的方法:

doc.image(qr_svg.pipe(require('fs').createWriteStream(file)))

因为每个 pdf 都有一个唯一的二维码。

提前致谢

node.js pdfkit
5个回答
4
投票

我也遇到同样的问题,获取 64 位编码形式的 PDF,并且我必须将 qr 图像附加到它。

下面是代码片段。

PDFDocument = require('pdfkit');
const base64 = require('base64-stream');
const doc = new PDFDocument();

doc.image('test.jpeg', {
  fit: [250, 300],
  align: 'center',
  valign: 'center'
});

const finalString = pdf.response;

// contains the base64 string
//logic to append the qr image.

const stream = doc.pipe(base64.encode());
stream.on('data', chunk => finalString += chunk);

stream.on('end', () => {
  // the stream is at its end, so push the resulting base64 string to the response
  const backToPDF  = new Buffer(finalString, 'base64');
  read.writeFileSync('./Report.pdf', backToPDF);
});

doc.end();

1
投票

这是我想出的解决方案。使用 pdf-lib、express 和 qrcode

const fs = require("fs");
const path = require("path");
const express = require("express");
const http = require("http");
const cors = require("cors");
const multer = require("multer");
const app = express();
const server = http.createServer(app);
const { PDFDocument } = require("pdf-lib");
const QRCode = require("qrcode");
const Joi = require("joi");
const { readFile, writeFile, unlink } = require("fs/promises");

app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: false }));

const dir = "public";
const subDirectory = "public/uploads";

if (!fs.existsSync(dir)) {
  fs.mkdirSync(dir);

  fs.mkdirSync(subDirectory);
}

const generateQRCodeImage = async function (filePath, text, color) {
  return new Promise((resolve, reject) => {
    QRCode.toFile(
      filePath,
      text,
      {
        color,
      },
      function (err) {
        if (err) return reject(err);
        resolve();
      }
    );
  });
};

const run = async ({
  width,
  height,
  x,
  y,
  pathToImage,
  pathToPDF,
  pathToOutputPDF,
  qrCodeText,
  qrDarkColor = "#000",
  qrLightColor = "#0000",
}) => {
  await generateQRCodeImage(pathToImage, qrCodeText, {
    dark: qrDarkColor,
    light: qrLightColor,
  });

  const pdfDoc = await PDFDocument.load(await readFile(pathToPDF));
  const img = await pdfDoc.embedPng(await readFile(pathToImage));

  Array.from({ length: pdfDoc.getPageCount() }).forEach((_, index) => {
    let imagePage = pdfDoc.getPage(index);
    imagePage.drawImage(img, {
      x,
      y,
      width,
      height,
    });
  });

  const pdfBytes = await pdfDoc.save();

  await writeFile(pathToOutputPDF, pdfBytes);
};

const pdfFileFilter = function (req, file, callback) {
  const ext = path.extname(file.originalname);

  if (ext !== ".pdf") {
    return callback("This extension is not supported");
  }
  callback(null, true);
};

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, "public/uploads");
  },
  filename: function (req, file, cb) {
    cb(
      null,
      file.fieldname + "-" + Date.now() + path.extname(file.originalname)
    );
  },
});

const filesToProcess = multer({ storage: storage, fileFilter: pdfFileFilter });

const schema = Joi.object({
  width: Joi.string().regex(/^\d+$/).required(),
  height: Joi.string().regex(/^\d+$/).required(),
  x: Joi.string().regex(/^\d+$/).required(),
  y: Joi.string().regex(/^\d+$/).required(),
  qrCodeData: Joi.string().required(),
  qrDarkColor: Joi.string(),
  qrLightColor: Joi.string(),
});

app.post("/addQrToPdf", filesToProcess.array("file", 1), async (req, res) => {
  const pathToImage = "public/uploads/" + Date.now() + "temp-qr.png";
  const pathToOutputPDF = "public/uploads/" + Date.now() + "-output.pdf";

  if (req.files) {
    const [file] = req.files;

    if (!file) {
      res.send("No file detected on input");
    }

    const pathToPDF = file.path;

    try {
      const { width, height, x, y, qrCodeData, qrDarkColor, qrLightColor } =
        await schema.validateAsync(req.body);

      await run({
        width: +width,
        height: +height,
        x: +x,
        y: +y,
        qrDarkColor,
        qrLightColor,
        qrCodeText: qrCodeData,
        pathToImage,
        pathToOutputPDF,
        pathToPDF,
      });

      const pdfFile = await readFile(pathToOutputPDF);
      res.contentType("application/pdf");
      res.send(pdfFile);

      await unlink(pathToImage);
      await unlink(pathToPDF);
      await unlink(pathToOutputPDF);
    } catch (error) {
      try {
        await unlink(pathToPDF);
        await unlink(pathToImage);
      } catch (err) {
        console.warn(err);
      }
      res.send(error);
    }
  }
});

server.listen(4000, () => console.log("listening on port *:4000"));

0
投票

我也遇到了同样的问题。

看起来这是一个异步问题。

如果您将 QR 码的生成视为承诺,然后运行创建 pdf 代码,它就会起作用。

我的代码如下(使用承诺)。它也应该使用 async wait 来工作

const createPDF = (ticketID) => {

  const doc = new pdf 

  doc.pipe(fs.createWriteStream(`${ticketID}.pdf`))

  doc.text('Your Tickets').fontSize(25)


  doc.image(`./qrCodes/${ticketID}.png`, {
    fit: [250, 300],
    align: 'center',
    valign: 'center'
  });

  doc.end()

}

const createQRCode = (ticketID) => {


    QR.toFile(`./qrCodes/${ticketID}.png`, String(ticket), {width: 250}).then(qr => {      

      createPDF(ticketID)
    })


}

0
投票

我使用的是不写入磁盘的版本,使用svg路径输出,从qrcode数据中提取路径并渲染成pdf

let s = await toString('hallo2', {
  type: 'svg'
})
// extract the 2nd path element
let path = Array.from(s.matchAll(/d="(.*?)"/gm))[1][1]
let doc = new PDFDocument({ size: 'A4' });
doc.scale(8)
.path(data)
.stroke()
doc.pipe(fs.createWriteStream('out2.pdf', {}));
doc.end()

0
投票

如果像我这样的人仍在寻找可行的异步/等待解决方案。 这个叉子有一个非常好的库,可以完美地工作。

https://github.com/Loskir/styled-qr-code

© www.soinside.com 2019 - 2024. All rights reserved.