最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript提取PDF圖片的方法詳解

 更新時(shí)間:2025年03月13日 09:26:49   作者:NeoYu  
這篇文章主要為大家詳細(xì)介紹了如何使用JavaScript提取 PDF 圖片,即把每一頁(yè)里的多張圖片都提取出來,不是把一整頁(yè)都轉(zhuǎn)換為一張圖片,感興趣的可以了解下

提取 PDF 圖片,是指把每一頁(yè)里的多張圖片都提取出來,不是把一整頁(yè)都轉(zhuǎn)換為一張圖片 ^_^ 。

效果 

技術(shù)實(shí)現(xiàn)詳解 

使用 PDF.js 解析和渲染 PDFs,在 github 上有 43.9kb Star,非常成熟。

一、 引入 pdf.js

需要同時(shí)引入 pdf.js 和 WebWorker,其中 WebWorker 在瀏覽器子線程解析圖片等資源,不阻塞頁(yè)面UI和交互。引入代碼如下:

<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.10.111/pdf.js"></script>

<script>
// pdf.js 從性能考慮,使用了 WebWorker, 在瀏覽器子線程解析圖片等資源,不阻塞頁(yè)面UI和交互。
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@3.10.111/build/pdf.worker.js';
</script>

二、上傳 PDF 文件并監(jiān)聽

上傳文件時(shí),使用 FileReader 異步文件讀取對(duì)象,讀取之后轉(zhuǎn)換為 Uint8Array,傳入 pdfjsLib,得到 PDF 加載任務(wù)。

代碼如下:

<input type="file" id="fileInput" name="avatar" title ="選擇 pdf 文件"/>

<script>
const fileInput = document.getElementById('fileInput');
fileInput.addEventListener(
  "change",
  () => {
    const file = fileInput.files[0];
    console.log('fileInput file: ', file);
    // 上傳文件時(shí),使用 FileReader 對(duì)象讀取
    var fileReader = new FileReader();
    fileReader.onload = function() {
          // 將文件對(duì)象轉(zhuǎn)化為 Uint8Array 
          var typedarray = new Uint8Array(this.result);
          // 返回 PDF 加載任務(wù) PDFDocumentLoadingTask
          const loadingTask = pdfjsLib.getDocument(typedarray);
          // 開始加載 PDF,這里封裝了一個(gè)函數(shù)
          loadPDFFile(loadingTask);
    };

    fileReader.readAsArrayBuffer(file);
  },
  false
);
</script>

三、獲取和遍歷 PDF 頁(yè)數(shù)

async function loadPDFFile(loadingTask) {
  // PDF 加載任務(wù)
  const pdf = await loadingTask.promise;
  // 獲取 PDF 頁(yè)數(shù)
  const numPages = pdf.numPages;
  for (let curPage = 1; curPage <= numPages; curPage++) {
    // 返回當(dāng)前頁(yè)
    console.log('loadingServerFile curPage: ', curPage);
    const page = await pdf.getPage(curPage);

    const scale = 1.5;
    // 獲取渲染視角尺寸
    const viewport = page.getViewport({ scale });
    // Support HiDPI-screens.
    const outputScale = window.devicePixelRatio || 1;
    // 傳入離屏 Canvas
    const canvas = new OffscreenCanvas(200, 200);
    // 獲取 Canvas 上下文
    const context = canvas.getContext("2d");
    // 轉(zhuǎn)換尺寸
    const transform = outputScale !== 1 
      ? [outputScale, 0, 0, outputScale, 0, 0] 
      : null;

    const renderContext = {
      canvasContext: context,
      transform,
      viewport,
    };
    // 調(diào)用 page.render 觸發(fā)渲染
    const renderTask = page.render(renderContext);
    // 等待 renderTask 渲染任務(wù)
    // await delay(500); // 如果渲染過快,可能導(dǎo)致 CPU 飆升、電腦可用內(nèi)存不夠,可以加延遲減慢速度
    await renderTask.promise;
  }
}

代碼里使用 OffscreenCanvas,提供了一個(gè)可以脫離屏幕渲染的 canvas 對(duì)象,在主線程和子線程 (web worker) 都可以使用,是為了性能優(yōu)化,提取 PDF 圖片不用渲染到頁(yè)面,但也要渲染任務(wù)

如果渲染過快,可能導(dǎo)致 CPU 飆升、電腦可用內(nèi)存不夠,可以加延遲 setTimeout 減慢速度

四、提取每頁(yè) PDF 的圖片

在這一步,我們獲取了 pdfjs 提取的 PDF 圖片,是 ImageBitmap 格式,它是對(duì) Canvas 上位圖數(shù)據(jù)的引用,存儲(chǔ)在 GPU 中,可以在 web worker 進(jìn)行生成,從而避免影響主線程繪制 UI,也避免阻塞響應(yīng)用戶交互。

代碼如下:

async function loadPDFFile(loadingTask) {
    // ...接上一步
    const renderTask = page.render(renderContext);
    // 等待當(dāng)前頁(yè)渲染任務(wù)執(zhí)行
    await renderTask.promise;
    // 獲取操作列表
    const ops = await page.getOperatorList();

    // 提取圖片
    const imageNames = ops.fnArray.reduce((acc, curr, i) => {
      if ([pdfjsLib.OPS.paintImageXObject, pdfjsLib.OPS.paintJpegXObject].includes(curr)) {
        acc.push(ops.argsArray[i][0]);
      }
      return acc;
    }, []);
    for (const imageName of imageNames) {
      console.log('imageName: ', imageName);
      page.objs.get(imageName, (image) => {
        // console.log('image: ', image);
        (async function() {          
          const bmp = image.bitmap;
          // create a canvas
          console.log('bmp: ', bmp);
        })();      
      });
    }
}

五、ImageBitmap 轉(zhuǎn)化為 Img

再堅(jiān)持一下,最后一步啦!─=≡Σ(((つ•?ω•?)つ

在上一步中,我們獲取了在 Canvas 繪圖的引用 ImageBitmap,我們需要轉(zhuǎn)換為瀏覽器下的 Img 圖片。

具體過程:先將 ImageBitmap 渲染到 Canvas,調(diào)用 canvas.convertToBlob 就能得到 Blob 對(duì)象。

async function loadPDFFile(loadingTask) {
    // ...接上一步,拿到了每頁(yè) PDF 的 image.bitmap 對(duì)象
    for (const imageName of imageNames) {
      console.log('imageName: ', imageName);
      page.objs.get(imageName, (image) => {
        // console.log('image: ', image);
        (async function() {          
            const bmp = image.bitmap;
            console.log('bmp: ', bmp);
            // OffscreenCanvas
            const resizeScale = 1/4; // 這個(gè)可以控制轉(zhuǎn)換后的圖片大小
            const width = bmp.width * resizeScale;
            const height = bmp.height * resizeScale;
            const canvas = new OffscreenCanvas(width, height);
            // 獲取 canvas bitmaprenderer 上下文
            const ctx = canvas.getContext('bitmaprenderer');
            // 把 ImageBitmap 渲染到 OffscreenCanvas
            ctx.transferFromImageBitmap(bmp);
            // 把 canvas 畫布轉(zhuǎn)化為 Blob 對(duì)象
            // https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas/convertToBlob
            const blob = await canvas.convertToBlob();
            console.log('blob: ', blob); // blob
            // 最后使用 Blob 作為 URL.createObjectURL 的參數(shù),渲染出 img 圖片
            // 如果不需要渲染,則可以講 Blob 數(shù)據(jù)上傳到云存儲(chǔ)
            const img = document.body.appendChild(new Image());
            img.width = width;
            img.height = height;
            img.src = URL.createObjectURL(blob);
        })();      
      });
    }
}

OffscreenCanvas 可以放在 Web Worker 中創(chuàng)建,從而不阻塞主線程的UI繪制和交互響應(yīng)。

bitmaprenderer.transferFromImageBitmap 可以實(shí)現(xiàn)不拷貝數(shù)據(jù),只傳遞地址的方式,把 ImageBitmap 傳遞到 Canvas 上。

背景(緣起)

前段時(shí)間遇到 從 PDF 中提取圖片用于 評(píng)論、審核 的功能。

由于項(xiàng)目時(shí)間趕、任務(wù)重,由后端實(shí)現(xiàn)了一頁(yè) PDF 轉(zhuǎn)換為一張圖片。

后端提取優(yōu)劣:

  • 優(yōu): 用戶體驗(yàn)好,不影響用戶電腦性能
  • 劣:加大服務(wù)器壓力
    • 占用大量CPU資源,在我Mac筆記本MacBook Pro (13-inch, 2017, Four Thunderbolt 3 Ports) 解析時(shí),能看到 CPU 每次都飆到 100% 以上
    • 占用大量?jī)?nèi)存,解析后的圖片,在上傳到 CDN 以前,放在服務(wù)器沒有釋放
    提取流程變長(zhǎng)
    • 需要把 PDF 文件上傳到服務(wù)器,由后端處理

前端提取優(yōu)劣:

  • 優(yōu): 不占用服務(wù)器資源,在瀏覽器端就能完成提取。
  • 劣: 可能會(huì)引起用戶電腦卡頓。

以上就是JavaScript提取PDF圖片的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于JavaScript提取PDF圖片的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JS隱藏參數(shù)post傳值實(shí)例

    JS隱藏參數(shù)post傳值實(shí)例

    JS隱藏參數(shù)post傳值實(shí)例,需要的朋友可以參考一下
    2013-04-04
  • 詳解Javascript中prototype屬性(推薦)

    詳解Javascript中prototype屬性(推薦)

    這篇文章主要介紹了Javascript中prototype屬性的相關(guān)資料,本文介紹的非常詳細(xì),具有參考借鑒價(jià)值,感興趣的朋友一起看看吧
    2016-09-09
  • JavaScript通過HTML的class來獲取HTML元素的方法總結(jié)

    JavaScript通過HTML的class來獲取HTML元素的方法總結(jié)

    除了getElementsByClassName()函數(shù),我們可以自己動(dòng)手編寫程式來通過class獲取元素,接下來我們整理了一下JavaScript通過HTML的class來獲取HTML元素的方法總結(jié),需要的朋友可以參考下
    2016-05-05
  • 淺談JavaScript中this的指向問題

    淺談JavaScript中this的指向問題

    這篇文章主要介紹了淺談JavaScript中this的指向問題,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • 發(fā)個(gè)自己寫的表格操作類(添加,刪除,排序,上移,下移)

    發(fā)個(gè)自己寫的表格操作類(添加,刪除,排序,上移,下移)

    發(fā)個(gè)自己寫的表格操作類(添加,刪除,排序,上移,下移)...
    2006-11-11
  • 詳解使用JS如何制作簡(jiǎn)單的ASCII圖與單極圖

    詳解使用JS如何制作簡(jiǎn)單的ASCII圖與單極圖

    這篇文章主要給大家介紹了使用JS如何制作簡(jiǎn)單的ASCII圖與單極圖的相關(guān)資料,文中介紹的非常詳細(xì),并在文末給出了詳細(xì)的示例代碼,相信對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來一起看看吧。
    2017-03-03
  • 微信小程序 this.triggerEvent()的具體使用

    微信小程序 this.triggerEvent()的具體使用

    這篇文章主要介紹了微信小程序 this.triggerEvent()的具體使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • 微信小程序?qū)崿F(xiàn)下拉框功能

    微信小程序?qū)崿F(xiàn)下拉框功能

    這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)下拉框功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • JavaScript中關(guān)于Object.create()的用法

    JavaScript中關(guān)于Object.create()的用法

    這篇文章主要介紹了JavaScript中關(guān)于Object.create()的用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • 學(xué)習(xí)JavaScript中的閉包c(diǎn)losure應(yīng)該注意什么

    學(xué)習(xí)JavaScript中的閉包c(diǎn)losure應(yīng)該注意什么

    這篇文章主要介紹了學(xué)習(xí)JavaScript中的閉包c(diǎn)losure應(yīng)該注意什么?在?JavaScript?中,?每當(dāng)創(chuàng)建一個(gè)函數(shù),?閉包就會(huì)在函數(shù)創(chuàng)建的同時(shí)被創(chuàng)建出來,但是學(xué)習(xí)的時(shí)候我們應(yīng)該注意哪些問題呢,帶著疑問一起進(jìn)入下面文章學(xué)習(xí)具體內(nèi)容吧
    2022-06-06

最新評(píng)論

大兴区| 福海县| 定安县| 永济市| 仁布县| 汝城县| 吉水县| 自治县| SHOW| 聂拉木县| 盐源县| 通州市| 额尔古纳市| 民权县| 横山县| 灯塔市| 佛教| 淮北市| 灵川县| 彭山县| 韩城市| 千阳县| 海林市| 金沙县| 武夷山市| 漠河县| 石阡县| 汨罗市| 宿松县| 班戈县| 万年县| 修文县| 忻州市| 阳春市| 阿拉善左旗| 黄山市| 武汉市| 洪湖市| 韶山市| 普兰店市| 衡东县|