正在加载中

最后更新于 2019年04月11日

昨天看到群里一个人的主题,首页的轮播很有意思,然后他的轮播底色是根据文章图片颜色来自动变动的,我当时就觉得蛮有意思的,但是我没怎么接触过canvas这个东西,html5的时候匆匆带过,然后js的时候也没有讲,索性就自己百度看看教程了,找了好久,大部分都是转载的同一篇文章,然后大佬的那个js算法我实在看不懂,搞不懂为什么要for循环的时候i要乘以图片的宽度,然后再乘以4,在加123这些,后面慢慢搞懂了*4和+123这些意思,但是还是不太懂为啥要乘以图片宽度,嘛,这些暂时不管了,先看看我的想法吧!

获取颜色平均值理论阶段

首先通过canvas获取到图片的每个像素点的rgba值,然后for循环的时候将r、g、b、a四个的值对应的相加,最后得到的rgba值是全部像素的总和,然后用这个对应的总和除以图片的像素点总和,最终求得每个像素点的平均值。

当然这只是理论的平均值,其实每张图片他有深色和浅色区域,往往深色区域的值高于浅色区域好多倍,那么这样得到的平均值是否就是我们需要的值呢,这个就要考虑下算法了,不过我们目前先将这个想法实现为目的。

了解canvas

canvas是用于绘制图像的,复杂点你甚至能玩出花样,但是canvas元素本身是没有绘画能力的,我初次使用感觉就是复制,有点像是拼图,你实现准备好图片,然后通过js进行拼接,这里我们只是使用到convas的复制图片的能力。

首先我们要了解需要使用到的几个代码:

getContext("2d")

drawImage(img,0,0)

getImageData(0,0,width,height)

.data 

第一个getContext("2d");是表示canvas要绘制一个2d图像,而且只有这一个选项,canvas目前只支持2d,所以你没得选,照着写就对了。

第二个是drawImage(img,0,0);表示规定要使用的图像,后面两个0表示开始裁剪这个图片的x,y轴坐标,其实他后面还有填值,具体我就拿w3c的说明吧!

context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
参数描述
img规定要使用的图像、画布或视频。
sx可选。开始剪切的 x 坐标位置。
sy可选。开始剪切的 y 坐标位置。
swidth可选。被剪切图像的宽度。
swidth可选。被剪切图像的宽度。
sheight可选。被剪切图像的高度。
x在画布上放置图像的 x 坐标位置。
y在画布上放置图像的 y 坐标位置。
width可选。要使用的图像的宽度。(伸展或缩小图像)
height可选。要使用的图像的高度。(伸展或缩小图像)

第三个getImageData(0,0,width,height);表示计算图片的像素数据,第一个0表示x轴哪个位置开始就算,第二个0表示从y轴哪个位置计算,width和height表示计算的宽高大小。

第四个.data是和getImageData配合使用的,只有使用了.data才能拿到对应的像素数据。

注意:

获取的像素数据是一个数组集合,每个下标分别保存r、g、b、a四个值的信息,也就是这样[r,g,b,a,r,g,b,a,.....]这样循环下去。

创建canvas并获取到图片信息

window.onload = function() {
    //获取图片颜色平均值
        (function getcolor() {
            //js创建一个canvas元素
            var canvas = document.createElement('canvas');
            //设置canvas的大小,默认是300*150,这样就无法获取到全部的图片像素了,这个值也是看你怎么设置的,动态获取也是可以的。
            canvas.width = 900;
            canvas.height = 350;
            //表示绘制一个2d图
            var context = canvas.getContext("2d");
            //获取图片元素
            var img = document.getElementById('myimg');    
            //创建图片元素用来加载图片地址        
            var nimg = new Image();
            nimg.onload = function(){
                var r = 0;
                var g = 0;
                var b = 0;
                var a = 0;
                var fxs = 900 * 300;
                //设置要绘制的图片
                context.drawImage(nimg,0,0);
                //获取图片的像素信息,并.data获得数组
                var data = context.getImageData(0,0,900,300).data;
                //获取所有的rgba的和
                for(var i = 0;i<data.length/4;i++) {
                    r += data[i * 4];
                    g += data[i * 4 + 1];
                    b += data[i * 4 + 2];
                    a += data[i * 4 + 3];
                }
                //获得平均值
                var rgba = 'rgba('+ parseInt(r/fxs) +','+ parseInt(g/fxs) +','+ parseInt(b/fxs) +','+ parseInt(a/fxs) +')';
                document.documentElement.style.backgroundColor = rgba;
            })
            //将图片地址传给nimg
            nimg.src = img.src ;
    
        })();
}

效果图

进阶想法

通过上面这个我们可以获取到图片的平均色,但是有时候并不是很如意,我们可以自行去调整算法,比如,你只需要计算某一个角,如80*80的大小,或者5x5的方块取一个点,如图:

并且还可以骚一点,取高亮色或者低亮色,那么怎么计算呢,你可以先取得平均色,然后再一个个for循环判断,如果这个颜色大于平均色50个值以上,那就push这个rgba到新的数组中,然后再求一次这个新数组的平均色,或者再复杂一点,多次for循环,直到高亮色的数组length不超过30对,那么再求平均估计会好很多,这个后续我要是有时间肯定会再次研究了,欢迎讨论。

  • weixiao kaixin tushetou jingkong deyi fanu liezui liuhan daku ganga bishi nanguo lihai qian yiwen numu tu yi haixiu se fadai minyan hehe henkaixin huaji biyiyan kuanghan maimeng shui xiaku penqi zhangzui pen aini ye niu laji ok chigua renshi kongbu shuai xiaoxiese touxiao huaixiao jingnu chihuai kaisang xiaoku koubi zhuangbi lianhong kanbujian shafa zhijing xiangjiao dabian yaowan redjing lazhu rizhi duocang chixigua hejiu xixi xiaopen goukun xiaobuchu shenme wusuowei guancha lajing chouyan xiaochi bie zhadanzui zhadanxiao
  1. 木灵鱼儿

    发表于:
    来自 FireFox 61 in windows 10

    写完发现对方的背景色变动只不过放大了然后磨砂效果,我日,我心好痛:hejiu::hejiu: