pdf.js 使用 base64 渲染为 PDF

pdf.js rendering as PDF with base64

我卡在了应用程序的最后一点,我应该以 PDF 格式显示用户表单,这在桌面浏览器上运行良好,因为它们内置了 pdf 查看器,但对于 Android / iOS 它无法正常工作,因为缺少 pdf 查看器。

所以我试图用PDF.js来显示它,(老实说,这是非常广泛使用但缺乏文档),唯一的问题是我我正在获取 base64 格式的数据。 PDF.js 网站上有示例显示如何呈现 base64 数据但它不是 PDF,对于将 PDF 显示为 "PDF" 我需要使用他们的 "viewer.html" 但它不采用 base64 数据?

我最接近Pdf.js: rendering a pdf file using base64... 堆栈溢出,但我不知道PDFJS.getDocument(pdfAsArray)? 之后如何使用它。

遇到的其他 link 是 other link

我不想依赖 Google/第三方 PDF 查看器,因为我不知道他们会支持多久。

社区中没有关于此主题的端到端答案,因此我尝试将一些内容放在这里。 (也许对其他人有帮助)

好的,PDF.js 是在浏览器中显示 PDF 的一种方式,特别是当您不想依赖安装 PDF 插件时。就我而言,我的应用程序生成 PDF 格式的报告,可以在下载前查看,但由于缺少 PDF 查看器插件,因此在手持设备上无法使用。

在我的例子中,PDF 被发送到 base64 字符串中进行浏览,我可以使用它来显示带有 <object src="base64-data"...></object> 的 PDF。这在 Chrome / FF 上就像魅力一样,但切换到移动视图时它会停止工作。

<object type="application/pdf" id="pdfbin" width="100%" height="100%" title="Report.pdf">
   <p class="text-center">Looks like there is no PDF viewer plugin installed, try one of the below approach...</p>                
</object>

在上面的代码中,它将尝试显示 PDF 或回退到 <p> 并显示错误消息。我正计划在此时添加 PDF 查看器,PDF.js 是选择,但无法显示它。 PDF.js 上使用 Base64 数据的一个示例显示了如何执行此操作,但将其呈现为图像而不是 PDF,我无法找到解决方案,因此问题是,这就是我所做的,

  1. 先添加JavaScript代码将base64转array

  2. 转换为 blob 并使用 PDF.js 打包的 viewer.html 文件显示为 PDF

如果您想知道为什么是 base64 数据,那么答案很简单我可以创建 PDF,阅读它,将数据发送给客户端并删除文件,我不必 运行 删除生成的 PDF 文件的任何清洁工 service/cron 工作

注意事项

  1. Below code is using Flask + Jinja2, change the way base64 is read in html if you are using something else
  2. viewer.html needs to be changed to have required js & css files in proper location (by default their location is relative; you need them to be referred from static folder)
  3. viewer.js looks for pdf.worker.js in predefined location, change that in case its throwing error as above file not found.
  4. viewer.js might throw file origin does not match viewer error in that case as a quick fix comment the code which throws this error and see if that solves the issue (look for that error in viewer.js)
  5. I am not the author of below code, I have just put it together from different places.

现在开始编写代码(因此当用户单击带有 id="open_id" 的按钮时将显示 PDF)


Jquery

var pdfDataX = '{{ base64Pdf }}';
var BASE64_MARKER = ';base64,';
PDFJS.workerSrc = "{{ url_for('static', filename='js/pdf.worker.js') }}";

$('#open_id').click(function() {        
    PDFJS.disableWorker = true;
    var pdfAsDataUri = "data:application/pdf;base64," + pdfDataX ;
    PDFJS.workerSrc = "{{ url_for('static', filename='js/pdf.worker.js') }}";

    // Try to show in the viewer.html

    var blob = base64toBlob(pdfDataX, 'application/pdf');
    var url = URL.createObjectURL(blob);
    var viewerUrl = "{{ url_for('static', filename='viewer.html') }}" + '?file=' + encodeURIComponent(url);
    $('#pdfViewer').attr('src', viewerUrl);

    // Finish

    var mdObj = $('#pdfbin');

    mdObj.hide();
    mdObj.attr('data', pdfAsDataUri);
    mdObj.show();

    $('#myModal').modal();
});

var base64toBlob = function(b64Data, contentType, sliceSize) {
    contentType = contentType || '';
    sliceSize = sliceSize || 512;

    var byteCharacters = atob(b64Data);
    var byteArrays = [];

    for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
        var slice = byteCharacters.slice(offset, offset + sliceSize);

        var byteNumbers = new Array(slice.length);
        for (var i=0; i<slice.length; i++) {
            byteNumbers[i] = slice.charCodeAt(i);
        }

        var byteArray = new Uint8Array(byteNumbers);

        byteArrays.push(byteArray);
    }
    var blob = new Blob(byteArrays, {type: contentType});
    return blob;
}

$('.save').click(function(e) {
    e.preventDefault();
    var blob = base64toBlob(pdfDataX, 'application/pdf');
    saveAs(blob, 'abcd.pdf');  // requires https://github.com/eligrey/FileSaver.js/
    return false;
});

HTML

<object type="application/pdf" id="pdfbin" width="100%" height="100%" title="Resume.pdf">
    <p class="text-center">Looks like there is no PDF viewer plugin installed, try one of the below approach...</p>
    <iframe id="pdfViewer" style="width: 100%; height: 100%;" allowfullscreen="" webkitallowfullscreen=""></iframe>                  
</object>

希望这对以后的其他人有用。