附加 Blob 未正确连接 pdf 页面

Posted

技术标签:

【中文标题】附加 Blob 未正确连接 pdf 页面【英文标题】:Append Blob not concatenating pdf pages correctly 【发布时间】:2021-07-03 07:50:54 【问题描述】:

我正在使用 Azure 存储将一些 pdf 存储为 blob。我想使用 Node SDK for Azure Storage 中提供的 AppendBlob class 即时连接它们。我的问题是,即使合并的 pdf 大小正确,当我打开它时,它也只显示其中的最后一页,而不是我连接的所有页面。我在代码中犯了错误吗?如果您能深入了解这个问题,我将不胜感激。

我不想下载它们并将它们连接到代码中,因为在某些情况下,生成的 pdf 大小超过 2gb,节点无法处理。

    let bundleUuid = uuidv4();
    var connString = process.env.ST_ENV_01_APS_03_CONNECTION_STRING;
    var appendBlobClient = new AppendBlobClient(connString, container, userId + "/bundles/" + bundleUuid + ".pdf");
    await appendBlobClient.create();
    context.log(userId + "/bundles/" + bundleUuid + ".pdf");
    
    for (const basketDocumentUri of basketDocumentUris) 
        
        context.log("Fetching: " + basketDocumentUri.document_uuid + "/" + (basketDocumentUri.page_index + 1) + ".pdf")
       
        let bbc = await containerClient.getBlockBlobClient(basketDocumentUri.document_uuid 
            + "/" + (basketDocumentUri.page_index + 1) + ".pdf");
        let details = await bbc.getProperties();
        let url = self.generateSasTokenPDF(basketDocumentUri.document_uuid + "/"
         + (basketDocumentUri.page_index + 1) + ".pdf", "r");
       
        try  
            
            let mbblk = 4194304
            let offset = 0;
            while(offset < details.contentLength)

                let response = await appendBlobClient.appendBlockFromURL(url.uri,offset,mbblk);
                context.log(response);
                
                offset += mbblk;
                
                context.log(offset);
            
            
         catch (error) 
            context.log(error);
            debugger;
        
    
    callback(bundleUuid)

【问题讨论】:

我不确定这种方法是否可行。本质上,PDF 文件是具有预定义格式的二进制文件。在附加 blob 中,您只是将字节附加到现有 blob,这会使 PDF 文件的格式无效。 生成的 pdf 似乎是有效的,因为它可以正常打开,唯一的问题是它只保留了添加的最后一页。 如果您认为我的评论粗鲁,我很抱歉。我只想表达的是,我很惊讶您认为观看者显示的内容与预期不同。 关于手头的问题:正如@Gaurav 已经暗示的那样,多个 pdf 文件的连接不会导致包含所有页面的单个有效 pdf。相反,它作为 pdf 是无效的。但请注意,众所周知,pdf 查看器会尝试修复损坏的 pdf。因此,您的查看器试图修复您的文件,导致它只显示一页。 【参考方案1】:

正如 Gaurav 在评论中所说,简单地将字节附加到现有 blob 会使 PDF 文件的格式无效。不下载文件就不可能与文件进行交互。

以下是将 blob 下载到 Buffer:

  const containerClient = blobServiceClient.getContainerClient(containerName);
  const blobClient = containerClient.getBlobClient(blobName);

  // Get blob content from position 0 to the end
  // In Node.js, get downloaded data by accessing downloadBlockBlobResponse.readableStreamBody
  const downloadBlockBlobResponse = await blobClient.download();
  const downloaded = (
    await streamToBuffer(downloadBlockBlobResponse.readableStreamBody)
  ).toString();
  console.log("Downloaded blob content:", downloaded);

  // [Node.js only] A helper method used to read a Node.js readable stream into a Buffer
  async function streamToBuffer(readableStream) 
    return new Promise((resolve, reject) => 
      const chunks = [];
      readableStream.on("data", (data) => 
        chunks.push(data instanceof Buffer ? data : Buffer.from(data));
      );
      readableStream.on("end", () => 
        resolve(Buffer.concat(chunks));
      );
      readableStream.on("error", reject);
    );
  

使用 HummusJS 合并 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);

【讨论】:

我们已经实现了这样的解决方案,我们希望使用 AppendBlob 或其他一些技巧来解决内存限制,因为有时我们最终会处理大小超过 500 MB 的 pdf,我们无法转换缓冲并存储在变量中以进行操作

以上是关于附加 Blob 未正确连接 pdf 页面的主要内容,如果未能解决你的问题,请参考以下文章

如何将特定页面从一个pdf附加到另一个pdf?

如何在保留书签的同时向现有 pdf 添加附加页面? (PDFSharp等)

如何使用 PyPDF2 附加 PDF 页面

pdf,外观流,焦点丢失后复选框未正确显示

iTextPDF(版本 5)超链接未链接到正确的位置

裁剪标记未在重影脚本中设置在正确位置