工做时遇到一个需求:提取图片主题色,经过某种映射关系,选取ui给出的对应颜色。脑海中浮现若是只是纯前端如何实现呢?前端
利用canvas获取图像像素信息,而后用某种算法将主题颜色提取出来。git
MDN: 事实上,你能够直接经过getImageData
,返回一个imageData
对象,获取场景像素数据。
imageData
对象包含下列几个只读属性:github
width
:图片宽度,单位是像素height
:图片高度,单位是像素data
:Uint8ClampedArray
类型的一维数组,包含着RGBA格式的整型数据,范围在0至255之间(包括255)。data
属性返回一个 Uint8ClampedArray
,它能够被使用做为查看初始像素数据。每一个像素用4个 1 bytes值(按照红,绿,蓝和透明值的顺序,"RGBA"格式) 来表明。每一个颜色值部份用0至255来表明。每一个部分被分配到一个在数组内连续的索引,左上角像素的红色部分在数组的索引0位置。像素从左到右被处理,而后往下,遍历整个数组。Uint8ClampedArray
包含高度 × 宽度 × 4 bytes数据,索引值从0到(高度×宽度×4)-1算法
中位切分法一般是在图像处理中下降图像位元深度的算法,可用来将高位的图转换位低位的图,如将24bit的图转换为8bit的图。咱们也能够用来提取图片的主题色,其原理是是将图像每一个像素颜色看做是以R、G、B为坐标轴的一个三维空间中的点,因为三个颜色的取值范围为0~255,因此图像中的颜色都分布在这个颜色立方体内。如图所示:canvas
以后将RGB中最长的一边从颜色统计的中位数一切为二,使获得的两个长方体所包含的像素数量相同,以下图所示重复这个过程直到切出长方体数量等于主题色数量为止,最后取每一个长方体的中点便可。数组
在实际使用中若是只是按照中点进行切割,会出现有些长方体的体积很大可是像素数量不多的状况。解决的办法是在切割前对长方体进行优先级排序,排序的系数为体积 * 像素数。这样就能够基本解决此类问题了。ui
其中color-thief库就是基于中位切分法实现的。atom
Pixels and Palettes: Extracting Color Palettes From Images
Pixel_manipulation_with_canvas_By MDNspa