¿Cómo obtener el color de coordenadas x, y de un píxel de una imagen?

124

¿Hay alguna forma de verificar si un punto seleccionado (x, y) de una imagen PNG es transparente?

Danny Fox
fuente
1
¿Se puede cargar la imagen de alguna manera en un elemento Canvas?
Si no hay otra manera, entonces
Danny Fox

Respuestas:

198

Sobre la base de la respuesta de Jeff, su primer paso sería crear una representación de lienzo de su PNG. Lo siguiente crea un lienzo fuera de la pantalla que tiene el mismo ancho y alto que su imagen y tiene la imagen dibujada en él.

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

Después de eso, cuando un usuario hace clic, use event.offsetXy event.offsetYpara obtener la posición. Esto se puede usar para adquirir el píxel:

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

Debido a que solo está tomando un píxel, pixelData es una matriz de cuatro entradas que contiene los valores R, G, B y A del píxel. Para alfa, cualquier cosa menor que 255 representa algún nivel de transparencia con 0 siendo completamente transparente.

Aquí hay un ejemplo de jsFiddle: http://jsfiddle.net/thirtydot/9SEMf/869/ Usé jQuery por conveniencia en todo esto, pero de ninguna manera es obligatorio.

Nota: getImageData cae bajo la política del mismo origen del navegador para evitar fugas de datos, lo que significa que esta técnica fallará si ensucia el lienzo con una imagen de otro dominio o (creo, pero algunos navegadores pueden haber resuelto esto) SVG de cualquier dominio. Esto protege contra los casos en los que un sitio ofrece un recurso de imagen personalizado para un usuario conectado y un atacante quiere leer la imagen para obtener información. Puede resolver el problema sirviendo la imagen desde el mismo servidor o implementando el intercambio de recursos de origen cruzado .

Brian Nickel
fuente
3
boom: trabajo increíble. Sabía que debería haber hecho un violín como este, pero estaba demasiado gordo y perezoso. lo mataste aquí
Jeff Escalante
Para que esto sea correcto, debe establecer el espacio de coordenadas del lienzo, es decir, establecer el ancho y la altura para que coincidan con las dimensiones de la imagen. El ancho y la altura de CSS solo sirven para estirar el lienzo final para el diseño, lo que no ayuda cuando se trata de un elemento no visualizado. Pruebe algo como $ ('<canvas width =' + img.width + 'height =' + img.height + '/>') ;. ¿O esto de alguna manera no se aplica con lienzos fuera de la pantalla?
fabspro
@fabspro: Ese es un excelente punto. Dado que dibujar y leer los datos de la imagen se realizan a través del contexto, los valores de ancho y alto no tienen sentido. No tienen ningún efecto negativo porque el lienzo, no el contexto, está contorsionado y la razón por la que no vi este efecto en mi demostración es simplemente porque la imagen es más pequeña que el ancho / alto inicial del contexto. Actualizaré en consecuencia, aunque es más seguro acceder .widthy .heighten el lienzo en sí que a través de la concatenación.
Brian Nickel
66
No puede usar esto para imágenes remotas. "No se pueden obtener datos de la imagen del lienzo porque el lienzo ha sido contaminado por datos de origen cruzado. SecurityError: se intentó romper la política de seguridad del agente de usuario".
Karl Glaser
18

Canvas sería una excelente manera de hacer esto, como @pst dijo anteriormente. Mira esta respuesta para un buen ejemplo:

getPixel de HTML Canvas?

Algún código que también le sirva específicamente:

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]
}

Esto irá fila por fila, por lo que necesitará convertir eso en una x, y y convertir el bucle for en una verificación directa o ejecutar un condicional dentro.

Al leer su pregunta nuevamente, parece que quiere poder obtener el punto en el que la persona hace clic. Esto se puede hacer fácilmente con el evento click de jquery. Simplemente ejecute el código anterior dentro de un controlador de clics como tal:

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

Esos deberían tomar sus valores x e y.

Jeff Escalante
fuente
Esto no es lo que el comentarista preguntó (aparentemente), y no responde a la pregunta en absoluto. La respuesta aceptada funciona. Recomiendo eliminar esta respuesta ...
Agamemnus
5

Las dos respuestas anteriores demuestran cómo usar Canvas e ImageData. Me gustaría proponer una respuesta con un ejemplo ejecutable y utilizando un marco de procesamiento de imágenes, por lo que no necesita manejar los datos de píxeles manualmente.

MarvinJ proporciona el método image.getAlphaComponent (x, y) que simplemente devuelve el valor de transparencia para el píxel en la coordenada x, y. Si este valor es 0, el píxel es totalmente transparente, los valores entre 1 y 254 son niveles de transparencia, finalmente 255 es opaco.

Para demostrarlo, he usado la siguiente imagen (300x300) con fondo transparente y dos píxeles en las coordenadas (0,0) y (150,150) .

ingrese la descripción de la imagen aquí

Salida de consola:

(0,0): TRANSPARENTE
(150,150): NO 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>

Gabriel Ambrósio Archanjo
fuente
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);
}
A-312
fuente