Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HTML5 Canvas: Change Image Color

I have an image(in greyscale form) of which i want to change the color(user specific). Since its quite difficult to change the color of a greyscale image, i come with an approach.

Image is divided into two parts.

  1. One is the image with white color.
  2. Second, a semi transparent image with grayscale.

Now, i place both image on top of each other(with white image on below and greyscale image on top) such that when i change the color of white image, it will be visible to user.

Problem: This approach works for me, except one issue. When i color the white image, it will pixellete from corners.

JSFiddle: http://jsfiddle.net/pandey_mohit/BeSwL/

JSFiddle contains three images for capsules:

  1. Top Capsule Part White Image (for coloring)
  2. Bottom Capsule Part White Image (for coloring)
  3. Semi Transparent Image for 3D effect (using grayscale)

Select red, green or blue color to see the issue.

function hexToRgb(color) {
    var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
    color = color.replace(shorthandRegex, function(m, r, g, b) {
        return r + r + g + g + b + b;
    });

    var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(color);
    return result ? {
        r: parseInt(result[1], 16),
        g: parseInt(result[2], 16),
        b: parseInt(result[3], 16)
    } : {
        r: 0,
        g: 0,
        b: 0
    };
}

function colorImage(imgId,hexaColor) {
    // create hidden canvas (using image dimensions)
    var imgElement = document.getElementById(imgId);

    var canvas = document.createElement("canvas");
    canvas.width = imgElement.width;
    canvas.height = imgElement.height;

    var ctx = canvas.getContext("2d");
    ctx.drawImage(imgElement,0,0);

    var imageData = ctx.getImageData(0,0,canvas.width,canvas.height);

    var data = imageData.data;

    // convert image to grayscale
    var rgbColor = hexToRgb(hexaColor);

    for(var p = 0, len = data.length; p < len; p+=4) {
        if(data[p+3] == 0)
           continue;
        data[p + 0] = rgbColor.r;
        data[p + 1] = rgbColor.g;
        data[p + 2] = rgbColor.b;
        data[p + 3] = 255;
    }
    ctx.putImageData(imageData, 0, 0);

    // replace image source with canvas data
    imgElement.src = canvas.toDataURL();
}

// changing color of capsule on select event
document.getElementById('sel_top').onchange = function(){
    colorImage('img_top', this.value);
}
document.getElementById('sel_bottom').onchange = function(){
    colorImage('img_bottom', this.value);
}
like image 816
Mohit Pandey Avatar asked Jun 25 '14 09:06

Mohit Pandey


1 Answers

Your recoloring algorithm sets the 4th byte of each RGBA quartet to 255, which discards the alpha channel of the overlay and breaks the anti-aliasing around the edges of the image. Keeping the alpha channel of the original gives you better results:

for(var p = 0, len = data.length; p < len; p+=4) {
    data[p + 0] = rgbColor.r;
    data[p + 1] = rgbColor.g;
    data[p + 2] = rgbColor.b;
}

JSFiddle with the lines commented out

like image 79
Philipp Avatar answered Oct 12 '22 20:10

Philipp