NodeJS:使用读取到的缓冲区将两个PDF文件合并成一个

24

我正在使用 fill-pdf npm 模块来填充模板 pdf,并创建一个新文件,从磁盘读取后返回给回调函数。我有两个文件需要执行相同的操作。我想将两个缓冲区合并成一个单独的 pdf 文件,以便将其发送回客户端。我尝试了不同的缓冲区合并方法。可以使用 Buffer.concat 合并缓冲区,如下所示:

var newBuffer = Buffer.concat([result_pdf.output, result_pdf_new.output]);

新缓冲区的大小也是输入缓冲区大小的总和。但当newBuffer作为响应发送给客户端时,它仅显示数组中最后一个提到的文件。

res.type("application/pdf");
return res.send(buffer);

有什么想法吗?


可能是Merging PDFs in Node的重复问题。 - rouan
3个回答

41

正如@MechaCode所述,创建者已经停止支持HummusJS

因此,我想给你两个解决方案。

  1. Using node-pdftk npm module

    The Following sample code uses node-pdftk npm module to combine two pdf buffers seamlessly.

    const pdftk = require('node-pdftk');
    
    var pdfBuffer1 = fs.readFileSync("./pdf1.pdf");
    var pdfBuffer2 = fs.readFileSync("./pdf2.pdf");
    
    pdftk
        .input([pdfBuffer1, pdfBuffer2])
        .output()
        .then(buf => {
            let path = 'merged.pdf';
            fs.open(path, 'w', function (err, fd) {
                fs.write(fd, buf, 0, buf.length, null, function (err) {
                    fs.close(fd, function () {
                        console.log('wrote the file successfully');
                    });
                });
            });
        });
    

    The requirement for node-pdftk npm module is you need to install the PDFtk library. Some of you may find this overhead / tedious. So I have another solution using pdf-lib library.

  2. Using pdf-lib npm module

    const PDFDocument = require('pdf-lib').PDFDocument
    
    var pdfBuffer1 = fs.readFileSync("./pdf1.pdf"); 
    var pdfBuffer2 = fs.readFileSync("./pdf2.pdf");
    
    var pdfsToMerge = [pdfBuffer1, pdfBuffer2]
    
    const mergedPdf = await PDFDocument.create(); 
    for (const pdfBytes of pdfsToMerge) { 
        const pdf = await PDFDocument.load(pdfBytes); 
        const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices());
        copiedPages.forEach((page) => {
             mergedPdf.addPage(page); 
        }); 
    } 
    
    const buf = await mergedPdf.save();        // Uint8Array
    
    let path = 'merged.pdf'; 
    fs.open(path, 'w', function (err, fd) {
        fs.write(fd, buf, 0, buf.length, null, function (err) {
            fs.close(fd, function () {
                console.log('wrote the file successfully');
            }); 
        }); 
    }); 
    
    

个人而言,我更喜欢使用pdf-lib npm模块。


3
谢谢!pdf-lib非常棒。 - Saurabh Mistry
1
或许这是使用PDF-LIB的更好示例 https://github.com/Hopding/pdf-lib#copy-pages - Richard Oliver Bray
请注意,pdf-lib无法处理加密的PDF文件。如果您尝试合并加密的PDF文件,结果将会是空白页。 - undefined

32

HummusJS支持使用其appendPDFPagesFromPDF方法合并PDF。

使用流处理缓冲区的示例:

const hummus = require('hummus');
const memoryStreams = require('memory-streams');

/**
 * Concatenate two PDFs in Buffers
 * @param {Buffer} firstBuffer 
 * @param {Buffer} secondBuffer 
 * @returns {Buffer} - a Buffer containing the concactenated PDFs
 */
const combinePDFBuffers = (firstBuffer, secondBuffer) => {
    var outStream = new memoryStreams.WritableStream();

    try {
        var firstPDFStream = new hummus.PDFRStreamForBuffer(firstBuffer);
        var secondPDFStream = new hummus.PDFRStreamForBuffer(secondBuffer);

        var pdfWriter = hummus.createWriterToModify(firstPDFStream, new hummus.PDFStreamForResponse(outStream));
        pdfWriter.appendPDFPagesFromPDF(secondPDFStream);
        pdfWriter.end();
        var newBuffer = outStream.toBuffer();
        outStream.end();

        return newBuffer;
    }
    catch(e){
        outStream.end();
        throw new Error('Error during PDF combination: ' + e.message);
    }
};

combinePDFBuffers(PDFBuffer1, PDFBuffer2);

请问,PDFBuffer1和PDFBuffer2的类型是什么? - M.Abulsoud
1
@M.Abulsoud 这两个Buffer都是填充了二进制PDF数据。在我的情况下,我使用Puppeteerpage.pdf()方法创建了这些缓冲区。 - Zach Esposito
1
这是一个合并PDF文件的例子,来自作者:https://github.com/galkahana/HummusJS/blob/master/tests/MergePDFPages.js - Govind Rai
我正在尝试在React组件中使用它,但似乎不可能。我漏掉了什么吗? - Gioce90
@ZachEsposito Puppeteer的page.pdf()方法返回一个Buffer。 - bentael
我正在从Firebase云存储获取文件,就像这样:const [files] = await storage.bucket(bucket).getFiles(options); 我能遍历这个数组来合并这些数组项吗?它们是什么?缓冲区吗? - Madcap

4
以下是我们在Express服务器中使用的代码,用于合并PDF blob列表。
const { PDFRStreamForBuffer, createWriterToModify, PDFStreamForResponse } = require('hummus');
const { WritableStream } = require('memory-streams');

// Merge the pages of the pdfBlobs (Javascript buffers) into a single PDF blob                                                                                                                                                                  
const mergePdfs = pdfBlobs => {
  if (pdfBlobs.length === 0) throw new Error('mergePdfs called with empty list of PDF blobs');
  // This optimization is not necessary, but it avoids the churn down below                                                                                                                                                
  if (pdfBlobs.length === 1) return pdfBlobs[0];

  // Adapted from: https://dev59.com/oloV5IYBdhLWcg3wCrLH                                                     
  // Hummus is useful, but with poor interfaces -- E.g. createWriterToModify shouldn't require any PDF stream                                                                                                              
  // And Hummus has many Issues: https://github.com/galkahana/HummusJS/issues                                                                                                                                              
  const [firstPdfRStream, ...restPdfRStreams] = pdfBlobs.map(pdfBlob => new PDFRStreamForBuffer(pdfBlob));
  const outStream = new WritableStream();
  const pdfWriter = createWriterToModify(firstPdfRStream, new PDFStreamForResponse(outStream));
  restPdfRStreams.forEach(pdfRStream => pdfWriter.appendPDFPagesFromPDF(pdfRStream));
  pdfWriter.end();
  outStream.end();
  return outStream.toBuffer();
};

module.exports = exports = {
  mergePdfs,
};

1
hummusJs现在已不被创建者支持。 - MechaCode
运行得非常好!如果您需要将PDF的base64表示合并为一个(而不使用文件),则需要将pdfBlobs作为此参数传递:Buffer.from(base64String,'base64') - Rodrigo García

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接