I am coding an app, which takes numbers to generate a QR Code with the qrcode module, takes the generated URL and parses it to the pdfkit doc.image method.
// Skript zur Erstellung von PDFs aus den Daten der mainApp
const PDFDocument = require("pdfkit");
const fs = require("fs");
const QRCode = require("qrcode");
const { resolve } = require("path");
const testList = "664584";
// Create a document
const doc = new PDFDocument({
size: "A4",
layout: "landscape",
});
doc.pipe(fs.createWriteStream("QRCode.pdf"));
// Actual Content
// Shapes
doc.rect(220.945, 50, 400, 400).stroke();
doc.rect(841.89 - 30 - 160, 50, 160, 50).stroke();
doc.rect(30, 50, 160, 50).stroke();
doc.rect(841.89 - 30 - 160, 595.28 - 250, 160, 50).stroke();
// QR Code
function getDataURL(str){
QRCode.toDataURL(str)
.then(base64 => {
doc.image(base64,245.945,75,{width:350});
})
.catch(err => {
console.error(`Debugger: Catched Error from QRCode.toDataURL promise: ${err}`)
})
.catch(err => {
console.error(err);
})
}
getDataURL(testList);
// Text
doc.fontSize(20).text("Field1", 30, 97.64 + 35);
doc.fontSize(20).text("Field2", 841.89 - (160 + 30), 97.64 + 35);
doc.fontSize(20).text("Field3", 841.89 - (160 + 30), 400 + 97.64 - 75);
doc.fontSize(25).text("Description", 40, 490, {
align: "center",
lineBreak: "false",
});
doc.end();
Here is the problem: The method to generate a QR Code is QRCode.toDataURL, which returns a promise. I am able to log the resulting data in the console, and if I parse it to doc.image method, the process is done without issues. Except that pdfkit inserts an empty image.
Generating the PDF with QRCode.toDataURL on the fly
If i take the generated base64 string, declare it as a value and passes it to doc.image, an image is generated just fine.
(...)
// QR Code
const testListtoURL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAB0CAYAAABUmhYnAAAAAklEQVR4AewaftIAAALRSURBVO3BQa7jSAwFwXyE7n/lnL/kqgBBsqdNMCL+YY1RrFGKNUqxRinWKMUapVijFGuUYo1SrFGKNUqxRinWKMUapVijFGuUi4eS8E0qJ0noVLoknKh0SfgmlSeKNUqxRinWKBcvU3lTEk6S0KmcqDyh8qYkvKlYoxRrlGKNcvFhSbhD5Q6VLgknKm9Kwh0qn1SsUYo1SrFGuRhGpUtCl4QTlV9WrFGKNUqxRrn4cUnoVDqVkyRMUqxRijVKsUa5+DCVT1LpktCpfJLKv6RYoxRrlGKNcvGyJHxTEjqVLgmdyhNJ+JcVa5RijVKsUeIfBklCp9Il4UTllxVrlGKNUqxRLh5KQqfSJaFT6ZLQqXRJ6FROVLoknKg8kYRO5SQJncqbijVKsUYp1igXD6mcqDyhckcSOpUnktCpdCpdEv5PxRqlWKMUa5T4hweS0Kl0SehUTpLwhEqXhE6lS0KnckcS7lD5pGKNUqxRijVK/MMXJeFE5YkknKjckYRO5SQJnco3FWuUYo1SrFEuPiwJJypdEk5UTlTuSEKnckcSOpX/U7FGKdYoxRol/uGHJeFEpUtCp9IloVPpktCpdEnoVLoknKg8UaxRijVKsUa5eCgJ36TSqXxSEu5Q6ZLQqXxSsUYp1ijFGuXiZSpvSsIdSbgjCScqXRK6JJyofFOxRinWKMUa5eLDknCHyh1J6FROktCpdEnoknCicpKETqVLQqfyRLFGKdYoxRrl4sepdEk4UTlR6ZLQqTyRhE7lTcUapVijFGuUix+XhE7ljiR0Kp3KSRI6lU7lJAmdyhPFGqVYoxRrlIsPU/kklS4JncqJykkSOpVO5SQJnUqn8qZijVKsUYo1ysXLkvBNSehU7khCp3JHEjqVO5LQqTxRrFGKNUqxRol/WGMUa5RijVKsUYo1SrFGKdYoxRqlWKMUa5RijVKsUYo1SrFGKdYoxRrlP6NMNdKR1U/EAAAAAElFTkSuQmCC";
doc.image(testListtoURL,245.945,75,{width:350});
// Text
(...)
PDF document generated with the data as a string variable
I first thought about a promise/async issue, but could show, that the pdfkit.js from the module receives the base64 data and returns without errors. I also declared the same variable globally and passed the resolved data to it, but without effect. As you see, I already tried with a simple variable declaration, which works just fine. I only got 3 months worth of js experience and do not know where to further look for the issue. Thank you.
The problem is that getDataURL
is async, so doc.end()
runs before image parsing is done, and the pdf is empty.
A quick-and-dirty solution would be to move doc.end part inside promise callback:
QRCode.toDataURL(str)
.then(base64 => {
doc.image(base64,245.945,75,{width:350});
// now finish the doc
doc.fontSize(20).text("Field1", 30, 97.64 + 35);
doc.fontSize(20).text("Field2", 841.89 - (160 + 30), 97.64 + 35);
doc.fontSize(20).text("Field3", 841.89 - (160 + 30), 400 + 97.64 - 75);
doc.fontSize(25).text("Description", 40, 490, {
align: "center",
lineBreak: "false",
});
doc.end();
})
or you could refactor the code, and use async/await, which would take more coding.
For example, make getDataURL
return a promise, and wait for it to finish, and then cal doc.end
part:
// QR Code
async function getDataURL(str){
try {
return QRCode.toDataURL(str);
} catch(err) {
console.error(`Debugger: Catched Error from QRCode.toDataURL promise: ${err}`)
throw err;
}
}
getDataURL(testList).then((base64)=>{
doc.image(base64,245.945,75,{width:350});
// Text
doc.fontSize(20).text("Field1", 30, 97.64 + 35);
doc.fontSize(20).text("Field2", 841.89 - (160 + 30), 97.64 + 35);
doc.fontSize(20).text("Field3", 841.89 - (160 + 30), 400 + 97.64 - 75);
doc.fontSize(25).text("Description", 40, 490, {
align: "center",
lineBreak: "false",
});
doc.end();
});