vue处理PDF文档流数据并实现PDF的预览以及打印功能以及处理PDF打印乱码问题

VUE项目处理PDF文档流数据并实现PDF的预览以及打印功能以及处理PDF打印乱码问题

1.业务需求:
  • vue项目需要对后端返回的PDF文档流数据进行处理,在前端实现处理后的PDF文件的预览以及打印功能,最后再处理PDF页面打印乱码问题。
2.需求分析:
  • 首先由于后端返回的是文档流数据,所以第一步要将文档流数据转换为正确的PDF格式的数据,第二步是要将转化的PDF数据在页面上进行预览(这里我使用的是vue-pdf插件),最后是要在预览的PDF页面上添加打印按钮以及实现打印功能(PDF打印功能vue-pdf插件里面有方法提供,不用再单独去引入外部的打印插件)。另外由于vue-pdf插件使用的是iframe进行渲染,所以存在乱码问题,所以需要对其源文件进行修改。
3.解决方案:
  • 第1步是处理后端返回的文档流数据(注意:请求PDF文档流数据的接口时如果是axios封装的post请求注意使用params,{responseType:'blob'},如果是axios封装的get请求注意使用{params:params,responseType:'blob'},否则文档流解析会报错,或者解析出来是一片空白):

  •       // 将返回的流数据转换为url(data: 文档流数据)
            getObjectURL(data) {
              let url = null
              let file = new Blob([data],{type:'application/pdf;chartset=utf-8'})
              if (window.createObjectURL != undefined) {
                  // 通用
                url = window.createObjectURL(file)
              } else if (window.webkitURL != undefined) {
                  // 兼容谷歌
                try {
                  url = window.webkitURL.createObjectURL(file)
                } catch (error) {
      
                }
              } else if (window.URL != undefined) {
                  // 兼容其他
                try {
                  url = window.URL.createObjectURL(file)
              } catch (error) {
    
                }
              }
                // 将转化后url赋值
              this.pdfUrl = url
            },
    
  • 第2步是下载及引入vue-pdf:

  •   // 首先是安装vue-pdf
      npm install --save vue-pdf
    
  • // 在页面引入
    import pdf from 'vue-pdf'
    components: {
          pdf,
        },
    
  • 第3步是将转化好的PDF数据通过vue-pdf插件进行预览及打印:

    <div v-if="src" style="overflow-y: auto;overflow-x: hidden;">
        
            <el-button type="primary" @click="$refs.pdf.print()" size="mini">打印el-button>
            <el-button type="warning" plain @click="viewDia = false" size="mini">关闭el-button>
            <div>
              <pdf
                ref="pdf"
                :src="pdfUrl"
              >pdf>
            div>
          div>
    
  • 第四部是处理PDF打印乱码问题:

  • 详情可参考https://github.com/FranckFreiburger/vue-pdf/pull/130/commits/253f6186ff0676abf9277786087dda8d95dd8ea7

  • 解决方法是修改pdfjsWrapper.js文件(索引:node_modules => vue-pdf => src => pdfjsWrapper.js)

  • 最后附上我这边最新的修改的pdfjsWrapper.js全部内容(亲测无误,可直接复制):

  •   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;
      
      		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 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({ scale: 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({ scale: 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;
      
      			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,
      	}
      }.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,
      	}
      }
      
    
  • 统一说明:最近有码友反馈修改pdfjsWrapper.js不生效,这里大家注意一下vue-pdf版本不要太高了,参考我使用的4.2.0版本,不然会有问题。

  • 解决

你可能感兴趣的:(vue,javascript,vue.js,html)