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

JavaScript提取PDF圖片的方法詳解

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

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

效果 

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

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

一、 引入 pdf.js

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

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

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

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

上傳文件時(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);
          // 開(kāi)始加載 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); // 如果渲染過(guò)快,可能導(dǎo)致 CPU 飆升、電腦可用內(nèi)存不夠,可以加延遲減慢速度
    await renderTask.promise;
  }
}

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

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

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

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

代碼如下:

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 圖片。

具體過(guò)程:先將 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 畫(huà)布轉(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)建,從而不阻塞主線(xiàn)程的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): 用戶(hù)體驗(yàn)好,不影響用戶(hù)電腦性能
  • 劣:加大服務(wù)器壓力
    • 占用大量CPU資源,在我Mac筆記本MacBook Pro (13-inch, 2017, Four Thunderbolt 3 Ports) 解析時(shí),能看到 CPU 每次都飆到 100% 以上
    • 占用大量?jī)?nèi)存,解析后的圖片,在上傳到 CDN 以前,放在服務(wù)器沒(méi)有釋放
    提取流程變長(zhǎng)
    • 需要把 PDF 文件上傳到服務(wù)器,由后端處理

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

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

以上就是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通過(guò)HTML的class來(lái)獲取HTML元素的方法總結(jié)

    JavaScript通過(guò)HTML的class來(lái)獲取HTML元素的方法總結(jié)

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

    淺談JavaScript中this的指向問(wèn)題

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

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

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

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

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

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

    這篇文章主要介紹了微信小程序 this.triggerEvent()的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(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)建出來(lái),但是學(xué)習(xí)的時(shí)候我們應(yīng)該注意哪些問(wèn)題呢,帶著疑問(wèn)一起進(jìn)入下面文章學(xué)習(xí)具體內(nèi)容吧
    2022-06-06

最新評(píng)論

绥中县| 衡水市| 邢台市| 宿迁市| 邵阳市| 封丘县| 清流县| 金门县| 南康市| 大安市| 临漳县| 海晏县| 延长县| 威远县| 监利县| 东海县| 车致| 靖州| 龙里县| 西华县| 廊坊市| 新竹县| 垫江县| 柳河县| 石河子市| 焦作市| 绥芬河市| 克拉玛依市| 沽源县| 乌苏市| 凤凰县| 邢台市| 泰和县| 西和县| 桓台县| 左云县| 新乡县| 井陉县| 远安县| 永昌县| 吴川市|