是否可以在鼠标下方获取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>
答案 0 :(得分:128)
这是一个完整的,独立的例子。首先,使用以下HTML:
<canvas id="example" width="200" height="60"></canvas>
<div id="status"></div>
相关的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);
});
上面的代码假定存在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);
}
在JSFIDDLE上查看它:
答案 1 :(得分: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]
比每次获取imageData容易得多。
答案 2 :(得分: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 :(得分:3)
context.getImageData(x, y, 1, 1).data;
返回一个rgba数组。例如[50, 50, 50, 255]
这是@ lwburk的rgbToHex函数的一个版本,它将rgba数组作为参数。
function rgbToHex(rgb){
return '#' + ((rgb[0] << 16) | (rgb[1] << 8) | rgb[2]).toString(16);
};
答案 4 :(得分:3)
每次调用getImageData会减慢进程...加快我建议存储图像数据的速度然后你可以轻松快速地获得像素值,所以做这样的事情以获得更好的性能
// 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);
答案 5 :(得分:2)
您可以尝试color-sampler。这是在画布中选择颜色的简单方法。请参阅demo。
答案 6 :(得分:1)
我有一个非常简单的工作示例,可以从画布中获取像素颜色。
首先是一些基本的HTML:
<canvas id="myCanvas" width="400" height="250" style="background:red;" onmouseover="echoColor(event)">
</canvas>
然后JS在Canvas上画一些东西,并获得颜色:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "black";
ctx.fillRect(10, 10, 50, 50);
function echoColor(e){
var imgData = ctx.getImageData(e.pageX, e.pageX, 1, 1);
red = imgData.data[0];
green = imgData.data[1];
blue = imgData.data[2];
alpha = imgData.data[3];
console.log(red + " " + green + " " + blue + " " + alpha);
}
这是一个working example,只需看看控制台。
答案 7 :(得分:0)
@Wayne Burkett的answer很好。如果您还想提取alpha值以获得rgba颜色,我们可以这样做:
var r = p[0], g = p[1], b = p[2], a = p[3] / 255;
var rgba = "rgb(" + r + "," + g + "," + b + "," + a + ")";
我将alpha值除以255,因为ImageData对象将其存储为0到255之间的整数,但是大多数应用程序(例如CanvasRenderingContext2D.fillRect()
)要求颜色采用有效的CSS格式,其中alpha值在0到1之间。
(还要记住,如果提取透明颜色然后将其重新绘制到画布上,它将覆盖先前存在的所有颜色。因此,如果将颜色rgba(0,0,0,0.1)
绘制到同一位置10次,它将会是黑色的。)
答案 8 :(得分:0)
如果您需要获取矩形区域的平均颜色,而不是单个像素的颜色,请查看另一个问题:
?JavaScript - Get average color from a certain area of an image
无论如何,两者都以非常相似的方式完成:
要获取单个像素的颜色,您首先需要将该图像绘制到已经完成的画布上:
const image = document.getElementById('image');
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const width = image.width;
const height = image.height;
canvas.width = width;
canvas.height = height;
context.drawImage(image, 0, 0, width, height);
然后获取像这样的单个像素的值:
const data = context.getImageData(X, Y, 1, 1).data;
// RED = data[0]
// GREEN = data[1]
// BLUE = data[2]
// ALPHA = data[3]
您需要使用相同的CanvasRenderingContext2D.getImageData()来获取整个图像的值,这可以通过更改其第三和第四参数来实现。该函数的签名是:
ImageData ctx.getImageData(sx, sy, sw, sh);
sx
:将从中提取ImageData的矩形的左上角的x坐标。sy
:将从中提取ImageData的矩形的左上角的y坐标。sw
:将从中提取ImageData的矩形的宽度。sh
:将从中提取ImageData的矩形的高度。您可以看到它返回了ImageData
对象whatever that is。这里的重要部分是该对象具有.data
属性,其中包含我们所有的像素值。
但是,请注意,.data
属性是一维Uint8ClampedArray
,这意味着所有像素的成分都已变平,因此您将获得如下所示的内容:
假设您有一个2x2的图像,如下所示:
RED PIXEL | GREEN PIXEL
BLUE PIXEL | TRANSPARENT PIXEL
然后,您将像这样获得它们:
[ 255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255, 0, 0, 0, 0 ]
| RED PIXEL | GREEN PIXEL | BLUE PIXEL | TRANSPAERENT PIXEL |
| 1ST PIXEL | 2ND PIXEL | 3RD PIXEL | 4TH PIXEL |
由于调用getImageData
是一个缓慢的操作,因此只能调用一次以获取所有图像的数据(sw
=图像宽度,sh
=图像高度)。 / p>
然后,在上面的示例中,如果要访问TRANSPARENT PIXEL
的组成部分,即此假想图像的位置x = 1, y = 1
的组成部分,您将找到其第一个索引{{ 1}}在其i
的{{1}}属性中,为:
ImageData
data
const i = (y * imageData.width + x) * 4;
const solidColor = document.getElementById('solidColor');
const alphaColor = document.getElementById('alphaColor');
const solidWeighted = document.getElementById('solidWeighted');
const solidColorCode = document.getElementById('solidColorCode');
const alphaColorCode = document.getElementById('alphaColorCode');
const solidWeightedCOde = document.getElementById('solidWeightedCode');
const brush = document.getElementById('brush');
const image = document.getElementById('image');
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const width = image.width;
const height = image.height;
const BRUSH_SIZE = brush.offsetWidth;
const BRUSH_CENTER = BRUSH_SIZE / 2;
const MIN_X = image.offsetLeft + 4;
const MAX_X = MIN_X + width - 1;
const MIN_Y = image.offsetTop + 4;
const MAX_Y = MIN_Y + height - 1;
canvas.width = width;
canvas.height = height;
context.drawImage(image, 0, 0, width, height);
const imageDataData = context.getImageData(0, 0, width, height).data;
function sampleColor(clientX, clientY) {
if (clientX < MIN_X || clientX > MAX_X || clientY < MIN_Y || clientY > MAX_Y) {
requestAnimationFrame(() => {
brush.style.transform = `translate(${ clientX }px, ${ clientY }px)`;
solidColorCode.innerText = solidColor.style.background = 'rgb(0, 0, 0)';
alphaColorCode.innerText = alphaColor.style.background = 'rgba(0, 0, 0, 0.00)';
solidWeightedCode.innerText = solidWeighted.style.background = 'rgb(0, 0, 0)';
});
return;
}
const imageX = clientX - MIN_X;
const imageY = clientY - MIN_Y;
const i = (imageY * width + imageX) * 4;
// A single pixel (R, G, B, A) will take 4 positions in the array:
const R = imageDataData[i];
const G = imageDataData[i + 1];
const B = imageDataData[i + 2];
const A = imageDataData[i + 3] / 255;
const iA = 1 - A;
// Alpha-weighted color:
const wR = (R * A + 255 * iA) | 0;
const wG = (G * A + 255 * iA) | 0;
const wB = (B * A + 255 * iA) | 0;
// Update UI:
requestAnimationFrame(() => {
brush.style.transform = `translate(${ clientX }px, ${ clientY }px)`;
solidColorCode.innerText = solidColor.style.background
= `rgb(${ R }, ${ G }, ${ B })`;
alphaColorCode.innerText = alphaColor.style.background
= `rgba(${ R }, ${ G }, ${ B }, ${ A.toFixed(2) })`;
solidWeightedCode.innerText = solidWeighted.style.background
= `rgb(${ wR }, ${ wG }, ${ wB })`;
});
}
document.onmousemove = (e) => sampleColor(e.clientX, e.clientY);
sampleColor(MIN_X, MIN_Y);
⚠️注意,如果我包含外部图像或答案大于尝试使用较长数据URI所允许的值,我将使用较小的数据URI来避免body {
margin: 0;
height: 100vh;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
cursor: none;
font-family: monospace;
overflow: hidden;
}
#image {
border: 4px solid white;
border-radius: 2px;
box-shadow: 0 0 32px 0 rgba(0, 0, 0, .25);
width: 150px;
box-sizing: border-box;
}
#brush {
position: absolute;
top: 0;
left: 0;
pointer-events: none;
width: 1px;
height: 1px;
mix-blend-mode: exclusion;
border-radius: 100%;
}
#brush::before,
#brush::after {
content: '';
position: absolute;
background: magenta;
}
#brush::before {
top: -16px;
left: 0;
height: 33px;
width: 100%;
}
#brush::after {
left: -16px;
top: 0;
width: 33px;
height: 100%;
}
#samples {
position: relative;
list-style: none;
padding: 0;
width: 250px;
}
#samples::before {
content: '';
position: absolute;
top: 0;
left: 27px;
width: 2px;
height: 100%;
background: black;
border-radius: 1px;
}
#samples > li {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
padding-left: 56px;
}
#samples > li + li {
margin-top: 8px;
}
.sample {
position: absolute;
top: 50%;
left: 16px;
transform: translate(0, -50%);
display: block;
width: 24px;
height: 24px;
border-radius: 100%;
box-shadow: 0 0 16px 4px rgba(0, 0, 0, .25);
margin-right: 8px;
}
.sampleLabel {
font-weight: bold;
margin-bottom: 8px;
}
.sampleCode {
}
问题。
如果将光标移动到星号形状的边界周围,有时会<img id="image" src="data:image/gif;base64,R0lGODlhSwBLAPEAACMfIO0cJAAAAAAAACH/C0ltYWdlTWFnaWNrDWdhbW1hPTAuNDU0NTUAIf4jUmVzaXplZCBvbiBodHRwczovL2V6Z2lmLmNvbS9yZXNpemUAIfkEBQAAAgAsAAAAAEsASwAAAv+Uj6mb4A+QY7TaKxvch+MPKpC0eeUUptdomOzJqnLUvnFcl7J6Pzn9I+l2IdfII8DZiCnYsYdK4qRTptAZwQKRVK71CusOgx2nFRrlhMu+33o2NEalC6S9zQvfi3Mlnm9WxeQ396F2+HcQsMjYGEBRVbhy5yOp6OgIeVIHpEnZyYCZ6cklKBJX+Kgg2riqKoayOWl2+VrLmtDqBptIOjZ6K4qAeSrL8PcmHExsgMs2dpyIxPpKvdhM/YxaTMW2PGr9GP76BN3VHTMurh7eoU14jsc+P845Vn6OTb/P/I68iYOfwGv+JOmRNHBfsV5ujA1LqM4eKDoNvXyDqItTxYX/DC9irKBlIhkKGPtFw1JDiMeS7CqWqySPZcKGHH/JHGgIpb6bCl1O0LmT57yCOqoI5UcU0YKjPXmFjMm0ZQ4NIVdGBdZRi9WrjLxJNMY1Yr4dYeuNxWApl1ALHb+KDHrTV1owlriedJgSr4Cybu/9dFiWYAagsqAGVkkzaZTAuqD9ywKWMUG9dCO3u2zWpVzIhpW122utZlrHnTN+Bq2Mqrlnqh8CQ+0Mrq3Kc++q7eo6dlB3rLuh3abPVbbbI2mxBdhWdsZhid8cr0oy9F08q0k5FXSadiyL1mF5z51a8VsQOp3/LlodkBfzmzWf2bOrtfzr48k/1hupDaLa9rUbO+zlwndfaOCURAXRNaCBqBT2BncJakWfTzSYkmCEFr60RX0V8sKaHOltCBJ1tAAFYhHaVVbig3jxp0IBADs=" >
<div id="brush"></div>
<ul id="samples">
<li>
<span class="sample" id="solidColor"></span>
<div class="sampleLabel">solidColor</div>
<div class="sampleCode" id="solidColorCode">rgb(0, 0, 0)</div>
</li>
<li>
<span class="sample" id="alphaColor"></span>
<div class="sampleLabel">alphaColor</div>
<div class="sampleCode" id="alphaColorCode">rgba(0, 0, 0, 0.00)</div>
</li>
<li>
<span class="sample" id="solidWeighted"></span>
<div class="sampleLabel">solidWeighted (with white)</div>
<div class="sampleCode" id="solidWeightedCode">rgb(0, 0, 0)</div>
</li>
</ul>
是红色的,但是要采样的像素看起来是白色的。这是因为即使该像素的Cross-Origin
分量可能很高,但alpha通道却很低,因此颜色实际上是几乎透明的红色阴影,但是avgSolidColor
却忽略了它。
另一方面,R
看起来是粉红色的。嗯,这实际上是不对的,它只是看起来是粉红色的,因为我们现在使用的是Alpha通道,这使其变为半透明,并允许我们看到页面的背景,在这种情况下为白色。 / p>
然后,我们该怎么做才能解决此问题?好吧,事实证明,我们只需要使用alpha通道及其反函数作为权重来计算新样本的成分,在这种情况下,将其与白色合并,因为这就是我们用作背景的颜色。
这意味着,如果像素为avgSolidColor
,其中avgAlphaColor
在间隔R, G, B, A
中,我们将计算alpha通道的倒数A
,以及加权样本的成分为:
[0, 1]
请注意像素越透明(iA
接近0),颜色越浅。