最近接了个需要:要求点击一个按钮(预览分享图)生成一个图片实现预览,图片要求在服务器图片的基础上加上二维码和文字;点击保存相册按钮实现保存,具体需求如下;
思路:
1、先用qrcode生产二维码,获取二维码url(其实是图片的base64);
2、获取背景图,将背景图缩小绘制到画布上,
3、将二维码绘制到背景图上的指定地方,
4、绘制文字
5、最后获取画布的图片的base64,
6、调用a标签的downLoad属性下载图片;
以下是部分html代码:
<div class="hideThis" id="closeBox" @click="exitPreview">
<div class="st" @click="cancleBubble1($event)">
<div class="frontClass"> <--用于预览的图片-->
<canvas id="canvasFront"></canvas>
</div>
<div class="sc-cover1-t1 hideThis"> <canvas id="canvasFrontDown" class="hideThis"></canvas></div> <--因为画布的图片经过压缩不满足后期打印,这个div保存的是用于存放原图和二维码用于下载的图片-->
</div>
<div id="erweimaImg" class="hideThis"></div> <--生成二维码临时存放-->
<div class="sc-cover1-b" @click="cancleBubble2($event)">保存到相册</div>
</div>
以上是html,主要用到点击exitPreview函数移除隐藏,弹出窗口,并且在<canvas id="canvasFront"></canvas>进行绘制图片;
<div id="erweimaImg" class="hideThis"></div>用于临时存放二维码;
下面是部分js 代码:内含有比较清楚的介绍每个步骤
previewShare: function () {
$("#previewBox").removeClass("hideThis");
$("#closeBox").removeClass("hideThis");
var url = vm.createQrcode();
vm.sourceImg("图片上要写的文字", url);
},
createQrcode: function () {
$("#erweimaImg").qrcode({ //选择存放链接容器
width: 100, //width height如果不写默认是 256 256
height: 100,
text: "https://blog.csdn.net/weixin_41679874?orderby=ViewCount" //二维码的链接
});
//定义方法
function canvasToImage(canvas) {
var image = new Image();
// 指定格式 PNG 图片后缀可自定义
image.src = canvas.toDataURL("image/png");
return image;
}
//找到需要转换的canvas
var mycanvas1 = $('canvas')[$('canvas').length - 1];
//进行方法转换
var img = canvasToImage(mycanvas1);
return img.src;
},
sourceImg: function (text, url) {
var canvas = document.getElementById("canvasFront"); // 获取指定画布
var ctx = canvas.getContext("2d"); // 获取context 对象:
var winWidth = window.innerWidth; //获取设备宽度 当初测试以屏幕宽度为准 375
var win = 207; //closeBox 这个div的宽度
var hei = 590.5; //closeBox 这个div的宽度
var left = 146; // 文字旋转的中心坐标
var top = 470; // 文字旋转的中心坐标
if (winWidth <= 1024) {
var win1 = 207 * (winWidth / 375);
var hei1 = 590.5 * (winWidth / 375);
var left1 = 146 * (winWidth / 375);
var top1 = 470 * (winWidth / 375);
var win2 = 118 * (winWidth / 375);
var left2 = 26 * (winWidth / 375);
var top2 = 42 * (winWidth / 375);
var size2 = 65 * (winWidth / 375);
} else {
var win1 = 565;
var hei1 = 1613;
var left1 = 395;
var top1 = 1283;
var win2 = 322;
var left2 = 71;
var top2 = 114.6;
var size2 = 177;
}// 以上的数字就是为了让div能适应不同屏幕的大小能让画布自适应大小
canvas.setAttribute('width', win1 + 'px'); //设置画布宽
canvas.setAttribute('height', hei1 + 'px'); // 设置画布高度 不设置会有默认
var imgs = new Image(); // 创建两个图片对象
var imgs2 = new Image();
imgs.src = vm.frontImageId; // 背景图的路径
imgs2.src = url; // 二维码的路径
imgs.onload = function(){
ctx.drawImage(imgs, 0, 0, win1, hei1);
};//图片加载完成再执行
imgs2.onload =function () {
ctx.drawImage(imgs2, left2, top2, win2, win2);
};//图片加载完成再执行
var moveToRight = function () {
// ctx.drawImage(imgs, 0, 0, win1, hei1);
// ctx.drawImage(imgs2, left2, top2, win2, win2);
ctx.font = size2 + "px PingFangSC-Medium";// 画文字,文字的大小,不建议用rem,苹果不兼容,用px
ctx.fillStyle = "#ed6a1a"; //字体颜色
ctx.fontWeight = "bold"; //粗细
ctx.save(); // 将以上画好的内容定妆保存
ctx.translate(left1, top1); // 设置旋转中心
ctx.rotate(Math.PI / 2 * 3); // 设置旋转角度
ctx.fillText(text, 0, 0); // 将文字绘制好并且完成保存之后的操作
ctx.restore(); // 把定妆保存的图片恢复融合旋转后的文字
}
setInterval(moveToRight, 0);
// 如果对图片的清晰度和大小没有要求下面的可以不用看,下面只是将上面的参数变为原图大小
var realcanvas = document.getElementById("canvasFrontDown");
var realctx = realcanvas.getContext("2d");
var realwin1 = 828;
var realhei1 = 2363;
var realleft1 = 590;
var realtop1 = 1880;
var realwin2 = 472;
var realleft2 = 104;
var realtop2 = 168;
realcanvas.setAttribute('width', realwin1 + 'px'); // 画布匹配原图尺寸
realcanvas.setAttribute('height', realhei1 + 'px');
var realimgs = new Image();
var realimgs2 = new Image();
realimgs.src = vm.frontImageId;
realimgs.setAttribute("crossOrigin", 'Anonymous'); //运行图片跨域,前提是你拿的背景图的服务器是允许跨域;
realimgs2.src = url;
realimgs.onload = drawImg;//图片加载完成再执行
realimgs2.onload = drawImg;//图片加载完成再执行
function drawImg() {
realctx.drawImage(realimgs, 0, 0, realwin1, realhei1);
realctx.drawImage(realimgs2, realleft2, realtop2, realwin2, realwin2);
realctx.font = "240px PingFangSC-Medium";
realctx.fillStyle = "#ed6a1a";
realctx.fontWeight = "bold";
realctx.save();
realctx.translate(realleft1, realtop1);
realctx.rotate(Math.PI / 2 * 3);
realctx.fillText(denomination, 0, 0);
realctx.restore();
}
},
图片生成之后,记得将隐藏属性关掉,才能展示图片
我项目成图为:
左边是效果图,右边是原图 下面的是预览图;
接下来是保存的js:
点击保存按钮会执行以下js
cancleBubble2:function (event) {
event.stopPropagation(); //方法阻止事件冒泡到父元素,阻止任何父事件处理程序被执行。父级点击灰色区域会关掉预览,保存相册要忽略父级的点击事件
var frontBase = document.getElementById("canvasFront").toDataURL("image/png"); // 保存预览图
// var frontBase1 = document.getElementById("canvasFrontDown").toDataURL("image/png"); //保存原比例图,隐藏的那张真实图片
try {
//调用IOSjs
window.webkit.messageHandlers.XXXX.postMessage();
} catch (e) {
try {
//调用Android js;
window.fnxls.XXXX(imgSrc);//,
} catch (e) {
//保存图片方法
vm.saveImg("couponFrontImg", frontBase);
}
}
},
/**
* @param fileName 下载的图片名称,默认:fnImg+时间戳
* @param content URL 或者图片内容(base64内容)
*/
saveImg:function (fileName,content) {
if(content.indexOf('data:image')>-1){
// base64 图片操作
vm.saveImgByBase64(fileName,content);
}else{
//path 图片操作
// vm.saveImgByUrl(fileName,content); 这个方法网上很多就不贴出来了
}
},
/**
* @param fileName 保存图片的名字,默认:fnImg+时间戳
* @param base 图片内容
*/
saveImgByBase64:function (fileName, base) {
if (!fileName || !/\S/.test(fileName)) {
fileName="fnImg"+new Date().getMilliseconds();
}
var aLink = document.createElement('a'); // 创建a标签
var blob = vm.base64ToBlob(base); //获得一个blob二进制大对象,
var evt = document.createEvent("HTMLEvents"); // 获取base64中的图片格式
evt.initEvent("click", true, true);//initEvent 不加后两个参数在FF下会报错 事件类型,是否冒泡,是否阻止浏览器的默认行为
aLink.download = fileName;
aLink.href = Windows.URL.createObjectURL(blob); // window.webkitURL和window.URL是一样的,担心不兼容的可以加多个if判读
aLink.dispatchEvent(new MouseEvent('click', {bubbles: true, cancelable: true, view: window}));//兼容火狐;
};
//base64转blob 这个方法网上也很多,但是基本一样自己可以网上看看
base64ToBlob:function (code) {
var parts = code.split(';base64,');
var contentType = parts[0].split(':')[1];
var raw = window.atob(parts[1]);
var rawLength = raw.length;
var uInt8Array = new Uint8Array(rawLength);
for (var i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], {type: contentType});
}
我这边因为是有移动端的,所以直接调用移动端的js,不知道在手机的浏览器是否可以执行,但是本人在谷歌浏览器和IE浏览器是没有问题;
有不清楚的可以留言,有时间会回复,有不同看法的欢迎发表;