Question

I am looking for an "eyedropper" tool, that gives me the hex value of the pixel the mouse cursor is under, in JavaScript for a CMS.

For Firefox, there is the excellent ColorZilla extension that does exactly that. However, it's FF only of course, and I would really like to deliver the tool along with the CMS.

A dutch developer has had the very clever idea of using a combination of Ajax and PHP's imagecolorat() to find out the Pixel colour on an image. But that limits the range to images I can access server side, and I'm really dreaming of a universal tool.

I will work with one of these approaches, but would much prefer a cross-browser, Javascript or Flash based way that requires no server-side fiddling and no installing of extensions.

I am also interested in any IE specific solutions that do what ColorZilla can do - I could live with supporting IE and FF only, though a cross browser solution would of course be ideal.

Was it helpful?

Solution

It's not possible with JavaScript as it goes against cross-domain security. It would be very bad if you knew what pixels made up the image, http://some-other-host/yourPassword.png. You can only tell the color of the pixel under the mouse if either the mouse is over a canvas or an image element of the same domain (or an image element of another domain which is served with an Access-Control-Allow-Origin: * header). In the case of the canvas, you would do canvasElement.getContext('2d').getImageData(x, y, 1, 1).data. In the case of the images, you would have to draw them to a canvas with:

var canvas = document.createElement("canvas");
canvas.width = yourImageElement.width;
canvas.height = yourImageElement.height;
canvas.getContext('2d').drawImage(yourImageElement, 0, 0);

And then just use the previous method explained for canvases. If you must be able to convert to various representations of color values, try my color.js library.

Also, you're never going to be able to support IE <9 (that's assuming that IE9 supports canvas) and using Flash won't help as it can't read the pixel data of the document either.

OTHER TIPS

Using a technique called Browser Timing Attack, it is possible to (sort of) determine the color of any pixel, even on iframes.

Basically, this technique measures the time to render an SVG filter on an element, rather than the color itself (requestAnimationFrame() allows to measure time with a much better accuracy than setTimeout()). Depending on the current pixel color, the filter takes more or less time to apply. This makes it possible to determine if a pixel is the same color as a known color - for instance black or white.

More details in this white paper (pdf): http://www.contextis.com/documents/2/Browser_Timing_Attacks.pdf

By the way: yes, this is a browser security hole, but I don't see how browser vendors can patch it.

Merging various references found here in StackOverflow and in other sites, I did so using javascript and JQuery:

<html>
<body>
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
<script src="jquery.js"></script>
<script type="text/javascript">
    window.onload = function(){
        var canvas = document.getElementById('myCanvas');
        var context = canvas.getContext('2d');
        var img = new Image();
        img.src = 'photo_apple.jpg';
        context.drawImage(img, 0, 0);
    };

    function findPos(obj){
    var current_left = 0, current_top = 0;
    if (obj.offsetParent){
        do{
            current_left += obj.offsetLeft;
            current_top += obj.offsetTop;
        }while(obj = obj.offsetParent);
        return {x: current_left, y: current_top};
    }
    return undefined;
    }

    function rgbToHex(r, g, b){
    if (r > 255 || g > 255 || b > 255)
        throw "Invalid color component";
    return ((r << 16) | (g << 8) | b).toString(16);
    }

$('#myCanvas').click(function(e){
    var position = findPos(this);
    var x = e.pageX - position.x;
    var y = e.pageY - position.y;
    var coordinate = "x=" + x + ", y=" + y;
    var canvas = this.getContext('2d');
    var p = canvas.getImageData(x, y, 1, 1).data;
    var hex = "#" + ("000000" + rgbToHex(p[0], p[1], p[2])).slice(-6);
    alert("HEX: " + hex);
});
</script>
<img src="photo_apple.jpg"/>
</body>
</html>

This is my complete solution.. Here I only used canvas and one image, but if you need to use <map> over the image, it's possible too. I hope I have helped.

I do agree with the very detailed answer provided by Elijah. In addition, I would say that you don't need the canvas when it comes to images. As you stated yourself, you have those images available from within php and can do the color-query on the server.

I would suggest that you handle this problem with an external tool - this makes it even browser indepedent (but OS dependent): write a small tool (for instance in c#) which does the color query for you, is invoked with a shortcut and submits the color to your server. Make the tool available as download on your CMS.

Another aproach I used for a CMS was to "steal" colors by parsing the CSS: the use case was to make the colors of an already existing web site available as color palette to my application:

  • I asked the user to provide a URL from the target system - mostly the company's home page
  • I parsed the page to find all color definitions in all inline styles and linked styles
  • (you can easily extend this to all referenced images)
  • the result was a nice color palette with all coporate colors to choose from

Maybe that's also a solution for your CMS?

I don't know if this is feasible, but if your pages are static you could save an image screenshot of each one of them (or maybe one for each browser/screen resolution? ) and then use AJAX to send the cursor coordinates to the server and return the pixel color with PHP's imagecolorat().

To take the screenshots, you could use Selenium IDE like described here.

Hope it helps.

See new input[type=color] HTML5 element: http://www.w3.org/TR/html-markup/input.color.html, http://demo.hongkiat.com/html5-form-input-type/index2.html.

Now it works at least in Chrome (tested in Ubuntu, should work for Windows too). It launches color-select dialog provided by operating system. If there is an eyedropper in this dialog (it is for Gnome), then it's possible to pick a color from any point on your screen. Not cross-browser yet, but clean and standards-based.

To add to the previous answers --

One way of thinking of this problem is that you want to be able to do a screen-capture of a 1px by 1px region. A fairly common technique for capturing screen regions (for instance from within Web-based bug-reporting systems) is to use a signed Java applet and java.awt.Robot to capture the picture. If you sign the applet, your users will get a "do you trust this app" dialog (with an "always trust apps from this publisher" checkbox) and then will be able to use the tool.

You can then pass the result out to JavaScript using LiveConnect (the docs are old, but Java applets still support this), or you can post it to your server. Similarly, you can call into the Java applet from JavaScript.

As a security precaution you can't capture screen pixels with Javascript (so developers can't take snapshots of your personal data), but you CAN do it in Flash -- you can get pixel data within the Flash container using the flash.display.BitmapData class.

Check out http://www.sephiroth.it/tutorials/flashPHP/print_screen/ -- I've used it in Flash-based WYSYWIG projects to save images to a LAMP (PHP) server.

The problem with using Flash is that it's not natively supported on iOS devices, which are extremely popular now and worth developing for. Flash is on its way down the tubes.

The canvas-based method will certainly be a good one provided all of your visitors have up-to-date web browsers that support the canvas tag and JavaScript.

There is no built in DOM method to generically get the color of a DOM element (other than images or a <canvas>) at a particular pixel location.

Thus, in order to do this, we must use something like HTML2Canvas or DOM Panda to take a "screenshot" of our website, get the user's click location, and get the pixel color of the "screenshot" at that particular location.

Using HTML2Canvas (version 0.5.0-beta3) you can do something like this:

// Take "screenshot" using HTML2Canvas
var screenshotCanvas,
    screenshotCtx,
    timeBetweenRuns = 10,
    lastTime = Date.now();
function getScreenshot() {
    // Limit how soon this can be ran again
    var currTime = Date.now();
    if(currTime - lastTime > timeBetweenRuns) {
        html2canvas(document.body).then(function(canvas) {
            screenshotCanvas = canvas;
            screenshotCtx = screenshotCanvas.getContext('2d');
        });
        lastTime = currTime;
    }
}
setTimeout(function() { // Assure the initial capture is done
    getScreenshot();
}, 100);

// Get the user's click location
document.onclick = function(event) {
    var x = event.pageX,
        y = event.pageY;

    // Look what color the pixel at the screenshot is
    console.log(screenshotCtx.getImageData(x, y, 1, 1).data);
}


// Update the screenshot when the window changes size
window.onresize = getScreenshot;

Demo

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top