pdf.js 流文件展示,禁止下载,限制用户查看页数,保存阅读进度.

前端有时会在页面展示pdf文件,falsh也可以展示pdf文件,但是效果不好,不可控制。pdf.js可以很好的实现该功能,可以接受后台二进制的pdf流文件或者后台提供的有URL地址的PDF文件。下图是我展示的效果:

上图pdf展示有下面几个功能可以控制:

1.pdf.js 可以从后台获取二进制pdf流文件展示,或者常规拥有URL的pdf文件

2.可控用户是否有权限下载,打印。

3.可控用户是否有权限查看pdf全部内容(一般用户只能查看前几页内容)

4.可控在pdf文档附上水印。

5.用户可保存阅读进度,下次可从保存进度出浏览。(也就是默认显示指定页面的功能)

1.上面案例是有pdf官网提供的demo修改而成的,首先要去官网下载demo https://mozilla.github.io/pdf.js/

1.从后台获取流文件进行内容展示,(注意:该功能只能在pdf页面没渲染前发送ajax获取pdf流文件数据,然后进行渲染.目前我还没想到好的办法,在A页面获取二进制数据流文件,去其他页面进行渲染)

  首先官网下载后

  注释掉build\generic\web\viewer.js  中的

var DEFAULT_URL = 'compressed.tracemonkey-pldi-09.pdf';  这个变量 

然后在引入build\generic\web\viewer.html页面中引入下面代码(注意:要在引入viewer.js前引入)

    <script type="text/javascript">
      $.ajax({
          type:"post",
          async:false,
          mimeType: 'text/plain; charset=utf-8',
          url:后台地址URL,
          success:function(data){
             PDFData = data;
          },
          error:function () {
            alert('加载失败')
          }
      }); 

        var rawLength = PDFData.length;
        //转换成pdf.js能直接解析的Uint8Array类型,见pdf.js-4068
        var array = new Uint8Array(new ArrayBuffer(rawLength));
        for(i = 0; i < rawLength; i++) {
          array[i] = PDFData.charCodeAt(i) & 0xff;
        }
        DEFAULT_URL = array 
    </script>

这样就可以实现二进制数据流展示pdf文件了,如果是常规的URL地址文件,则直接把PDFdata 赋值给 DEFAULT_URL即可。

2.可控制用户下载 打印功能。

  该功能我是控制下载 和打印按钮的显示和隐藏,实际逻辑没有改变,只是改变了视图。

js代码

if (ControlBtn) {
        $('#print').css('display','none')
        $('#download').css('display','none')
      } else {
        $('#baifen').css('right','216px')
        $('#print').css('display','inline-block')
        $('#download').css('display','inline-block')
      }

html代码:

             <div id="baifen">
                <span>阅读进度:<i id="baifenpro">0%</i></span>
                 <span title="保存阅读进度" class="keepbtn"></span>
              </div>
              <div id="toolbarViewerRight">
                <button id="presentationMode" class="toolbarButton presentationMode hiddenLargeView" title="Switch to Presentation Mode" tabindex="31" data-l10n-id="presentation_mode">
                  <span data-l10n-id="presentation_mode_label">Presentation Mode</span>
                </button>

                <button id="openFile" class="toolbarButton openFile hiddenLargeView" title="Open File" tabindex="32" data-l10n-id="open_file">
                  <span data-l10n-id="open_file_label">Open</span>
                </button>

                <button id="print"  class="toolbarButton print hiddenMediumView" title="Print" tabindex="33" data-l10n-id="print">
                  <span data-l10n-id="print_label">Print</span>
                </button>

                <button id="download"   class="toolbarButton download hiddenMediumView" title="Download" tabindex="34" data-l10n-id="download">
                  <span data-l10n-id="download_label">Download</span>
                </button>
                <a href="#" id="viewBookmark" class="toolbarButton bookmark hiddenSmallView" title="Current view (copy or open in new window)" tabindex="35" data-l10n-id="bookmark">
                  <span data-l10n-id="bookmark_label">Current View</span>
                </a>

                <div class="verticalToolbarSeparator hiddenSmallView"></div>

                <button id="secondaryToolbarToggle" class="toolbarButton" title="Tools" tabindex="36" data-l10n-id="tools">
                  <span data-l10n-id="tools_label">Tools</span>
                </button>
              </div>

css代码

 @media  screen and (max-width:1024px) {
      #baifen {
        display:none;
      }
    }
    #baifen{
      position:relative;
      float: right;
      right: 150px;
      line-height:32px;
      text-align: center;
      font-size:12px;
      color:#ddd;
    }
    .cover{
       position:absolute;
       top:0;
      overflow:hidden;
    }
    #baifenpro{
      font-style: normal;
    }
    #baifen .keepbtn{
      display:inline-block;
      width:16px;
      height:14px;
      padding:2px 2px 0px 3px;
      background:#474747 url('images/keep1.png') no-repeat center;
      vertical-align: sub;
    }

由上面的代码可以看出下载和打印显示与否 是由ControlBtn 这个变量控制。还增加了阅读进度的显示和保存阅读进度的按钮

3.可控用户是否有权限查看pdf全部内容(一般用户只能查看前几页内容)

 该功能 需要去build\generic\web\viewer.js  中修改

var PDFFintPageNumber = 3; // 阅读进度的变量
var LimitPage = 0;  // 是否限制页数的变量
var ControlBtn = true; // 是否显示下载的变量
var DEFAULT_URL = 'compressed.tracemonkey-pldi-09.pdf';
var DEFAULT_SCALE_DELTA = 1.1;
var MIN_SCALE = 0.25;
var MAX_SCALE = 10.0;
var VIEW_HISTORY_MEMORY = 20;
var SCALE_SELECT_CONTAINER_PADDING = 8;
var SCALE_SELECT_PADDING = 22;
var PAGE_NUMBER_LOADING_INDICATOR = 'visiblePageIsLoading';
var DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT = 5000;

我声明了一个 LimitPage 的变量 进行控制是否限制页数和限制几页

this.pdfDocument.getMetadata().then(function(data) {
        var content = {
          'fileName': getPDFFileNameFromURL(this.url),
          'fileSize': this._parseFileSize(),
          'title': data.info.Title,
          'author': data.info.Author,
          'subject': data.info.Subject,
          'keywords': data.info.Keywords,
          'creationDate': this._parseDate(data.info.CreationDate),
          'modificationDate': this._parseDate(data.info.ModDate),
          'creator': data.info.Creator,
          'producer': data.info.Producer,
          'version': data.info.PDFFormatVersion,
          'pageCount': LimitPage ? LimitPage : this.pdfDocument.numPages
        };


 var pagesCount = LimitPage ? LimitPage : pdfDocument.numPages;
      var pagesRefMap = this.pagesRefMap = {};
      var self = this;


   return pdfDocument.getPage(1).then(function (firstPage) {
        var pagesCount = LimitPage ? LimitPage : pdfDocument.numPages;
        var viewport = firstPage.getViewport(1.0);
        for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) {
          var thumbnail = new PDFThumbnailView({
            container: this.container,
            id: pageNum,
            defaultViewport: viewport.clone(),
            linkService: this.linkService,
            renderingQueue: this.renderingQueue
          });
          this.thumbnails.push(thumbnail);
        }
      }.bind(this));
    },


var pagesCount = LimitPage ? LimitPage : pdfDocument.numPages;
    document.getElementById('numPages').textContent =
      mozL10n.get('page_of', {pageCount: pagesCount}, 'of {{pageCount}}');
    document.getElementById('pageNumber').max = pagesCount;

    var id = this.documentFingerprint = pdfDocument.fingerprint;
    var store = this.store = new ViewHistory(id);

我在这里更改了4处内容,用三元运算符和变量改变了是否显示全部页数和限制页数的功能。

我是根据 pdfDocument.numPages 这个变量来进行决定是否要把值替换成三元运算符表单式的

4.可控在pdf文档附上水印

水印功能上面css代码已经写了,我这里只展示js代码(该功能 需要去build\generic\web\viewer.js  中修改)

canvas.width = (Math.floor(viewport.width) * outputScale.sx) | 0;
      canvas.height = (Math.floor(viewport.height) * outputScale.sy) | 0;
      canvas.style.width = Math.floor(viewport.width) + 'px';
      canvas.style.height = Math.floor(viewport.height) + 'px';
      // Add the viewport so it's known what it was originally drawn with.
      canvas._viewport = viewport;

      var textLayerDiv = null;
      var textLayer = null;
      if (this.textLayerFactory) {
        textLayerDiv = document.createElement('div');
        textLayerDiv.className = 'textLayer';
        textLayerDiv.style.width = canvas.style.width;
        textLayerDiv.style.height = canvas.style.height;
      // 从这里开始 水印
      var cover = document.createElement('div');
          cover.className = "cover";
          var defaultSettings = {
              watermark_txt: "福通",
              watermark_x: 0,//水印起始位置x轴坐标
              watermark_y: 0,//水印起始位置Y轴坐标
              watermark_rows: 20,//水印行数
              watermark_cols: 50,//水印列数
              watermark_x_space: 20,//水印x轴间隔
              watermark_y_space: 20,//水印y轴间隔
              watermark_color: 'red',//水印字体颜色
              watermark_alpha: 0.3,//水印透明度
              watermark_fontsize: '20px',//水印字体大小
              watermark_font: '微软雅黑',//水印字体
              watermark_width: 120,//水印宽度
              watermark_height: 80,//水印长度
              watermark_angle: 45//水印倾斜度数
          };
          var oTemp = document.createDocumentFragment();

          //获取页面最大宽度
          var page_width = Math.max(document.body.scrollWidth, canvas.style.width);
          //获取页面最大长度
          var page_height = Math.max(document.body.scrollHeight, canvas.style.height);
          //如果将水印列数设置为0,或水印列数设置过大,超过页面最大宽度,则重新计算水印列数和水印x轴间隔
          if (defaultSettings.watermark_cols == 0 || (parseInt(defaultSettings.watermark_x + defaultSettings.watermark_width * defaultSettings.watermark_cols + defaultSettings.watermark_x_space * (defaultSettings.watermark_cols - 1)) > page_width)) {
              defaultSettings.watermark_cols = parseInt((page_width - defaultSettings.watermark_x + defaultSettings.watermark_x_space) / (defaultSettings.watermark_width + defaultSettings.watermark_x_space));
              defaultSettings.watermark_x_space = parseInt((page_width - defaultSettings.watermark_x - defaultSettings.watermark_width * defaultSettings.watermark_cols) / (defaultSettings.watermark_cols - 1));
          }
          //如果将水印行数设置为0,或水印行数设置过大,超过页面最大长度,则重新计算水印行数和水印y轴间隔
          if (defaultSettings.watermark_rows == 0 || (parseInt(defaultSettings.watermark_y + defaultSettings.watermark_height * defaultSettings.watermark_rows + defaultSettings.watermark_y_space * (defaultSettings.watermark_rows - 1)) > page_height)) {
              defaultSettings.watermark_rows = parseInt((defaultSettings.watermark_y_space + page_height - defaultSettings.watermark_y) / (defaultSettings.watermark_height + defaultSettings.watermark_y_space));
              defaultSettings.watermark_y_space = parseInt(((page_height - defaultSettings.watermark_y) - defaultSettings.watermark_height * defaultSettings.watermark_rows) / (defaultSettings.watermark_rows - 1));
          }
          var x;
          var y;
          for (var i = 0; i < defaultSettings.watermark_rows; i++) {
              y = defaultSettings.watermark_y + (defaultSettings.watermark_y_space + defaultSettings.watermark_height) * i;
              for (var j = 0; j < defaultSettings.watermark_cols; j++) {
                  x = defaultSettings.watermark_x + (defaultSettings.watermark_width + defaultSettings.watermark_x_space) * j;

                  var mask_div = document.createElement('div');
                  mask_div.id = 'mask_div' + i + j;
                  mask_div.className = 'mask_div';
                  mask_div.appendChild(document.createTextNode(defaultSettings.watermark_txt));
                  //设置水印div倾斜显示
                  mask_div.style.webkitTransform = "rotate(-" + defaultSettings.watermark_angle + "deg)";
                  mask_div.style.MozTransform = "rotate(-" + defaultSettings.watermark_angle + "deg)";
                  mask_div.style.msTransform = "rotate(-" + defaultSettings.watermark_angle + "deg)";
                  mask_div.style.OTransform = "rotate(-" + defaultSettings.watermark_angle + "deg)";
                  mask_div.style.transform = "rotate(-" + defaultSettings.watermark_angle + "deg)";
                  mask_div.style.visibility = "";
                  mask_div.style.position = "absolute";
                  //奇偶行错开,这样水印就不对齐,显的不呆板
                  if (i % 2 != 0) {
                      mask_div.style.left = x + 100 + 'px';
                  } else {
                      mask_div.style.left = x + 'px';
                  }
                  mask_div.style.top = y + 'px';
                  mask_div.style.overflow = "hidden";
                  mask_div.style.opacity = defaultSettings.watermark_alpha;
                  mask_div.style.fontSize = defaultSettings.watermark_fontsize;
                  mask_div.style.fontFamily = defaultSettings.watermark_font;
                  mask_div.style.color = defaultSettings.watermark_color;
                  mask_div.style.textAlign = "center";
                  mask_div.style.width = canvasWrapper.style.width + 'px';
                  mask_div.style.height = canvasWrapper.style.height + 'px';
                  mask_div.style.display = "block";
                  oTemp.appendChild(mask_div);
              }
          }
          cover.appendChild(oTemp);
      //  大字水印
      // var cover = document.createElement('div');
      //     cover.className = "cover";
      //     cover.innerText = "北京";
      // 结束
        if (this.annotationLayer) {
          // annotationLayer needs to stay on top
          div.insertBefore(textLayerDiv, this.annotationLayer.div);
          // 添加水印
          div.appendChild(cover);
        } else {
          div.appendChild(textLayerDiv);
          // 添加水印
          div.appendChild(cover);
        }

        textLayer = this.textLayerFactory.createTextLayerBuilder(textLayerDiv,
                                                                 this.id - 1,
                                                                 this.viewport);
        // 添加水印
        var cover = document.getElementsByClassName('cover');
            for (var i = 0, len = cover.length; i < len; i++) {
                cover[i].style.width = canvasWrapper.style.width;
                cover[i].style.height = canvasWrapper.style.height;
            }
        var cover = document.getElementsByClassName('cover'),size = 0,
            nowWidth = +canvas.style.width.split("p")[0],
            //714为100%时,每页的宽度。对比当前的宽度可以计算出页面变化后字体的数值
            size = 30*nowWidth/714 +"px";  
            for(var i=0, len=cover.length; i<len; i++) {   
                cover[i].style.fontSize = size;
                cover[i].style.width = canvas.style.width;
                cover[i].style.height = canvas.style.height;            
             }
        // 水印结束
      }
      this.textLayer = textLayer;

上面有两个水印,我注释掉了一个,只要按照我的方法添加水印,即可出现效果,水印我没用变量控制,小伙伴们可以变量进行控制。

5.用户可保存阅读进度,下次可从保存进度出浏览

 其实这个功能我是想用户关闭浏览器/刷新浏览器/退后/ 时发送进度给后台,但是遇到各种各样的问题,就增加了一个保存按钮,确保用户可以把进度保存到后台中。

该功能只要只要记录到用户当前看到第几页就可以(这个功能更简单)

由于人家已经记录了现在的页数,我们只要用常规的方法获取input的value即可。如果大家还是不明白,我把我这个demo文件已经上传到我资源中,大家可以下载

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值