我有一张图片,我需要更改它的背景颜色,但保持"效果"在它上(在图像上的黑点,白线等)
这是原始图像:
我设法改变了颜色,但我也不断删除那些"效果"。预览:
这里是代码:
//let's say I want it to be red
var r = 255;
var g = 0;
var b = 0;
var imgElement = document.getElementById('img');
var canvas = document.getElementById('canvas');
canvas.width = imgElement.width;
canvas.height = imgElement.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(imgElement, 0, 0);
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var data = imageData.data;
for (var i = 0; i < data.length; i += 4) {
if (data[i + 3] !== 0) {
data[i] = r;
data[i + 1] = g;
data[i + 2] = b;
data[i + 3] = data[i + 3];
}
}
ctx.putImageData(imageData, 0, 0);
&#13;
<img src="foo" id="img" />
<canvas id="canvas"></canvas>
&#13;
如何阻止那个?
答案 0 :(得分:2)
对于除Internet Explorer之外的现代浏览器,您可以使用合成来更改原始图像的色调,同时保持饱和度&amp;亮度不变。这将“重新着色”您的原始图像,同时保持轮廓完好。
在现代浏览器中工作的示例代码,但Internet Explorer
除外
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/M449a.png";
function start(){
// create an overlay with solid #00d9c6 color
var tempCanvas=document.createElement('canvas');
var tempctx=tempCanvas.getContext('2d');
canvas.width=tempCanvas.width=img.width;
canvas.height=tempCanvas.height=img.height;
tempctx.drawImage(img,0,0);
tempctx.globalCompositeOperation='source-atop';
tempctx.fillStyle='#00d9c6';
tempctx.fillRect(0,0,tempCanvas.width,tempCanvas.height);
//
canvas.width=img.width;
canvas.height=img.height;
// use compositing to change the hue of the original image
ctx.drawImage(img,0,0);
ctx.globalCompositeOperation='hue';
ctx.drawImage(tempCanvas,0,0);
// always clean up: reset compositing to its default
ctx.globalCompositeOperation='source-over';
}
#canvas{border:1px solid red; }
<canvas id="canvas" width=300 height=300></canvas>
由于Internet Explorer不支持Blend Compositing,因此您必须手动执行此操作。
以下是手动移动色调的示例代码:
重要提示:此手动方法适用于使用.getImageData
处理像素。因此,您必须确保原始图像与网页位于同一域中。否则,出于安全原因,画布将受到污染,您将无法使用.getImageData
。
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var img = new Image();
img.crossOrigin = "anonymous";
img.onload = start;
img.src = "https://dl.dropboxusercontent.com/u/139992952/multple/marioStanding.png";
function start() {
ctx.drawImage(img, 0, 0);
ctx.drawImage(img, 150, 0);
// shift blueish colors to greenish colors
recolorPants(-.33);
}
function recolorPants(colorshift) {
var imgData = ctx.getImageData(150, 0, canvas.width, canvas.height);
var data = imgData.data;
for (var i = 0; i < data.length; i += 4) {
red = data[i + 0];
green = data[i + 1];
blue = data[i + 2];
alpha = data[i + 3];
// skip transparent/semiTransparent pixels
if (alpha < 200) {
continue;
}
var hsl = rgbToHsl(red, green, blue);
var hue = hsl.h * 360;
// change blueish pixels to the new color
if (hue > 200 && hue < 300) {
var newRgb = hslToRgb(hsl.h + colorshift, hsl.s, hsl.l);
data[i + 0] = newRgb.r;
data[i + 1] = newRgb.g;
data[i + 2] = newRgb.b;
data[i + 3] = 255;
}
}
ctx.putImageData(imgData, 150, 0);
}
function rgbToHsl(r, g, b) {
r /= 255, g /= 255, b /= 255;
var max = Math.max(r, g, b),
min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
if (max == min) {
h = s = 0; // achromatic
} else {
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r:
h = (g - b) / d + (g < b ? 6 : 0);
break;
case g:
h = (b - r) / d + 2;
break;
case b:
h = (r - g) / d + 4;
break;
}
h /= 6;
}
return ({
h: h,
s: s,
l: l,
});
}
function hslToRgb(h, s, l) {
var r, g, b;
if (s == 0) {
r = g = b = l; // achromatic
} else {
function hue2rgb(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
return ({
r: Math.round(r * 255),
g: Math.round(g * 255),
b: Math.round(b * 255),
});
}
<p>Example shifting color Hue with .getImageData</p>
<p>(Original: left, Recolored: right)</p>
<canvas id="canvas" width=300 height=300></canvas>
答案 1 :(得分:1)
您需要将每个像素转换为LSH色彩空间(亮度/亮度,色调,饱和度)。然后将Hue设置为所需的颜色并保持计算的亮度和饱和度,然后转换回RGB并将imageData设置为新的RGB值。
我添加了自己的转化代码。那里可能有更快的版本。
// returns RGB in an array on 3 numbers 0-255
var lshToRGB = function(ll,ss,hh){ //ll 0-255,ss 0-255, hh 0-360
var l = ll/255;
var s = ss/255;
var hhh = (hh/255)*360;
var C = (1 - Math.abs(2*l - 1)) * s;
var X = C*(1 - Math.abs(((hhh / 60)%2) - 1));
var m = l - C/2;
if(hhh < 60){
var r = C;
var g = X;
var b = 0;
}else
if(hhh < 120){
var r = X;
var g = C;
var b = 0;
}else
if(hhh < 180){
var r = 0;
var g = C;
var b = X;
}else
if(hhh < 240){
var r = 0;
var g = X;
var b = C;
}else
if(hhh < 300){
var r = X;
var g = 0;
var b = C;
}else{
var r = C;
var g = 0;
var b = X;
}
r += m;
g += m;
b += m;
// is there a need to clamp these ????)
r = Math.round(Math.min(255,Math.max(0,r*255)));
g = Math.round(Math.min(255,Math.max(0,g*255)));
b = Math.round(Math.min(255,Math.max(0,b*255)));
return [r,g,b];
}
// returns array of 3 numbers 0-255,0-255,0-360
var rgbToLSH = function(rr,gg,bb){ // could do without the conversion from 360 to 255 on hue
var r,
g,
b,
h,
s,
l,
min,
max,
d;
r = rr / 255;
g = gg / 255;
b = bb / 255;
max = Math.max(r, g, b);
min = Math.min(r, g, b);
l = (max + min) / 2;
if (max == min) {
h = 0;
s = 0; // achromatic
} else {
d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r:
h = (g - b) / d;
break;
case g:
h = 2 + ((b - r) / d);
break;
case b:
h = 4 + ((r - g) / d);
break;
}
h *= 60;
if (h < 0) {
h += 360;
}
h = Math.round(h);
}
return [
Math.min(Math.round(l*255),255),
Math.min(Math.round(s*255),255),
Math.min(Math.round((h/360)*255),255)
];
}