base64
(function (){ window.toTransparentDataUrl=function(srcImage, result) { let targetCanvas = toTransparentCanvas(srcImage, null, result); if (targetCanvas===null){ return null; } return targetCanvas.toDataURL("image/png"); } window.toTransparentImage=function(srcImage, targetImage, result) { let data = toTransparentDataUrl(srcImage, result); if (data===null){ return null; } if (!targetImage){ targetImage = new Image(); } targetImage.src = data; return targetImage; } /** * 将给定Image对象所引用的图片,转换为背景透明的canvas返回 * @param {Image} srcImage 源图像元素 * @param {Element} targetCanvas 目标画布,用于保存转换后的图片. 如果传了这个参数,那么结果将展现在指定画布上; 如果不传这个参数, 那么函数会创建一个canvas对象,并返回 * @returns 变为背景透明的图像canvas; 如果源图像就是背景透明的,那么返回null. */ window.toTransparentCanvas=function(srcImage, targetCanvas, result) { //背景色误差容忍度 const tolerance = 10; //获取图像size let width = srcImage.naturalWidth, height = srcImage.naturalHeight; //源canvas, 用于获取图像数据 let sourceCanvas = document.createElement("canvas"); sourceCanvas.width = width; sourceCanvas.height = height; //将图像内容绘制到源canvas,并获得数据 let sourceContext = sourceCanvas.getContext('2d'); sourceContext.drawImage(srcImage, 0, 0); //获取像素数据 let srcImageData = sourceContext.getImageData(0, 0, width, height) let srcImgDataArray = srcImageData.data; let length = srcImgDataArray.length; //推测可能的背景色 let possibleBgColor = getPosibleBgColor(srcImageData); if (result){ result.bgColor = colorToHex(possibleBgColor); } //定义结果像素数据 let trtImgDataArray = new Uint8ClampedArray(length); //将接近背景色的像素都置为全透明,其他的取源像素值 //但如果本来就有透明像素存在, 就不再处理, 直接返回false for (var i = 0; i < length; i += 4) { let r = srcImgDataArray[i]; let g = srcImgDataArray[i + 1]; let b = srcImgDataArray[i + 2]; let a = srcImgDataArray[i + 3]; if (a!=255){ return null; } let diffR = r - possibleBgColor.r; let diffG = g - possibleBgColor.g; let diffB = b - possibleBgColor.b; if ( Math.sqrt( diffR*diffR + diffG*diffG + diffB*diffB ) <= tolerance ) { trtImgDataArray[i] = 0; trtImgDataArray[i+1]=0; trtImgDataArray[i+2]=0; trtImgDataArray[i+3]=0; } else { trtImgDataArray[i] = r; trtImgDataArray[i+1]=g; trtImgDataArray[i+2]=b; trtImgDataArray[i+3]=a; } } if (!targetCanvas){ targetCanvas = document.createElement("canvas"); } targetCanvas.width = width; targetCanvas.height = height; let targetContext = targetCanvas.getContext('2d'); let targetImageData = new ImageData(trtImgDataArray, width, height); targetContext.putImageData(targetImageData, 0, 0 ); //targetContext.drawImage(image, 0, 0); // let trtImgData = targetContext.getImageData(0, 0, width, height); if (result){ result.imageData = targetImageData; result.canvas = targetCanvas; } return targetCanvas; } function numToHex(number){ let hex = number.toString(16); return (hex.length < 2) ? '0' + hex : hex; } function colorToHex(color){ return '#'+ numToHex(color.r) + numToHex(color.g) + numToHex(color.b); } /** * 一个存储颜色出现次数的数据结构 */ function Frequency(){}; /** * 把颜色存入,如果已经存在,计数+1 */ Frequency.prototype.put = function(r,g,b){ if (this[r]===undefined){ this[r]={}; this[r][g]={}; this[r][g][b]=1; }else if (this[r][g]===undefined){ this[r][g]={}; this[r][g][b]=1; }else if (this[r][g][b]===undefined){ this[r][g][b]=1; }else{ this[r][g][b] += 1; } }; /** * 获取数据结构中最频繁出现的颜色 */ Frequency.prototype.getMostRgb = function(){ let most = 0; let rIndex,gIndex,bIndex; for (let r in this) { let ro = this[r]; for (let g in ro) { let rgo = ro[g]; for (let b in rgo) { if (most<rgo[b]){ most=rgo[b]; rIndex = r; gIndex = g; bIndex = b; } } } } return {r:parseInt(rIndex), g:parseInt(gIndex), b:parseInt(bIndex)}; }; /** * 获取图片数据中最有可能的背景颜色 * @param {ImageData} imgData 这个是canvas.getImageData()获取的数据结构,应该有width,height和data三个属性 */ function getPosibleBgColor(imgData){ //定义一个统计频次的对象 let frequency = new Frequency(); let dataArray = imgData.data; let width = imgData.width, height = imgData.height; let length = dataArray.length; //统计第一行 for (let i = 0; i < width*4; i+=4) { frequency.put(dataArray[i], dataArray[i+1], dataArray[i+2]); } //统计最后一行 let lastLineStart = width*4*(height -1); for (let i = lastLineStart; i < length; i+=4) { frequency.put(dataArray[i], dataArray[i+1], dataArray[i+2]); } //统计第一列(除去首行和末行) for (let i = width*4; i < lastLineStart; i+=width*4) { frequency.put(dataArray[i], dataArray[i+1], dataArray[i+2]); } //统计最后一列(除去首行和末行) for (let i = width*4*2 - 4; i < length - width*4; i+=width*4) { frequency.put(dataArray[i], dataArray[i+1], dataArray[i+2]); } return frequency.getMostRgb(); } })();