解决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 相关文章推荐
jQuery使用手册之一
Mar 24 Javascript
JS 实现双色表格实现代码
Nov 24 Javascript
javascript 使用 NodeList需要注意的问题
Mar 04 Javascript
JavaScript实现的日期控件具体代码
Nov 18 Javascript
javascript读写json示例
Apr 11 Javascript
JavaScript利用正则表达式替换字符串中的内容
Dec 12 Javascript
使用BootStrap建立响应式网页——通栏轮播图(carousel)
Dec 21 Javascript
通过命令行生成vue项目框架的方法
Jul 12 Javascript
浅谈React + Webpack 构建打包优化
Jan 23 Javascript
Vue实现表格中对数据进行转换、处理的方法
Sep 06 Javascript
使用react context 实现vue插槽slot功能
Jul 18 Javascript
详解JS WebSocket断开原因和心跳机制
May 07 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
十个PHP高级应用技巧果断收藏
2015/09/25 PHP
jQuery向下滚动即时加载内容实现的瀑布流效果
2016/01/07 PHP
php解决DOM乱码的方法示例代码
2016/11/20 PHP
jscript之List Excel Color Values
2007/06/13 Javascript
JQuery 学习笔记 选择器之三
2009/07/23 Javascript
document.getElementById的简写方式(获取id对象的简略写法)
2010/09/10 Javascript
百度UEditor编辑器如何关闭抓取远程图片功能
2015/03/03 Javascript
jQuery获取当前点击的对象元素(实现代码)
2016/05/19 Javascript
Javascript+CSS3实现进度条效果
2016/10/28 Javascript
深入理解选择框脚本[推荐]
2016/12/13 Javascript
jQury Ajax使用Token验证身份实例代码
2017/09/22 Javascript
Node中使用ES6语法的基础教程
2018/01/05 Javascript
浅谈Webpack打包优化技巧
2018/06/12 Javascript
AngularJs分页插件使用详解
2018/06/30 Javascript
Three.js实现3D机房效果
2018/12/30 Javascript
Vue实现固定定位图标滑动隐藏效果
2019/05/30 Javascript
微信小程序如何获取地址
2019/12/24 Javascript
[06:10]6.81新信使新套装!给你一个炫酷的DOTA2
2014/05/06 DOTA
python命令行参数解析OptionParser类用法实例
2014/10/09 Python
Python实现测试磁盘性能的方法
2015/03/12 Python
Python多线程编程(二):启动线程的两种方法
2015/04/05 Python
Python中的命令行参数解析工具之docopt详解
2017/03/27 Python
10个Python小技巧你值得拥有
2018/09/29 Python
python实现将多个文件分配到多个文件夹的方法
2019/01/07 Python
详解python中__name__的意义以及作用
2019/08/07 Python
利用纯CSS3实现tab选项卡切换示例代码
2016/09/21 HTML / CSS
意大利包包和行李箱销售网站:Bagaglio.it
2021/03/02 全球购物
幼儿园国庆节活动方案
2014/02/01 职场文书
西式婚礼主持词
2014/03/13 职场文书
班干部演讲稿
2014/04/24 职场文书
历史名人教你十五个读书方法,赶快Get起来!
2019/07/18 职场文书
pyqt5打包成exe可执行文件的方法
2021/05/14 Python
pytorch 使用半精度模型部署的操作
2021/05/24 Python
java设计模式--建造者模式详解
2021/07/21 Java/Android
教你修复 Win11应用商店加载空白问题
2021/12/06 数码科技
SpringBoot整合Minio文件存储
2022/04/03 Java/Android