问题
I am new to javascript and I'm trying to make a PDF file from a firebase function using pdfkit. Below is my function code.
const pdfkit = require('pdfkit');
const fs = require('fs');
exports.PDFTest = functions.https.onRequest((req, res) => {
var doc = new pdfkit();
var loremIpsum = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam in...';
doc.y = 320;
doc.fillColor('black')
doc.text(loremIpsum, {
paragraphGap: 10,
indent: 20,
align: 'justify',
columns: 2
});
doc.pipe( res.status(200) )
});
The function starts but then a timeout error happens. Is this the best way of going about creating a pdf file in firebase? I have some html that I want made into a pdf file.
回答1:
Just working on this too, for saving the PDF in the storage it works like this
const myPdfFile = admin.storage().bucket().file('/test/Arbeitsvertrag.pdf');
const doc = new pdfkit();
const stream = doc.pipe(myPdfFile.createWriteStream());
doc.fontSize(25).text('Test 4 PDF!', 100, 100);
doc.end();
return res.status(200).send();
Guess you should wait until the stream is closed and listen for Errors and Things, but this is the first working example I was able to make, now working on how to get a Image from the storage into the PDF.
回答2:
I worked on this too and here below you can find a sample of cloud function that is creating a PDF file from a template HTML hosted on firebase storage. It uses Hanldebars to apply some data to the template and then upload it again on firebase storage. I used node-html-pdf here.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const pdf = require('html-pdf');
const gcs = require('@google-cloud/storage')({
projectId: '[YOUR PROJECT ID]',
//key generated from here https://console.firebase.google.com/project/_/settings/serviceaccounts/adminsdk?authuser=1
keyFilename: '[YOUR KEY]'
});
const handlebars = require('handlebars');
const path = require('path');
const os = require('os');
const fs = require('fs');
const bucket = gcs.bucket('[YOUR PROJECT ID].appspot.com');
admin.initializeApp(functions.config().firebase);
exports.helloWorld = functions.https.onRequest((request, response) => {
// data to apply to template file
const user = {
"date": new Date().toISOString(),
"firstname" : "Guillaume",
};
const options = {
"format": 'A4',
"orientation": "portrait"
};
const localTemplate = path.join(os.tmpdir(), 'localTemplate.html');
const localPDFFile = path.join(os.tmpdir(), 'localPDFFile.pdf');
bucket.file('template.html').download({ destination: localTemplate }).then(() => {
console.log("template downloaded locally");
const source = fs.readFileSync(localTemplate, 'utf8');
const html = handlebars.compile(source)(user);
console.log("template compiled with user data", html);
pdf.create(html, options).toFile(localPDFFile, function(err, res) {
if (err){
console.log(err);
return response.send("PDF creation error");
}
console.log("pdf created locally");
return bucket.upload(localPDFFile, { destination: user.name + '.pdf', metadata: { contentType: 'application/pdf'}}).then(() => {
response.send("PDF created and uploaded!");
}).catch(error => {
console.error(error);
response.send("PDF created and uploaded!");
});
});
});
});
Hope this will help the next one doing this :)
回答3:
I tried Guillaume's suggestion and it ALMOST got me there. Unfortunately, Phantomjs was exiting without finishing.
I ended up solving this by combining Guillaume's solution and https://phantomjscloud.com (and their library.) Now it's all working like a charm.
After "template compiled with user data", substitute the following:
const phantomJsCloud = require("phantomjscloud");
const browser = new phantomJsCloud.BrowserApi([YOURPHANTOMJSCLOUDAPIKEY]);
var pageRequest = { content: html, renderType: "pdf" };
// Send our HTML to PhantomJS to convert to PDF
return browser.requestSingle(pageRequest)
.then(function (userResponse) {
if (userResponse.statusCode != 200) {
console.log("invalid status code" + userResponse.statusCode);
} else {
console.log('Successfully generated PDF');
// Save the PDF locally
fs.writeFile(localPDFFile, userResponse.content.data, {
encoding: userResponse.content.encoding,
}, function (err) {
// Upload the file to our cloud bucket
return pdfBucket.upload(localPDFFile, { destination: 'desired-filename.pdf', metadata: { contentType: 'application/pdf'}}).then(() => {
console.log('bucket upload complete: '+ localPDFFile);
}).catch(error => {
console.error('bucket upload error:', error);
});
});
}
});
回答4:
A little bit late.
https://edgecoders.com/generating-a-pdf-with-express-in-node-js-d3ff5107dff1
import * as functions from 'firebase-functions';
import * as PDFDocument from 'pdfkit';
export const yourFunction = functions
.https
.onRequest((req, res) => {
const doc = new PDFDocument();
let filename = req.body.filename;
// Stripping special characters
filename = encodeURIComponent(filename) + '.pdf';
// Setting response to 'attachment' (download).
// If you use 'inline' here it will automatically open the PDF
res.setHeader('Content-disposition', 'attachment; filename="' + filename + '"');
res.setHeader('Content-type', 'application/pdf');
const content = req.body.content;
doc.y = 300;
doc.text(content, 50, 50);
doc.pipe(res);
doc.end();
});
hope this can help anyone
回答5:
I ran into this question while searching for the same as the OP but in my particular case switching libraries wasn't an option and I was particularly interested in outputting the PDF directly.
After getting it to work successfully and comparing to what the OP was doing it seems that all that was missing was
doc.end() to flush the data.
Here's PDFKit's demo being output by Firebase Function:
const PDFDocument = require('pdfkit');
exports.PDFTest = functions.https.onRequest((req, res) => {
var doc = new PDFDocument();
// draw some text
doc.fontSize(25)
.text('Here is some vector graphics...', 100, 80);
// some vector graphics
doc.save()
.moveTo(100, 150)
.lineTo(100, 250)
.lineTo(200, 250)
.fill("#FF3300");
doc.circle(280, 200, 50)
.fill("#6600FF");
// an SVG path
doc.scale(0.6)
.translate(470, 130)
.path('M 250,75 L 323,301 131,161 369,161 177,301 z')
.fill('red', 'even-odd')
.restore();
// and some justified text wrapped into columns
doc.text('And here is some wrapped text...', 100, 300)
.font('Times-Roman', 13)
.moveDown()
.text("... lorem ipsum would go here...", {
width: 412,
align: 'justify',
indent: 20,
columns: 2,
height: 300,
ellipsis: true
});
doc.pipe(res.status(200));
doc.end();
});
This is a very simple example and probably would need appropriate headers to be sent but it works as is in modern browsers. I hope this helps anyone looking for the same.
来源:https://stackoverflow.com/questions/45335543/create-pdf-in-firebase-cloud-functions