JS逐頁轉(zhuǎn)pdf文件為圖片格式

背景

年前的時(shí)候虑乖,開發(fā)一個(gè)電子雜志項(xiàng)目坪郭,功能需求是通過上傳pdf文件褂删,將其轉(zhuǎn)為圖片格式收叶,所以雜志的內(nèi)容其實(shí)就是一張張圖片

不過當(dāng)時(shí)技術(shù)要求用后端實(shí)現(xiàn)结啼,所以使用的是PHP實(shí)現(xiàn)該功能蝗肪。項(xiàng)目完成后轻掩,尋思著在前端是否也能實(shí)現(xiàn)pdf轉(zhuǎn)圖片的功能补鼻。一番研究后剃执,果真可行誓禁。以下就分享如何通過前端js將pdf文件轉(zhuǎn)為圖片格式,并且支持翻頁預(yù)覽肾档、以及圖片打包下載

效果預(yù)覽

所需工具

  1. pdf.js(負(fù)責(zé)API解析现横,可將pdf文件渲染成canvas實(shí)現(xiàn)預(yù)覽)
  2. pdf.worker.js(負(fù)責(zé)核心解析)
  3. jszip.js(將圖片打包成生成.zip文件)
  4. Filesaver.js(保存下載zip文件)

工具下載

一、pdf.js及pdf.worker.js下載地址:
http://mozilla.github.io/pdf.js/getting_started/#download

1.選擇穩(wěn)定版下載

2.解壓后將bulid中的pdf.js及pdf.worker.js拷貝到項(xiàng)目中

二阁最、jszip.js及Filesaver.js下載地址:
https://stuk.github.io/jszip/

1.點(diǎn)擊download.JSZip

2.解壓后將dist文件夾下的jszip.js文件以及vendor文件夾下的FileSaver.js文件拷貝到項(xiàng)目中


至此戒祠,所需工具已齊全。以下直接附上項(xiàng)目完整代碼(代碼可直接復(fù)制使用速种,查看效果姜盈。對應(yīng)的文件需自行下載引入)

源代碼:嫌麻煩的小伙伴可以直接在公眾號后回復(fù):pdf轉(zhuǎn)圖片

代碼實(shí)現(xiàn)

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>PDF文件轉(zhuǎn)圖片</title>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript" src="js/pdf.js"></script>
<script type="text/javascript" src="js/pdf.worker.js"></script>
<script type="text/javascript" src="js/jszip.js"></script>
<script type="text/javascript" src="js/FileSaver.js"></script>
<style type="text/css">

  button {
    width: 120px;
    height: 30px;
    background: none;
    border: 1px solid #b1afaf;
    border-radius: 5px;
    font-size: 12px;
    font-weight: 1000;
    color: #384240;
    cursor: pointer;
    outline: none;
    margin: 0 0.5%
  }

  button:hover {
    background: #ccc;
  }

  #container {
      width: 600px;
      height: 780px;
      margin-top: 1%;
    border-radius: 2px;
    border: 2px solid #a29b9b;
  }

  .pdfInfos {
    margin: 0 2%;
  }
</style>
</head>

<body>

  <div style="margin-top:1%">            
      <button id="prevpage">上一頁</button>
      <button id="nextpage">下一頁</button>
    <button id="exportImg">導(dǎo)出圖片</button>
    <button onclick="choosePdf()">選擇一個(gè)pdf文件</button>
    <input style="display:none" id='chooseFile' type='file' accept="application/pdf">
  </div>

  <div style="margin-top:1%">
    <span class="pdfInfos">頁碼:<span id="currentPages"></span><span id="totalPages"></span></span>
    <span class="pdfInfos">文件名:<span id="fileName"></span></span>
    <span class="pdfInfos">文件大小:<span id="fileSize"></span></span>
  </div>

  <div style="position: relative;">
    <div id="container"></div>
    <img id="imgloading" style="position: absolute;top: 20%;left: 2%;display:none" src="loading.gif">
  </div>

</body>


<script>

  var currentPages,totalPages //聲明一個(gè)當(dāng)前頁碼及總頁數(shù)變量
  var scale = 2; //設(shè)置縮放比例配阵,越大生成圖片越清晰

  $('#chooseFile').change(function() {
    var pdfFilePath = $('#chooseFile').val();
    if(pdfFilePath) {

      $("#imgloading").css('display','block');
      $("#container").empty(); //清空上一PDF文件展示圖

      currentPages=1; //重置當(dāng)前頁數(shù)
      totalPages=0; //重置總頁數(shù)

        var filesdata = $('#chooseFile')[0].files; //jquery獲取到文件 返回屬性的值
      var fileSize = filesdata[0].size; //文件大小
      var mb;

      if(fileSize) {
        mb = fileSize / 1048576;
        if(mb > 10) {
          alert("文件大小不能>10M");
          return;
        }
      }

      $("#fileName").text(filesdata[0].name);
      $("#fileSize").text(mb.toFixed(2) + "Mb");

      var reader = new FileReader();
      reader.readAsDataURL(filesdata[0]); //將文件讀取為 DataURL
      reader.onload = function(e) { //文件讀取成功完成時(shí)觸發(fā)

        pdfjsLib.getDocument(this.result).then(function(pdf) { //調(diào)用pdf.js獲取文件
          if(pdf) {
            totalPages = pdf.numPages; //獲取pdf文件總頁數(shù)
            $("#currentPages").text("1/");
            $("#totalPages").text(totalPages);

            //遍歷動(dòng)態(tài)創(chuàng)建canvas
            for(var i = 1; i <= totalPages; i++) {
              var canvas = document.createElement('canvas');
              canvas.id = "pageNum" + i;
              $("#container").append(canvas);
              var context = canvas.getContext('2d');
              renderImg(pdf,i,context);
            }

          }
        });

      };
    }
  });

  //渲染生成圖片
  function renderImg(pdfFile,pageNumber,canvasContext) {
    pdfFile.getPage(pageNumber).then(function(page) { //逐頁解析PDF
      var viewport = page.getViewport(scale); // 頁面縮放比例
      var newcanvas = canvasContext.canvas;

      //設(shè)置canvas真實(shí)寬高
      newcanvas.width = viewport.width;
      newcanvas.height = viewport.height;

      //設(shè)置canvas在瀏覽中寬高
      newcanvas.style.width = "100%";
      newcanvas.style.height = "100%";

      //默認(rèn)顯示第一頁馏颂,其他頁隱藏
      if (pageNumber!=1) {
         newcanvas.style.display = "none";
      }

      var renderContext = {
        canvasContext: canvasContext,
        viewport: viewport
      };

      page.render(renderContext); //渲染生成
    });

    $("#imgloading").css('display','none');

    return;
  };

  //上一頁
  $("#prevpage").click(function(){

        if (!currentPages||currentPages <= 1) {
            return;
        }

    nowpage=currentPages;
        currentPages--;

    $("#currentPages").text(currentPages+"/");

    var prevcanvas = document.getElementById("pageNum"+currentPages);
    var currentcanvas = document.getElementById("pageNum"+nowpage);
    currentcanvas.style.display = "none";
    prevcanvas.style.display = "block";

  })

  //下一頁
  $("#nextpage").click(function(){

    if (!currentPages||currentPages>=totalPages) {
      return;
    }

    nowpage=currentPages;
    currentPages++;

    $("#currentPages").text(currentPages+"/");

    var nextcanvas = document.getElementById("pageNum"+currentPages);
    var currentcanvas = document.getElementById("pageNum"+nowpage);
    currentcanvas.style.display = "none";
    nextcanvas.style.display = "block";

  })

  //導(dǎo)出圖片
  $("#exportImg").click(function() {

    if (!$('#chooseFile').val()) {
      alert('請先上傳pdf文件')
      return false;
    }

    $("#imgloading").css('display','block');

    var zip = new JSZip(); //創(chuàng)建一個(gè)JSZip實(shí)例
    var images = zip.folder("images"); //創(chuàng)建一個(gè)文件夾用來存放圖片

    //遍歷canvas,將其生成圖片放進(jìn)文件夾images中
    $("canvas").each(function(index, ele) {
      var canvas = document.getElementById("pageNum" + (index + 1));

      //將圖片放進(jìn)文件夾images中
      //參數(shù)1為圖片名稱棋傍,參數(shù)2為圖片數(shù)據(jù)(格式為base64救拉,需去除base64前綴 data:image/png;base64)
      images.file("photo-" + (index + 1) + ".png", splitBase64(canvas.toDataURL("image/png", 1.0)), {
        base64: true
      });

    })

    //打包下載
    zip.generateAsync({
      type: "blob"
    }).then(function(content) {
      saveAs(content, "picture.zip"); //saveAs依賴的js文件是FileSaver.js
        $("#imgloading").css('display','none');
    });

  });

  //截取base64前綴
  function splitBase64(dataurl) {
    var arr = dataurl.split(',')
    return arr[1]
  }

  function choosePdf(){
    $("#chooseFile").click()
  }
</script>
</html>

項(xiàng)目實(shí)現(xiàn)原理分析

  1. 首先利用pdf.js將上傳的pdf文件轉(zhuǎn)化成canvas
  2. 然后使用jszip.js將canvas打包圖片生成.zip文件
  3. 最后使用Filesaver.js將zip文件保存下載

項(xiàng)目注意要點(diǎn)

  1. 由于pdf文件是通過上傳的,因此需要通過js的FileReader()對象將其讀取為DataURL瘫拣,pdf.js文件才可讀取渲染
  2. JSZip對象的.file()函數(shù)中第二個(gè)參數(shù)傳入的是base64格式圖片亿絮,但是要去掉base64前綴標(biāo)識

最后

覺得文章不錯(cuò)的,請點(diǎn)個(gè)贊哇麸拄!
文章首發(fā)于微信公眾號:GitWeb派昧,歡迎關(guān)注學(xué)習(xí)技術(shù)討論交流。
微信交流群:公眾號內(nèi)加好友拢切,拉你入群

歡迎關(guān)注
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蒂萎,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子淮椰,更是在濱河造成了極大的恐慌五慈,老刑警劉巖纳寂,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異泻拦,居然都是意外死亡毙芜,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門聪轿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來爷肝,“玉大人猾浦,你說我怎么就攤上這事陆错。” “怎么了金赦?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵音瓷,是天一觀的道長。 經(jīng)常有香客問我夹抗,道長绳慎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任漠烧,我火速辦了婚禮杏愤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘已脓。我一直安慰自己珊楼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布度液。 她就那樣靜靜地躺著厕宗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪堕担。 梳的紋絲不亂的頭發(fā)上已慢,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機(jī)與錄音霹购,去河邊找鬼佑惠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛齐疙,可吹牛的內(nèi)容都是我干的兢仰。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼剂碴,長吁一口氣:“原來是場噩夢啊……” “哼把将!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起忆矛,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤察蹲,失蹤者是張志新(化名)和其女友劉穎请垛,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體洽议,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宗收,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了亚兄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片混稽。...
    茶點(diǎn)故事閱讀 38,059評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖审胚,靈堂內(nèi)的尸體忽然破棺而出匈勋,到底是詐尸還是另有隱情,我是刑警寧澤膳叨,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布洽洁,位于F島的核電站,受9級特大地震影響菲嘴,放射性物質(zhì)發(fā)生泄漏饿自。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一龄坪、第九天 我趴在偏房一處隱蔽的房頂上張望昭雌。 院中可真熱鬧,春花似錦健田、人聲如沸烛卧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽唱星。三九已至,卻和暖如春跟磨,著一層夾襖步出監(jiān)牢的瞬間间聊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工抵拘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留哎榴,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓僵蛛,卻偏偏與公主長得像尚蝌,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子充尉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容