JavaScript-Pipette (Farbe des Pixels unter dem Mauszeiger anzeigen)

73

Ich suche nach einer Pipette , die mir den Hex-Wert des Pixels gibt, unter dem sich der Mauszeiger befindet, in JavaScript für ein CMS.

Für Firefox gibt es die hervorragende ColorZilla- Erweiterung, die genau das tut. Es ist jedoch natürlich nur FF, und ich würde das Tool wirklich gerne zusammen mit dem CMS liefern.

Ein niederländischer Entwickler hatte die sehr clevere Idee , eine Kombination aus Ajax und PHP zu verwenden imagecolorat(), um die Pixelfarbe auf einem Bild herauszufinden. Aber das beschränkt die Reichweite auf Bilder, auf die ich serverseitig zugreifen kann , und ich träume wirklich von einem universellen Tool.

Ich werde mit einem dieser Ansätze arbeiten, würde aber eine browserübergreifende, Javascript- oder Flash-basierte Methode bevorzugen, die kein serverseitiges Fummeln und keine Installation von Erweiterungen erfordert.

Ich interessiere mich auch für IE-spezifische Lösungen, die das tun, was ColorZilla kann - ich könnte nur mit der Unterstützung von IE und FF leben, obwohl eine browserübergreifende Lösung natürlich ideal wäre.

Pekka
quelle
In Javascript ist dies nicht möglich. Bei Flash bin ich mir nicht sicher.
SLaks
Theoretisch können Sie möglicherweise die Stilinformationen verarbeiten, die dem obersten Element unter dem Mauszeiger zugeordnet sind, und bestimmen, welche Farbe das Element haben soll , wenn es sich nicht um ein Bild oder eine Leinwand handelt. In der Praxis würde dies Sie wahrscheinlich wahnsinnig machen, wenn Sie sich mit Rändern, Rändern und Browser-Macken befassen. Ich denke, Elijahs Antwort ist die einzig praktische.
Aaronaught

Antworten:

80

Mit JavaScript ist dies nicht möglich, da dies gegen die domänenübergreifende Sicherheit verstößt. Es wäre sehr schlecht, wenn Sie wüssten, aus welchen Pixeln das Bild besteht http://some-other-host/yourPassword.png. Sie können die Farbe des Pixels unter der Maus nur erkennen, wenn sich die Maus über einer Leinwand oder einem Bildelement derselben Domäne befindet (oder einem Bildelement einer anderen Domäne, die mit einer Access-Control-Allow-Origin: *Kopfzeile bedient wird). Im Fall der Leinwand würden Sie tun canvasElement.getContext('2d').getImageData(x, y, 1, 1).data. Bei den Bildern müssten Sie sie auf eine Leinwand zeichnen mit:

var canvas = document.createElement("canvas");
canvas.width = yourImageElement.width;
canvas.height = yourImageElement.height;
canvas.getContext('2d').drawImage(yourImageElement, 0, 0);

Verwenden Sie dann einfach die zuvor für Leinwände erläuterte Methode. Wenn Sie in der Lage sein müssen, in verschiedene Darstellungen von Farbwerten zu konvertieren, versuchen Sie es mit meiner color.js- Bibliothek.

Außerdem werden Sie IE <9 niemals unterstützen können (vorausgesetzt, IE9 unterstützt Canvas), und die Verwendung von Flash hilft nicht, da es auch die Pixeldaten des Dokuments nicht lesen kann.

Eli Gray
quelle
5
Interessanter Aspekt zur Sicherheit und vielen Dank für den Canvas-Winkel. Ich könnte jedoch damit leben, nur auf Pixel innerhalb meiner Domain zugreifen zu können.
Pekka
Danke Elijah. Ich bin etwas traurig, dass dies auf Firefox beschränkt ist, aber das ist nicht deine Schuld und dies ist definitiv die einfachste Lösung. Ich werde es wahrscheinlich mit einer (langsameren) serverseitigen Fallback-Option kombinieren, um den IE zu bedienen. Akzeptiere deine Antwort.
Pekka
1
Was würde mich davon abhalten, mich yourPassword.pngin die Leinwand einzubetten und sie dort abzutasten? (vorausgesetzt, ich kenne die URL)
Hughes
1
@zzzzBov, @hughes, Sie verpassen den Punkt: Wenn Sie Pixel auf dem Bildschirm erfassen könnten, könnten Sie Werte in einem anderen Browserfenster oder sogar auf einem PDF-Kontoauszug in einem anderen Fenster anzeigen. Niemand sollte nicht vertrauenswürdiges JS auf einer Seite ausführen, die vertrauliche Informationen verarbeitet, und das Bereitstellen vertraulicher Dateien sollte eine ordnungsgemäße Authentifizierung beinhalten. Sie müssten die Sitzung des Benutzers entführen, um auf dessen Sitzung zugreifen zu können password.png.
Dan Ross
2
@danross, js hat keinen sandboxübergreifenden Zugriff zum Ausführen von Skripten (ohne ausdrückliche Genehmigung). Es gibt keinen Grund, warum eine API nicht auf Farbwerte von Frames beschränkt werden kann, die sich in derselben Sicherheitssandbox befinden.
zzzzBov
18

Mit einer Technik namens Browser Timing Attack ist es möglich, die Farbe eines beliebigen Pixels (auch auf Iframes) zu bestimmen.

Grundsätzlich misst diese Technik die Zeit zum Rendern eines SVG-Filters für ein Element und nicht die Farbe selbst ( requestAnimationFrame()ermöglicht das Messen der Zeit mit einer viel besseren Genauigkeit als setTimeout()). Abhängig von der aktuellen Pixelfarbe dauert das Anwenden des Filters mehr oder weniger lange. Auf diese Weise kann festgestellt werden, ob ein Pixel dieselbe Farbe wie eine bekannte Farbe hat - beispielsweise Schwarz oder Weiß.

Weitere Informationen finden Sie in diesem Whitepaper (pdf): https://www.contextis.com/media/downloads/Pixel_Perfect_Timing_Attacks_with_HTML5_Whitepaper.pdf

Übrigens: Ja, dies ist eine Sicherheitslücke im Browser, aber ich sehe nicht, wie Browser-Anbieter sie patchen können.

François Zaninotto
quelle
Interessante Problemumgehung, aber aufgrund der Cross Origin-Richtlinien nicht sicher?
BürgermeisterMonty
Dieses Papier ist fast 7 Jahre alt! Weiß jemand, ob diese Sicherheitslücke noch heute besteht?
Rodrigo
Ich bezweifle, dass es behoben wurde und CORS nicht gilt.
Xendi
11

Beim Zusammenführen verschiedener Referenzen, die hier in StackOverflow 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 es <map>über dem Bild verwenden müssen, ist es auch möglich. Ich hoffe ich habe geholfen.

Ebragaparah
quelle
2
Wie wäre es mit der Pipette, um Farbe von überall zu erhalten?
SearchForKnowledge
7

Ich stimme der sehr detaillierten Antwort von Elia zu. Außerdem würde ich sagen, dass Sie die Leinwand nicht benötigen, wenn es um Bilder geht. Wie Sie selbst angegeben haben, haben Sie diese Bilder in PHP verfügbar und können die Farbabfrage auf dem Server durchführen.

Ich würde vorschlagen, dass Sie dieses Problem mit einem externen Tool behandeln - dies macht es sogar browserunabhängig (aber vom Betriebssystem abhängig): Schreiben Sie ein kleines Tool (zum Beispiel in c #), das die Farbabfrage für Sie ausführt, wird mit einer Verknüpfung aufgerufen und übermittelt die Farbe zu Ihrem Server. Stellen Sie das Tool als Download auf Ihrem CMS zur Verfügung.

Ein weiterer Ansatz, den ich für ein CMS verwendet habe, war das "Stehlen" von Farben durch Parsen des CSS: Der Anwendungsfall bestand darin, die Farben einer bereits vorhandenen Website meiner Anwendung als Farbpalette zur Verfügung zu stellen:

  • Ich habe den Benutzer gebeten, eine URL vom Zielsystem anzugeben - hauptsächlich die Homepage des Unternehmens
  • Ich habe die Seite analysiert, um alle Farbdefinitionen in allen Inline-Stilen und verknüpften Stilen zu finden
  • (Sie können dies problemlos auf alle Bilder erweitern, auf die verwiesen wird.)
  • Das Ergebnis war eine schöne Farbpalette mit allen Farben zur Auswahl

Vielleicht ist das auch eine Lösung für Ihr CMS?

rdmüller
quelle
Prost Ralf. Das Erstellen einer benutzerdefinierten Palette ist eine sehr gute Idee, aber nicht für meine Aufgabe, da es viele neue Inhalte ohne definierten Farbbereich geben wird. Eine clientseitige Anwendung ist sicherlich der sauberste Ansatz, aber ich benötige ein Tool, das sowohl unter Windows als auch unter Mac OS funktioniert. Es wäre ein guter Grund, wieder in die clientseitige Programmierung einzusteigen (und zum ersten Mal auf dem Mac), aber ich habe momentan sooooo viel zu tun. Ich denke, ich gehe mit dem Bild nur Ansatz.
Pekka
6

Siehe neues HTML5-Element für Eingabe [Typ = Farbe]: http://www.w3.org/TR/html-markup/input.color.html , http://demo.hongkiat.com/html5-form-input-type /index2.html .

Jetzt funktioniert es zumindest in Chrome (in Ubuntu getestet, sollte auch für Windows funktionieren). Es startet den vom Betriebssystem bereitgestellten Farbauswahldialog . Wenn sich in diesem Dialogfeld eine Pipette befindet (für Gnome), können Sie an jedem Punkt Ihres Bildschirms eine Farbe auswählen . Noch nicht browserübergreifend, aber sauber und standardbasiert.

tema
quelle
Nett. Funktioniert natürlich auch in Firefox, aber es wäre großartig, wenn Sie dies tun könnten, ohne einen Browser-Dialog öffnen zu müssen.
NoBugs
1
Leider hat Chrome kürzlich das Design der Formularsteuerung aktualisiert und der neue Farbwähler verfügt nicht über eine Pipette.
Mattsven
5

Ich weiß nicht, ob dies machbar ist, aber wenn Ihre Seiten statisch sind, können Sie einen Bild-Screenshot von jedem von ihnen speichern (oder vielleicht einen für jede Browser- / Bildschirmauflösung?) Und dann AJAX verwenden, um die Cursorkoordinaten an die zu senden Server und geben Sie die Pixelfarbe mit PHPs zurück imagecolorat().

Um die Screenshots zu machen, können Sie Selenium IDE wie hier beschrieben verwenden .

Ich hoffe es hilft.

jbochi
quelle
3

Zu den vorherigen Antworten hinzufügen -

Eine Möglichkeit, dieses Problem zu betrachten, besteht darin, dass Sie in der Lage sein möchten, eine Bildschirmaufnahme eines Bereichs von 1 x 1 Pixel durchzuführen. Eine weit verbreitete Technik zum Erfassen von Bildschirmbereichen (z. B. aus webbasierten Fehlerberichterstattungssystemen) besteht darin, ein signiertes Java-Applet und java.awt.Robot zum Erfassen des Bildes zu verwenden. Wenn Sie das Applet signieren, erhalten Ihre Benutzer das Dialogfeld "Vertrauen Sie dieser App" (mit dem Kontrollkästchen "Apps von diesem Publisher immer vertrauen") und können das Tool dann verwenden.

Sie können das Ergebnis dann mit LiveConnect an JavaScript weitergeben (die Dokumente sind alt, aber Java-Applets unterstützen dies weiterhin), oder Sie können es auf Ihrem Server veröffentlichen. Ebenso können Sie das Java-Applet über JavaScript aufrufen.

William Billingsley
quelle
Der Java Applet-Winkel ist interessant. Ich bin jedoch nicht in der Lage, Applets zu codieren, daher kann ich dies wahrscheinlich nicht für meine jeweilige Aufgabe implementieren und werde auf den oben beschriebenen Canvas-Ansatz zurückgreifen. Vielen Dank, dass Sie mich darauf aufmerksam gemacht haben. Vielleicht kann ich zu einem späteren Zeitpunkt etwas damit anfangen.
Pekka
3

Aus Sicherheitsgründen können Sie keine Bildschirmpixel mit Javascript erfassen (Entwickler können also keine Schnappschüsse Ihrer persönlichen Daten erstellen), aber Sie können dies in Flash tun - Sie können Pixeldaten im Flash-Container mithilfe der Datei flash.display abrufen .BitmapData-Klasse.

Check out http://www.sephiroth.it/tutorials/flashPHP/print_screen/ - Ich habe es in Flash-basierten WYSYWIG-Projekten verwendet, um Bilder auf einem LAMP (PHP) -Server zu speichern.

Das Problem bei der Verwendung von Flash ist, dass es auf iOS-Geräten, die derzeit sehr beliebt sind und für die es sich zu entwickeln lohnt, nicht nativ unterstützt wird. Der Blitz ist auf dem Weg durch die Röhren.

Die Canvas-basierte Methode ist sicherlich eine gute, vorausgesetzt, alle Ihre Besucher verfügen über aktuelle Webbrowser, die das Canvas-Tag und JavaScript unterstützen.

supershwa
quelle
3

Es gibt keine eingebaute DOM-Methode, um die Farbe eines DOM-Elements (außer Bildern oder a <canvas>) an einer bestimmten Pixelposition generisch abzurufen.

Dazu müssen wir beispielsweise HTML2Canvas oder DOM Panda verwenden , um einen "Screenshot" unserer Website zu erstellen, den Klickort des Benutzers zu ermitteln und die Pixelfarbe des "Screenshots" an diesem bestimmten Ort abzurufen .

Mit HTML2Canvas (Version 0.5.0-beta3) können Sie Folgendes tun:

// Take "screenshot" using HTML2Canvas
var screenshotCanvas,
    screenshotCtx,
    timeBetweenRuns = 10,
    lastTime = Date.now();
function getScreenshot() {
    // Limit how soon this can be ran again
    var currTime = Date.now();
    if(currTime - lastTime > timeBetweenRuns) {
        html2canvas(document.body).then(function(canvas) {
            screenshotCanvas = canvas;
            screenshotCtx = screenshotCanvas.getContext('2d');
        });
        lastTime = currTime;
    }
}
setTimeout(function() { // Assure the initial capture is done
    getScreenshot();
}, 100);

// Get the user's click location
document.onclick = function(event) {
    var x = event.pageX,
        y = event.pageY;

    // Look what color the pixel at the screenshot is
    console.log(screenshotCtx.getImageData(x, y, 1, 1).data);
}


// Update the screenshot when the window changes size
window.onresize = getScreenshot;

Demo

Zach Saucier
quelle
Hier ist eine Demo, die die obige Lösung implementiert: jsfiddle.net/8850s/an9f24hp Klicken Sie irgendwo, um das background-colorDiv oben links (sogar auf dem Div selbst)
festzulegen