Come ottenere le coordinate x, y di un pixel da un'immagine?


124

C'è un modo per verificare se un punto selezionato (x, y) di un'immagine PNG è trasparente?


1
L'immagine può in qualche modo essere caricata su un elemento Canvas?

Se non c'è altro modo, allora
Danny Fox

Risposte:


199

Basandosi sulla risposta di Jeff, il tuo primo passo sarebbe creare una rappresentazione su tela del tuo PNG. Quanto segue crea una tela fuori dallo schermo che ha la stessa larghezza e altezza dell'immagine e ha l'immagine disegnata su di essa.

var img = document.getElementById('my-image');
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);

Dopodiché, quando un utente fa clic, utilizza event.offsetXe event.offsetYper ottenere la posizione. Questo può quindi essere utilizzato per acquisire il pixel:

var pixelData = canvas.getContext('2d').getImageData(event.offsetX, event.offsetY, 1, 1).data;

Poiché stai afferrando solo un pixel, pixelData è un array di quattro voci contenente i valori R, G, B e A del pixel. Per alfa, qualsiasi valore inferiore a 255 rappresenta un certo livello di trasparenza con 0 che è completamente trasparente.

Ecco un esempio di jsFiddle: http://jsfiddle.net/thirtydot/9SEMf/869/ Ho usato jQuery per comodità in tutto questo, ma non è affatto richiesto.

Nota: getImageData rientra nella politica della stessa origine del browser per prevenire la fuga di dati, il che significa che questa tecnica fallirà se sporchi la tela con un'immagine di un altro dominio o (credo, ma alcuni browser potrebbero aver risolto questo) SVG da qualsiasi dominio. Ciò protegge dai casi in cui un sito offre una risorsa immagine personalizzata per un utente connesso e un utente malintenzionato desidera leggere l'immagine per ottenere informazioni. Puoi risolvere il problema servendo l'immagine dallo stesso server o implementando la condivisione delle risorse tra le origini .


3
boom - lavoro fantastico. Sapevo che avrei dovuto fare un violino come questo, ma ero troppo grasso e pigro. l'hai ucciso qui
Jeff Escalante

Affinché ciò sia corretto, è necessario impostare lo spazio delle coordinate della tela, ovvero impostare la larghezza e l'altezza in modo che corrispondano alle dimensioni dell'immagine. La larghezza e l'altezza CSS servono solo per allungare la tela finale per il layout, il che non aiuta quando è un elemento non visualizzato. Prova qualcosa come $ ('<canvas width =' + img.width + 'height =' + img.height + '/>') ;. O questo in qualche modo non si applica alle tele fuori schermo?
fabspro

@fabspro: Questo è un punto eccellente. Poiché il disegno e la lettura dei dati dell'immagine vengono eseguiti tramite il contesto, i valori di larghezza e altezza sono privi di significato. Non hanno alcun effetto negativo perché la tela e non il contesto è contorta e il motivo per cui non ho visto questo effetto nella mia demo è semplicemente perché l'immagine è più piccola della larghezza / altezza iniziale del contesto. Aggiornerò di conseguenza, sebbene sia più sicuro accedere .widthe .heightsulla tela stessa che tramite la concatenazione.
Brian Nickel


6
Non puoi usarlo per le immagini remote. "Impossibile ottenere i dati dell'immagine dalla tela perché la tela è stata contaminata da dati tra le origini. SecurityError: è stato effettuato un tentativo di infrangere la politica di sicurezza dell'agente utente."
Karl Glaser

18

Canvas sarebbe un ottimo modo per farlo, come ha detto @pst sopra. Dai un'occhiata a questa risposta per un buon esempio:

getPixel da HTML Canvas?

Un po 'di codice che ti servirebbe in modo specifico anche:

var imgd = context.getImageData(x, y, width, height);
var pix = imgd.data;

for (var i = 0, n = pix.length; i < n; i += 4) {
  console.log pix[i+3]
}

Questo andrà riga per riga, quindi dovresti convertirlo in una x, y e convertire il ciclo for in un controllo diretto o eseguire un condizionale all'interno.

Leggendo di nuovo la tua domanda, sembra che tu voglia essere in grado di capire il punto su cui la persona fa clic. Questo può essere fatto abbastanza facilmente con l'evento click di jquery. Basta eseguire il codice sopra all'interno di un gestore di clic come tale:

$('el').click(function(e){
   console.log(e.clientX, e.clientY)
}

Quelli dovrebbero afferrare i tuoi valori xey.


Questo non è ciò che il commentatore ha chiesto (apparentemente) e non risponde affatto alla domanda. La risposta accettata funziona. Consiglio di cancellare questa risposta ...
Agamemnus

5

Le due risposte precedenti dimostrano come utilizzare Canvas e ImageData. Vorrei proporre una risposta con un esempio eseguibile e utilizzando un framework di elaborazione delle immagini, quindi non è necessario gestire manualmente i dati dei pixel.

MarvinJ fornisce il metodo image.getAlphaComponent (x, y) che restituisce semplicemente il valore di trasparenza per il pixel nelle coordinate x, y. Se questo valore è 0, il pixel è totalmente trasparente, i valori tra 1 e 254 sono livelli di trasparenza, infine 255 è opaco.

Per la dimostrazione ho usato l'immagine sottostante (300x300) con sfondo trasparente e due pixel alle coordinate (0,0) e (150,150) .

inserisci qui la descrizione dell'immagine

Uscita console:

(0,0): TRASPARENTE
(150,150): NON_TRANSPARENTE

image = new MarvinImage();
image.load("https://i.imgur.com/eLZVbQG.png", imageLoaded);

function imageLoaded(){
  console.log("(0,0): "+(image.getAlphaComponent(0,0) > 0 ? "NOT_TRANSPARENT" : "TRANSPARENT"));
  console.log("(150,150): "+(image.getAlphaComponent(150,150) > 0 ? "NOT_TRANSPARENT" : "TRANSPARENT"));
}
<script src="https://www.marvinj.org/releases/marvinj-0.7.js"></script>


2

Con : i << 2

const data = context.getImageData(x, y, width, height).data;
const pixels = [];

for (let i = 0, dx = 0; dx < data.length; i++, dx = i << 2) {
    if (data[dx+3] <= 8)
        console.log("transparent x= " + i);
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.