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

javascript - Is canvas getImageData method machinebrowser dependent? - Stack Overflow

programmeradmin0浏览0评论

A client required help with a program that extracts the dominant color of a product image.

I was able to quickly implement this in Javascript; the algorithm below only samples the central square of a 3x3 grid on the image for a quick estimate of the t-shirt color in the image.

var image = new Image();
image.onload = function() {
    try {
        // get dominant color by sampling the central square of a 3x3 grid on image
        var dominantColor = getDominantColor();

        // output color
        $("#output").html(dominantColor);
    }
    catch(e) {
        $("#output").html(e);
    }
};
image.src = "sample_image.jpg";

function getDominantColor() {

    // Copy image to canvas
    var canvas = $("<canvas/>")[0];
    canvas.width = image.width;
    canvas.height = image.height;
    canvas.getContext("2d").drawImage(image, 0, 0);

    // get pixels from the central square of a 3x3 grid
    var imageData = canvas.getContext("2d").getImageData(canvas.width/3, canvas.height/3, canvas.width/3, canvas.height/3).data;

    var colorOccurrences = {};
    var dominantColor = "";
    var dominantColorOccurrence = 0;

    for(var i = 0; i < imageData.length; i += 4) {
        var red = imageData[i];
        var green = imageData[i+1];
        var blue = imageData[i+2];
        //var alpha = imageData[i+3]; // not required for this task

        var color = RGBtoHEX({"red": red, "green": green, "blue": blue});

        if(colorOccurrences[color] == undefined) {
            colorOccurrences[color] = 1;
        }
        else {
            colorOccurrences[color] ++;

            if(colorOccurrences[color] > dominantColorOccurrence) {
                dominantColorOccurrence = colorOccurrences[color];
                dominantColor = color;
            }
        }
    }

    return dominantColor;
}

function RGBtoHEX(rgb) {
    var hexChars = "0123456789ABCDEF";
    return "#"
            + (hexChars[~~(rgb.red/16)] + hexChars[rgb.red%16])
            + (hexChars[~~(rgb.green/16)] + hexChars[rgb.green%16])
            + (hexChars[~~(rgb.blue/16)] + hexChars[rgb.blue%16]);
}

The image in question is this (preview below).

However, the results when this image is processed in the code above are varied across machines/browsers: #FF635E is what I see on my machine, running Windows7 and using Firefox 32. My client running Mac gets a result of #FF474B on Safari and #FF474C on Firefox 33.

Though the results are close, why are they ideally not the exact same? Does getImageData indeed vary depending on the local setup, or is the JPG data being interpreted differently on different machines?

Edit: This image isn't a one-off case. Such color variations were noticed across a range of the image that the client requested to process. My client and I obtained different results for the same set of images.

A client required help with a program that extracts the dominant color of a product image.

I was able to quickly implement this in Javascript; the algorithm below only samples the central square of a 3x3 grid on the image for a quick estimate of the t-shirt color in the image.

var image = new Image();
image.onload = function() {
    try {
        // get dominant color by sampling the central square of a 3x3 grid on image
        var dominantColor = getDominantColor();

        // output color
        $("#output").html(dominantColor);
    }
    catch(e) {
        $("#output").html(e);
    }
};
image.src = "sample_image.jpg";

function getDominantColor() {

    // Copy image to canvas
    var canvas = $("<canvas/>")[0];
    canvas.width = image.width;
    canvas.height = image.height;
    canvas.getContext("2d").drawImage(image, 0, 0);

    // get pixels from the central square of a 3x3 grid
    var imageData = canvas.getContext("2d").getImageData(canvas.width/3, canvas.height/3, canvas.width/3, canvas.height/3).data;

    var colorOccurrences = {};
    var dominantColor = "";
    var dominantColorOccurrence = 0;

    for(var i = 0; i < imageData.length; i += 4) {
        var red = imageData[i];
        var green = imageData[i+1];
        var blue = imageData[i+2];
        //var alpha = imageData[i+3]; // not required for this task

        var color = RGBtoHEX({"red": red, "green": green, "blue": blue});

        if(colorOccurrences[color] == undefined) {
            colorOccurrences[color] = 1;
        }
        else {
            colorOccurrences[color] ++;

            if(colorOccurrences[color] > dominantColorOccurrence) {
                dominantColorOccurrence = colorOccurrences[color];
                dominantColor = color;
            }
        }
    }

    return dominantColor;
}

function RGBtoHEX(rgb) {
    var hexChars = "0123456789ABCDEF";
    return "#"
            + (hexChars[~~(rgb.red/16)] + hexChars[rgb.red%16])
            + (hexChars[~~(rgb.green/16)] + hexChars[rgb.green%16])
            + (hexChars[~~(rgb.blue/16)] + hexChars[rgb.blue%16]);
}

The image in question is this (preview below).

However, the results when this image is processed in the code above are varied across machines/browsers: #FF635E is what I see on my machine, running Windows7 and using Firefox 32. My client running Mac gets a result of #FF474B on Safari and #FF474C on Firefox 33.

Though the results are close, why are they ideally not the exact same? Does getImageData indeed vary depending on the local setup, or is the JPG data being interpreted differently on different machines?

Edit: This image isn't a one-off case. Such color variations were noticed across a range of the image that the client requested to process. My client and I obtained different results for the same set of images.

Share Improve this question edited Oct 28, 2014 at 18:25 SNag asked Oct 28, 2014 at 18:16 SNagSNag 18.2k11 gold badges57 silver badges69 bronze badges 3
  • This has to do with the browser applying or not a color profile, and which one. – GameAlchemist Commented Oct 28, 2014 at 20:33
  • 1 A third party image processing library that doesn't depend on the browser's canvas functionality might help. For example, this is a good library. – Adam Commented Aug 6, 2016 at 0:10
  • 1 There are 2 other ways around this. One is to use WebGL and readPixels. WebGL can turn off the color correction by calling gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE); before uploading the image. You'd then render it and read back the pixels. Another way is to use the ImageBitmap api. Unfortunately it looks like only Chrome supports the full spec with options to ignore color space conversions. – user128511 Commented Dec 10, 2018 at 13:39
Add a ment  | 

1 Answer 1

Reset to default 8

Yes. This fact is exploited by canvas fingerprinting:

The same HTML5 Canvas element can produce exceptional pixels on a different web browsers, depending on the system on which it was executed.

This happens for several reasons: at the image format level — web browsers uses different image processing engines, export options, pression level, final images may got different hashes even if they are pixel-perfect; at the pixmap level — operating systems use different algorithms and settings for anti-aliasing and sub-pixel rendering. We don't know all the reasons, but we have already collected more than a thousand unique signatures.

发布评论

评论列表(0)

  1. 暂无评论