群里跟人斗图的时候,有没有碰到这样的?

这时候没有图咋办?总不能真退群啊,但是又没图可以斗,于是乎~

唉,尴尬不尴尬,斗图拼的就是时效性,等你找到,黄花菜都凉了。于是乎,这篇博客就应运而生了

我会那么肤浅,直接把文字贴到图片上就算了?
你是喜欢下左边的图当表情还是右边的图?


是我就选右边,为啥?当然是因为高清的表情包是没有灵魂的
,咳咳,当然是因为这个啦

这才是我们要的效果嘛,来,看我怎么实(zhuang)现(B)。
这里只谈核心实现,博客底部放源码和在线地址。
国际惯例,先讲原理:canvas有这么一个接口可以把canvas内容转化为base64字符串:HTMLCanvasElement.toDataURL(),接收俩参数,第一个是mime类型,如果mime是image/jpeg 或 image/webp,第二个参数表示输出质量,类型是0~1之间的浮点数,通过这个参数,我们就可以获取低质量的图片的base64字符串,然后将其赋值给一张图片的src属性,载入完成后再将这张图片绘制到canvas上,然后通过CanvasRenderingContext2D.getImageData() 获取每个像素的rgb数据,然后修改g通道的值,为了保证亮度不变,当g通道变化了delta,r和b通道应该变化-delta/2。
因为涉及的知识点不是很多,直接看render部分的代码吧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| function render () { ... ... offScreenContext.fillStyle = '#ffffff' offScreenContext.fillRect(0, 0, cvsWidth, cvsHeight) ... ... originImageData = offScreenContext.getImageData(0, 0, cvsWidth, cvsHeight) originImageDataContent = originImageData.data var img = new Image() img.onload = function () { offScreenContext.drawImage(img, 0, 0, cvsWidth, cvsHeight) imageData = offScreenContext.getImageData(0, 0, cvsWidth, cvsHeight) imageDataContent = imageData.data for (y = 0; y < cvsHeight; y++) { for (x = 0; x < cvsWidth; x++) { pos = y * cvsWidth + x r = imageDataContent[pos * 4] g = imageDataContent[pos * 4 + 1] b = imageDataContent[pos * 4 + 2] imageDataContent[pos * 4] = r - gOffset / 2 < 0 ? 0 : r - gOffset / 2 imageDataContent[pos * 4 + 1] = g + gOffset > 255 ? 255 : g + gOffset imageDataContent[pos * 4 + 2] = b - gOffset / 2 < 0 ? 0 : b - gOffset / 2 imageDataContent[pos * 4 + 3] = originImageDataContent[pos * 4 + 3] } } offScreenContext.putImageData(imageData, 0, 0) context.drawImage(offScreenCanvas, 0, 0, cvsWidth, cvsHeight) } img.src = offScreenCanvas.toDataURL('image/jpeg', quality) }
|
这里我用了两个canvas,一个用来做离屏渲染,提高性能,另一个是输出到屏幕上的。
额~好像其他没什么能讲的了,就这样吧,还有一些功能要完善,比如裁剪图片,修改图片在画布中的定位等,留个坑吧。
有什么其他好玩的建议欢迎交流
完整代码戳这里
在线演示