Можно ли получить под мышкой пиксель значения RGB? Есть полный пример этого? Вот что у меня есть на данный момент:
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]);
};
}
javascript
html
jquery
canvas
getimagedata
винс83000
источник
источник
Ответы:
Вот полный, самодостаточный пример. Сначала используйте следующий HTML-код:
<canvas id="example" width="200" height="60"></canvas> <div id="status"></div>
Затем поместите на холст несколько квадратов со случайным цветом фона:
var example = document.getElementById('example'); var context = example.getContext('2d'); context.fillStyle = randomColor(); context.fillRect(0, 0, 50, 50); context.fillStyle = randomColor(); context.fillRect(55, 0, 50, 50); context.fillStyle = randomColor(); context.fillRect(110, 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); } function randomInt(max) { return Math.floor(Math.random() * max); } function randomColor() { return `rgb(${randomInt(256)}, ${randomInt(256)}, ${randomInt(256)})` }
Посмотрите это в действии здесь:
Показать фрагмент кода
// set up some sample squares with random colors var example = document.getElementById('example'); var context = example.getContext('2d'); context.fillStyle = randomColor(); context.fillRect(0, 0, 50, 50); context.fillStyle = randomColor(); context.fillRect(55, 0, 50, 50); context.fillStyle = randomColor(); context.fillRect(110, 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); }); 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); } function randomInt(max) { return Math.floor(Math.random() * max); } function randomColor() { return `rgb(${randomInt(256)}, ${randomInt(256)}, ${randomInt(256)})` }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <canvas id="example" width="200" height="60"></canvas> <div id="status"></div>
источник
offsetParent
s - действительно хороший способ добиться этого. Я никогда не думал об этом. Но почему бы вам не использовать обычныйwhile
цикл вместоif
аdo...while
?Я знаю, что это старый вопрос, но есть альтернатива. Я бы сохранил эти данные изображения в массиве, затем при событии перемещения мыши по холсту:
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.
источник
Объединив различные ссылки, найденные здесь, в 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>
поверх изображения, это тоже возможно.источник
вызов 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);
источник
Если вам нужно получить средний цвет прямоугольной области, а не цвет одного пикселя, взгляните на другой вопрос:
👉 JavaScript - получить средний цвет из определенной области изображения
Во всяком случае, оба сделаны очень похоже:
🔍 Получение цвета / значения одного пикселя из изображения или холста
Чтобы получить цвет одного пикселя, вы сначала должны нарисовать это изображение на холсте, что вы уже сделали:
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]
🚀 Ускорение работы за счет одновременного получения всех данных ImageData
Вам нужно использовать тот же CanvasRenderingContext2D.getImageData (), чтобы получить значения всего изображения, что вы делаете, изменяя его третий и четвертый параметры. Сигнатура этой функции:
sx
: Координата x левого верхнего угла прямоугольника, из которого будут извлечены данные ImageData.sy
: Координата Y верхнего левого угла прямоугольника, из которого будут извлечены данные ImageData.sw
: Ширина прямоугольника, из которого будут извлечены данные ImageData.sh
: Высота прямоугольника, из которого будут извлечены данные ImageData.Вы можете увидеть , он возвращает
ImageData
объект, что бы это . Важная часть здесь заключается в том, что этот объект имеет.data
свойство, которое содержит все наши значения пикселей.Однако обратите внимание, что
.data
свойство является одномернымUint8ClampedArray
, что означает, что все компоненты пикселя сглажены, поэтому вы получаете что-то похожее на это:Допустим, у вас есть изображение 2x2, подобное этому:
Тогда вы получите их вот так:
[ 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
= высота изображения).Затем, в приведенном выше примере, если вы хотите получить доступ к компонентам
TRANSPARENT PIXEL
, то есть, один в положенииx = 1, y = 1
этого воображаемого образом, вы найдете свой первый индексi
в его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);
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>
⚠️ Обратите внимание, что я использую небольшой URI данных, чтобы избежать
Cross-Origin
проблем, если я включаю внешнее изображение или ответ, размер которого превышает допустимый, если я пытаюсь использовать более длинный URI данных.🕵️ Эти цвета выглядят странно, правда?
Если вы переместите курсор вокруг границ звездочки, вы иногда увидите
avgSolidColor
он красный, но пиксель, который вы выбираете, выглядит белым. Это потому, что даже еслиR
компонент для этого пикселя может быть высоким, альфа-канал низкий, поэтому цвет на самом деле почти прозрачный оттенок красного, ноavgSolidColor
игнорирует это.С другой стороны,
avgAlphaColor
выглядит розовым. Ну, на самом деле это неправда, он просто выглядит розовым, потому что теперь мы используем альфа-канал, что делает его полупрозрачным и позволяет нам видеть фон страницы, который в данном случае белый.🎨 Альфа-взвешенный цвет
Тогда что мы можем сделать, чтобы это исправить? Что ж, оказывается, нам просто нужно использовать альфа-канал и его инверсию в качестве весов для вычисления компонентов нашего нового образца, в данном случае объединяя его с белым, так как этот цвет мы используем в качестве фона.
Это означает, что если пиксель равен
R, G, B, A
, гдеA
находится в интервале[0, 1]
, мы будем вычислять инверсию альфа-каналаiA
, и компоненты взвешенной выборки как:const iA = 1 - A; const wR = (R * A + 255 * iA) | 0; const wG = (G * A + 255 * iA) | 0; const wB = (B * A + 255 * iA) | 0;
Обратите внимание: чем прозрачнее пиксель (
A
ближе к 0), тем светлее цвет.источник
Быстрый ответ
context.getImageData(x, y, 1, 1).data;
возвращает массив rgba. например[50, 50, 50, 255]
Вот версия функции rgbToHex @ lwburk, которая принимает в качестве аргумента массив rgba.
function rgbToHex(rgb){ return '#' + ((rgb[0] << 16) | (rgb[1] << 8) | rgb[2]).toString(16); };
источник
[10, 42, 67, 255]
производит,#a2a43
которое не является допустимым / хорошо отформатированным шестнадцатеричным цветовым кодом.Можете попробовать color-sampler . Это простой способ подобрать цвет на холсте. См. Демонстрацию .
источник
У меня есть очень простой рабочий пример получения цвета пикселя с холста.
Сначала немного базового HTML:
<canvas id="myCanvas" width="400" height="250" style="background:red;" onmouseover="echoColor(event)"> </canvas>
Затем JS, чтобы нарисовать что-то на холсте и получить цвет:
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); }
Вот рабочий пример , просто посмотрите на консоль.
источник
@Wayne Беркитта ответ хорош. Если вы хотите также извлечь альфа-значение, чтобы получить цвет rgba, мы могли бы сделать это:
var r = p[0], g = p[1], b = p[2], a = p[3] / 255; var rgba = "rgb(" + r + "," + g + "," + b + "," + a + ")";
Я разделил альфа-значение на 255, потому что объект ImageData хранит его как целое число от 0 до 255, но большинство приложений (например,
CanvasRenderingContext2D.fillRect()
) требуется чтобы цвета были в допустимом формате CSS, где альфа-значение находится в диапазоне от 0 до 1.(Также помните, что если вы извлечете прозрачный цвет, а затем снова нарисуете его на холст, он наложит любой цвет, который был там ранее. Поэтому, если вы нарисовали цвет
rgba(0,0,0,0.1)
на одном и том же месте 10 раз, он будет черным.)источник