Jak uzyskać kolor współrzędnych x, y piksela z obrazu?

124

Czy istnieje sposób, aby sprawdzić, czy wybrany punkt (x, y) obrazu PNG jest przezroczysty?

Danny Fox
źródło
1
Czy obraz można w jakiś sposób załadować do elementu Canvas?
Jeśli nie ma innego wyjścia, to
Danny Fox

Odpowiedzi:

199

Opierając się na odpowiedzi Jeffa, pierwszym krokiem byłoby utworzenie płótna reprezentującego plik PNG. Poniższy rysunek tworzy obszar roboczy poza ekranem, który ma taką samą szerokość i wysokość jak obraz i jest narysowany na nim.

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

Następnie, gdy użytkownik kliknie, użyj event.offsetXi, event.offsetYaby uzyskać pozycję. Można to następnie wykorzystać do pozyskania piksela:

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

Ponieważ pobierasz tylko jeden piksel, pixelData jest tablicą składającą się z czterech wpisów, zawierającą wartości R, G, B i A. W przypadku alfa cokolwiek poniżej 255 reprezentuje pewien poziom przezroczystości, przy czym 0 oznacza pełną przezroczystość.

Oto przykład jsFiddle: http://jsfiddle.net/thirtydot/9SEMf/869/ Użyłem jQuery dla wygody w tym wszystkim, ale w żadnym wypadku nie jest to wymagane.

Uwaga: getImageData podlega polityce tego samego pochodzenia przeglądarki, aby zapobiec wyciekom danych, co oznacza, że ​​ta technika nie powiedzie się, jeśli zabrudzisz płótno obrazem z innej domeny lub (uważam, ale niektóre przeglądarki mogły to rozwiązać) SVG z dowolnej domeny. Chroni to przed przypadkami, gdy witryna wyświetla niestandardowy zasób obrazu dla zalogowanego użytkownika, a osoba atakująca chce odczytać obraz, aby uzyskać informacje. Możesz rozwiązać problem, udostępniając obraz z tego samego serwera lub wdrażając udostępnianie zasobów między źródłami .

Brian Nickel
źródło
3
boom - niesamowita robota. Wiedziałem, że powinienem zrobić takie skrzypce, ale byłem zbyt gruby i leniwy. zabiłeś to tutaj
Jeff Escalante,
Aby to było poprawne, musisz ustawić przestrzeń współrzędnych płótna, tj. Ustawić szerokość i wysokość, aby pasowały do ​​wymiarów obrazu. Szerokość i wysokość CSS służą tylko do rozciągania ostatecznego płótna do układu, co nie pomaga, gdy jest to niewidoczny element. Spróbuj czegoś takiego jak $ ('<szerokość płótna =' + img.width + 'wysokość =' + img.height + '/>') ;. A może to w jakiś sposób nie dotyczy płócien pozaekranowych?
fabspro
@fabspro: To doskonała uwaga. Ponieważ rysowanie i odczytywanie danych obrazu odbywa się za pośrednictwem kontekstu, wartości szerokości i wysokości są bez znaczenia. Nie mają żadnego złego efektu, ponieważ płótno, a nie kontekst, jest wykrzywione, a powodem, dla którego nie widziałem tego efektu na moim demo, jest po prostu to, że obraz jest mniejszy niż początkowa szerokość / wysokość kontekstu. Zaktualizuję odpowiednio, chociaż bezpieczniej jest uzyskać dostęp .widthi .heightna samym płótnie niż przez konkatenację.
Brian Nickel
4
Napraw to w przeglądarce Firefox jsfiddle.net/9SEMf/622 za pomocą tego stackoverflow.com/questions/11334452/event-offsetx-in-firefox
benoît
6
Nie możesz tego użyć do zdalnych obrazów. „Nie można pobrać danych obrazu z kanwy, ponieważ kanwa została skażona danymi pochodzącymi z różnych źródeł. SecurityError: Podjęto próbę przełamania polityki bezpieczeństwa klienta użytkownika.”
Karl Glaser,
18

Canvas byłby świetnym sposobem na zrobienie tego, jak powiedział @pst powyżej. Sprawdź tę odpowiedź, aby uzyskać dobry przykład:

getPixel z HTML Canvas?

Kod, który również by Ci służył:

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

Będzie to przebiegać wiersz po wierszu, więc musisz przekonwertować to na x, y i albo przekonwertować pętlę for na bezpośrednie sprawdzenie, albo uruchomić warunek wewnątrz.

Czytając ponownie swoje pytanie, wygląda na to, że chcesz uzyskać informację, w którą stronę klika dana osoba. Można to zrobić dość łatwo za pomocą zdarzenia kliknięcia jquery. Po prostu uruchom powyższy kod w module obsługi kliknięć, takim jak:

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

Powinny one obejmować wartości x i y.

Jeff Escalante
źródło
Nie o to zapytał komentator (pozornie) i wcale nie odpowiada na to pytanie. Przyjęta odpowiedź działa. Polecam usunąć tę odpowiedź ...
Agamemnus
5

Dwie poprzednie odpowiedzi pokazują, jak używać Canvas i ImageData. Chciałbym zaproponować odpowiedź z uruchomionym przykładem i przy użyciu struktury przetwarzania obrazu, więc nie musisz ręcznie obsługiwać danych pikseli.

MarvinJ udostępnia metodę image.getAlphaComponent (x, y), która po prostu zwraca wartość przezroczystości dla piksela we współrzędnych x, y. Jeśli ta wartość wynosi 0, piksel jest całkowicie przezroczysty, wartości od 1 do 254 to poziomy przezroczystości, a na końcu 255 jest nieprzezroczyste.

Do zademonstrowania użyłem poniższego obrazu (300x300) z przezroczystym tłem i dwoma pikselami o współrzędnych (0,0) i (150,150) .

wprowadź opis obrazu tutaj

Wyjście konsoli:

(0,0):
PRZEŹROCZYSTY (150,150): NIE_TRANSPARENTNY

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
źródło
1

Z : 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
źródło