JavaScript eyedropper (tell color of pixel under mouse cursor)

JavascriptJqueryColorsSelectionColor Picker

Javascript Problem Overview


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.

Javascript Solutions


Solution 1 - Javascript

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.

Solution 2 - Javascript

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): https://www.contextis.com/media/downloads/Pixel_Perfect_Timing_Attacks_with_HTML5_Whitepaper.pdf

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

Solution 3 - Javascript

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.

Solution 4 - Javascript

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?

Solution 5 - Javascript

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.

Solution 6 - Javascript

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.

Solution 7 - Javascript

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.

Solution 8 - 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.

Solution 9 - Javascript

Chrome Canary now supports EyeDropper API!

https://www.chromestatus.com/feature/6304275594477568

I believe we can expect it soon in all popular browsers.

Basically it will change user's cursor to magnifying glass and lets him select any pixel on page (works with images, videos and iframes).

const eyeDropper = new EyeDropper()

async function useEyeDropper() {
  try {
    const selectedColor = await eyeDropper.open()
    console.log(selectedColor) // { sRGBHex: '#008080' }
  } catch (err) {
    console.log('eye dropper cancelled')
  }
}

someTriggerEl.addEventListener('click', () => {
  useEyeDropper();
})

If you don't understand async/await well:

const eyeDropper = new EyeDropper()

someTriggerEl.addEventListener('click', () => {
  eyeDropper.open().then(selectedColor => {
    console.log(selectedColor) // { sRGBHex: '#008080' }
  }).catch(() => {
    console.log('eye dropper cancelled')
  })
})

I'm so hyped about this feature

Solution 10 - 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

Solution 11 - Javascript

I know this is a very old post but a new API call feature from google chrome came up called "eyeDropper"

this was taken from that blog

const eyeDropper = new EyeDropper();

try {
  const selectedColor = await eyeDropper.open();
  console.log(selectedColor);
  // logs: { sRGBHex: '#ff0000' }
} catch (err) {
  console.log("color selection cancelled");
}
//You can test for support of EyeDropper using the following snippet, if you’re browsing with a browser that supports the EyeDropper API a button will be rendered below the code snippet.

if ("EyeDropper" in window) {
  // supported
}

https://pqina.nl/blog/use-the-javascript-eye-dropper-api-to-select-colors-on-the-web/

Solution 12 - Javascript

I would like to add two important considerations on @BorrisTB's answer (and to everyone's answer pointing to the availability of EyeDropper API).

  1. We implemented Eyedropper API on a project which was running smoothly on my machine but was giving me EyeDropper is undefined on production server. Turns out it needed window.isSecureContext = true. Which is possible on localhost, and on HTTPS only. So make sure the page is loaded over HTTPS, for API to be available.
  2. At the moment it is only available on chromium based browsers and that too on Desktops only. Mozilla and Safari do not support this feature, and have no plan for supporting it for security reason. Please refer to the table below https://developer.mozilla.org/en-US/docs/Web/API/EyeDropper_API#browser_compatibility

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPekkaView Question on Stackoverflow
Solution 1 - JavascriptEli GreyView Answer on Stackoverflow
Solution 2 - JavascriptFrançois ZaninottoView Answer on Stackoverflow
Solution 3 - JavascriptebragaparahView Answer on Stackoverflow
Solution 4 - JavascriptrdmuellerView Answer on Stackoverflow
Solution 5 - JavascripttemaView Answer on Stackoverflow
Solution 6 - JavascriptjbochiView Answer on Stackoverflow
Solution 7 - JavascriptWilliam BillingsleyView Answer on Stackoverflow
Solution 8 - JavascriptsupershwaView Answer on Stackoverflow
Solution 9 - JavascriptBorisTBView Answer on Stackoverflow
Solution 10 - JavascriptZach SaucierView Answer on Stackoverflow
Solution 11 - JavascriptSir XtCView Answer on Stackoverflow
Solution 12 - JavascriptUsman ShaukatView Answer on Stackoverflow