老板让我这个不会P图的伪前端把公司的Logo放到公司网站上,结果给了我一张 JPEG 格式的图片,做为一个有追求的码农,怎么能现学 ps,因而利用一点HTML5+NODE的知识写了个转换的脚本。node
此脚本的功能是将 JPEG 格式的图片中的白色背景转成透明,而后再保存成PNG格式的图片;若是图片自己有不想被转换的白色区域,使用其余方法吧。git
原理很简单,只有两点:github
RGBA的解释 咱们知道图片由不少个像素点组成的,每一个像素点都有颜色,而颜色是由三基色RGB构成。而A是Alpha通道,用做不透明度参数,0%为彻底透明,100%是彻底不透明。因此说若是咱们想实现白色背景的JPEG 图片转成透明的 PNG 图片,只须要将白色背景对应的像素点得Alpha值变成0就行了。canvas
HTML5新增长了canvas,能够用来绘制图形,也能够对图片的像素进行操做。经过 getImageData()
方法能够返回原始的像素信息 ImageData 对象。ImageData 对象中的像素是可写的(由 RGBA 组成),所以咱们能够修改像素的Alpha通道值,而后再经过 putImageData() 方法将这些像素复制到画布中。数组
有了上面的知识,咱们能够很轻松的经过查 canvas 的 API 来写出转换的代码(ES6),代码在下面,代码不难,也写了很详细的注释,虽然我是用 node-canvas 实现的,可是改为浏览器版本的话,也不须要几行代码,原理是想通的:浏览器
import Canvas from 'canvas' import fs from 'fs' const Image = Canvas.Image // 初始化 img 和 start time // 获取命令行输入的源图片和保存的图片地址 let img = new Image , start = new Date() , rawPath = process.argv[2] , savePath = process.argv[3] // 在命令行中没有输入图片地址,抛错 if(!rawPath) throw new Error('input raw image path') if(!savePath) throw new Error('input save image path') img.onerror = function(err){ throw err } // 图片加载完成 img.onload = function(){ // 获取图片的width和height let width = img.width , height = img.height , canvas = new Canvas(width, height) , ctx = canvas.getContext('2d') // 将源图片复制到画布上 // canvas 全部的操做都是在 context 上,因此要先将图片放到画布上才能操做 ctx.drawImage(img, 0, 0, width, height) let imageData = ctx.getImageData(0, 0, width, height) // 获取画布的像素信息 // 是一个一维数组,包含以 RGBA 顺序的数据,数据使用 0 至 255(包含)的整数表示 // 如:图片由两个像素构成,一个像素是白色,一个像素是黑色,那么 data 为 // [255,255,255,255,0,0,0,255] // 这个一维数组能够当作是两个像素中RBGA通道的数组的集合即: // [R,G,B,A].concat([R,G,B,A]) , data = imageData.data // 对像素集合中的单个像素进行循环,每一个像素是由4个通道组成,因此 i=i+4 for(let i = 0; i < data.length; i+=4) { // 获得 RGBA 通道的值 let r = data[i] , g = data[i+1] , b = data[i+2] // 咱们从最下面那张颜色生成器中能够看到在图片的右上角区域,有一小块在 // 肉眼的观察下基本都是白色的,因此我在这里把 RGB 值都在 245 以上的 // 的定义为白色 // 你们也能够本身定义的更精确,或者更宽泛一些 if([r,g,b].every(v => v < 256 && v > 245)) data[i+3] = 0 } // 将修改后的代码复制回画布中 ctx.putImageData(imageData, 0, 0) // 将修改后的图片保存 let out = fs.createWriteStream(`${__dirname}/${savePath}`) , stream = canvas.pngStream() stream.on('data', function (chunk) { out.write(chunk) }) stream.on('end', function () { console.log(`保存到 ${__dirname}/${savePath}`) console.log(`耗时: ${new Date()-start}ms`) }) } img.src = `${__dirname}/${rawpath}`