vue 在线阅读PDF

项目中使用到在线阅读PDF的功能很常见,平时的话,我都用的window.open或者下面这俩属性,都可以直接展示出来

<object :data="fileById" width="90%" height="600"/>
<embed :src="fileById" style=" width:90%;height: 600px; " /> 

但是用户那边有要求,不能右键下载,复制之类的,本来想用pdf.js去处理的,在途中突然发现vue-pdf这个东西,发现还挺不错的,简单记录一下,直接上效果图和代码
在这里插入图片描述

安装:npm install --save vue-pdf
引入:import pdf from 'vue-pdf'
 components:{
           pdf
       },

demo代码:

<template>
    <!--筛选查询-->
    <!--设置默认被选中-->
    <div>
      <el-row>
        <el-col :span="20" ><div class="grid-content bg-purple"  >
           <!-- <object data="http://192.168.6.98:8080/profile/tmp/shardingsphere_docs_cn1622625198005.pdf" width="90%" height="600"/> -->
           <div style="width: 100px;position: fixed;top: 50%;z-index: 99;left: 10%;">
              <el-button icon="el-icon-top" @click.stop="prePage" style="display: block;margin-left: 10px;" />
              <span style="color: red;margin-left: 20px;">{{pageNum}}/{{pageTotalNum}}</span>
              <el-button @click.stop="nextPage" icon="el-icon-bottom" style="display: block;margin-left: 10px;"  />
              <el-button icon="el-icon-refresh-right" @click.stop="clock"  style="display: block;" />
              <el-button icon="el-icon-refresh-left"  @click.stop="counterClock"  style="display: block;" />
              <el-button @touchstart="idx=0" @touchend="idx=-1" @click="scaleD" icon="el-icon-zoom-in"  style="display: block;" />
              <el-button @touchstart="idx=1" @touchend="idx=-1" @click="scaleX" icon="el-icon-zoom-out"  style="display: block;" />
           </div>
           		<pdf ref="pdf"
           		:src="url"
           		:page="pageNum"
           		:rotate="pageRotate"
           		@progress="loadedRatio = $event"
           		@page-loaded="pageLoaded($event)"
           		@num-pages="pageTotalNum=$event"
           		@error="pdfError($event)"
           		@link-clicked="page = $event">
           		</pdf>
        </div></el-col>
        <el-col :span="4" class="detailsMsg"><div class="grid-content bg-purple-light">
             1
            111
        </div></el-col>
      </el-row>
    </div>
</template>


<script>
  import pdf from 'vue-pdf'
   export default {
     name: 'hello',
      components:{
           pdf
       },
     data () {
       return {
         msg: 'Welcome to Your Vue.js App',
          url:"http://192.168.6.98:8080/profile/tmp/shardingsphere_docs_cn1622625198005.pdf",
          				pageNum: 1,
          				pageTotalNum: 1,
          				pageRotate: 0,
          				// 加载进度
          				loadedRatio: 0,
          				curPageNum: 0,
                   scale: 100, //放大系数
                          idx: -1,
       }
     },
     methods: {
         // 上一页函数,
        			prePage() {
        				var page = this.pageNum
        				page = page > 1 ? page - 1 : this.pageTotalNum
        				this.pageNum = page
        			},
                    // 下一页函数
        			nextPage() {
        				var page = this.pageNum
        				page = page < this.pageTotalNum ? page + 1 : 1
        				this.pageNum = page
        			},
                    // 页面顺时针翻转90度。
        			clock() {
        				this.pageRotate += 90
        			},
                    // 页面逆时针翻转90度。
        			counterClock() {
        				this.pageRotate -= 90
        			},
                    // 页面加载回调函数,其中e为当前页数
        			pageLoaded(e) {
        				this.curPageNum = e
        			},
                    // 其他的一些回调函数。
        			pdfError(error) {
        				console.error(error)
        			},
               //放大
              scaleD() {
                this.scale += 5;
                this.$refs.pdf.$el.style.width = parseInt(this.scale) + "%";
              },

              //缩小
              scaleX() {
                if (this.scale == 50) {
                  return;
                }
                this.scale += -5;
                this.$refs.pdf.$el.style.width = parseInt(this.scale) + "%";
              },
     }
   }
</script>

<style>
</style>

参考地址:https://www.cnblogs.com/shaozhu520/p/12801184.html

这上面存在一个问题,就是我用代码处理过的PDF是带有水印的,但是这里水印却不显示了,百度相关却没有找到好的解决方案,然后通过前端处理了一下。
首先自定义一下水印指令 新建watermark.js

import Vue from "vue";

Vue.directive("watermark", (el, binding) => {
  (function (str, container, id, font) {
    setTimeout(function () {
      var containerWidth = container.offsetWidth || "400"; // 获取父容器宽
      var containerHeight = container.offsetHeight || "100"; // 获取父容器高
      container.style.position = "relative"; // 设置布局为相对布局

      // 创建canvas元素(先制作一块背景图)
      const can = document.createElement("canvas");
      can.width = containerWidth; // 设置每一块的宽度
      can.height = containerHeight; // 高度
      const cans = can.getContext("2d"); // 获取canvas画布
      cans.rotate((-20 * Math.PI) / 270); // 逆时针旋转π/9
      cans.font = font || "20px PingFang-SC-Regular"; // 设置字体
      cans.fillStyle = "rgba(219,8,8, 0.3)"; // 设置字体的颜色
      cans.textAlign = "left"; // 文本对齐方式
      cans.textBaseline = "Middle"; // 文本基线
      cans.fillText(str, 0, (4 * can.height) / 5); // 绘制文字
       cans.fillText(str, 0, (4 * can.height) / 10); // 绘制文字

      // 创建一个div元素
      const div = document.createElement("div");
      div.id = id; // 设置id
      div.style.pointerEvents = "none"; // 取消所有事件
      div.style.top = "-15px";
      div.style.left = "80px";
      div.style.position = "absolute";
      div.style.zIndex = "100000";
      div.style.width = containerWidth + "px";
      div.style.height = containerHeight + "px";
      div.style.background =
        "url(" + can.toDataURL("image/png") + ") left top repeat";
      container.appendChild(div); // 追加到页面
    }, 300);
  })(binding.value.text, el, binding.value.id, binding.value.font);
});

然后在main.js引入import "@/api/file/watermark";
使用如下:

<div v-watermark="{id: 'watermark',text: waterMark,font: '46px Microsoft JhengHei',}">
</div>

waterMark 是你动态传入的水印值

参考地址:https://www.cnblogs.com/zhaomeizi/p/13577701.html

如果打包运行出现 ***worker.js 404 错误,
在这里插入图片描述

解决方案:
找到该目录 node_modules/worker-loader/dist/index.js
修改

const filename = _loaderUtils2.default.interpolateName(this, options.name || '[hash].worker.js', {
	    context: options.context || this.rootContext || this.options.context,
	    regExp: options.regExp
  	});

修改后

const filename = _loaderUtils2.default.interpolateName(this, options.name || 'static/js/[hash].worker.js', {
	   	 context: options.context || this.rootContext || this.options.context,
   		regExp: options.regExp
  	});

成功解决

20211026处理打印乱码
官方提供的解决方案:https://github.com/FranckFreiburger/vue-pdf/pull/130/commits/253f6186ff0676abf9277786087dda8d95dd8ea7
但是我按照这个修改后会出现多的空白页,也不能直接复制过来使用,所幸看到一个老哥也有过同样问题,他贴出来了修改后的代码,复制过来直接使用,没问题了

https://blog.csdn.net/qq_42249552/article/details/112860593

修改后的代码

import {PDFLinkService} from 'pdfjs-dist/es5/web/pdf_viewer';
 
var pendingOperation = Promise.resolve();
 
export default function (PDFJS) {
 
  function isPDFDocumentLoadingTask(obj) {
 
    return typeof (obj) === 'object' && obj !== null && obj.__PDFDocumentLoadingTask === true;
    // or: return obj.constructor.name === 'PDFDocumentLoadingTask';
  }
 
  function createLoadingTask(src, options) {
 
    var source;
    if (typeof (src) === 'string')
      source = {url: src};
    else if (src instanceof Uint8Array)
      source = {data: src};
    else if (typeof (src) === 'object' && src !== null)
      source = Object.assign({}, src);
    else
      throw new TypeError('invalid src type');
 
    // source.verbosity = PDFJS.VerbosityLevel.INFOS;
    // source.pdfBug = true;
    // source.stopAtErrors = true;
 
    if (options && options.withCredentials)
      source.withCredentials = options.withCredentials;
 
    var loadingTask = PDFJS.getDocument(source);
    loadingTask.__PDFDocumentLoadingTask = true; // since PDFDocumentLoadingTask is not public
 
    if (options && options.onPassword)
      loadingTask.onPassword = options.onPassword;
 
    if (options && options.onProgress)
      loadingTask.onProgress = options.onProgress;
 
    return loadingTask;
  }
 
 
  function PDFJSWrapper(canvasElt, annotationLayerElt, emitEvent) {
 
    var pdfDoc = null;
    var pdfPage = null;
    var pdfRender = null;
    var canceling = false;
 
    canvasElt.getContext('2d').save();
 
    function clearCanvas() {
 
      canvasElt.getContext('2d').clearRect(0, 0, canvasElt.width, canvasElt.height);
    }
 
    function clearAnnotations() {
 
      while (annotationLayerElt.firstChild)
        annotationLayerElt.removeChild(annotationLayerElt.firstChild);
    }
 
    this.destroy = function () {
 
      if (pdfDoc === null)
        return;
 
      // Aborts all network requests and destroys worker.
      pendingOperation = pdfDoc.destroy();
      pdfDoc = null;
    }
 
    this.getResolutionScale = function () {
 
      return canvasElt.offsetWidth / canvasElt.width;
    }
 
    this.printPage = function (dpi, pageNumberOnly) {
 
      if (pdfPage === null)
        return;
 
      // 1in == 72pt
      // 1in == 96px
      var PRINT_RESOLUTION = dpi === undefined ? 150 : dpi;
      var PRINT_UNITS = PRINT_RESOLUTION / 72.0;
      var CSS_UNITS = 96.0 / 72.0;
 
      var printContainerElement = document.createElement('div');
      printContainerElement.setAttribute('id', 'print-container')
 
      function removePrintContainer() {
 
        printContainerElement.parentNode.removeChild(printContainerElement);
      }
 
      new Promise(function (resolve, reject) {
 
        printContainerElement.frameBorder = '0';
        printContainerElement.scrolling = 'no';
        printContainerElement.width = '0px;'
        printContainerElement.height = '0px;'
        printContainerElement.style.cssText = 'position: absolute; top: 0; left: 0';
 
        window.document.body.appendChild(printContainerElement);
        resolve(window);
      })
        .then(function (win) {
 
          win.document.title = '';
 
          return pdfDoc.getPage(1)
            .then(function (page) {
 
              var viewport = page.getViewport({scale: 1});
              win.document.head.appendChild(win.document.createElement('style')).textContent =
                '@supports ((size:A4) and (size:1pt 1pt)) {' +
                '.print-canvas { display: none }' +
                '@media print {' +
                '* { margin: 0 ;padding: 0}' +
                '@page { margin: 3mm; size: ' + ((viewport.width * PRINT_UNITS) / CSS_UNITS) + 'pt ' + ((viewport.height * PRINT_UNITS) / CSS_UNITS) + 'pt; }' +
                '.print-canvas { page-break-before: avoid; page-break-after: always; page-break-inside: avoid; display: block }' +
                'body > *:not(#print-container) { display: none; }' +
                '}'
              return win;
            })
        })
        .then(function (win) {
 
          var allPages = [];
 
          for (var pageNumber = 1; pageNumber <= pdfDoc.numPages; ++pageNumber) {
 
            if (pageNumberOnly !== undefined && pageNumberOnly.indexOf(pageNumber) === -1)
              continue;
 
            allPages.push(
              pdfDoc.getPage(pageNumber)
                .then(function (page) {
 
 
                  var viewport = page.getViewport({scale: 1});
 
                  var printCanvasElt = printContainerElement.appendChild(win.document.createElement('canvas'));
                  printCanvasElt.setAttribute('class', 'print-canvas')
                  printCanvasElt.width = (viewport.width * PRINT_UNITS);
                  printCanvasElt.height = (viewport.height * PRINT_UNITS);
 
                  return page.render({
                    canvasContext: printCanvasElt.getContext('2d'),
                    transform: [ // Additional transform, applied just before viewport transform.
                      PRINT_UNITS, 0, 0,
                      PRINT_UNITS, 0, 0
                    ],
                    viewport: viewport,
                    intent: 'print'
                  }).promise;
                })
            );
          }
 
          Promise.all(allPages)
            .then(function () {
              win.focus(); // Required for IE
              if (win.document.queryCommandSupported('print')) {
                win.document.execCommand('print', false, false);
              } else {
                win.print();
              }
              removePrintContainer();
            })
            .catch(function (err) {
 
              removePrintContainer();
              emitEvent('error', err);
            })
        })
    }
 
    this.renderPage = function (rotate) {
      if (pdfRender !== null) {
 
        if (canceling)
          return;
        canceling = true;
        pdfRender.cancel();
        return;
      }
 
      if (pdfPage === null)
        return;
 
      var pageRotate = (pdfPage.rotate === undefined ? 0 : pdfPage.rotate) + (rotate === undefined ? 0 : rotate);
 
      var scale = canvasElt.offsetWidth / pdfPage.getViewport({scale: 1}).width * (window.devicePixelRatio || 1);
      var viewport = pdfPage.getViewport({scale: scale, rotation: pageRotate});
 
      emitEvent('page-size', viewport.width, viewport.height, scale);
 
      canvasElt.width = viewport.width;
      canvasElt.height = viewport.height;
 
      pdfRender = pdfPage.render({
        canvasContext: canvasElt.getContext('2d'),
        viewport: viewport
      });
 
      annotationLayerElt.style.visibility = 'hidden';
      clearAnnotations();
 
      var viewer = {
        scrollPageIntoView: function (params) {
          emitEvent('link-clicked', params.pageNumber)
        },
      };
 
      var linkService = new PDFLinkService();
      linkService.setDocument(pdfDoc);
      linkService.setViewer(viewer);
 
      pendingOperation = pendingOperation.then(function () {
 
        var getAnnotationsOperation =
          pdfPage.getAnnotations({intent: 'display'})
            .then(function (annotations) {
 
              PDFJS.AnnotationLayer.render({
                viewport: viewport.clone({dontFlip: true}),
                div: annotationLayerElt,
                annotations: annotations,
                page: pdfPage,
                linkService: linkService,
                renderInteractiveForms: false
              });
            });
 
        var pdfRenderOperation =
          pdfRender.promise
            .then(function () {
 
              annotationLayerElt.style.visibility = '';
              canceling = false;
              pdfRender = null;
            })
            .catch(function (err) {
 
              pdfRender = null;
              if (err instanceof PDFJS.RenderingCancelledException) {
 
                canceling = false;
                this.renderPage(rotate);
                return;
              }
              emitEvent('error', err);
            }.bind(this))
 
        return Promise.all([getAnnotationsOperation, pdfRenderOperation]);
      }.bind(this));
    }
 
 
    this.forEachPage = function (pageCallback) {
 
      var numPages = pdfDoc.numPages;
 
      (function next(pageNum) {
 
        pdfDoc.getPage(pageNum)
          .then(pageCallback)
          .then(function () {
 
            if (++pageNum <= numPages)
              next(pageNum);
          })
      })(1);
    }
 
 
    this.loadPage = function (pageNumber, rotate) {
 
      pdfPage = null;
 
      if (pdfDoc === null)
        return;
 
      pendingOperation = pendingOperation.then(function () {
 
        return pdfDoc.getPage(pageNumber);
      })
        .then(function (page) {
 
          pdfPage = page;
          this.renderPage(rotate);
          emitEvent('page-loaded', page.pageNumber);
        }.bind(this))
        .catch(function (err) {
 
          clearCanvas();
          clearAnnotations();
          emitEvent('error', err);
        });
    }
 
    this.loadDocument = function (src) {
 
      pdfDoc = null;
      pdfPage = null;
 
      emitEvent('num-pages', undefined);
 
      if (!src) {
 
        canvasElt.removeAttribute('width');
        canvasElt.removeAttribute('height');
        clearAnnotations();
        return;
      }
 
      // wait for pending operation ends
      pendingOperation = pendingOperation.then(function () {
 
        var loadingTask;
        if (isPDFDocumentLoadingTask(src)) {
 
          if (src.destroyed) {
 
            emitEvent('error', new Error('loadingTask has been destroyed'));
            return
          }
 
          loadingTask = src;
        } else {
 
          loadingTask = createLoadingTask(src, {
            onPassword: function (updatePassword, reason) {
 
              var reasonStr;
              switch (reason) {
                case PDFJS.PasswordResponses.NEED_PASSWORD:
                  reasonStr = 'NEED_PASSWORD';
                  break;
                case PDFJS.PasswordResponses.INCORRECT_PASSWORD:
                  reasonStr = 'INCORRECT_PASSWORD';
                  break;
              }
              emitEvent('password', updatePassword, reasonStr);
            },
            onProgress: function (status) {
 
              var ratio = status.loaded / status.total;
              emitEvent('progress', Math.min(ratio, 1));
            }
          });
        }
 
        return loadingTask.promise;
      })
        .then(function (pdf) {
 
          pdfDoc = pdf;
          emitEvent('num-pages', pdf.numPages);
          emitEvent('loaded');
        })
        .catch(function (err) {
 
          clearCanvas();
          clearAnnotations();
          emitEvent('error', err);
        })
    }
 
    annotationLayerElt.style.transformOrigin = '0 0';
  }
 
  return {
    createLoadingTask: createLoadingTask,
    PDFJSWrapper: PDFJSWrapper,
  }
}

2022-2-16 补更 涉及到打印问题了,火狐这边很难搞,最终选定pdf.js,由于火狐版本比较低,所以选择使用2.0.x版本的pdf.js去使用,感觉效果比较赞。
官网地址:http://mozilla.github.io/pdf.js/ 老版本自己找找吧,下载完解压后如下
在这里插入图片描述
把这三个文件放到public下面
在这里插入图片描述

页面使用: <iframe :src="'pdf/web/viewer.html?file='+this.fileById+'&locale=zh-CN'" style="width: 100%;height: 1000px;z-index: 999;">
在这里插入图片描述
第一次使用会有跨域问题,注释viewer.js 中throw new Error('file origin does not match viewer\'s')
在这里插入图片描述
其他常见问题就百度吧,效果嘎嘎的
在这里插入图片描述

**

pdf加密解密

**

 <repositories>
        <repository>
            <id>com.e-iceblue</id>
            <url>http://repo.e-iceblue.cn/repository/maven-public/</url>
        </repository>
    </repositories>
    <dependencies>
        <dependency>
            <groupId> e-iceblue </groupId>
            <artifactId>spire.pdf</artifactId>
            <version>3.4.2</version>
        </dependency>
   </dependencies>
     import com.spire.pdf.PdfDocument;
import com.spire.pdf.security.PdfEncryptionKeySize;
import com.spire.pdf.security.PdfPermissionsFlags;

import java.util.EnumSet;

public class PdfTest {
    public static void main(String[] args) {
        encryptPdf("C:\\Users\\ljw\\Desktop\\12\\1.pdf","C:\\Users\\ljw\\Desktop\\12\\2.pdf");

        decryptPdf("C:\\Users\\ljw\\Desktop\\12\\2.pdf","C:\\Users\\ljw\\Desktop\\12\\3.pdf");
    }

    private static String password="123456";

    /**
     *
     * @param orgFile 要加密的文件绝对地址
     * @param descFile 加密后的文件绝对地址
     */
    public static void encryptPdf(String orgFile,String descFile) {
        PdfDocument doc =null;
        try {
            //创建PdfDocument实例
            doc = new PdfDocument();
            //加载PDF文件
            doc.loadFromFile(orgFile);
            //加密PDF文件
            PdfEncryptionKeySize keySize = PdfEncryptionKeySize.Key_128_Bit;
            String openPassword = password;//打开文档时,仅用于查看文档
            String permissionPassword = password;//打开文档时,可编辑文档
            EnumSet flags = EnumSet.of(PdfPermissionsFlags.Print, PdfPermissionsFlags.Fill_Fields);
            doc.getSecurity().encrypt(openPassword, permissionPassword, flags, keySize);
            //保存文件
            doc.saveToFile(descFile);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(doc!=null) {
                doc.close();
            }
        }
    }

    /**
     *
     * @param orgFile 被加密的文件地址
     * @param descFile解密后的文件地址
     * @throws Exception
     */
    public static void decryptPdf(String orgFile,String descFile) {
        PdfDocument doc = null;
        try {
            //创建PdfDocument实例
            doc = new PdfDocument();
            //加载带密码保护的PDF文件
            doc.loadFromFile(orgFile, password);
            //解除文档中的密码保护
            doc.getSecurity().encrypt("", "", PdfPermissionsFlags.getDefaultPermissions(), PdfEncryptionKeySize.Key_256_Bit, password);
            //保存文件
            doc.saveToFile(descFile);
        } catch (Exception e) {
        }finally {
            if(doc!=null) {
                doc.close();
            }
        }
    }
}

在这里插入图片描述

在这里插入图片描述

解决生成的文件有水印警告

import com.spire.pdf.PdfDocument;
import com.spire.pdf.PdfPageBase;
import com.spire.pdf.security.PdfEncryptionKeySize;
import com.spire.pdf.security.PdfPermissionsFlags;

import java.util.EnumSet;

public class PdfTest {
    public static void main(String[] args) {
        encryptPdf("C:\\Users\\ljw\\Desktop\\12\\1.pdf","C:\\Users\\ljw\\Desktop\\12\\2.pdf");

        decryptPdf("C:\\Users\\ljw\\Desktop\\12\\2.pdf","C:\\Users\\ljw\\Desktop\\12\\3.pdf");
    }

    private static String password="123456";

    /**
     *
     * @param orgFile 要加密的文件绝对地址
     * @param descFile 加密后的文件绝对地址
     */
    public static void encryptPdf(String orgFile,String descFile) {
        PdfDocument doc =null;
        try {
            //创建PdfDocument实例
            doc = new PdfDocument();
            //加载PDF文件
            doc.loadFromFile(orgFile);
            //解决生成的文件有警告水印
            PdfPageBase pb = doc.getPages().add(); //新增一页
            doc.getPages().remove(pb);
            //加密PDF文件
            PdfEncryptionKeySize keySize = PdfEncryptionKeySize.Key_128_Bit;
            String openPassword = password;//打开文档时,仅用于查看文档
            String permissionPassword = password;//打开文档时,可编辑文档
            EnumSet flags = EnumSet.of(PdfPermissionsFlags.Print, PdfPermissionsFlags.Fill_Fields);
            doc.getSecurity().encrypt(openPassword, permissionPassword, flags, keySize);
            //保存文件
            doc.saveToFile(descFile);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(doc!=null) {
                doc.close();
            }
        }
    }

    /**
     *
     * @param orgFile 被加密的文件地址
     * @param descFile解密后的文件地址
     * @throws Exception
     */
    public static void decryptPdf(String orgFile,String descFile) {
        PdfDocument doc = null;
        try {
            //创建PdfDocument实例
            doc = new PdfDocument();
            //加载带密码保护的PDF文件
            doc.loadFromFile(orgFile, password);
            //解决生成的文件有警告水印
            PdfPageBase pb = doc.getPages().add(); //新增一页
            doc.getPages().remove(pb);
            //解除文档中的密码保护
            doc.getSecurity().encrypt("", "", PdfPermissionsFlags.getDefaultPermissions(), PdfEncryptionKeySize.Key_256_Bit, password);
            //保存文件
            doc.saveToFile(descFile);
        } catch (Exception e) {
        }finally {
            if(doc!=null) {
                doc.close();
            }
        }
    }
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值