Como obter as coordenadas x, y de um pixel de uma imagem?

124

Existe alguma maneira de verificar se um ponto selecionado (x, y) de uma imagem PNG é transparente?

Danny Fox
fonte
1
De alguma forma, a imagem pode ser carregada em um elemento Canvas?
Se não houver outro jeito, então
Danny Fox

Respostas:

198

Com base na resposta de Jeff, seu primeiro passo seria criar uma representação de tela do seu PNG. A seguir, é criada uma tela fora da tela com a mesma largura e altura da sua imagem e com a imagem desenhada nela.

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

Depois disso, quando um usuário clicar, use event.offsetXe event.offsetYpara obter a posição. Isso pode ser usado para adquirir o pixel:

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

Como você está capturando apenas um pixel, pixelData é uma matriz de quatro entradas que contém os valores R, G, B e A do pixel. Para alfa, qualquer coisa menor que 255 representa algum nível de transparência, com 0 sendo totalmente transparente.

Aqui está um exemplo do jsFiddle: http://jsfiddle.net/thirtydot/9SEMf/869/ Usei o jQuery por conveniência em tudo isso, mas não é de forma alguma necessário.

Nota: getImageData se enquadra na política de mesma origem do navegador para evitar vazamentos de dados, o que significa que essa técnica falhará se você sujar a tela com uma imagem de outro domínio ou (acredito, mas alguns navegadores tenham resolvido isso) SVG de qualquer domínio. Isso protege contra casos em que um site fornece um recurso de imagem personalizado para um usuário conectado e um invasor deseja ler a imagem para obter informações. Você pode resolver o problema servindo a imagem do mesmo servidor ou implementando o compartilhamento de recursos de origem cruzada .

Brian Nickel
fonte
3
boom - trabalho incrível. Eu sabia que deveria ter feito um violino como esse, mas era muito gordo e preguiçoso. você matou aqui
Jeff Escalante
Para que isso esteja correto, você precisa definir o espaço de coordenadas da tela, ou seja, definir a largura e a altura para corresponder às dimensões da imagem. A largura e a altura do CSS servem apenas para esticar a tela final do layout, o que não ajuda quando é um elemento não exibido. Tente algo como $ ('<canvas width =' + img.width + 'height =' + img.height + '/>') ;. Ou isso de alguma forma não se aplica a telas fora da tela?
Fab123 #
@fabspro: Esse é um ponto excelente. Como o desenho e a leitura dos dados da imagem são feitos via contexto, os valores de largura e altura não têm sentido. Eles não têm nenhum efeito negativo porque a tela e o contexto não estão distorcidos e a razão pela qual não vi esse efeito na minha demonstração é simplesmente porque a imagem é menor que a largura / altura inicial do contexto. Vou atualizar de acordo, embora seja mais seguro acessar .widthe .heightna tela do que através da concatenação.
Brian Nickel
6
Você não pode usar isso para imagens remotas. "Não foi possível obter dados da imagem da tela porque a tela foi contaminada por dados de origem cruzada. SecurityError: Foi feita uma tentativa de romper a política de segurança do agente do usuário."
precisa
18

O Canvas seria uma ótima maneira de fazer isso, como o @pst disse acima. Confira esta resposta para um bom exemplo:

getPixel do HTML Canvas?

Algum código que também serviria especificamente para você:

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

Isso irá linha por linha, portanto, você precisará convertê-lo em um x, ye converter o loop for em uma verificação direta ou executar uma condicional dentro.

Lendo sua pergunta novamente, parece que você deseja entender o ponto em que a pessoa clica. Isso pode ser feito facilmente com o evento click do jquery. Basta executar o código acima em um manipulador de cliques, como tal:

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

Aqueles devem pegar seus valores x e y.

Jeff Escalante
fonte
Não é isso que o comentarista perguntou (aparentemente) e nem responde à pergunta. A resposta aceita funciona. Eu recomendo excluir esta resposta ...
Agamemnus 13/01/19
5

As duas respostas anteriores demonstram como usar o Canvas e o ImageData. Gostaria de propor uma resposta com um exemplo executável e usando uma estrutura de processamento de imagem, para que você não precise manipular os dados de pixel manualmente.

MarvinJ fornece o método image.getAlphaComponent (x, y) que simplesmente retorna o valor da transparência do pixel nas coordenadas x, y. Se esse valor for 0, o pixel é totalmente transparente, os valores entre 1 e 254 são níveis de transparência e, finalmente, 255 é opaco.

Para demonstrar, usei a imagem abaixo (300x300) com fundo transparente e dois pixels nas coordenadas (0,0) e (150,150) .

insira a descrição da imagem aqui

Saída do console:

(0,0): TRANSPARENTE
(150,150): NOT_TRANSPARENT

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
fonte
2

Com: 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
fonte