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
1 Answer
Reset to default 7Here's one way using getImageData
to manipulate the hue of each image pixel:
Use
getImageData
to fetch the RGBA color data of each pixelConvert 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>