在上一篇的基础上,实现了一下另外一种方式。
上一篇地址:https://www.cnblogs.com/ljwsyt/p/9525290.html
首先,该方式也是有几种方法。
1.在上一篇的基础上,将生成的html转化成canvas,然后就可以直接对canvas进行打印和保存。
需要注意的是,canvas打印的时候是一片空白的,需要先转化为图片然后打印。而生成canvas之后可以直接右键保存了,也可以增加按钮进行保存,保存的时候也是先转化为base64图片然后再进行保存。
方法:使用html2canvas插件进行转化,只需引入就可以直接运行,
html2canvas(document.querySelector("#toPrint")).then(canvas => { ???document.body.appendChild(canvas)});
其源码应该也是根据元素的位置绘制的canvas。
2.直接绘制canvas。
html代码:增加了两个按钮
1 <div> 2 ????<div id="printArea"> 3 ????????<!--startprint--> 4 ????????<canvas id="toPrint"> 5 ????????</canvas> 6 ????????<!--endprint--> 7 ????</div> 8 ????<div id="bottom_btns"> 9 ????????<button onclick="printNotifier()" class="layui-btn">打印</button>10 ????????<button onclick="saveNotifier1()" class="layui-btn">保存</button>11 ????</div>12 </div>
css代码:
1 #toPrint { 2 ????position:absolute; 3 ????left: 50%; 4 ????top: 50%; 5 } 6 ?7 #bottom_btns { 8 ????position: absolute; 9 ????bottom: 10px;10 ????left: 50%;11 ????/* 按钮宽度加缩进 */12 ????margin-left: -70px;13 }
js代码:移动端兼容也很OK
?1 myApp.controller(‘notifierController2‘, function ($rootScope, $scope, services, $sce, $stateParams, $state) { ?2 ????$scope.services = services; ?3 ??????4 ????//查询录取通知书内容 ?5 ????services["getApplyStatus"] = function (param) { ?6 ????????return $rootScope.serverAction(‘/apply/queryDegreeApplyInfo‘, param, "GET"); ?7 ????}; ?8 ??????9 ????$scope.mobile = /Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent); 10 ????if(1 == $rootScope._USERINFO.role || 2 == $rootScope._USERINFO.role) { 11 ????????if($scope.mobile) { 12 ????????????$rootScope._ALLMENU = [{ 13 ????????????????children: [{ 14 ????????????????????res_name: "查看审核状态", 15 ????????????????????res_url: "#status_mobile", 16 ????????????????????res_id: "#status_mobile" 17 ????????????????},{ 18 ????????????????????res_name: "查看修改申请资料", 19 ????????????????????res_url: "#registerMsg#review", 20 ????????????????????res_id: "#registerMsg#review" 21 ????????????????},{ 22 ????????????????????res_name: "打印录取通知书", 23 ????????????????????res_url: "#notifier", 24 ????????????????????res_id: "#notifier" 25 ????????????????}] 26 ????????????}]; 27 ????????????//$rootScope.mobile_regstatus = true; 28 ????????} else { 29 ????????????$rootScope._ALLMENU = [{ 30 ????????????????children: [{ 31 ????????????????????res_name: "查看审核状态", 32 ????????????????????res_url: "#status", 33 ????????????????????res_id: "#status" 34 ????????????????},{ 35 ????????????????????res_name: "查看修改申请资料", 36 ????????????????????res_url: "#registerMsg#review", 37 ????????????????????res_id: "#registerMsg#review" 38 ????????????????},{ 39 ????????????????????res_name: "打印录取通知书", 40 ????????????????????res_url: "#notifier", 41 ????????????????????res_id: "#notifier" 42 ????????????????}] 43 ????????????}]; 44 ????????} 45 ????} 46 ????$rootScope.curentSel = "#notifier"; 47 ????$rootScope.setContent = function(url) { 48 ????????if($scope.mobile) { 49 ????????????$(‘#main-layout‘).removeClass(‘hide-side‘); 50 ????????????if(-1 < url.indexOf("#registerMsg")) { 51 ????????????????window.open(encodeURI(encodeURI(‘/pages/index_mobile.html#/registers#review?id=‘ + $rootScope._USERINFO.id))); 52 ????????????????window.location.href = "/pages/index_mobile.html#/home"; 53 ????????????????return; 54 ????????????} else { 55 ????????????????$rootScope.curentSel = url; 56 ????????????} 57 ????????} else { 58 ????????????if(-1 < url.indexOf("#registerMsg")) { 59 ????????????????window.open(encodeURI(encodeURI(‘/pages/index.html#/registers#review?id=‘ + $rootScope._USERINFO.id))); 60 ????????????????window.location.href = "/pages/index.html#/home"; 61 ????????????????return; 62 ????????????} else { 63 ????????????????$rootScope.curentSel = url; 64 ????????????} 65 ????????} 66 ????} 67 ?????68 ????//模板 69 ????$scope.printObj = { 70 ????????notifierObj:{ 71 ????????????"url": "/res/img/notifications.png", 72 ????????????"height": "631", 73 ????????????"width": "942" 74 ????????}, 75 ????????paramList:[{ 76 ????????????????"objName":"黄大明", 77 ????????????????"left":"133", 78 ????????????????"top":"191", 79 ????????????????"size": "28" 80 ????????????},{ 81 ????????????????"objName":"SXXX小学", 82 ????????????????"left":"460", 83 ????????????????"top":"272", 84 ????????????????"size": "28" 85 ????????????},{ 86 ????????????????"objName":"2018", 87 ????????????????"left":"195", 88 ????????????????"top":"312", 89 ????????????????"size": "28" 90 ????????????},{ 91 ????????????????"objName":"8", 92 ????????????????"left":"325", 93 ????????????????"top":"312", 94 ????????????????"size": "28" 95 ????????????},{ 96 ????????????????"objName":"31", 97 ????????????????"left":"405", 98 ????????????????"top":"312", 99 ????????????????"size": "28"100 ????????????}]101 ????}102 ????103 ????services.getApplyStatus(‘token‘).success(function(res) {104 ????????if (‘OK‘ == res.result) {105 ????????????if(res.msg) {106 ????????????????userName = res.msg.studentName;107 ????????????????$scope.printObj.paramList[0].objName = res.msg.studentName;108 ????????????????$scope.printObj.paramList[1].objName = res.msg.applySchoolName;109 ????????????????110 ????????????????//屏幕自适应111 ????????????????suitScreen($scope);112 ????????????????//画图113 ????????????????drawNotifier($scope);114 ????????????????//组装页面115 ????????????????//assembleHtml($scope); ???????????????116 ????????????????//打印117 ????????????????//printNotifier();118 ????????????}119 ????????} else {120 ????????????layer.alert(res.msg);121 ????????}122 ????});123 ????124 });125 126 var userName;127 128 function saveNotifier1() {129 ????//一样需要先转化为图片后保存130 ????var type = ‘png‘;//格式可以自定义131 ????var imgData = $("#toPrint")[0].toDataURL(type);132 ????// 加工image data,替换mime type133 ????imgData = imgData.replace(_fixType(type),‘image/octet-stream‘);134 ????//可以直接用以下下载,但是下载的文件名没有后缀135 ????//window.location.href=image; // it will save locally136 ????//文件名可以自定义137 ????var filename = ‘录取通知书_‘ + userName + ‘.‘ + type;138 ????saveFile(imgData,filename);139 }140 141 function _fixType(type) {142 ????//imgData是一串string,base64143 ????type = type.toLowerCase().replace(/jpg/i, ‘jpeg‘);144 ????var r = type.match(/png|jpeg|bmp|gif/)[0];145 ????return ‘image/‘ + r;146 }147 148 function saveFile(data, filename) {149 ????//命名空间150 ????var save_link = document.createElementNS(‘http://www.w3.org/1999/xhtml‘, ‘a‘);151 ????save_link.href = data;152 ????save_link.download = filename;153 ???154 ????//window.location = save_link;//此方法可下载但是文件名无效155 ????//下载156 ????var event = document.createEvent(‘MouseEvents‘);157 ????event.initMouseEvent(‘click‘, true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);158 ????save_link.dispatchEvent(event);159 }160 161 function printNotifier() {162 ????try{163 ????????print.portrait = false;//横向打印 ,去掉页眉页脚164 ????}catch(e){165 ????????//alert("不支持此方法");166 ????}167 168 ????//canvas无法直接打印,需先转换成img169 ????$(convertCanvasToImage($("#toPrint")[0])).jqprint(); ??170 }171 172 function convertCanvasToImage(canvas) {173 ????var image = new Image();174 ????image.src = canvas.toDataURL("image/png");175 ????return image;176 }177 178 function suitScreen($scope) {179 ????//下方留30放按钮180 ????var effectiveHeight = findParam("#printArea", "height") - 30;181 ????var effectiveWidth = findParam("#printArea","width");182 ????if($scope.printObj.notifierObj.width/effectiveWidth > $scope.printObj.notifierObj.height/effectiveHeight) {183 ????????//取最接近的一个属性进行自适应,并适当调小一些184 ????????var suitTimes = $scope.printObj.notifierObj.width/effectiveWidth*1.2;185 ????} else {186 ????????var suitTimes = $scope.printObj.notifierObj.height/effectiveHeight*1.2;187 ????}188 ????$scope.printObj.notifierObj.width = $scope.printObj.notifierObj.width/suitTimes;189 ????$scope.printObj.notifierObj.height = $scope.printObj.notifierObj.height/suitTimes;190 ????for(i=0;i<$scope.printObj.paramList.length;i++) {191 ????????$scope.printObj.paramList[i].size = $scope.printObj.paramList[i].size/suitTimes;192 ????????$scope.printObj.paramList[i].left = $scope.printObj.paramList[i].left/suitTimes;193 ????????$scope.printObj.paramList[i].top = $scope.printObj.paramList[i].top/suitTimes;194 ????}195 }196 197 function drawNotifier($scope) {198 ????//canvas需要先定位好,否则画好再动就清除了199 ????$("#toPrint").css("margin-left", (0-$scope.printObj.notifierObj.width)/2+"px");200 ????//上移30放按钮201 ????$("#toPrint").css("margin-top", (0-$scope.printObj.notifierObj.height-60)/2+"px");202 ????var canvas = document.getElementById("toPrint");203 ????canvas.width = $scope.printObj.notifierObj.width;204 ????canvas.height = $scope.printObj.notifierObj.height;205 ????var ctx = canvas.getContext("2d");206 ????var img=new Image();207 ????img.src = $scope.printObj.notifierObj.url;208 ????img.onload=function() {209 ????????//需要onload方法接收,否则画不出210 ????????ctx.drawImage(img, 0, 0, $scope.printObj.notifierObj.width, $scope.printObj.notifierObj.height);211 ????????//写文字,且要在画好图片之后写,否则会被图片覆盖212 ????????$.each($scope.printObj.paramList, function(index, e) {213 ????????????//canvas的字体不会有12px的兼容性问题214 ????????????ctx.font = "bold "+e.size+"px KaiTi";215 ????????????//canvas写字以字体的左下角为基准,因而要再加一个字体大小的高度216 ????????????ctx.fillText(e.objName,e.left, e.top+e.size);217 ????????});218 ????}219 ????220 }221 222 function assembleHtml($scope) {223 ????var htmlStr = "<img src=‘" + $scope.printObj.notifierObj.url+"‘ style=‘width:"+$scope.printObj.notifierObj.width+"px;height:"+224 ????????$scope.printObj.notifierObj.height+"px‘>";225 ????for(i=0;i<$scope.printObj.paramList.length;i++) {226 ????????var nowObj = $scope.printObj.paramList[i];227 ????????if(nowObj.size < 12) {228 ????????????htmlStr += "<div style=‘font-size:"+nowObj.size+"px;top:"+nowObj.top+"px;left:"+nowObj.left+229 ????????????//谷歌浏览器字体小于12px时会不再变小,使用-webkit-transform兼容,并设置已左上角作为变换原点230 ????????????????"px;-webkit-transform:scale("+nowObj.size/12+","+nowObj.size/12+");transform-origin:0 0‘>"+nowObj.objName+"</div>";231 ????????} else {232 ????????????htmlStr += "<div style=‘font-size:"+nowObj.size+"px;top:"+nowObj.top+"px;left:"+nowObj.left+233 ????????????????"px‘>"+nowObj.objName+"</div>";234 ????????}235 ????}236 ????$("#toPrint").css("margin-left", (0-$scope.printObj.notifierObj.width)/2+"px");237 ????//上移30放按钮238 ????$("#toPrint").css("margin-top", (0-$scope.printObj.notifierObj.height-60)/2+"px");239 ????$("#toPrint").css("height", $scope.printObj.notifierObj.height+"px");240 ????$("#toPrint").css("width", $scope.printObj.notifierObj.width+"px");241 ????$("#toPrint").append(htmlStr);242 }243 244 //获取有效区域245 function findParam(targetObj, attribute) {246 ????//取数字247 ????if($(targetObj).css(attribute) && $(targetObj).css(attribute).replace(/[^0-9]/ig,"") != ‘0‘) {248 ????????return $(targetObj).css(attribute).replace(/[^0-9]/ig,"");249 ????} else {250 ????????//递归251 ????????return findParam($(targetObj).parent(), attribute);252 ????}253 }
几个需要注意的点:
(1)由于需要留出30像素高的底部放按钮,所有在计算绘制区域的有效高度时应减去30;
(2)绘制顺序:先调整好画布的高宽和位置-->绘制图片-->绘制文字。否则绘制后再调画布会清空,而且先绘制图片再绘制文字时文字覆盖图片而不是反过来;
(3)绘制图片和文字要在图片的onload事件中进行,否则图片还未加载完成就绘制的话会是一片空白区域;
(4)canvas的字体大小不必考虑12px的兼容性问题;
(5)fillText和strokeText,前者是绘制实心文字,后者是空心文字;
(6)画布在未设置宽和高的情况下,会有默认100多的高宽,没有研究源码,但是调试的时候发现的,所有我们取有效区域的时候,就不能直接用toPrint这个canvas进行取了,而要根据其父元素进行取;
(7)createElementNS,下载时用到的,创建带有指定命名空间的元素节点,和createElement类似;
(8)在定义好字体后绘制之前,可以
cxt.fillStyle = "blue";
进行设置颜色
(9)最后就是canvas转图片的方法了,
var image = new Image(); ???image.src = canvas.toDataURL("image/png");
其中
canvas.toDataURL("image/png")就可以用来进行图片转base64.首先绘制canvas,画图片进去,然后就可以生成了。
附另外一种图片转base64的方法
使用FileReader
1 var reader = new FileReader(); 2 ????????var AllowImgFileSize = 2100000; //上传图片最大值(单位字节)( 2 M = 2097152 B )超过2M上传失败 3 ????????var file = $("#img1")[0].files[0]; 4 ????????var imgUrlBase64; 5 ????????if (file) { 6 ????????????//将文件以Data URL形式读入页面 ??7 ????????????imgUrlBase64 = reader.readAsDataURL(file); 8 ????????????reader.onload = function (e) { 9 ??????????????//var ImgFileSize = reader.result.substring(reader.result.indexOf(",") + 1).length;//截取base64码部分(可选可不选,需要与后台沟通)10 ??????????????if (AllowImgFileSize != 0 && AllowImgFileSize < reader.result.length) {11 ????????????????????alert( ‘上传失败,请上传不大于2M的图片!‘);12 ????????????????????return;13 ????????????????}else{14 ????????????????????//执行上传操作15 ????????????????????//alert(reader.result);16 ????????????????????var tempPhoto;17 ????????????????????for(var i=0;i<$scope.registerMsg.userPhotoInfos.length;i++) {18 ????????????????????????//其他允许多张,否则只允许一张19 ????????????????????????if($scope.img_url_code == $scope.registerMsg.userPhotoInfos[i].photoType20 ????????????????????????????????//&& 12 != $scope.registerMsg.userPhotoInfos[i].photoType21 ????????????????????????????????) {22 ????????????????????????????tempPhoto = $scope.registerMsg.userPhotoInfos[i];23 ????????????????????????????$scope.registerMsg.userPhotoInfos.splice(i, 1);24 ????????????????????????????break;25 ????????????????????????}26 ????????????????????}27 ????????????????????if(tempPhoto) {28 ????????????????????????/*if(tempPhoto.photoName) {29 ????????????????????????????tempPhoto.photoName = $("#img1")[0].files[0].name;30 ????????????????????????} else if(!$scope.review) {31 ????????????????????????????tempPhoto[‘photoName‘] = $("#img1")[0].files[0].name;32 ????????????????????????}*/33 ????????????????????????tempPhoto.photoUrl = "";34 ????????????????????????tempPhoto.base64 = reader.result; 35 ????????????????????????$scope.registerMsg.userPhotoInfos.push(tempPhoto);36 ????????????????????} else {37 ????????????????????????$scope.registerMsg.userPhotoInfos.push({38 ????????????????????????????????"id": ‘‘, ??//记录的id(更新接口需要带上)39 ????????????????????????????????"extendProperty": null,40 ????????????????????????????????"photoPath": "",41 ????????????????????????????????"photoUrl": "", //照片的预览路径42 ????????????????????????????????"userId": $scope.userId, //对应的user的id43 ????????????????????????????????"createTime": 0,44 ????????????????????????????????"photoType": $scope.img_url_code,45 ????????????????????????????????"updateTime": 0,46 ????????????????????????????????//"photoName": $("#img1")[0].files[0].name,47 ????????????????????????????????"base64": reader.result ?//图片的base64编码48 ????????????????????????????})49 ????????????????????}50 51 ????????????????????......52 ????????????????}53 ????????????}54 ?????????}
其他还有图片转化与保存及自定义文件名的方法,大家也可以作为参照。
js开发打印证书功能(二)
原文地址:https://www.cnblogs.com/ljwsyt/p/9530525.html