Ist es möglich, das RGB-Wertpixel unter die Maus zu bekommen? Gibt es ein vollständiges Beispiel dafür? Folgendes habe ich bisher:
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
canvas
getimagedata
vince83000
quelle
quelle
Antworten:
Hier ist ein vollständiges, in sich geschlossenes Beispiel. Verwenden Sie zunächst den folgenden HTML-Code:
<canvas id="example" width="200" height="60"></canvas> <div id="status"></div>
Dann lege ein paar Quadrate mit zufälligen Hintergrundfarben auf die Leinwand:
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);
Und drucken Sie jede Farbe per Mouseover aus:
$('#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); });
Der obige Code setzt das Vorhandensein von jQuery und den folgenden Dienstprogrammfunktionen voraus:
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)})` }
Sehen Sie es hier in Aktion:
Code-Snippet anzeigen
// 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>
quelle
offsetParent
s ist ein wirklich guter Weg, um dies zu erreichen. Daran habe ich noch nie gedacht. Aber warum verwenden Sie nicht eine regulärewhile
Schleife anstelle vonif
und dann ado...while
?Ich weiß, dass dies eine alte Frage ist, aber hier ist eine Alternative. Ich würde diese Bilddaten dann in einem Array speichern, wenn ich das Ereignis mit der Maus über die Leinwand bewege:
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]
Viel einfacher als jedes Mal die imageData abzurufen.
quelle
Durch das Zusammenführen verschiedener Referenzen, die hier in StackOverflow (einschließlich des obigen Artikels) und auf anderen Websites gefunden wurden, habe ich Javascript und JQuery verwendet:
<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>
Dies ist meine Komplettlösung. Hier habe ich nur Leinwand und ein Bild verwendet, aber wenn Sie
<map>
über dem Bild verwenden müssen, ist es auch möglich.quelle
Wenn Sie getImageData jedes Mal aufrufen, wird der Prozess verlangsamt. Um die Dinge zu beschleunigen, empfehle ich, Bilddaten zu speichern. Dann können Sie den Pix-Wert einfach und schnell abrufen. Tun Sie also etwas Ähnliches, um eine bessere Leistung zu erzielen
// 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);
quelle
Schnelle Antwort
context.getImageData(x, y, 1, 1).data;
Gibt ein RGBA-Array zurück. z.B[50, 50, 50, 255]
Hier ist eine Version der rgbToHex-Funktion von @ lwburk, die das rgba-Array als Argument verwendet.
function rgbToHex(rgb){ return '#' + ((rgb[0] << 16) | (rgb[1] << 8) | rgb[2]).toString(16); };
quelle
[10, 42, 67, 255]
erzeugt ,#a2a43
die kein gültiger / gut formatierte hex Farbcode ist.Wenn Sie die durchschnittliche Farbe eines rechteckigen Bereichs anstelle der Farbe eines einzelnen Pixels erhalten möchten, werfen Sie bitte einen Blick auf diese andere Frage:
👉 JavaScript - Ermittelt die durchschnittliche Farbe aus einem bestimmten Bereich eines Bildes
Wie auch immer, beide werden auf sehr ähnliche Weise gemacht:
🔍 Abrufen der Farbe / des Werts eines einzelnen Pixels aus einem Bild oder einer Leinwand
Um die Farbe eines einzelnen Pixels zu erhalten, zeichnen Sie dieses Bild zunächst auf eine Leinwand, was Sie bereits getan haben:
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);
Und dann erhalten Sie den Wert eines einzelnen Pixels wie folgt:
const data = context.getImageData(X, Y, 1, 1).data; // RED = data[0] // GREEN = data[1] // BLUE = data[2] // ALPHA = data[3]
🚀 Die Geschwindigkeit wird verringert, indem alle ImageData auf einmal abgerufen werden
Sie müssen dasselbe CanvasRenderingContext2D.getImageData () verwenden , um die Werte des gesamten Bilds abzurufen. Dies geschieht durch Ändern der dritten und vierten Parameter. Die Signatur dieser Funktion lautet:
sx
: Die x-Koordinate der oberen linken Ecke des Rechtecks, aus dem die ImageData extrahiert werden.sy
: Die y-Koordinate der oberen linken Ecke des Rechtecks, aus dem die ImageData extrahiert werden.sw
: Die Breite des Rechtecks, aus dem die ImageData extrahiert werden.sh
: Die Höhe des Rechtecks, aus dem die ImageData extrahiert werden.Sie können sehen, dass es ein
ImageData
Objekt zurückgibt , was auch immer das ist . Der wichtige Teil hier ist, dass dieses Objekt eine.data
Eigenschaft hat, die alle unsere Pixelwerte enthält.Beachten Sie jedoch, dass die
.data
Eigenschaft eine 1-DimensionUint8ClampedArray
ist. Dies bedeutet, dass alle Komponenten des Pixels abgeflacht wurden, sodass Sie Folgendes erhalten:Angenommen, Sie haben ein 2x2-Bild wie dieses:
Dann erhalten Sie sie wie folgt:
[ 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 |
Da das Aufrufen
getImageData
ein langsamer Vorgang ist, können Sie ihn nur einmal aufrufen, um die Daten aller Bilder abzurufen (sw
= Bildbreite,sh
= Bildhöhe).Dann im obigen Beispiel, wenn Sie die Komponenten des zugreifen wollen
TRANSPARENT PIXEL
, das heißt, die man an der Positionx = 1, y = 1
dieses imaginären Bildes, würden Sie ihr erstes Index findeni
in seinerImageData
‚s -data
Eigenschaft als:const i = (y * imageData.width + x) * 4;
✨ Lassen Sie es uns in Aktion sehen
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>
⚠️ Hinweis: Ich verwende einen URI für kleine Daten, um
Cross-Origin
Probleme zu vermeiden , wenn ich ein externes Bild oder eine Antwort einbinde , die größer als zulässig ist, wenn ich versuche, einen URI für längere Daten zu verwenden.🕵️ Diese Farben sehen komisch aus, nicht wahr?
Wenn Sie den Cursor um die Ränder der Sternchenform bewegen, wird manchmal
avgSolidColor
rot angezeigt, aber das Pixel, das Sie abtasten, sieht weiß aus. Das liegt daran,R
dass der Alpha-Kanal niedrig ist, obwohl die Komponente für dieses Pixel möglicherweise hoch ist. Die Farbe ist also tatsächlich ein fast transparenter Rotton,avgSolidColor
ignoriert dies jedoch.Auf der anderen Seite
avgAlphaColor
sieht rosa aus. Nun, das stimmt eigentlich nicht, es sieht nur rosa aus, weil wir jetzt den Alphakanal verwenden, der halbtransparent ist und es uns ermöglicht, den Hintergrund der Seite zu sehen, der in diesem Fall weiß ist.🎨 Alpha-gewichtete Farbe
Was können wir dann tun, um dies zu beheben? Nun, es stellt sich heraus, dass wir nur den Alphakanal und seine Umkehrung als Gewichtung verwenden müssen, um die Komponenten unserer neuen Stichprobe zu berechnen. In diesem Fall wird sie mit Weiß zusammengeführt, da dies die Farbe ist, die wir als Hintergrund verwenden.
Das heißt, wenn ein Bildpunkt ist
R, G, B, A
, woA
in dem Intervall[0, 1]
, werden wir die Inverse des Alphakanal berechnen,iA
und die Komponenten des gewichteten Probe als: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;
Beachten Sie, dass
A
die Farbe umso heller ist, je transparenter ein Pixel ist ( näher an 0).quelle
Sie können den Farb-Sampler ausprobieren . Es ist eine einfache Möglichkeit, Farbe auf einer Leinwand auszuwählen. Siehe Demo .
quelle
Ich habe ein sehr einfaches Arbeitsbeispiel für das Abrufen von Pixelfarben von der Leinwand.
Zuerst einige grundlegende HTML:
<canvas id="myCanvas" width="400" height="250" style="background:red;" onmouseover="echoColor(event)"> </canvas>
Dann JS, um etwas auf die Leinwand zu zeichnen und Farbe zu bekommen:
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); }
Hier ist ein funktionierendes Beispiel , schauen Sie sich einfach die Konsole an.
quelle
@ Wayne Burketts Antwort ist gut. Wenn Sie auch den Alpha-Wert extrahieren möchten, um eine RGBA-Farbe zu erhalten, können Sie dies tun:
var r = p[0], g = p[1], b = p[2], a = p[3] / 255; var rgba = "rgb(" + r + "," + g + "," + b + "," + a + ")";
Ich habe den Alpha-Wert durch 255 geteilt, da das ImageData-Objekt ihn als Ganzzahl zwischen 0 und 255 speichert. In den meisten Anwendungen (zum Beispiel
CanvasRenderingContext2D.fillRect()
) müssen Farben jedoch im gültigen CSS-Format vorliegen, wobei der Alpha-Wert zwischen 0 und 1 liegt.(Denken Sie auch daran, dass beim Extrahieren einer transparenten Farbe und anschließendes Zurückzeichnen auf die Leinwand die zuvor vorhandene Farbe überlagert wird. Wenn Sie die Farbe also
rgba(0,0,0,0.1)
zehnmal über denselben Punkt gezeichnet haben, ist sie schwarz.)quelle