Create PDFs in Firebase Cloud Features

I am new to javascript and I am trying to render a PDF from a firebase function using pdfkit. Below is the code for my function.

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 runs, but then a timeout error occurs. Is this the best way to create PDF in firebase? I have html which I want to render into pdf file.

+7


source to share


5 answers


Just working on it, for saving the PDF to the repository, 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 to "Errors and Things", but this is the first working example I was able to do, now working on how to get an image from the repository to PDF.

+2


source


I worked on this too, and here below you can find a sample cloud function that creates a PDF file from an HTML template hosted on firebase. It uses Hanldebars to apply some data to the template and then load it again into firebase repository. I have 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 helps the next one: 1)

+10


source


I tried Guillaume's suggestion and it FULLY got me there. Unfortunately Phantomjs came out without decoration.

I ended up solving this by combining Guillaume's solution and https://phantomjscloud.com (and their library). Now everything works like a charm.

After the "template compiled with custom data" replace 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);
                           });
                       });

                   }

                   });

      

+2


source


I came across this question when I was looking for the same thing as the OP, but in my particular case, switching libraries was not possible and I was especially interested in directly outputting the PDF.

After getting it up and running successfully and comparing to what the OP was doing, it seems that all that was missing was doc.end()

for the doc.end()

data.

Here is a PDFKit demo outputted 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 basic example and it will probably need the appropriate headers to send, but it works like it does in modern browsers. I hope this helps anyone looking for the same.

0


source


A 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 helps someone

0


source







All Articles