JavaScript 吸管(在鼠标光标下分辨像素的颜色)

JavaScript eyedropper (tell color of pixel under mouse cursor)

提问人:Pekka 提问时间:12/20/2009 最后编辑:Zach SaucierPekka 更新时间:10/14/2022 访问量:68865

问:

我正在寻找一个“吸管”工具,它为我提供了鼠标光标所在像素的十六进制值,在 JavaScript 中用于 CMS。

对于Firefox,有一个出色的ColorZilla扩展可以做到这一点。但是,它当然只是 FF,我真的很想将该工具与 CMS 一起交付。

一位荷兰开发人员有一个非常聪明的想法,即结合使用 Ajax 和 PHP 来找出图像上的像素颜色。但这限制了我可以访问服务器端的图像的范围,我真的梦想着一个通用工具。imagecolorat()

我将使用其中一种方法,但更喜欢跨浏览器、Javascript 或基于 Flash 的方式,不需要服务器端摆弄,也不需要安装扩展。

我也对任何 IE 特定的解决方案感兴趣,这些解决方案可以做 ColorZilla 可以做的事情 - 我可以忍受只支持 IE 和 FF,尽管跨浏览器解决方案当然是理想的。

javascript jquery 颜色 选择器

评论

0赞 SLaks 12/20/2009
这在 Javascript 中是不可能的;我不确定 Flash。
0赞 Aaronaught 1/4/2010
从理论上讲,您可能能够在鼠标光标下处理与最顶层元素关联的样式信息,并确定元素的颜色如果它不是图像或画布)。在实践中,这可能会让你发疯,处理边框、边距和浏览器怪癖。我认为以利亚的回答是唯一实用的答案。

答:

90赞 Eli Grey 12/20/2009 #1

JavaScript 是不可能的,因为它违反了跨域安全性。如果您知道图像是由哪些像素构成的,那就太糟糕了。只有当鼠标位于画布或同一域的图像元素(或带有标题的另一个域的图像元素)上时,才能分辨鼠标下方像素的颜色。对于画布,你会做.对于图像,您必须使用以下命令将它们绘制到画布上:http://some-other-host/yourPassword.pngAccess-Control-Allow-Origin: *canvasElement.getContext('2d').getImageData(x, y, 1, 1).data

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

然后只需使用前面为画布解释的方法。如果您必须能够转换为颜色值的各种表示形式,请尝试我的 color.js 库。

此外,你永远无法支持 IE <9(假设 IE9 支持 canvas),使用 Flash 也无济于事,因为它也无法读取文档的像素数据。

评论

6赞 Pekka 12/21/2009
关于安全性的有趣方面,感谢 Canvas 角度。但是,我可以忍受只能访问我的域中的像素。
0赞 Pekka 1/8/2010
谢谢以利亚。我有点难过,这仅限于Firefox,但这不是你的错,这绝对是最简单的解决方案。我可能会将它与(较慢的)服务器端回退选项结合起来,以满足 IE 的需求。接受你的答案。
1赞 hughes 11/9/2013
什么会阻止我嵌入到画布中,然后在那里采样?(假设我知道网址)yourPassword.png
1赞 Dan Ross 1/12/2014
@zzzzBov,@hughes,你错过了重点:如果你能抓取屏幕上的任何像素,那么你就可以在不同的浏览器窗口中查看值,甚至可以在不同的窗口中查看PDF银行对账单上的值。任何人都不应在处理敏感信息的页面上运行不受信任的 JS,并且提供敏感文件应涉及适当的身份验证。您需要劫持用户的会话才能访问他们的 .password.png
2赞 zzzzBov 1/12/2014
@danross,JS 没有用于执行脚本的跨沙盒访问权限(除非获得明确权限),因此没有理由不能将 API 限制为来自同一安全沙箱中帧的颜色值。
7赞 rdmueller 1/4/2010 #2

我确实同意以利亚提供的非常详细的回答。此外,我想说的是,当涉及到图像时,你不需要画布。正如您自己所说,您可以从 php 中获取这些图像,并且可以在服务器上进行颜色查询。

我建议你用一个外部工具来处理这个问题 - 这使得它甚至独立于浏览器(但依赖于操作系统):编写一个小工具(例如在c#中),它为你执行颜色查询,使用快捷方式调用并将颜色提交到你的服务器。将该工具作为下载工具提供在您的 CMS 上。

我用于 CMS 的另一个方法是通过解析 CSS 来“窃取”颜色:用例是将现有网站的颜色作为调色板提供给我的应用程序:

  • 我要求用户提供来自目标系统的 URL——主要是公司的主页
  • 我解析了页面以查找所有内联样式和链接样式中的所有颜色定义
  • (您可以轻松地将其扩展到所有引用的图像)
  • 结果是一个漂亮的调色板,有所有公司的颜色可供选择

也许这也是您的 CMS 的解决方案?

评论

0赞 Pekka 1/8/2010
干杯拉尔夫。构建自定义调色板是一个非常好的主意,但不适合我手头的任务,因为会有很多没有定义颜色范围的新内容。客户端应用程序当然是最干净的方法,但我需要一个同时适用于 Windows 和 Mac OS 的工具。这是一个很好的理由,可以再次回到客户端编程(也是第一次在Mac上),但我现在有很多事情要做。我想我只采用图像方法。
5赞 jbochi 1/5/2010 #3

我不知道这是否可行,但是如果您的页面是静态的,您可以保存每个页面的图像屏幕截图(或者每个浏览器/屏幕分辨率都保存一个图像屏幕截图?),然后使用AJAX将光标坐标发送到服务器并使用PHP返回像素颜色。imagecolorat()

要截取屏幕截图,您可以使用 Selenium IDE如此处所述。

希望它有所帮助。

3赞 William Billingsley #4

补充前面的答案——

考虑此问题的一种方式是,您希望能够对 1px x x 1px 区域进行屏幕截图。捕获屏幕区域(例如,从基于 Web 的错误报告系统中)的一种相当常见的技术是使用签名的 Java 小程序和 java.awt.Robot 来捕获图片。如果对小程序进行签名,用户将看到一个“是否信任此应用”对话框(其中包含“始终信任此发布者中的应用”复选框),然后将能够使用该工具。

然后,您可以使用 LiveConnect 将结果传递给 JavaScript(文档很旧,但 Java 小程序仍然支持此功能),也可以将其发布到服务器。同样,您可以从 JavaScript 调入 Java 小程序。

评论

0赞 Pekka 1/8/2010
Java Applet 的角度很有趣。然而,我并不精通编写小程序,所以我可能无法为我手头的任务实现它,我将求助于上面概述的 Canvas 方法。但是,感谢您引起我的注意,我以后可能会用它做点什么。
12赞 ebragaparah 1/10/2012 #5

合并了 StackOverflow 和其他站点中的各种引用,我使用 javascript 和 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>

这是我的完整解决方案..在这里,我只使用了画布和一张图像,但如果您需要在图像上使用,也可以。我希望我有所帮助。<map>

评论

3赞 SearchForKnowledge 4/13/2015
使用滴管从任何地方获取颜色怎么样?
3赞 supershwa 3/20/2012 #6

为了安全起见,您不能使用 Javascript 捕获屏幕像素(因此开发人员无法拍摄您的个人数据的快照),但您可以在 Flash 中执行此操作 - 您可以使用 flash.display.BitmapData 类在 Flash 容器中获取像素数据。

查看 http://www.sephiroth.it/tutorials/flashPHP/print_screen/ -- 我在基于 Flash 的 WYSYWIG 项目中使用它来将图像保存到 LAMP (PHP) 服务器。

使用 Flash 的问题在于它在 iOS 设备上不受原生支持,而 iOS 设备现在非常流行,值得开发。闪光灯正在沿着管子向下移动。

基于 canvas 的方法肯定是一个不错的方法,前提是您的所有访问者都拥有支持 canvas 标签和 JavaScript 的最新 Web 浏览器。

7赞 tema 3/3/2013 #7

请参阅新的 input[type=color] HTML5 元素:http://www.w3.org/TR/html-markup/input.color.htmlhttp://demo.hongkiat.com/html5-form-input-type/index2.html

现在它至少可以在 Chrome 中工作(在 Ubuntu 中测试,也应该适用于 Windows)。它启动操作系统提供的颜色选择对话框。如果这个对话框中有一个吸管(它是给Gnome的),那么你可以从屏幕上的任何一点选择一种颜色。还不是跨浏览器的,但干净且基于标准。

评论

0赞 NoBugs 2/7/2016
好。当然,在Firefox中也可以使用,但是如果您可以在不弹出浏览器对话框的情况下做到这一点,那就太好了。
3赞 mattsven 7/14/2020
不幸的是,Chrome 最近更新了他们的表单控件设计,他们的新颜色选择器没有吸管。
22赞 François Zaninotto 1/30/2014 #8

使用一种称为浏览器定时攻击的技术,可以(某种程度上)确定任何像素的颜色,即使在 iframe 上也是如此。

基本上,这种技术测量的是渲染 SVG 滤镜在元素上的时间,而不是颜色本身(允许以比 更好的精度测量时间)。根据当前的像素颜色,滤镜需要或多或少的时间来应用。这样就可以确定像素是否与已知颜色相同 - 例如黑色或白色。requestAnimationFrame()setTimeout()

本白皮书(pdf)中的更多详细信息:https://www.contextis.com/media/downloads/Pixel_Perfect_Timing_Attacks_with_HTML5_Whitepaper.pdf

顺便说一句:是的,这是一个浏览器安全漏洞,但我不明白浏览器供应商如何修补它。

评论

0赞 bren 8/8/2016
有趣的解决方法,但由于跨域策略,它不是安全的吗?
0赞 Rodrigo 6/26/2020
这篇论文已经快 7 岁了!有谁知道这个安全漏洞今天是否仍然存在?
0赞 xendi 8/10/2020
我怀疑它是否已修复,CORS 不适用。
3赞 Zach Saucier 3/14/2017 #9

没有内置的 DOM 方法可以在特定像素位置获取 DOM 元素(图像或 除外)的颜色。<canvas>

因此,为了做到这一点,我们必须使用 HTML2CanvasDOM Panda 之类的东西来截取我们网站的“屏幕截图”,获取用户的点击位置,并在该特定位置获取“屏幕截图”的像素颜色。

使用 HTML2Canvas(版本 0.5.0-beta3),您可以执行如下操作:

// 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;

演示

评论

0赞 shreyasm-dev 6/23/2020
下面是实现上述解决方案的演示: jsfiddle.net/8850s/an9f24hp 单击左上角的 div 设置(甚至在 div 本身上)background-color
7赞 BorisTB 9/28/2021 #10

Chrome Canary 现在支持 EyeDropper API!

更新:在 Chrome 95+ 中受支持

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

我相信我们很快就会在所有流行的浏览器中期待它。

基本上,它会将用户的光标更改为放大镜,并让他选择页面上的任何像素(适用于图像、视频和 iframe)。

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();
})

如果你不太了解 async/await:

const eyeDropper = new EyeDropper()

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

我对这个功能非常兴奋

评论

1赞 kevin walker 10/21/2021
从 Chrome 95 开始,这是实时😀的 很棒的 snippit @BorisTB
1赞 sarkiroka 10/14/2022
今天,Linux 上最新的 chrome 会产生“rgba(172, 150, 118, 0)”,其中 alpha 通道始终为零,而不是十六进制结果。因此,您需要对结果进行一些手动处理。
3赞 Sir XtC 10/20/2021 #11

我知道这是一个非常古老的帖子,但是谷歌浏览器出现了一个新的 API 调用功能,称为“eyeDropper”

这是从那个博客中摘录的

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/

1赞 Usman Shaukat 12/2/2021 #12

我想对 @BorrisTB 的回答(以及每个人的回答都指向 EyeDropper API 的可用性)添加两个重要的考虑因素。

  1. 我们在一个运行顺利的项目上实现了 Eyedropper API 在我的机器上,但给了我 生产服务器。事实证明它需要.这在 localhost 上是可能的,并且仅在 HTTPS 上是可能的。所以让 确保页面通过 HTTPS 加载,以便 API 可用。EyeDropper is undefinedwindow.isSecureContext = true
  2. 目前,它仅在基于 chromium 的浏览器上可用,并且 也仅适用于台式机。Mozilla 和 Safari 不支持此功能 功能,并且出于安全原因没有计划支持它。 请参阅下表 https://developer.mozilla.org/en-US/docs/Web/API/EyeDropper_API#browser_compatibility