前端base64转pdf预览方案(js处理、小程序处理)

本章分为js处理、小程序处理

JS处理PDF的base64数据进行预览

两种预览方式:跳转新窗口预览;当前页面预览(使用embed标签等、或需引入pdf.js)

跳转新窗口预览

转blob类型(注意要设置类型为application/pdf打开才是预览,不然就是直接下载)
——使用createObjectURL转url格式(处理后会变成blob://... 这种格式)
——打开(两种打开方式:img标签直接打开、window.open窗口打开)

拓展:
具体的MIME类型:
text/html: 对于一般网页
text/plain: 对于一般文本
text/css :对于级联样式表
text/javascript :对于脚本
application/octet-stream: 意味着“下载这个文件”
application/x-java-applet :对于 Java applets
application/pdf :对于 PDF 文档

 let bytes = Uint8Array.from(atob(base64Data), character => character.charCodeAt(0)); //atob将base64转为二进制数据,unit8Array将二进制数据转为字节数组
 let blob = new Blob([bytes], { type: 'application/pdf' });//将字节数组包装成一个PDF的Blob对象(二进制大对象)
 let url = URL.createObjectURL(blob);//为Blob对象创建一个临时的本地URL
 window.open(url, "_blank");//访问pdf

iframe内嵌视图预览

可使用html的iframe 标签 embed 标签 object 标签、

效果:

let bytes = Uint8Array.from(atob(base64Data), character => character.charCodeAt(0));
 let blob = new Blob([bytes], { type: 'application/pdf' });
 let url = URL.createObjectURL(blob);
 
 <embed  src={url} type="application/pdf" ></embed>
 <iframe src={url}" ></iframe>
 <object src={url} type="application/pdf" ></object>
 

引入pdf.js

效果:
image

  1. 首先,项目中需要引入pdf.js
    注意:不同版本的pdf.js的引入在项目中的引入方式不同,这里下载的是3.8.162的版本
npm install --save pdfjs-deist
或
yarn add --save pdfjs-dist@3.8.162
  1. 项目中引入并使用
import {GlobalWorkerOptions,getDocument} from 'pdfjs-dist/legacy/build/pdf.js' //getDocument 用于加载 PDF,GlobalWorkerOptions 用于配置工作线程
import * as workerSrc from 'pdfjs-dist/build/pdf.worker.entry.js'//pdf.worker.entry.js,负责 PDF 解析的底层计算,不阻塞主线程
/**
 * 
 * @param {canvas的id} id 
 * @param {pdf的base64数据} base64Data 
 * @param {缩放数值,1为正常值,<1缩小,>1放大} scale 
 */
export const getPDFCanvas = (id,base64Data,scale=2.5) => {
  const pdfData = atob(base64Data) //将 Base64 编码的字符串解码为原始二进制数据(以 ASCII 字符形式表示)
  
  //配置 PDF 工作线程。为 PDF.js 设置工作线程脚本路径,确保解析 PDF 时使用独立线程,避免卡顿页面
  GlobalWorkerOptions.workerSrc = workerSrc
  
  // 加载 PDF 文档
  let loadingTask = getDocument({data: pdfData});
  loadingTask.promise.then(function(pdf) {
    console.log('PDF loaded');

    // 获取第一页
    let pageNumber = 1;
    pdf.getPage(pageNumber).then(function(page) {
      console.log('Page loaded');
      //计算渲染视口(根据缩放比例)
      let viewport = page.getViewport({scale: scale});

      // 准备 canvas 元素(设置宽高与视口一致)
      let canvas = document.getElementById(id);
      let context = canvas.getContext('2d');
      canvas.height = viewport.height;
      canvas.width = viewport.width;

      // 将 PDF 页面渲染到 canvas
      let renderContext = {
        canvasContext: context,
        viewport: viewport
      };
      let renderTask = page.render(renderContext);
      renderTask.promise.then(function () {
        console.log('Page rendered');
      });
    });
  }, function (reason) {
    // PDF loading error
    console.error(reason);
  });
}
在组件中使用:
getPDFCanvas('pdf-cavas',base64数据,1.5)

<canvas id="pdf-canvas"></canvas>

小程序处理PDF的base64数据进行预览(Taro开发微信小程序为例)

Taro.getFileSystemManager()将文件保存到本地——Taro.openDocument()打开

 const checkPDF = (item) =>{
    const { result, recordName} = item
    const fullPath = Taro.env.USER_DATA_PATH + '/' + recordName
    const FileSystermManagement = Taro.getFileSystemManager()
    FileSystermManagement.writeFile({
      filePath: fullPath,
      data: Taro.base64ToArrayBuffer(result?.replace(/[\r\n]/g, '')),
      encoding: 'binary',
      success: (res) => {
        console.log('完成写入文件', res)
        Taro.openDocument({
          filePath: fullPath,
          showMenu: true,
          fileType:'pdf',
          success: (r) => {
            console.log('完成打开文件', r)
          },
          fail:(error)=>{
          },
          complete: () => {
            Toast.close()
          },
        })
      },
    })
  }

微信小程序查看PDF文件(已经有现成的链接的情况)

有现成PDF链接的情况下,先downloadFiles下载PDF再openDocument打开查看

import { useEffect, useState } from "react"
import Router, { NavigateType } from 'tarojs-router-next'
import Taro, { useRouter } from '@tarojs/taro'
import { Button, Loading } from "@taroify/core"
import { View } from "@tarojs/components"
import { Dialog } from '@taroify/core'




const Index = (props) => {

    const { url, title } = Router?.getParams()
    const [loading, setLoading] = useState(false)
    const [openFileUrl, setOpenFileUrl] = useState()

    useEffect(() => {

        Taro.setNavigationBarTitle({
            title: title || '查看文件',
        })
        downloadFile(url)
    }, [url, title])

    const downloadFile = (url) => {
        setLoading(true)
        Taro.downloadFile({
            url: url || '',
            success: function (res) {
                const filePath = res?.tempFilePath
                setOpenFileUrl(filePath)
                openFile(filePath)
            },
            fail: function (params) {
                setLoading(false)
                Dialog.alert({
                    message: '访问失败',
                    confirm: '确定',
                    onConfirm: () => {
                        Router.back()
                    },
                })

            }

        })
    }

    const openFile = (filePath) => {
        setLoading(true)
        wx.openDocument({
            filePath: filePath,
            success: function (res) {
                setLoading(false)
                console.log('打开文档成功')

            },
            finally: function () {
                setLoading(false)
            }
        })
    }

    return <View style={{ width: '100vw', height: '100vh' }} className="flex items-center justify-center">
        {
            loading ? <Loading size="30px" type="spinner"></Loading>
                :
                <Button color="default" onClick={() => {

                    if (openFileUrl) {
                        openFile(openFileUrl)
                    } else {
                        downloadFile(url)
                    }
                }}>查看文件</Button>
        }

        <Dialog id="dialog" />
    </View>
}

export default Index
posted @ 2024-01-15 17:38  huangchun0121  阅读(365)  评论(0)    收藏  举报