解决vue-pdf查看pdf文件及打印乱码的问题


Posted in Javascript onNovember 04, 2020

前言

vue中简单使用vue-pdf预览pdf文件,解决打印预览乱码问题

vue-pdf 使用

安装

npm install --save vue-pdf

引入

import pdf from "vue-pdf

自定义封装pdf预览组件

<template>
 <el-dialog
  :visible.sync="pdfDialog"
  :close-on-click-modal="false"
  :show-close="false"
  width="900px"
  top="52px"
 >
  <div class="pdf" v-show="fileType == 'pdf'">
   <p class="arrow">
    <!-- 上一页 -->
    <span
     @click="changePdfPage(0)"
     class="currentPage"
     :class="{ grey: currentPage == 1 }"
     >上一页  </span
    >
    <span style="color: #8c8e92;">{{ currentPage }} / {{ pageCount }}</span>
    <!-- 下一页 -->
    <span
     @click="changePdfPage(1)"
     class="currentPage"
     :class="{ grey: currentPage == pageCount }"
     >  下一页</span
    >    <button @click="$refs.pdf.print()">下载</button>

    <span
     style="float :right;padding-right:40px;font-size: 20px;color: #8c8e92;cursor: pointer;"
     @click="close"
     ><i class="el-icon-close"></i
    ></span>
   </p>
   <!-- loadPdfHandler:加载事件 src:需要展示的PDF地址;currentPage:当前展示的PDF页码;pageCount=$event:PDF文件总页码;currentPage=$event:一开始加载的页面-->
   <pdf
     ref="pdf"
    :src="src"
    :page="currentPage"
    @num-pages="pageCount = $event"
    @page-loaded="currentPage = $event"
    @loaded="loadPdfHandler"
   ></pdf>
  </div>
 </el-dialog>
</template>

<script>
import pdf from "vue-pdf";
export default {
 components: { pdf },
 props: ["src"],
 data() {
  return {
   filesProps: {
    label: "originName"
   },
   pdfDialog: false,
   currentPage: 0, // pdf文件页码
   pageCount: 0, // pdf文件总页数
   fileType: "pdf" // 文件类型
  };
 },
 methods: {
  // 改变PDF页码,val传过来区分上一页下一页的值,0上一页,1下一页
  changePdfPage(val) {
   if (val === 0 && this.currentPage > 1) {
    this.currentPage--;
   }
   if (val === 1 && this.currentPage < this.pageCount) {
    this.currentPage++;
   }
  },
  // pdf加载时
  loadPdfHandler() {
   this.currentPage = 1; // 加载的时候先加载第一页
  },
  handleOpen() {
   this.pdfDialog = true;
  },
  //关闭弹框
  close() {
   this.pdfDialog = false;
  }
 }
};
</script>

<style lang="stylus">
.currentPage {
  cursor: pointer;
  color: #8c8e92;
}

.currentPage:hover {
  color: #2761ff;
}
.arrow{
  position: fixed;
  top: 0px;
  left :0px;
  z-index: 2;
  width: 100%;
  background-color: #191919;
  padding: 12px 0;
  margin: 0;
  text-align :center;
}
>>>.el-dialog__body {
  color: #606266;
  font-size: 14px;
  padding:0;
}
</style>

使用

<template>
 <el-container>
  <el-header>
   <el-card>
    <div>
     <el-button
      style="font-style:oblique;font-size: 18px;"
      @click="handlePreviewFile"
      >PDF 预览</el-button
     >
     <el-button
      style="float: right;line-height: 40px;padding: 3px;"
      type="text"
      @click="handleSafetyExperience"
      ><i class="el-icon-caret-left">返回</i></el-button
     >
    </div>
   </el-card>
  </el-header>
  <el-main>
   <el-card class="card-style">
    <pdf-preview ref="pdfSearch" :src="src"></pdf-preview>
   </el-card>
  </el-main>
 </el-container>
</template>

<script>
import PdfPreview from "../widget/PdfPreview";
export default {
 name: "InfoExperience",
 components: {
  PdfPreview
 },
 data() {
  return {
   src:
    "http://storage.xuetangx.com/public_assets/xuetangx/PDF/PlayerAPI_v1.0.6.pdf"
  };
 },
 created() {},
 methods: {
  handlePreviewFile() {
   this.$refs.pdfSearch.handleOpen();
  },
  handleSafetyExperience() {
   this.$router.push({ path: "/safetyApp/sharedExperience" });
  }
 }
};
</script>

<style scoped></style>

预览效果

解决vue-pdf查看pdf文件及打印乱码的问题

点击下载打印预览

预览出现乱码

解决vue-pdf查看pdf文件及打印乱码的问题

pdf打印乱码解决办法

打开vue-pdf插件目录node_modules/vue-pdf/src/pdfjsWrapper.js

解决vue-pdf查看pdf文件及打印乱码的问题

解决办法

详见Github上提供解决办法 Fix fonts issue in printing #130

乱码解决,打印预览正常

解决vue-pdf查看pdf文件及打印乱码的问题

修改后pdfjsWrapper.js源码

以下为本人修改的pdfjsWrapper.js文件,亲测解决乱码问题

import { PDFLinkService } from 'pdfjs-dist/lib/web/pdf_link_service';

export default function(PDFJS) {

 function isPDFDocumentLoadingTask(obj) {

 return typeof(obj) === 'object' && obj !== null && obj.__PDFDocumentLoadingTask === true;
 }

 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');

 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;
  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 iframeElt = document.createElement('iframe');
  var printContainerElement = document.createElement('div');
  printContainerElement.setAttribute('id', 'print-container')

  // function removeIframe() {
  //
  // iframeElt.parentNode.removeChild(iframeElt);
  function removePrintContainer() {
  printContainerElement.parentNode.removeChild(printContainerElement);

  }

  new Promise(function(resolve, reject) {

  // iframeElt.frameBorder = '0';
  // iframeElt.scrolling = 'no';
  // iframeElt.width = '0px;'
  // iframeElt.height = '0px;'
  // iframeElt.style.cssText = 'position: absolute; top: 0; left: 0';
  //
  // iframeElt.onload = function() {
  //
  // resolve(this.contentWindow);
  // }
  //
  // window.document.body.appendChild(iframeElt);
  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(1);
   // win.document.head.appendChild(win.document.createElement('style')).textContent =
   printContainerElement.appendChild(win.document.createElement('style')).textContent =
   '@supports ((size:A4) and (size:1pt 1pt)) {' +
    '@page { margin: 1pt; size: ' + ((viewport.width * PRINT_UNITS) / CSS_UNITS) + 'pt ' + ((viewport.height * PRINT_UNITS) / CSS_UNITS) + 'pt; }' +
   '}' +

   '#print-canvas { display: none }' +

   '@media print {' +
    'body { margin: 0 }' +
    'canvas { page-break-before: avoid; page-break-after: always; page-break-inside: avoid }' +
   '#print-canvas { page-break-before: avoid; page-break-after: always; page-break-inside: avoid; display: block }' +
   'body > *:not(#print-container) { display: none; }' +
   '}'+

   '@media screen {' +
    'body { margin: 0 }' +
   // '}'+
   //
   // ''
   '}'
   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(1);

    // var printCanvasElt = win.document.body.appendChild(win.document.createElement('canvas'));
    var printCanvasElt = printContainerElement.appendChild(win.document.createElement('canvas'));
    printCanvasElt.setAttribute('id', '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, null);
   } else {
   win.print();
    }
   // removeIframe();
   removePrintContainer();
  })
  .catch(function(err) {

   // removeIframe();
   removePrintContainer();
   emitEvent('error', err);
  })
  })
 }

 this.renderPage = function(rotate) {
  if ( pdfRender !== null ) {

  if ( canceling )
   return;
  canceling = true;
  pdfRender.cancel();
  return;
  }

  if ( pdfPage === null )
  return;

  if ( rotate === undefined )
  rotate = pdfPage.rotate;

  var scale = canvasElt.offsetWidth / pdfPage.getViewport(1).width * (window.devicePixelRatio || 1);
  var viewport = pdfPage.getViewport(scale, rotate);

  emitEvent('page-size', viewport.width, viewport.height);

  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);

  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
  });
  });

  pdfRender
  .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))
 }


 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;

  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;
  }

  if ( isPDFDocumentLoadingTask(src) ) {

  if ( src.destroyed ) {

   emitEvent('error', new Error('loadingTask has been destroyed'));
   return
  }

  var loadingTask = src;
  } else {

  var 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));
   }
  });
  }

  loadingTask
  .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,
 }
}

补充知识:vueshowpdf插件预览中文pdf出现乱码问题+pdf.js加载bcmap文件404报错

vue项目中使用到pdf在线预览,使用了vueshowpdf,测试pdf是好好的,但是当上传到服务器出现预览的pdf乱码问题,很是纠结,网上找了好多资料没有,于是找找pdf相关的pdf预览乱码(中文乱码)问题解决方案。

之前也试过pdf.js插件本地测试,当去掉cmaps文件夹之后PDF会乱码,添加之后又好了。查看.bcmap文件原来时候字体有关系的,于是估计就是字体问题。

解决方法:

1、下载pdf.js插件,复制cmaps文件夹放到vue项目中,我放在static文件夹下面

2、在对应使用到vueshowpdf插件中添加代码

***
PDFJS.cMapUrl = '../../static/cmaps/';
PDFJS.cMapPacked = true;
***
PDFJS.cMapUrl = '../../static/cmaps/';//这里面是相对路径

然后神奇的效果就是成功啦,不再乱码了。

注意:

可能您的页面在服务器端还会出现乱码,中文不识别,不要怕,我找到了问题所在,IIS的MIME问题(然后找到网上一篇文章,证实了我是的想法)

新增:2018-11-16

我们会发现

我的bcmp文件已经放到了对应目录了,配置也对了,怎么还是404

其实这个是iis的MIME文件设置

新增.bcmap文件 配置值 .bcmap -> image/svg+xml

我遇到的问题是.net项目,所以或者在Web.config添加如下代码

<system.webServer>
  <staticContent>
   <mimeMap fileExtension=".bcmap" mimeType="image/svg+xml" />
  </staticContent>
 </system.webServer>

现在重新运行下应该是可以了,如果还不行的话,暂时就不知道是什么原因引起的了

作为一个前端,难为我了!

以上这篇解决vue-pdf查看pdf文件及打印乱码的问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
在textarea中显示html页面的javascript代码
Apr 20 Javascript
Javascript中的delete介绍
Sep 02 Javascript
初识Node.js
Mar 20 Javascript
jquery转盘抽奖功能实现
Nov 13 Javascript
etmvc+jQuery EasyUI+combobox多值操作实现角色授权实例
Nov 09 Javascript
使用jQuery操作DOM的方法小结
Feb 27 Javascript
vue路由组件按需加载的几种方法小结
Jul 12 Javascript
js实现黑白div块画空心的图形
Dec 13 Javascript
jQuery实现的五星点评功能【案例】
Feb 18 jQuery
使用node搭建自动发图文微博机器人的方法
Mar 22 Javascript
layui实现数据表格自定义数据项
Oct 26 Javascript
微信小程序实现电子签名功能
Jul 29 Javascript
vantUI 获得piker选中值的自定义ID操作
Nov 04 #Javascript
浅谈vant组件Picker 选择器选单选问题
Nov 04 #Javascript
vue项目打包后请求地址错误/打包后跨域操作
Nov 04 #Javascript
原生JavaScript实现贪吃蛇游戏
Nov 04 #Javascript
通过实例解析javascript Date对象属性及方法
Nov 04 #Javascript
解决vue项目打包上服务器显示404错误,本地没出错的问题
Nov 03 #Javascript
解决vant-UI库修改样式无效的问题
Nov 03 #Javascript
You might like
星际争霸中的热键
2020/03/04 星际争霸
通达OA公共代码 php常用检测函数
2011/12/14 PHP
PHP答题类应用接口实例
2015/02/09 PHP
学习PHP session的传递方式
2016/06/15 PHP
jquery判断浏览器类型的代码
2012/11/05 Javascript
jQuery学习笔记(1)--用jQuery实现异步通信(用json传值)具体思路
2013/04/08 Javascript
jQuery实现鼠标滑过Div层背景变颜色的方法
2015/02/17 Javascript
JavaScript实现获得所有兄弟节点的方法
2015/07/23 Javascript
高性能JavaScript DOM编程(1)
2015/08/11 Javascript
js弹出框、对话框、提示框、弹窗实现方法总结(推荐)
2016/05/31 Javascript
Bootstrap警告(Alerts)的实现方法
2017/03/22 Javascript
jQueryMobile之窗体长内容的缺陷与解决方法实例分析
2017/09/20 jQuery
基于node.js实现微信支付退款功能
2017/12/19 Javascript
详解angular分页插件tm.pagination二次触发问题解决方案
2018/07/20 Javascript
jQuery中ajax请求后台返回json数据并渲染HTML的方法
2018/08/08 jQuery
详解ES6 Symbol 的用途
2018/10/14 Javascript
vue实现图片懒加载的方法分析
2020/02/05 Javascript
解决echarts 一条柱状图显示两个值,类似进度条的问题
2020/07/20 Javascript
Python数据结构与算法之二叉树结构定义与遍历方法详解
2017/12/12 Python
Mac下Anaconda的安装和使用教程
2018/11/29 Python
python 计算平均平方误差(MSE)的实例
2019/06/29 Python
python openpyxl使用方法详解
2019/07/18 Python
python百行代码自制电脑端网速悬浮窗的实现
2020/05/12 Python
如何对python的字典进行排序
2020/06/19 Python
汽车检测与维修个人求职信
2013/09/24 职场文书
物流管理专业大学生自荐信
2013/10/04 职场文书
自荐信不宜过于夸大
2013/11/06 职场文书
大学生简短的自我评价分享
2014/02/20 职场文书
2014植树节活动总结
2014/03/11 职场文书
个人授权委托书
2014/04/03 职场文书
《庐山的云雾》教学反思
2014/04/22 职场文书
2014年自愿离婚协议书范本
2014/09/25 职场文书
民事代理词范文
2015/05/25 职场文书
春节慰问简报
2015/07/21 职场文书
2016年读书月活动总结范文
2016/04/06 职场文书
Python 循环读取数据内存不足的解决方案
2021/05/25 Python