likes
comments
collection
share

【CLODOP】用pdfjs和clodop实现pdf打印本文通过使用pdfjs和clodop来实现pdf打印,流程简介:

作者站长头像
站长
· 阅读数 5

本文通过使用pdfjs和clodop来实现pdf打印,我的gitee地址:pdf打印,可以直接下载使用

主要流程:

  1. 下载clodop并注册,将官网的LodopFuncs.js文件放到项目中,并引入要使用的vue文件中
  2. 下载pdfjs,并引入到要使用的vue文件中
  3. 在 index.html中添加<script src='http://localhost:18000/CLodopfuncs.js?name=CLODOPA'></script>(否则在使用时会出现getCLodop is not defined的报错)
  4. 对pdf文件地址的处理:从后端获得blob类型地址,通过pdfjsLib.getDocument方法将blob处理;再通过loadingTask.promise得到pdf的详细信息对象,对象中包含页数(注意:当pdf文件页数较多时需要分批处理,我这里是分10页一批去处理)
  5. 处理pdf,新建画布,再将画好的画布转换成图片,接着将图片放到colodop的中配置,最后删除画布。(注意这个过程只能一页一页的进行处理,目前只研究出了这样的方法)

当然如果公司资金充足可以直接注册colodp包含pdf打印的商用注册

一、pdfjs引入

方法一

在index.html中cdn引入, 加载远程pdf时会出现 CORS 跨域的问题

 <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.7.107/pdf.min.js"></script>

方法二

去官网mozilla.github.io/pdf.js/下载插件包,将pdf.js和pdf.worker.js放在项目中,在index.html中引入,会加大项目的体积也不灵活

 <script type="text/javascript" src="pdfjs/pdf.js"></script>
 <script type="text/javascript" src="pdfjs/pdf.worker.js"></script>

方法三

npm安装 npm i pdfjs-dist

二、clodop下载和使用

去clodop官网下载www.lodop.net/, 现在样例中有许多已经封装好的方法,一部分的方法可以免费使用,另外部分方法可以本地测试使用,商用要商用注册,这里介绍一些我用到的clodop的方法,要了解其他就去clodop的官网查看使用

  1. 初始化LODOP 对象 LODOP.PRINT_INIT('任务名字')

  2. 设置纸张大小和打印方向

     `LODOP.SET_PRINT_PAGESIZE(pageDirection, pageWidth, pageHeight, pageName)`
     pageDirection: 纸张方向,1纵向 2横向
     pageWidth: 纸张宽度,单位mm
     pageHeight: 纸张高度,单位mm
     pageName:设置纸张格式名称,比如A4
     ​
     举个栗子: 
     LODOP.SET_PRINT_PAGESIZE(1, 2200, 2970, "A4") // 设置纸张大小A4 纵向打印
     LODOP.SET_PRINT_PAGESIZE(2, 1480, 2100, "A5") // 设置纸张大小A5 横向打印
    
  3. 设置打印数据

     `LODOP.ADD_PRINT_IMAGE(top, left, width, height, imageSrc)`
     top:距离将放置图像的页面顶部的距离
     left:距离要放置图像的页面左侧的距离
     width:图像的宽度
     height:图像的高度
     imageSrc:镜像文件的源路径
    
  4. 设置打印样式

     `LODOP.SET_PRINT_STYLEA(nStyle1, nStyle2, nValue)`
     nStyle1: 表示要设置的样式类型,可以是字体样式、对齐方式、边框样式等
     nStyle2: 表示要设置的具体样式属性,如字体大小、字体颜色、边框宽度等
     nValue: 表示具体的属性值,如字体大小为12px,字体颜色为红色等
     ​
     举个栗子: 
     LODOP.SET_PRINT_STYLEA(0, 1, 12); // 设置字体大小为12px
     LODOP.SET_PRINT_STYLEA(0, 2, "red") // 设置字体颜色为红色
     LODOP.SET_PRINT_STYLEA(0,"Stretch",2) // 设置打印文本的拉伸属性为两倍大小
    
  5. 设置打印模式(我这里在分批打印时给单个任务命名)

     `LODOP.SET_PRINT_MODE("ModeName", ModeValue)`
    
  6. 设置打印份数

      `LODOP.SET_PRINT_COPIES('打印份数')`
    
  7. 设置打印机

     `LODOP.SET_PRINTER_INDEX('打印机名称')`
    
  8. 直接打印 LODOP.PRINT()

  9. 打印预览 LODOP.PREVIEW()

具体使用

pdfjs可以直接根据pdf地址去获取和解析pdf,但是在客户环境中可能会出现跨域问题,当出现跨域问题就改成让后端直接返回文件流

LodopFuncs.js

【CLODOP】用pdfjs和clodop实现pdf打印本文通过使用pdfjs和clodop来实现pdf打印,流程简介:

【CLODOP】用pdfjs和clodop实现pdf打印本文通过使用pdfjs和clodop来实现pdf打印,流程简介:

 import { MessageBox } from 'element-ui'
 ​
 //====判断是否需要安装CLodop云打印服务器:====
 export function needCLodop() {
   try {
     var ua = navigator.userAgent
     if (ua.match(/Windows\sPhone/i) != null) return true
     if (ua.match(/iPhone|iPod/i) != null) return true
     if (ua.match(/Android/i) != null) return true
     if (ua.match(/Edge\D?\d+/i) != null) return true
 ​
     var verTrident = ua.match(/Trident\D?\d+/i)
     var verIE = ua.match(/MSIE\D?\d+/i)
     var verOPR = ua.match(/OPR\D?\d+/i)
     var verFF = ua.match(/Firefox\D?\d+/i)
     var x64 = ua.match(/x64/i)
     if (verTrident == null && verIE == null && x64 !== null) return true
     else if (verFF !== null) {
       verFF = verFF[0].match(/\d+/)
       if (verFF[0] >= 42 || x64 !== null) return true
     } else if (verOPR !== null) {
       verOPR = verOPR[0].match(/\d+/)
       if (verOPR[0] >= 32) return true
     } else if (verTrident == null && verIE == null) {
       var verChrome = ua.match(/Chrome\D?\d+/i)
       if (verChrome !== null) {
         verChrome = verChrome[0].match(/\d+/)
         if (verChrome[0] >= 42) return true
       }
     }
     return false
   } catch (err) {
     return true
   }
 }
 ​
 //====页面引用CLodop云打印必须的JS文件:====
 if (needCLodop()) {
   var head =
     document.head ||
     document.getElementsByTagName('head')[0] ||
     document.documentElement
   var oscript = document.createElement('script')
   oscript.src = 'http://localhost:8000/CLodopfuncs.js?priority=1'
   head.insertBefore(oscript, head.firstChild)
 ​
   //引用双端口(8000和18000)避免其中某个被占用:
   oscript = document.createElement('script')
   oscript.src = 'http://localhost:18000/CLodopfuncs.js?priority=0'
   head.insertBefore(oscript, head.firstChild)
 }
 ​
 // 下载loadLodop  可以将指定版本的clodop下载到项目的静态资源中
 function loadLodop() {
   window.open('../../static/Lodop/CLodop_Setup_for_Win32NT.exe')
 }
 ​
 //====获取LODOP对象的主过程:====
 export function getLodop() {
   var LODOP
   try {
     LODOP = getCLodop()
     if (!LODOP && document.readyState !== 'complete') {
       return  MessageBox.alert('C-Lodop打印控件还没准备好,请稍后再试!')
     }
     //===如下空白位置适合调用统一功能(如注册语句、语言选择等):===
     //LODOP.SET_LICENSES("北京XXXXX公司","8xxxxxxxxxxxxx5","","");
   } catch (err) {
     MessageBox({
       title: '温馨提示',
       type: 'warning',
       showCancelButton: true,
       confirmButtonText: '下载',
       cancelButtonText: '取消',
       message: '检测到您还未安装C-LODOP套打控件,请确认启用后再打印。或您可点击下载该套打控件,安装成功后刷新页面再进行打印',
       callback: res => {
         if (res === 'confirm') {
           loadLodop()
         }
       }
     })
   }
   return LODOP
 }
print.js
 /*
  * @Author: xiaxia
  * @Description: 
  * @Date: 2023-06-08 17:35:19
  * @LastEditTime: 2023-12-20 11:22:40
  * @FilePath: \pdf-print\src\utils\printjs.js
  */
 import axios from 'axios'
 import {getLodop} from './LodopFuncs'
 const instance = axios.create({
   timeout: 1000
 })
 var LODOP = getLodop(); // 创建一个LODOP对象
 ​
 // 获取本地打印机 
 function getLocalPrint() {
   let counter = LODOP.GET_PRINTER_COUNT(); // 获取打印机个数
   let printerList= []
   for (let i = 0; i < counter; i++) {
     printerList.push({//将打印机存入printerList数组中
       value: LODOP.GET_PRINTER_NAME(i),
       label: LODOP.GET_PRINTER_NAME(i)
     });
   }
   return printerList
 }
 ​
 // 打印Base64图片
 const lodopImageBase64 = (img64, printer) => {
   if (!LODOP) return
   LODOP.PRINT_INIT("测试打印");
   // LODOP.SET_PRINT_PAGESIZE(2, 0, 0, 'A4') // 设置纸张大小
   LODOP.ADD_PRINT_IMAGE(0, 0, "100%", "100%", img64)
   LODOP.SET_PRINTER_INDEX(printer)
   LODOP.PREVIEW() // 预览
 }
 ​
 // 1. 模拟请求
 const getFileBase64 = async pdfUrl => {
   let fileData = null
   try {
     fileData = await instance({
       method: 'get',
       url: pdfUrl, // 请求地址
       responseType: 'blob' // 指明服务器返回的数据类型
     })
   } catch {
     fileData = null
   }
   if (fileData && fileData.data) {
     const result = getObjectURL(fileData.data) // 流转成url
     return result
   } else {
     return false
   }
 }
 // 2.流转成url
 const getObjectURL = (file) => {
   let url = null
   if (window.createObjectURL !== undefined) { // basic
     url = window.createObjectURL(file)
   } else if (window.webkitURL !== undefined) { // webkit or chrome
       try {
         url = window.webkitURL.createObjectURL(file)
       } catch (error) {
         console.log(error)
       }
   } else if (window.URL !== undefined) { // mozilla(firefox)
       try {
         url = window.URL.createObjectURL(file)
       } catch (error) {
         console.log(error)
       }
   }
     return url
   }
 ​
 export  { getLocalPrint, lodopImageBase64, getFileBase64, getObjectURL }
Vue文件
 <template>
   <div clas="app">
     <div>
       <h2>pdf打印</h2>
       <el-form label-width="85px"  size="mini">
         <el-form-item label="打印机">
           <el-select
             v-model="dyParam.printer"
             placeholder="请选择"
           >
             <el-option
               v-for="item in locaolPrinter"
               :key="item.value"
               :label="item.label"
               :value="item.value"
             ></el-option>
           </el-select>
         </el-form-item>
       </el-form>
       <el-button type="primary" @click="getLocalPrint()">获取本地打印机</el-button>
       <el-button type="primary" @click="printPdf(dyParam, true)">直接打印</el-button>
       <el-button type="primary" @click="printPdf(dyParam, false)">打印预览</el-button>
     </div>
   </div>
 </template>
 ​
 <script>
   // pdfjs识别解析pdf文件--> Canvas将解析后的数据画出来 --> 转换成image --> 通过clodop打印
   import { getFileBase64, getLocalPrint } from './utils/printjs.js'
   import {getLodop} from './utils/LodopFuncs' // clodop
   import * as pdfjsLib from "pdfjs-dist"
   const pdfjsWorker = import("pdfjs-dist/build/pdf.worker.entry")
   pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker
 ​
   export default {
     name: 'App',
     data(){
       return{
         // dyParam 包含打印的配置信息:发票号码 打印机,打印份数等...
         dyParam: {
           goldtaxNum: '', // 发票号码
           printer: '', // 打印机名称
           dyNumber: 1, // 打印份数
         },
         locaolPrinter: null, // 获取到的本地打印机
       }
     },
     methods:{
       async printPdf(dyParam, ispreview) {
         let answer = null
         let fpNum = dyParam.goldtaxNum// 这里去获取发票号码
         let LODOP = getLodop() // 初始化clodop 没有控件会提示用户安装
         
         // 1. pdf地址
         // 这里使用pdf地址 可根据自己项目替换
         const url = "http://localhost:8000/CLodopDemos/PDFDemo.pdf"
         const zhUrl = await getFileBase64(url) // 模拟请求,获得blob类型地址
         const loadingTask = pdfjsLib.getDocument(zhUrl)
         console.log('pdf地址111111:', zhUrl)
 ​
         // 2. 文件流
         // let strURL = dyParam.row.file.address // pdf地址
         // let res = await getPrintFeil({FileAddress: strURL}) // 请求后端 获取文件流
         // let bolbFile = new Blob([res.data], { type: 'application/pdf; charset=utf-8' })
         // let blobUrl =  getObjectURL(bolbFile)
         // const loadingTask = pdfjsLib.getDocument(blobUrl)
         // console.log( 'pdf地址111111:' , blobUrl);
 ​
         let pdf = null
         try {
           pdf= await loadingTask.promise
         } catch(e) {
           return answer = { success: false,msg: "未查询到pdf地址,请联系管理员" }
         }
         let numPages = pdf.numPages
         // 1. 如果当前打印的页数 <= 10 ------------------------------------------------------------------
         if(numPages <= 10) {
           LODOP.PRINT_INIT('发票'+fpNum)
           LODOP.SET_PRINT_PAGESIZE(1, 2200, 2970, "") // 设置纸张大小A4 纵向打印
           // LODOP.SET_PRINT_PAGESIZE(2, 0, 0, "A4") // 设置纸张大小A4 横向打印
           for(let i=1; i<=numPages; i++){
             await this.CreateOnePage( LODOP, pdf, i)
           }
 ​
           if(ispreview) { // 判断是预览还是直接打印
             LODOP.SET_PRINTER_INDEX(dyParam.printer)
             LODOP.PRINT() // 打印
           } else {
             LODOP.PREVIEW() // 预览
           }
           this.$message.success('发票 '+ dyParam.goldtaxNum +' 解析完成正在发送请求到打印机,请耐心等待......');
 ​
           return new Promise((resolve) => {
             LODOP.On_Return = function (TaskID, Value) {
               if(Value){
                 console.log('打印成功:发送打印请求成功')
                 answer = { success: true, msg: "发送打印请求成功" }
               } else {
                 console.log('打印失败:发送打印请求失败')
                 answer = { success: false, msg: "发送打印请求失败" }
               }
               resolve(answer) // 完成Promise
             }
           })
         }
         // 2. 当前页数>10--需要进行分组 ------------------------------------------------------------------
         else {
           let num1 = Math.ceil(numPages/10) // 向上取整
           for (let it = 0; it <= num1-1; it++) {
             LODOP.PRINT_INIT('发票'+fpNum)
             LODOP.SET_PRINT_PAGESIZE(1, 2200, 2970, ""); // 设置纸张大小
             // LODOP.SET_PRINT_PAGESIZE(2, 0, 0, "A4"); // 设置纸张大小A4 横向打印
             if(it == 0) {
               for (let ind = 1; ind <= 10; ind++) {
                 await this.CreateOnePage( LODOP, pdf, ind)
               }
             } else{
               for (let ind = 1; ind <= 10; ind++) {
                 if(ind == 10){
                   await this.CreateOnePage(LODOP, pdf, parseInt(it+1+''+0))
                   if(parseInt(it+1+''+0)==numPages) break
                 } else {
                   await this.CreateOnePage( LODOP, pdf, parseInt(it+''+ind))
                   if(parseInt(it+''+ind)==numPages) break
                 }
               }
             }
             LODOP.SET_PRINT_MODE("CUSTOM_TASK_NAME",'发票'+fpNum+'第'+(it+1)+'份') // 单独任务名
             console.log('当前打印的页数>10,打印份数:', this.dyNumber)
             LODOP.SET_PRINT_COPIES(this.dyNumber) // 打印份数
 ​
             if(ispreview) { // 判断是预览还是直接打印
               LODOP.SET_PRINTER_INDEX(dyParam.printer)
               LODOP.PRINT() // 打印
             } else {
               LODOP.PREVIEW() // 预览
             }
           }
           this.$message.success(' 解析完成正在发送请求到打印机,请耐心等待......');
           return new Promise((resolve) => {
             LODOP.On_Return = function (TaskID, Value) {
               if(Value){
                 console.log('打印成功:发送打印请求成功')
                 answer = { success: true, msg: "发送打印请求成功" }
               } else {
                 console.log('发送打印请求失败')
                 answer = { success: false, msg: "发送打印请求失败" }
               }
               resolve(answer); // 完成Promise
             }
           })
         }
       },
       // pdf解析
       async CreateOnePage(LODOP, pdf, i){
         LODOP.NewPage()
         let pdfId = "pdf" + i
         const newCanvas = document.createElement("canvas") // 新建画布
         newCanvas.setAttribute("id", pdfId) // 赋id
         const page = await pdf.getPage(i)
         const context = newCanvas.getContext("2d")
         const viewport = page.getViewport({ scale: 7}) // scale值越大越清晰 解析时间越长
         newCanvas.height = viewport.height
         newCanvas.width = viewport.width
         const renderContext = {
           canvasContext: context,
           viewport: viewport,
         };
         await page.render(renderContext).promise
         console.log("Page rendered")
         const img = newCanvas.toDataURL("image/jpeg") // 转换成image地址
 ​
         LODOP.ADD_PRINT_IMAGE(0, 0, "95%", "95%", img)
         LODOP.SET_PRINT_STYLEA(0,"Stretch",2)
         newCanvas.remove() // 销毁画布
       },
       getLocalPrint() {
         this.locaolPrinter = getLocalPrint()
         console.log(this.locaolPrinter);
       }
     }
   }
 </script>
 ​
 <style>
 .app {
   text-align: center;
 }
 canvas {
   border: 1px solid #ccc;
 }
 img {
   width: 600px;
   height: 500px;
   border: 1px solid red;
 }
 .content {
   display: flex;
   align-items: center;
   justify-content: center;
 }
 .pdf {
   margin-right: 20px;
 }
 </style>

注意

打印pdf时可能出现报错,中文文字缺失,解决办法参考文档:blog.csdn.net/gentleman_h…

Warning: Error during font loading: The CMap "baseUrl" parameter must be specified, ensure that the "cMapUrl" and "cMapPacked" API parameters are provided

处理前 【CLODOP】用pdfjs和clodop实现pdf打印本文通过使用pdfjs和clodop来实现pdf打印,流程简介:

处理【CLODOP】用pdfjs和clodop实现pdf打印本文通过使用pdfjs和clodop来实现pdf打印,流程简介:

 params.cMapPacked = true
 params.cMapUrl = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.2.228/cmaps/'
 
 

处理后【CLODOP】用pdfjs和clodop实现pdf打印本文通过使用pdfjs和clodop来实现pdf打印,流程简介:

转载自:https://juejin.cn/post/7411480128528990262
评论
请登录