Canvas实现微信红包图片

前一段时间微信曾经出过一个微信红包图片的功能,你只能看到图片的一小部分,其他的部分都做了模糊处理,要想看全部图片,需要先发红包。虽然这个功能只上线了短短几天就下线了,但是他真真正正的存在过。下面我们用js来简单的实现以下这个效果。

其实实现这个效果,用css3来实现可能相对简单一些,但是这里我想使用canvas来实现,在实现这个效果之前首先我们需要想清楚怎样组织元素。

假设我们有一个img标签,它显示的是一张清晰的图片,然后我们有另一个canvas标签,它和前面的img标签,同宽同高同位置,也就是说它会完全遮住后面清晰的图片。然后我们通过一些方法将清晰的图片数据模糊处理,然后绘制到canvas标签上,现在模糊的图片后面是清晰图片,要想显示局部清晰的部分,我们只需要在模糊层上面挖一个洞,透过这个洞我们就可以看到后面清晰的相应部分的图片了。那么现在就只剩下两个问题待解决:

1、如何对图片进行模糊处理

这个使用了我之前一篇文章里面的模糊滤镜,虽然这个模糊算法有问题,但是在这里还是将就将就用了。

2、如何在模糊的canvas层上挖一个洞

这个问题只需要使用canvas的图层添加原理就可以轻松实现

以下是一个简单的实例代码:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>微信红包图片</title>

<style type="text/css">
		img{
			display: block;
			margin: 0 auto;
		}
		#buttons{
			width: 300px;
			margin: 10px auto;
		}
	</style>

</head>
<body>
	<img src="pic.jpg" width="300px" height="286px" id="pic" alt="">

<div id="buttons">
		<button id="generate">生成图片</button>
		<button id="show">全部显示</button>
	</div>

	<script type="text/javascript">
		var im = document.getElementById("pic"),
			canvas = createCanvas(),
			ctx = canvas.getContext("2d"),
			dataCanvas = createCanvas(),
			dataCtx = dataCanvas.getContext("2d"),
			generateButt = document.getElementById("generate"),
			showButt = document.getElementById("show"),
			x,y,r;
		dataCanvas.width = canvas.width = im.width;
		dataCanvas.height = canvas.height = im.height;
		canvas.style.position="absolute";
		canvas.style.left=im.offsetLeft+'px';
		canvas.style.top=im.offsetTop+'px';
		document.body.appendChild(canvas)
		im.onload = function(){
			dataCtx.drawImage(im,0,0);
		}
		generateButt.onclick = function(){
			generate();
		}
		showButt.onclick = function(){
			show();
		}
		function show(){
			var maxM = getMaxMargin(x,y,canvas.width,canvas.height);
			r+=30;
			generate(true);
			if(r>maxM){
				return;
			}
			requestAnimationFrame(show);
		}
		function generate(noRand){
			ctx.clearRect(0,0,canvas.width,canvas.height);
			var imageData = dataCtx.getImageData(0,0,dataCanvas.width,dataCanvas.height);
			imageData = blurEffect(imageData,6);
			ctx.putImageData(imageData,0,0);
			ctx.globalCompositeOperation = 'destination-out';
			ctx.beginPath();
			if(!noRand){
				r = rand(10,40);
				x = rand(r,canvas.width-r);
				y = rand(r,canvas.height-r);
			}
			ctx.arc(x,y,r,0,2*Math.PI);
			ctx.fill();
		}
		function createCanvas(){
			return document.createElement("canvas");
		}
		function rand(min,max){
			return Math.random()*(max-min)+min;
		}
		function blurEffect(imageData,size){
		    var pixelData = imageData.data,
		        tmpimageData = copy(imageData),
		        tmppixelData = tmpimageData.data;
		    size = size ? size : 1;
		    var count = Math.pow((size*2+1),2)-1;
		    for(var i=0;i<canvas.height;i++){
		        for(var j=0;j<canvas.width;j++){
		            var totalr = 0,totalg = 0,totalb = 0;
		            for(var dx=i-size;dx<=i+size;dx++){
		                for(var dy=j-size;dy<=j+size;dy++){
		                    var p = dx * canvas.width + dy;
		                    if(dx===i && dy===j) continue;
		                    tmppixelData[p*4+0] && (totalr += tmppixelData[p*4+0]);
		                    tmppixelData[p*4+1] && (totalg += tmppixelData[p*4+1]);
		                    tmppixelData[p*4+2] && (totalb += tmppixelData[p*4+2]);
		                }
		            }
		            var p = i * canvas.width + j;
		            pixelData[p*4+0] = totalr/count;
		            pixelData[p*4+1] = totalg/count;
		            pixelData[p*4+2] = totalb/count;
		        }
		    }
		    return imageData;
		}
		function getMaxMargin(x,y,width,height){
			return Math.max(cacuDis(x,y,0,0),cacuDis(x,y,0,height),cacuDis(x,y,width,0),cacuDis(x,y,width,height));
		}
		function cacuDis(sx,sy,ex,ey){
			return Math.sqrt(Math.pow(sx-ex,2)+Math.pow(sy-ey,2));
		}
		function copy(source){
			var result = new Object();
			for(var key in source){
				result[key] = typeof source[key]==='object'?copy(source[key]):source[key];
			}
			result.constructor = source.constructor;
			return result;
		}
	</script>
</body>
</html>

上面这个代码写的是很烂的,我只是想借这个代码来演示这个效果的原理。相信聪明的你一定能写出更好的代码,甚至将这个功能封装成一个插件。

在线Demo:http://demo.deanhan.cn/red-pocket

  • 支付宝二维码 支付宝
  • 微信二维码 微信
相关文章