最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - HTML5 Canvas changing image color - Stack Overflow

programmeradmin2浏览0评论

I am using jquery slider to change my image color from Blue to red (with range of -100 to 100), by tinting it. It means when the slider value is 0, the image should look normal (default one) and changes based on the value of the slider from blue (-100) to (100).

In my local I am able to load the image into my canvas (for some reason the image is not loaded on jsfiddle).

The main issue is the current code does not modify the color as expected.

/

   $(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 = '.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);

    }

Please have a look.

I am using jquery slider to change my image color from Blue to red (with range of -100 to 100), by tinting it. It means when the slider value is 0, the image should look normal (default one) and changes based on the value of the slider from blue (-100) to (100).

In my local I am able to load the image into my canvas (for some reason the image is not loaded on jsfiddle).

The main issue is the current code does not modify the color as expected.

http://jsfiddle/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./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);

    }

Please have a look.

Share Improve this question edited Mar 19, 2015 at 23:50 ComeRun asked Mar 19, 2015 at 23:30 ComeRunComeRun 9211 gold badge20 silver badges39 bronze badges 5
  • 1 I ran the code you supplied and I am getting an error 'theImage' is undefined, are you not setting a variable called theImage? – user2836518 Commented Mar 19, 2015 at 23:35
  • @SythnetP sorry just edited the post. thats not the issue I just missed to set the correct var names. fixed now. – ComeRun Commented Mar 19, 2015 at 23:51
  • Do you know how to use the console on any browser? I just ran it again and I am getting x.canvas.width is not defined – user2836518 Commented Mar 19, 2015 at 23:55
  • @SythnetP I dont get any error on console! anyway My point is the function changeIt which does not work properly and as expected. can you see where the issue is? – ComeRun Commented Mar 20, 2015 at 0:32
  • You're putting the destination image on top of the original layer, causing you to lose the original pixel data using globalAlpha. You can use alpha channel for the fill style (rgba), and it will get you a bit farther, but I strongly suggest you use pixel manipulation as @markE has described. – Shomz Commented Mar 20, 2015 at 0:38
Add a ment  | 

1 Answer 1

Reset to default 7

Here's one way using getImageData to manipulate the hue of each image pixel:

  • Use getImageData to fetch the RGBA color data of each pixel

  • Convert the RGBA color to HSL color. The H in HSL means Hue which is what we normally think of as "color".

  • If the Hue of an original pixel is red-ish (Hue<30 or Hue>300) then shift the hue by the amount specified in your range control. If you want to shift from red to blue, then your slider should shift the color (Hue) from 0 to -.33.

Note: getImageData requires that the image originate on the same domain as the webpage or else you will get a cross-domain security error.

Here's example code and a Demo:

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./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./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>

发布评论

评论列表(0)

  1. 暂无评论