Manish Kumar
Manish Kumar

Reputation: 1176

Javascript canvas pixel manipulation

I have product images and each image has two configurable areas as below: 1. background 2. Foreground

I have to develop a feature where customer can change the color of both areas and save the design.

My problem is, i am traversing the image to read old pixel value and change it with new selected color.

Bit old pixel values are not consistent. There is textured effect on the image, which is causing the pixel value to be changed at every pixel.

How can i achieve the desired the functionality?

or, if you can suggest me any other approach, that will be great.

sample image link: http://developersbench.com/canvas/img/design_2.jpg

Upvotes: 2

Views: 3765

Answers (2)

GameAlchemist
GameAlchemist

Reputation: 19294

If i guess right, what you want is to change the pixels that are 'near' from a given color to be changed into another color.

Easiest way i see is to use h,s,l color space : in this 'natural' color space, colors that have a similar hue will be similarly perceived by the eye. And you can just 'shift' the hue, while keeping same saturation (== color 'strength'), and lightness.

So process your image point by point :
• Convert point r, g, b to hue, saturation, lightness
• ? Is the current hue near enough from sourceHue ?
---->> shift it to newHue (keeping same saturation / lightness)

fiddle is here :

http://jsfiddle.net/9GLNP/

You can play around with parameters. The texture you provided has 18 avg hue, so if the source hue is too far from 18, no changes will be done. 8-10 seems a good tolerance.

enter image description here

// Provides a new canvas containing [img] where
// all pixels having a hue less than [tolerance] 
// distant from [tgtHue] will be replaced by [newHue]
function shiftHue(img, tgtHue, newHue, tolerance) {
    // normalize inputs
    var normalizedTargetHue = tgtHue / 360;
    var normalizedNewHue = newHue / 360;
    var normalizedTolerance = tolerance / 360;
    // create output canvas
    var cv2 = document.createElement('canvas');
    cv2.width = img.width;
    cv2.height = img.height;
    var ctx2 = cv2.getContext('2d');
    ctx2.drawImage(img, 0, 0);
    // get canvad img data 
    var imgData = ctx2.getImageData(0, 0, img.width, img.height);
    var data = imgData.data;
    var lastIndex = img.width * img.height * 4;
    var rgb = [0, 0, 0];
    var hsv = [0.0, 0.0, 0.0];
    // loop on all pixels
    for (var i = 0; i < lastIndex; i += 4) {
        // retrieve r,g,b (! ignoring alpha !) 
        var r = data[i];
        var g = data[i + 1];
        var b = data[i + 2];
        // convert to hsv
        RGB2HSV(r, g, b, hsv);
        // change color if hue near enough from tgtHue
        var hueDelta = hsv[0] - normalizedTargetHue;
        if (Math.abs(hueDelta) < normalizedTolerance) {
            // adjust hue
            // ??? or do not add the delta ???
            hsv[0] = normalizedNewHue  //+ hueDelta;
            // convert back to rgb
            hsvToRgb(rgb, hsv);
            // store
            data[i] = rgb[0];
            data[i + 1] = rgb[1];
            data[i + 2] = rgb[2];
        }
    }
    ctx2.putImageData(imgData, 0, 0);
    return cv2;
}

EDIT : To get the hue, i consoled.log the hues... ;-) But many (if not all) image software have a color picker that shows hsl.
For hsl, i have no specific links. google it, and also play with it within a graphic software.
To avoid coding nightmare, i guess you have to decide of a convention on the textures you use, like they are 60 +/- 5 hue or like. So then you only have to decide of the final hue in your game. Detection might be tricky.

Upvotes: 3

markE
markE

Reputation: 105015

I'm assuming you already know how to do context.getImageData to get the RGBA pixel data of your images.

The RGBA format that html5 canvas uses by default is not very useful when changing colors. Two visually similar colors often have very different RGB values.

Instead, convert these RGBA colors to HSL format. The "H" in HSL is "hue" which is what we think of as color. You will find similar colored pixels will have similar HSL "Hue" values.

Then you can let the user recolor the image by "shifting" the existing hue values by a constant offset.

A Demo: http://jsfiddle.net/m1erickson/326yc/

Upvotes: 1

Related Questions