在鼠标悬停时从画布获取像素颜色

vin*_*000 71 javascript html5 canvas getimagedata

是否可以在鼠标下方获取RGB值像素?有一个完整的例子吗?这是我到目前为止所拥有的:

<script>
function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');
  var img = new Image();
  img.src = 'Your URL';

  img.onload = function(){
    ctx.drawImage(img,0,0);


  };

  canvas.onmousemove = function(e) {
        var mouseX, mouseY;

        if(e.offsetX) {
            mouseX = e.offsetX;
            mouseY = e.offsetY;
        }
        else if(e.layerX) {
            mouseX = e.layerX;
            mouseY = e.layerY;
        }
        var c = ctx.getImageData(mouseX, mouseY, 1, 1).data;

        $('#ttip').css({'left':mouseX+20, 'top':mouseY+20}).html(c[0]+'-'+c[1]+'-'+c[2]);
  };
}

</script>
Run Code Online (Sandbox Code Playgroud)

Way*_*ett 138

这是一个完整的,独立的例子.首先,使用以下HTML:

<canvas id="example" width="200" height="60"></canvas>
<div id="status"></div>
Run Code Online (Sandbox Code Playgroud)

相关的JavaScript:

// set up some sample squares
var example = document.getElementById('example');
var context = example.getContext('2d');
context.fillStyle = "rgb(255,0,0)";
context.fillRect(0, 0, 50, 50);
context.fillStyle = "rgb(0,0,255)";
context.fillRect(55, 0, 50, 50);

$('#example').mousemove(function(e) {
    var pos = findPos(this);
    var x = e.pageX - pos.x;
    var y = e.pageY - pos.y;
    var coord = "x=" + x + ", y=" + y;
    var c = this.getContext('2d');
    var p = c.getImageData(x, y, 1, 1).data; 
    var hex = "#" + ("000000" + rgbToHex(p[0], p[1], p[2])).slice(-6);
    $('#status').html(coord + "<br>" + hex);
});
Run Code Online (Sandbox Code Playgroud)

上面的代码假定存在jQuery和以下实用程序函数:

function findPos(obj) {
    var curleft = 0, curtop = 0;
    if (obj.offsetParent) {
        do {
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop;
        } while (obj = obj.offsetParent);
        return { x: curleft, y: curtop };
    }
    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);
}
Run Code Online (Sandbox Code Playgroud)

在JSFIDDLE上查看它的实际操作:

  • 哇哇 哇哇.太令人敬畏了. (3认同)
  • 这个答案还显示了鼠标悬停时的像素坐标. (3认同)

Dan*_*ger 16

如果您需要获取矩形区域的平均颜色,而不是单个像素的颜色,请看一下另一个问题:

\n

JavaScript - 获取图像特定区域的平均颜色

\n

无论如何,两者都是以非常相似的方式完成的:

\n

从图像或画布中获取单个像素的颜色/值

\n

要获取单个像素的颜色,您首先需要将该图像绘制到画布上,您已经完成了此操作:

\n
const image = document.getElementById(\'image\');\nconst canvas = document.createElement(\'canvas\');\nconst context = canvas.getContext(\'2d\');\nconst width = image.width;\nconst height = image.height;\n\ncanvas.width = width;\ncanvas.height = height;\n\ncontext.drawImage(image, 0, 0, width, height);\n
Run Code Online (Sandbox Code Playgroud)\n

然后获取单个像素的值,如下所示:

\n
const data = context.getImageData(X, Y, 1, 1).data;\n\n// RED   = data[0]\n// GREEN = data[1]\n// BLUE  = data[2]\n// ALPHA = data[3]\n
Run Code Online (Sandbox Code Playgroud)\n

通过一次获取所有图像数据来加快速度

\n

您需要使用相同的CanvasRenderingContext2D.getImageData()来获取整个图像的值,您可以通过更改其第三个和第四个参数来实现。该函数的签名是:

\n
ImageData ctx.getImageData(sx, sy, sw, sh);\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  • sx:从中提取 ImageData 的矩形左上角的 x 坐标。
  • \n
  • sy:从中提取 ImageData 的矩形左上角的 y 坐标。
  • \n
  • sw:将从中提取图像数据的矩形的宽度。
  • \n
  • sh:将从中提取 ImageData 的矩形的高度。
  • \n
\n

您可以看到它返回一个ImageData对象,无论它是什么。这里重要的部分是该对象有一个.data包含我们所有像素值的属性。

\n

但是,请注意,.data属性是一维的Uint8ClampedArray,这意味着所有像素的组件都已被展平,因此您将得到如下所示的内容:

\n

假设您有一个如下所示的 2x2 图像:

\n
 RED PIXEL |       GREEN PIXEL\nBLUE PIXEL | TRANSPARENT PIXEL\n
Run Code Online (Sandbox Code Playgroud)\n

然后,你会像这样得到它们:

\n
[ 255, 0, 0, 255,    0, 255, 0, 255,    0, 0, 255, 255,    0, 0, 0, 0          ]\n|   RED PIXEL   |    GREEN PIXEL   |     BLUE PIXEL   |    TRANSPAERENT  PIXEL |\n|   1ST PIXEL   |      2ND PIXEL   |      3RD PIXEL   |             4TH  PIXEL | \n
Run Code Online (Sandbox Code Playgroud)\n

由于调用getImageData是一个缓慢的操作,您只需调用一次即可获取所有图像的数据(sw=图像宽度,sh=图像高度)。

\n

然后,在上面的示例中,如果您想访问 的组件TRANSPARENT PIXEL,即该假想x = 1, y = 1图像位置处的组件,您将i在其ImageData\'sdata属性中找到它的第一个索引,如下所示:

\n
const i = (y * imageData.width + x) * 4;\n
Run Code Online (Sandbox Code Playgroud)\n

\xe2\x9c\xa8 让我们看看它的实际效果

\n

\r\n
\r\n
const image = document.getElementById(\'image\');\nconst canvas = document.createElement(\'canvas\');\nconst context = canvas.getContext(\'2d\');\nconst width = image.width;\nconst height = image.height;\n\ncanvas.width = width;\ncanvas.height = height;\n\ncontext.drawImage(image, 0, 0, width, height);\n
Run Code Online (Sandbox Code Playgroud)\r\n
const data = context.getImageData(X, Y, 1, 1).data;\n\n// RED   = data[0]\n// GREEN = data[1]\n// BLUE  = data[2]\n// ALPHA = data[3]\n
Run Code Online (Sandbox Code Playgroud)\r\n
ImageData ctx.getImageData(sx, sy, sw, sh);\n
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

\xe2\x9a\xa0\xef\xb8\x8f 注意,我使用小数据 URI 来避免Cross-Origin在包含外部图像时出现问题,或者在尝试使用较长的数据 URI 时避免出现大于允许值的答案。

\n

\xef\xb8\x8f 这些颜色看起来很奇怪,不是吗?

\n

如果将光标移动到星号形状的边界周围,您有时会看到avgSolidColor红色,但您正在采样的像素看起来是白色的。这是因为即使R该像素的分量可能较高,但 Alpha 通道较低,因此颜色实际上是几乎透明的红色阴影,但avgSolidColor忽略了这一点。

\n

另一方面,avgAlphaColor看起来粉红色。嗯,这实际上不是真的,它只是看起来粉红色的,因为我们现在使用 Alpha 通道,这使得它半透明,并允许我们看到页面的背景,在本例中是白色的。

\n

Alpha 加权颜色

\n

那么,我们能做些什么来解决这个问题呢?好吧,事实证明我们只需要使用 alpha 通道及其倒数作为权重来计算新样本的分量,在本例中将其与白色合并,因为这是我们用作背景的颜色。

\n

这意味着如果像素为R, G, B, A,其中A位于区间 中[0, 1],我们将计算 alpha 通道的倒数 ,iA以及加权样本的分量如下:

\n
const iA = 1 - A;\nconst wR = (R * A + 255 * iA) | 0;\nconst wG = (G * A + 255 * iA) | 0;\nconst wB = (B * A + 255 * iA) | 0;\n
Run Code Online (Sandbox Code Playgroud)\n

请注意像素越透明(A接近 0),颜色越浅。

\n


Cai*_*tti 7

我知道这是一个老问题,但这里有另一种选择.我将图像数据存储在一个数组中,然后,在画布上的鼠标移动事件中:

var index = (Math.floor(y) * canvasWidth + Math.floor(x)) * 4
var r = data[index]
var g = data[index + 1]
var b = data[index + 2]
var a = data[index + 3]
Run Code Online (Sandbox Code Playgroud)

比每次获取imageData容易得多.


ebr*_*rah 6

合并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>
Run Code Online (Sandbox Code Playgroud)

这是我的完整解决方案.在这里我只使用了画布和一个图像,但是如果你需要<map>在图像上使用它,它也是可能的.


use*_*030 5

每次调用 getImageData 都会减慢进程...为了加快速度,我建议存储图像数据,然后您可以轻松快速地获取 pix 值,因此请执行以下操作以获得更好的性能

// keep it global
let imgData = false;  // initially no image data we have

// create some function block 
if(imgData === false){   
  // fetch once canvas data     
  var ctx = canvas.getContext("2d");
  imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
}
    // Prepare your X Y coordinates which you will be fetching from your mouse loc
    let x = 100;   // 
    let y = 100;
    // locate index of current pixel
    let index = (y * imgData.width + x) * 4;

        let red = imgData.data[index];
        let green = imgData.data[index+1];
        let blue = imgData.data[index+2];
        let alpha = imgData.data[index+3];
   // Output
   console.log('pix x ' + x +' y '+y+ ' index '+index +' COLOR '+red+','+green+','+blue+','+alpha);
Run Code Online (Sandbox Code Playgroud)