在 Firebase 函数中从 Firebase 存储填充 PDFKit 图像?

Populating a PDFKit Image from Firebase Storage while in a Firebase Function?

我一直在尝试从 PDFKit 填充 PDFDoc 中的图像,但无法让它工作。使用下面的函数时,Firebase 控制台函数日志中出现以下错误。该文件以 "image/png" 类型存储在 Firebase 存储中。名称只是一个字符串。我尝试在名称后附加“.PNG”,但我收到了同样的错误。我包含了整个函数文件,因为也许有更可接受的方法来处理这个问题?在 Firebase 函数中,我应该如何将 PDF 从 Firebase 存储插入 PDFDoc?谢谢。

获取文档时出错:错误:未知的图像格式。 在 Function.PDFImage.open (/user_code/node_modules/pdfkit/js/image.js:43:15) 在 PDFDocument.openImage (/user_code/node_modules/pdfkit/js/mixins/images.js:102:26) 在 PDFDocument.image (/user_code/node_modules/pdfkit/js/mixins/images.js:30:24) 在 /user_code/lib/index.js:71:48 在 QuerySnapshot.forEach (/user_code/node_modules/firebase-admin/node_modules/@google-cloud/firestore/src/reference.js:1012:16) 在 /user_code/lib/index.js:24:31 在 process._tickDomainCallback (internal/process/next_tick.js:135:7)

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import * as firebase from 'firebase/app';
import * as PDFDocument from 'pdfkit';

admin.initializeApp(functions.config().firebase);

export const genPdf = functions.https.onRequest((request, response) => {

    const bucket = admin.storage().bucket("decteac2-3hcec.appspot.com");

    const text = request.query.text;
    const pdfdoc = new PDFDocument({ autoFirstPage: false });
    pdfdoc.info['Title'] = text + ".pdf";

    let x = 5;
    let y = 5;

    pdfdoc.pipe(response);

    const docRef = admin.firestore().collection("cxforms").doc(text);
    docRef.get().then(function (doc) {
        if (doc.exists) {
            const pagesRef = admin.firestore().collection("pages").where("formKey", "==", text).orderBy("pageno");
            pagesRef.get().then(function (querySnapshot) {
                let cnt = 1;
                querySnapshot.forEach(function (page) {
                    pdfdoc.addPage({ margin: 0 });
                    x = 5;
                    y = 5;
                    pdfdoc.moveTo(x, y)
                        .lineTo(607, 5)
                        .lineTo(607, 787)
                        .lineTo(5, 787)
                        .lineTo(x, y)
                        .stroke();
                    for (let i = 0; i < page.data().tables.length; i++) {
                        const table = page.data().tables[i];
                        y = y + 8.5; // margin

                        var tableWidth = 5;
                        for (let p = 0; p < table.cols.length; p++) {
                            tableWidth = tableWidth + (table.cols[p] * .82);
                        }
                        var offset = (597 - tableWidth) / 2;
                        for (let j = 0; j < table.rows.length; j++) {
                            const row = table.rows[j];
                            x = 10 + offset;
                            for (let k = 0; k < row.cells.length; k++) {
                                const cell = row.cells[k];
                                const colwidth = table.cols[k];
                                var height = 22.2;
                                for (let l = 0; l < cell.cellels.length; l++) {
                                    const cellEl = cell.cellels[l];

                                    if (cellEl.type === "Text") {
                                        pdfdoc.text(cellEl.text, x + 1, y + 7);
                                    } else if (cellEl.type == "Image") {
                                        const filename = cellEl.storageid;
                                        const file = bucket.file(filename);
                                        const bucketFileStream = file.createWriteStream();
                                        const buffer = new Buffer([1000000]);
                                        bucketFileStream.write(buffer);
                                        bucketFileStream.end();
                                        pdfdoc.image(buffer, x, y);

                                    }
                                }
                                if (height < 20) {
                                    height = 20;
                                }
                                pdfdoc.moveTo(x, y)
                                    .lineTo(x + (colwidth * .82), y)
                                    .lineTo(x + (colwidth * .82), y + height)
                                    .lineTo(x, y + height)
                                    .lineTo(x, y)
                                    .stroke();
                                x = x + (colwidth * .82);
                            }
                            y = y + height;
                        }
                    }
                    cnt++;
                });
                pdfdoc.end();
            }).catch(function (error) {
                console.log("Error getting documents: ", error);
            })

        } else {
            console.log("No such document!");
        }
    }).catch(function (error) {
        console.log("Error gettting documents: ", error);
    });
});

我是这样解决这个问题的。关键项目是将响应编码设置为 'base64' 以调用 Firestorage。另一项是使用 async 和 await 以等待每个单元格元素图像填充 pdfdoc,然后再继续下一个要呈现的单元格元素。

if (cellEl.type == "Image") {await toBase64(cellEl.url, x, y, pdfdoc);}

function toBase64(url, x, y, pdfdoc) {
    return new Promise(async(resolve, reject) => {
        var req = await https.get(url, (res) => {
            res.setEncoding('base64');
            let body = "data:" + res.headers["content-type"] + ";base64,";
            res.on('data', (d) => {
                body += d;
            });
            res.on('end', () => {
                pdfdoc.image(body, x, y);
                resolve(res);
            });
        });
        req.on('error', err => {
            console.error('error!');
            reject(err);
        });

    });

}