I'm using ocanvas to design a game and I'm wondering if there is some way to change the hue of a sprite. If not, is there a way to integrate an html5 canvas way of changing the hue of a sprite to ocanvas?
-
why is my question getting down-voted? There's nothing on ocanvas' documentation about this at all, and I don't know how to integrate canvas' abilities into ocanvas – Jeff May 29 '15 at 01:23
2 Answers
I don't have information about ocanvas, but here's how to change the hue of a sprite drawn onto an html5 canvas.
This method uses context.getImageData
to fetch the color data of every pixel on the canvas. Then any pixel with a blue-ish hue is changed to a green-ish hue.
Note: If your sprites have more discrete coloring (f.ex: the sprite has a specific blue color that you wish to change to a specific green color) then you won't need to convert to-and-from the HSL color format.
If necessary, you can convert this recolored html5 canvas into a sprite-image to include in ocanvas using .toDataURL
.
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<230){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),
});
}
body{ background-color: ivory; }
canvas{border:1px solid red;}
<p>Example shifting color Hue with .getImageData</p>
<p>(Original: left, Recolored: right)</p>
<canvas id="canvas" width=300 height=300></canvas>

- 102,905
- 11
- 164
- 176
-
That's an awesome answer, thank you! but I can't use it because i need to know how to change a sprite, not an area on the canvas. Is there a way to change only the pixels on the sprite and not the pixels on the canvas? – Jeff May 30 '15 at 10:51
-
Sure, you just draw the desired sprite onto a separate canvas element and do you magic there. Since another canvas can be the image source for `drawImage`, you just drawImage the sprite canvas to your main canvas: `context.drawImage(aSpriteCanvas,x,y);` ;-) – markE May 30 '15 at 14:30
Another popular solution is to use grayscale images and color them in JS via globalCompositeOperation in canvas. Described in detail here: http://buildnewgames.com/global-composit-operations/#colored-sprite-masks-with-codesource-atopcode
I put together an example of how it could be done in conjunction with oCanvas: http://jsfiddle.net/g0tj7vrv/
HTML:
<script src="https://cdnjs.cloudflare.com/ajax/libs/ocanvas/2.7.4/ocanvas.min.js"></script>
<canvas id="canvas" width="400" height="400"></canvas>
JS:
var canvas = oCanvas.create({
canvas: '#canvas',
background: '#000'
});
canvas.display.register('colorizedImage', {
hue: '',
path: '',
width: 0,
heigth: 0,
_renderNewColor: function(tempImage) {
if (!this._tempCanvas) {
this._tempCanvas = document.createElement('canvas');
}
this._createColorizedImage(this._tempCanvas, tempImage, this.hue);
var self = this;
setTimeout(function() {
self.core.redraw();
}, 0);
},
_createColorizedImage: function(tempCanvas, imageElement, hue) {
var tempContext = tempCanvas.getContext('2d');
tempCanvas.width = imageElement.width;
tempCanvas.height = imageElement.height;
tempContext.drawImage(imageElement, 0, 0);
tempContext.fillStyle = 'hsla(' + hue + ', 50%, 50%, 0.5)';
tempContext.globalCompositeOperation = 'source-atop';
tempContext.fillRect(0, 0, tempCanvas.width, tempCanvas.height);
}
}, function(context) {
if (this._tempCanvas) {
var origin = this.getOrigin();
var x = this.abs_x - origin.x;
var y = this.abs_y - origin.y;
var w = this.width || this._tempCanvas.width;
var h = this.height || this._tempCanvas.height;
context.drawImage(this._tempCanvas, x, y, w, h);
}
if (this.path !== this._lastPathBeingLoaded) {
this._lastPathBeingLoaded = this.path;
var tempImage = new Image();
tempImage.src = this.path;
var self = this;
tempImage.onload = function() {
if (self.path === this.src) {
self._renderNewColor(tempImage);
}
};
this._lastImageElement = tempImage;
}
if (this.hue !== this._lastHueBeingLoaded) {
this._lastHueBeingLoaded = this.hue;
this._renderNewColor(this._lastImageElement);
}
});
var colorizedImage = canvas.display.colorizedImage({
hue: 0,
path: 'https://dl.dropboxusercontent.com/u/2645586/gco/cobra-primary.png',
origin: {x: -60, y: 0},
width: 120,
height: 120,
x: canvas.width / 2,
y: canvas.height / 2
});
canvas.addChild(colorizedImage);
canvas.setLoop(function() {
colorizedImage.hue = (colorizedImage.hue + 10) % 360;
colorizedImage.rotation -= 2;
}).start();

- 51
- 2