画布改变图像背景颜色,但保持它的效果"

时间:2015-08-19 12:14:19

标签: javascript canvas

我有一张图片,我需要更改它的背景颜色,但保持"效果"在它上(在图像上的黑点,白线等)

这是原始图像:

orginal image

我设法改变了颜色,但我也不断删除那些"效果"。预览:

enter image description here

这里是代码



//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;
&#13;
&#13;

如何阻止那个?

2 个答案:

答案 0 :(得分:2)

对于除Internet Explorer之外的现代浏览器,您可以使用合成来更改原始图像的色调,同时保持饱和度&amp;亮度不变。这将“重新着色”您的原始图像,同时保持轮廓完好。

enter image description here

在现代浏览器中工作的示例代码,但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,因此您必须手动执行此操作。

  1. 读取每个像素的RGBA值。
  2. 将该RGBA值转换为HSL。
  3. 将色调值(HSL中的“H”)移动蓝色色调与所需绿色色调之间的差异。
  4. 将色调偏移的HSL值转换为RGBA值。
  5. 将色调偏移的RGBA值写回像素。
  6. 以下是手动移动色调的示例代码:

    重要提示:此手动方法适用于使用.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)
    ];
}