HTML5画布如何改变图像颜色

3
我正在使用jQuery滑块将我的图像颜色从蓝色变为红色(范围为-100到100),通过着色实现。这意味着当滑块值为0时,图像应该看起来正常(默认状态),并根据滑块的值从蓝色(-100)到(100)进行更改。
在本地环境中,我能够将图像加载到画布中(由于某种原因,在jsfiddle上无法加载图像)。
主要问题是当前代码不能按预期修改颜色。

http://jsfiddle.net/q3qw1c0o/3/

   $(function(){

    var currentValue = $('#currentValue');


   $( "#slider" ).slider({
        range: "max",
        min: -100,
        max: 100,
        value: 0,
        slide: function( event, ui ) {
            $( "#sliderValue" ).val( ui.value );
            $(ui.value).val($('#sliderValue').val());
            changeIt(ui.value);
        }
        });

    $("#sliderValue").change(function() {
    $("#slider").slider("value" , $(this).val())
    });

});

 var x; //drawing context
var width;
var height;
var fg;
var buffer

window.onload = function() {
    var drawingCanvas = document.getElementById('myDrawing');
    // Check the element is in the DOM and the browser supports canvas
    if(drawingCanvas && drawingCanvas.getContext) {
        // Initaliase a 2-dimensional drawing context
        x = drawingCanvas.getContext('2d');
        width = x.canvas.width;
        height = x.canvas.height;

        fg = new Image();
        fg.src = 'http://icons.iconarchive.com/icons/iconshow/transport/256/Sportscar-car-icon.png';

        // to tint the image, draw it first
        x.drawImage(fg,0,0);

    }
}

    function changeIt(value) {


        // create offscreen buffer, 
        buffer = document.createElement('canvas');
        buffer.width = fg.width;
        buffer.height = fg.height;
        bx = buffer.getContext('2d');

        // fill offscreen buffer with the tint color
        bx.fillStyle = 'rgb(' + value + ', 0, ' + (255 - value) + ')';
        bx.fillRect(0,0,buffer.width,buffer.height);

        // destination atop makes a result with an alpha channel identical to fg, but with all pixels retaining their original color *as far as I can tell*
        bx.globalCompositeOperation = "destination-atop";
        bx.drawImage(fg,0,0);

                //then set the global alpha to the amound that you want to tint it, and draw the buffer directly on top of it.
        x.globalAlpha = 0.5;
        x.drawImage(buffer,0,0);

    }

请看一下。

1
我运行了你提供的代码,但是出现了一个错误:“theImage”未定义,你没有设置一个名为theImage的变量吗? - user2836518
@SythnetP 抱歉,我刚刚编辑了帖子。那不是问题,我只是错过了设置正确的变量名称。现在已经修复了。 - ComeRun
你知道如何在任何浏览器上使用控制台吗?我刚刚再次运行它,但是出现了“x.canvas.width未定义”的错误。 - user2836518
@SythnetP 我在控制台上没有看到任何错误!不过我的意思是函数changeIt没有按照预期的那样正常工作。你能看出问题出在哪里吗? - ComeRun
你正在使用globalAlpha将目标图像放在原始图层的顶部,导致你丢失了原始像素数据。你可以使用alpha通道作为填充样式(rgba),这会让你走得更远一些,但我强烈建议你像@markE所描述的那样使用像素操作。 - Shomz
1个回答

7
以下是使用getImageData来操作每个像素点的色调的一种方法:
  • 使用getImageData获取每个像素的RGBA颜色数据。
  • 将RGBA颜色转换为HSL颜色。HSL中的H表示色相,通常我们认为它就是“颜色”。
  • 如果原始像素的色相为红色(Hue<30或Hue>300),则按您所指定的范围控制器的数量移动色相。如果您想从红色向蓝色移动,则滑块应该将颜色(Hue)从0移动到-0.33。
注意:getImageData要求图像源与网页在同一个域中,否则您将收到跨域安全错误。
以下是示例代码和演示:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

var imgData,data,originalData;

$myslider=$('#myslider');
$myslider.attr({min:0,max:33}).val(0);
$myslider.on('input change',function(){
  var value=parseInt($(this).val());
  HueShift(30,300,-value/100);
});

var img=new Image();
img.crossOrigin='anonymous';
img.onload=start;
img.src="http://icons.iconarchive.com/icons/iconshow/transport/256/Sportscar-car-icon.png";
function start(){
  cw=canvas.width=img.width;
  ch=canvas.height=img.height;
  ctx.drawImage(img,0,0);

  imgData=ctx.getImageData(0,0,cw,ch);
  data=imgData.data;
  imgData1=ctx.getImageData(0,0,cw,ch);
  originalData=imgData1.data;

}



function HueShift(hue1,hue2,shift){

  for(var i=0;i<data.length;i+=4){
    red=originalData[i+0];
    green=originalData[i+1];
    blue=originalData[i+2];
    alpha=originalData[i+3];

    // skip transparent/semiTransparent pixels
    if(alpha<230){continue;}

    var hsl=rgbToHsl(red,green,blue);
    var hue=hsl.h*360;

    // change redish pixels to the new color
    if(hue<30 || hue>300){


      var newRgb=hslToRgb(hsl.h+shift,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,0,0);
}






////////////////////////
// Helper functions
//

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),
  });
}
body{ background-color: ivory; }
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Change the slider to change the car color</h4>
<input id=myslider type=range min=0 max=100 value=0><br>
<canvas id="canvas" width=300 height=300></canvas>


不用客气!以下是如何使用范围为 -100 到 100 从红色到蓝色的转变方法:https://jsfiddle.net/2cq8rf4n/ 祝您的项目好运! - markE
再次感谢,所以0值是正常图像,对吗? - ComeRun
1
如果你想从原始(红色)颜色变成蓝色,那么原始图像必须位于范围的两端(-100或100)。您可以将范围控件设置为0,这将是紫色。;-) - markE
有没有可能直接设置特定的颜色,例如当前默认图像颜色为红色,现在我想直接更改为白色或随机颜色,该如何传递值给 HueShift(30,300,-value/100); 函数呢?请帮忙解决这个小问题。 - Hitesh Tank
为什么不使用矩阵来直接相乘RGB呢? - user2039981
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接