Nodejs和pdfKit和qr-image

时间:2018-02-14 08:21:49

标签: node.js pdfkit

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

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都有一个唯一的QR码。

提前致谢

3 个答案:

答案 0 :(得分:2)

我完全有同样的问题,以64位编码形式获取PDF,我必须将qr图像附加到它。

以下是代码段。

                PDFDocument = require('pdfkit');

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

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

                var finalString = pdf.response;

                // contains the base64 string

                //logic to append the qr image.

                var stream = doc.pipe(base64.encode());

                stream.on('data', function(chunk) {
                    finalString += chunk;
                });

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

                doc.end();

答案 1 :(得分:0)

我有同样的问题。

似乎是一个异步问题。

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

我的代码在下面(使用promise)。它也应该使用async await

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


}

答案 2 :(得分:0)

这是我想出的解决方案。使用 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"));