web-dev-qa-db-fra.com

Pipette JavaScript (indiquer la couleur du pixel sous le curseur de la souris)

Je recherche un outil " Pipette ", qui me donne la valeur hexadécimale du pixel sous lequel se trouve le curseur de la souris, en JavaScript pour un CMS.

Pour Firefox, il y a l'excellente extension ColorZilla qui fait exactement cela. Cependant, c'est FF uniquement bien sûr, et j'aimerais vraiment fournir l'outil avec le CMS.

Un développeur néerlandais a eu une idée très intelligente d'utiliser une combinaison d'Ajax et de la imagecolorat() de PHP pour découvrir la couleur Pixel sur une image. Mais cela limite la plage aux images auxquelles je peux accéder côté serveur , et je rêve vraiment d'un outil universel.

Je travaillerai avec l'une de ces approches, mais je préférerais de loin une méthode basée sur plusieurs navigateurs, Javascript ou Flash qui ne nécessite aucun bidouillage côté serveur et aucune installation d'extensions.

Je suis également intéressé par toutes les solutions IE spécifiques qui font ce que ColorZilla peut faire - je pourrais vivre avec le support IE et FF uniquement, bien qu'une solution multi-navigateur le ferait) bien sûr être idéal.

66
Pekka 웃

Ce n'est pas possible avec JavaScript car cela va à l'encontre de la sécurité inter-domaines. Ce serait très mauvais si vous saviez quels pixels constituaient l'image, http://some-other-Host/yourPassword.png. Vous ne pouvez dire la couleur du pixel sous la souris que si la souris est sur un canevas ou un élément image du même domaine (ou un élément image d'un autre domaine qui est servi avec un en-tête Access-Control-Allow-Origin: *). Dans le cas du canevas, vous feriez canvasElement.getContext('2d').getImageData(x, y, 1, 1).data. Dans le cas des images, vous devrez les dessiner sur une toile avec:

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

Et puis il suffit d'utiliser la méthode précédente expliquée pour les toiles. Si vous devez être capable de convertir en différentes représentations de valeurs de couleur, essayez ma bibliothèque color.js .

En outre, vous ne pourrez jamais prendre en charge IE <9 (cela suppose que IE9 prend en charge le canevas) et l'utilisation de Flash n'aidera pas car il ne peut pas lire les données en pixels du document soit.

73
Eli Grey

En utilisant une technique appelée Attaque de synchronisation du navigateur , il est possible de (en quelque sorte) déterminer la couleur de n'importe quel pixel, même sur des iframes.

Fondamentalement, cette technique mesure le temps de rendu d'un filtre SVG sur un élément, plutôt que la couleur elle-même (requestAnimationFrame() permet de mesurer le temps avec une bien meilleure précision que setTimeout()). Selon la couleur actuelle des pixels, le filtre prend plus ou moins de temps à appliquer. Cela permet de déterminer si un pixel est de la même couleur qu'une couleur connue - par exemple noir ou blanc.

Plus de détails dans ce livre blanc (pdf): http://www.contextis.com/documents/2/Browser_Timing_Attacks.pdf

Soit dit en passant: oui, il s'agit d'une faille de sécurité du navigateur, mais je ne vois pas comment les fournisseurs de navigateurs peuvent le corriger.

14
François Zaninotto

Fusionnant diverses références trouvées ici dans StackOverflow et dans d'autres sites, je l'ai fait en utilisant javascript et 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>

Ceci est ma solution complète .. Ici, je n'ai utilisé qu'une toile et une image, mais si vous avez besoin d'utiliser <map> sur l'image, c'est possible aussi. J'espère avoir aidé.

11
ebragaparah

Je suis d'accord avec la réponse très détaillée fournie par Elijah. De plus, je dirais que vous n'avez pas besoin de la toile pour les images. Comme vous l'avez dit vous-même, vous avez ces images disponibles à partir de php et pouvez faire la requête de couleur sur le serveur.

Je suggère que vous gériez ce problème avec un outil externe - cela le rend même indépendant du navigateur (mais dépendant du système d'exploitation): écrivez un petit outil (par exemple en c #) qui fait la requête de couleur pour vous, est invoqué avec un raccourci et soumet la couleur à votre serveur. Rendez l'outil disponible en téléchargement sur votre CMS.

Une autre approche que j'ai utilisée pour un CMS était de "voler" des couleurs en analysant le CSS: le cas d'utilisation était de rendre les couleurs d'un site Web déjà existant disponibles comme palette de couleurs pour mon application:

  • J'ai demandé à l'utilisateur de fournir une URL à partir du système cible - principalement la page d'accueil de l'entreprise
  • J'ai analysé la page pour trouver toutes les définitions de couleurs dans tous les styles en ligne et les styles liés
  • (vous pouvez facilement l'étendre à toutes les images référencées)
  • le résultat était une belle palette de couleurs avec toutes les couleurs de coporate à choisir

C'est peut-être aussi une solution pour votre CMS?

7
rdmueller

Voir le nouvel élément HTML5 d'entrée [type = couleur]: http://www.w3.org/TR/html-markup/input.color.html , http: // démo. hongkiat.com/html5-form-input-type/index2.html .

Maintenant, cela fonctionne au moins dans Chrome (testé dans Ubuntu, devrait également fonctionner pour Windows). Il ouvre la boîte de dialogue de sélection des couleurs fournie par le système d'exploitation . S'il y a une pipette dans cette boîte de dialogue (c'est pour Gnome), alors il est possible de choisir une couleur à partir de n'importe quel point de votre écran Pas encore multi-navigateur, mais propre et basé sur des normes.

4
tema

Je ne sais pas si cela est possible, mais si vos pages sont statiques, vous pouvez enregistrer une capture d'écran de chacune d'entre elles (ou peut-être une pour chaque résolution de navigateur/écran?), Puis utiliser AJAX pour envoyer les coordonnées du curseur au serveur et renvoyer la couleur des pixels avec la fonction imagecolorat() de PHP.

Pour prendre les captures d'écran, vous pouvez utiliser Selenium IDE comme décrit ici .

J'espère que ça aide.

4
jbochi

Par mesure de sécurité, vous ne pouvez pas capturer les pixels de l'écran avec Javascript (les développeurs ne peuvent donc pas prendre d'instantanés de vos données personnelles), mais vous POUVEZ le faire en Flash - vous pouvez obtenir des données de pixels dans le conteneur Flash en utilisant le flash.display Classe .BitmapData.

Découvrez http://www.sephiroth.it/tutorials/flashPHP/print_screen/ - Je l'ai utilisé dans des projets WYSYWIG basés sur Flash pour enregistrer des images sur un serveur LAMP (PHP).

Le problème avec l'utilisation de Flash est qu'il n'est pas pris en charge nativement sur les appareils iOS, qui sont extrêmement populaires maintenant et méritent d'être développés. Le flash est en train de descendre les tubes.

La méthode basée sur le canevas sera certainement bonne à condition que tous vos visiteurs disposent de navigateurs Web à jour qui prennent en charge la balise canvas et JavaScript.

3
supershwa

Pour ajouter aux réponses précédentes -

Une façon de penser à ce problème est que vous voulez pouvoir faire une capture d'écran d'une région de 1px par 1px. Une technique assez courante pour capturer des régions d'écran (par exemple à partir de systèmes de rapport de bogues basés sur le Web) consiste à utiliser une applet signée Java et Java.awt.Robot pour capturer l'image. Si vous signez l'applet, vos utilisateurs obtiendront une boîte de dialogue "faites-vous confiance à cette application" (avec une case à cocher "toujours faire confiance aux applications de cet éditeur") et pourront ensuite utiliser l'outil.

Vous pouvez ensuite transmettre le résultat à JavaScript à l'aide de LiveConnect (les documents sont anciens, mais Java le prennent toujours en charge), ou vous pouvez le publier sur votre serveur. De même, vous pouvez appeler le Java applet de JavaScript.

3

Il n'y a pas de méthode DOM intégrée pour obtenir génériquement la couleur d'un élément DOM (autre que des images ou un <canvas>) à un emplacement de pixel particulier.

Ainsi, pour ce faire, nous devons utiliser quelque chose comme HTML2Canvas ou DOM Panda pour prendre une "capture d'écran" de notre site Web, obtenir l'emplacement de clic de l'utilisateur et obtenir le la couleur des pixels de la "capture d'écran" à cet emplacement particulier.

En utilisant HTML2Canvas (version 0.5.0-beta3), vous pouvez faire quelque chose comme ceci:

// 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;

Démo

2
Zach Saucier