Czy można uzyskać piksel wartości RGB pod myszką? Czy jest na to pełny przykład? Oto, co mam do tej pory:
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
vince83000
źródło
źródło
Odpowiedzi:
Oto kompletny, samodzielny przykład. Najpierw użyj następującego kodu HTML:
<canvas id="example" width="200" height="60"></canvas> <div id="status"></div>
Następnie umieść na płótnie kilka kwadratów z losowymi kolorami tła:
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);
I wydrukuj każdy kolor po najechaniu myszą:
$('#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); });
Powyższy kod zakłada obecność jQuery i następujących funkcji narzędziowych:
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)})` }
Zobacz to w akcji tutaj:
Pokaż fragment kodu
// 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>
źródło
offsetParent
s to naprawdę dobry sposób na zrobienie tego. Nigdy o tym nie myślałem. Ale dlaczego nie użyjesz zwykłejwhile
pętli zamiastif
a potem ado...while
?Wiem, że to stare pytanie, ale mam alternatywę. Przechowałbym dane obrazu w tablicy, a następnie zdarzenie ruchu myszy nad płótnem:
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]
O wiele łatwiejsze niż pobieranie imageData za każdym razem.
źródło
Łącząc różne odniesienia znalezione tutaj w StackOverflow (w tym artykuł powyżej) i na innych stronach, zrobiłem to za pomocą javascript i 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>
To jest moje kompletne rozwiązanie. Tutaj użyłem tylko płótna i jednego obrazu, ale jeśli chcesz użyć
<map>
go na obrazie, jest to również możliwe.źródło
wywoływanie getImageData za każdym razem spowolni proces ... aby przyspieszyć działanie, zalecam przechowywanie danych obrazu, a następnie łatwo i szybko uzyskasz wartość pix, więc zrób coś takiego dla lepszej wydajności
// 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);
źródło
Jeśli chcesz uzyskać średni kolor prostokątnego obszaru, a nie kolor pojedynczego piksela, spójrz na to drugie pytanie:
👉 JavaScript - uzyskaj średni kolor z określonego obszaru obrazu
Zresztą oba są wykonywane w bardzo podobny sposób:
🔍 Pobieranie koloru / wartości pojedynczego piksela z obrazu lub płótna
Aby uzyskać kolor pojedynczego piksela, najpierw narysowałbyś ten obraz na płótnie, co już zrobiłeś:
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);
A następnie uzyskaj wartość pojedynczego piksela w następujący sposób:
const data = context.getImageData(X, Y, 1, 1).data; // RED = data[0] // GREEN = data[1] // BLUE = data[2] // ALPHA = data[3]
🚀 Przyspieszenie tempa dzięki jednoczesnemu pobieraniu wszystkich danych obrazu
Musisz użyć tej samej CanvasRenderingContext2D.getImageData (), aby uzyskać wartości całego obrazu, co robisz, zmieniając jego trzeci i czwarty parametr. Podpis tej funkcji to:
sx
: Współrzędna x lewego górnego rogu prostokąta, z którego zostaną wyodrębnione ImageData.sy
: Współrzędna y lewego górnego rogu prostokąta, z którego zostaną wyodrębnione ImageData.sw
: Szerokość prostokąta, z którego zostaną wyodrębnione ImageData.sh
: Wysokość prostokąta, z którego zostaną wyodrębnione ImageData.Możesz zobaczyć, że zwraca
ImageData
obiekt, cokolwiek to jest . Ważną częścią jest to, że ten obiekt ma.data
właściwość, która zawiera wszystkie nasze wartości pikseli.Należy jednak pamiętać, że
.data
właściwość jest 1-wymiaremUint8ClampedArray
, co oznacza, że wszystkie komponenty piksela zostały spłaszczone, więc otrzymujesz coś, co wygląda tak:Powiedzmy, że masz taki obraz 2x2:
Następnie otrzymasz je w ten sposób:
[ 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 |
Ponieważ wywołanie
getImageData
jest powolną operacją, możesz wywołać je tylko raz, aby uzyskać dane całego obrazu (sw
= szerokość obrazu,sh
= wysokość obrazu).Następnie, w powyższym przykładzie, jeśli chcesz uzyskać dostęp do części składowych
TRANSPARENT PIXEL
, czyli jeden na pozycjix = 1, y = 1
tego wyimaginowanego obrazu, to znajdzie swój pierwszy indeksi
w swojejImageData
„sdata
nieruchomości jako:const i = (y * imageData.width + x) * 4;
✨ Zobaczmy to w akcji
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>
⚠️ Uwaga Używam małego identyfikatora URI danych, aby uniknąć
Cross-Origin
problemów, jeśli dołączę obraz zewnętrzny lub odpowiedź, która jest większa niż dozwolona, jeśli próbuję użyć dłuższego identyfikatora URI danych.🕵️ Te kolory wyglądają dziwnie, prawda?
Jeśli przesuniesz kursor wokół krawędzi kształtu gwiazdki, czasami zobaczysz, że
avgSolidColor
jest czerwony, ale piksel, który próbkujesz, wygląda na biały. Dzieje się tak, ponieważ nawet jeśliR
składnik tego piksela może być wysoki, kanał alfa jest niski, więc kolor jest w rzeczywistości prawie przezroczystym odcieniem czerwieni, aleavgSolidColor
ignoruje to.Z drugiej strony
avgAlphaColor
wygląda na różowo. Cóż, to właściwie nieprawda, wygląda po prostu na różowo, ponieważ teraz używamy kanału alfa, co sprawia, że jest półprzezroczysty i pozwala nam zobaczyć tło strony, które w tym przypadku jest białe.🎨 Kolor ważony alfa
Co w takim razie możemy zrobić, aby to naprawić? Cóż, okazuje się, że musimy użyć kanału alfa i jego odwrotności jako wag do obliczenia składników naszej nowej próbki, w tym przypadku scalając ją z bielą, ponieważ tego koloru używamy jako tła.
Oznacza to, że jeśli piksel jest
R, G, B, A
, gdzieA
jest w interwale[0, 1]
, obliczymy odwrotność kanału alfaiA
, a składowe ważonej próbki jako: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;
Zwróć uwagę, że im bardziej przezroczysty piksel (
A
bliżej 0), tym jaśniejszy kolor.źródło
Szybka odpowiedź
context.getImageData(x, y, 1, 1).data;
zwraca tablicę rgba. na przykład[50, 50, 50, 255]
Oto wersja funkcji rgbToHex @ lwburka, która przyjmuje tablicę rgba jako argument.
function rgbToHex(rgb){ return '#' + ((rgb[0] << 16) | (rgb[1] << 8) | rgb[2]).toString(16); };
źródło
[10, 42, 67, 255]
tworzy,#a2a43
który nie jest prawidłowym / dobrze sformatowanym kodem szesnastkowym.Możesz spróbować próbnika kolorów . To łatwy sposób na wybranie koloru na płótnie. Zobacz demo .
źródło
Mam bardzo prosty przykład działania pobierania koloru piksela z płótna.
Najpierw trochę podstawowego HTML:
<canvas id="myCanvas" width="400" height="250" style="background:red;" onmouseover="echoColor(event)"> </canvas>
Następnie JS, aby narysować coś na płótnie i uzyskać kolor:
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); }
Oto działający przykład , wystarczy spojrzeć na konsolę.
źródło
@Wayne Burkitta odpowiedź jest dobra. Jeśli chcesz również wyodrębnić wartość alfa, aby uzyskać kolor rgba, możemy zrobić to:
var r = p[0], g = p[1], b = p[2], a = p[3] / 255; var rgba = "rgb(" + r + "," + g + "," + b + "," + a + ")";
Podzieliłem wartość alfa przez 255, ponieważ obiekt ImageData przechowuje ją jako liczbę całkowitą od 0 do 255, ale większość aplikacji (na przykład
CanvasRenderingContext2D.fillRect()
) wymaga , aby kolory były w prawidłowym formacie CSS, gdzie wartość alfa wynosi od 0 do 1.(Pamiętaj też, że jeśli wyodrębnisz przezroczysty kolor, a następnie narysujesz go z powrotem na płótnie, pokryje on dowolny kolor, który był tam wcześniej. Więc jeśli narysujesz kolor
rgba(0,0,0,0.1)
na tym samym miejscu 10 razy, będzie on czarny).źródło