จะรับสีพิกัด x, y ของพิกเซลจากรูปภาพได้อย่างไร?


124

มีวิธีใดบ้างในการตรวจสอบว่าจุด (x, y) ที่เลือกของภาพ PNG โปร่งใสหรือไม่


1
สามารถโหลดรูปภาพบนองค์ประกอบ Canvas ได้หรือไม่

หากไม่มีทางอื่นแล้ว
Danny Fox

คำตอบ:


199

จากคำตอบของ Jeff ขั้นตอนแรกของคุณคือการสร้างภาพแทนผ้าใบของ PNG ของคุณ ต่อไปนี้จะสร้างผืนผ้าใบนอกหน้าจอที่มีความกว้างและความสูงเท่ากับภาพของคุณและมีภาพวาดอยู่

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

หลังจากนั้นเมื่อผู้ใช้คลิกใช้event.offsetXและevent.offsetYเพื่อรับตำแหน่ง จากนั้นสามารถใช้เพื่อรับพิกเซล:

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

เนื่องจากคุณมีเพียงหนึ่งพิกเซลเท่านั้น pixelData จึงเป็นอาร์เรย์รายการสี่รายการที่มีค่า R, G, B และ A ของพิกเซล สำหรับอัลฟ่าค่าที่น้อยกว่า 255 จะแสดงถึงความโปร่งใสระดับหนึ่งโดย 0 จะโปร่งใสทั้งหมด

นี่คือตัวอย่าง jsFiddle: http://jsfiddle.net/thirtydot/9SEMf/869/ ฉันใช้ jQuery เพื่อความสะดวกในทั้งหมดนี้ แต่ก็ไม่จำเป็นต้องใช้

หมายเหตุ: getImageDataอยู่ภายใต้นโยบายแหล่งกำเนิดเดียวกันของเบราว์เซอร์เพื่อป้องกันการรั่วไหลซึ่งหมายความว่าเทคนิคนี้จะล้มเหลวหากคุณทำให้ผืนผ้าใบสกปรกด้วยรูปภาพจากโดเมนอื่นหรือ (ฉันเชื่อว่าเบราว์เซอร์บางตัวอาจแก้ปัญหานี้ได้) SVG จากโดเมนใด ๆ วิธีนี้ป้องกันกรณีที่ไซต์แสดงเนื้อหารูปภาพที่กำหนดเองสำหรับผู้ใช้ที่ลงชื่อเข้าใช้และผู้โจมตีต้องการอ่านรูปภาพเพื่อรับข้อมูล คุณสามารถแก้ปัญหาโดยการให้บริการทั้งภาพจากเซิร์ฟเวอร์เดียวกันหรือการใช้ทรัพยากรร่วมกันข้ามจุด


3
บูม - งานที่ยอดเยี่ยม ฉันรู้ว่าฉันควรจะทำซอแบบนี้ แต่อ้วนและขี้เกียจเกินไป คุณฆ่ามันที่นี่
Jeff Escalante

เพื่อให้ถูกต้องคุณต้องตั้งค่าพื้นที่พิกัดของผืนผ้าใบเช่นกำหนดความกว้างและความสูงให้ตรงกับขนาดของภาพ ความกว้างและความสูง CSS ทำหน้าที่ในการยืดผืนผ้าใบสุดท้ายสำหรับการจัดวางซึ่งไม่ได้ช่วยอะไรเมื่อเป็นองค์ประกอบที่ไม่แสดง ลองทำอย่างเช่น $ ('<canvas width =' + img.width + 'height =' + img.height + '/>'); หรือวิธีนี้ใช้ไม่ได้กับแคนวาสนอกจอ?
fabspro

@fabspro: นั่นเป็นจุดที่ยอดเยี่ยม เนื่องจากการวาดและการอ่านข้อมูลรูปภาพนั้นทำผ่านบริบทค่าความกว้างและความสูงจึงไม่มีความหมาย พวกเขาไม่มีผลกระทบใด ๆ เนื่องจากผืนผ้าใบไม่ใช่บริบทที่ผิดเพี้ยนและสาเหตุที่ฉันไม่เห็นผลกระทบนี้ในการสาธิตของฉันเป็นเพียงเพราะภาพมีขนาดเล็กกว่าความกว้าง / ความสูงเริ่มต้นของบริบท ฉันจะอัปเดตตามนั้นแม้ว่าจะปลอดภัยกว่าในการเข้าถึง.widthและ.heightบนผืนผ้าใบเองมากกว่าการเชื่อมต่อ
Brian Nickel

4
แก้ไขสำหรับ Firefox jsfiddle.net/9SEMf/622โดยใช้stackoverflow.com/questions/11334452/event-offsetx-in-firefox
benoît

6
คุณไม่สามารถใช้สิ่งนี้สำหรับภาพระยะไกล "ไม่สามารถรับข้อมูลรูปภาพจากแคนวาสได้เนื่องจากผืนผ้าใบถูกแปดเปื้อนด้วยข้อมูลข้ามแหล่งที่มา SecurityError: มีความพยายามที่จะทำลายนโยบายความปลอดภัยของตัวแทนผู้ใช้"
Karl Glaser

18

Canvas จะเป็นวิธีที่ดีในการทำเช่นนี้ตามที่ @pst กล่าวไว้ข้างต้น ลองดูคำตอบนี้เพื่อเป็นตัวอย่างที่ดี:

getPixel จาก HTML Canvas?

รหัสบางอย่างที่จะให้บริการคุณโดยเฉพาะเช่นกัน:

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

สิ่งนี้จะไปทีละแถวดังนั้นคุณต้องแปลงสิ่งนั้นเป็น x, y และแปลง for loop เป็นการตรวจสอบโดยตรงหรือเรียกใช้เงื่อนไขภายใน

อ่านคำถามของคุณอีกครั้งดูเหมือนว่าคุณต้องการที่จะได้รับประเด็นที่คนคลิกเข้ามา สิ่งนี้สามารถทำได้อย่างง่ายดายด้วยเหตุการณ์คลิกของ jquery เพียงเรียกใช้โค้ดด้านบนภายในตัวจัดการการคลิกดังต่อไปนี้:

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

สิ่งเหล่านี้ควรคว้าค่า x และ y ของคุณ


นี่ไม่ใช่สิ่งที่ผู้แสดงความคิดเห็นถาม (ดูเหมือน) และไม่ได้ตอบคำถามเลย คำตอบที่ยอมรับได้ผล ฉันขอแนะนำให้ลบคำตอบนี้ ...
Agamemnus

5

สองคำตอบก่อนหน้านี้แสดงวิธีใช้ Canvas และ ImageData ฉันต้องการเสนอคำตอบพร้อมตัวอย่างที่รันได้และใช้กรอบการประมวลผลภาพดังนั้นคุณไม่จำเป็นต้องจัดการข้อมูลพิกเซลด้วยตนเอง

MarvinJจัดเตรียมเมธอดimage.getAlphaComponent (x, y)ซึ่งจะส่งคืนค่าความโปร่งใสของพิกเซลในพิกัด x, y หากค่านี้เป็น 0 พิกเซลจะโปร่งใสทั้งหมดค่าระหว่าง 1 ถึง 254 คือระดับความโปร่งใสสุดท้าย 255 จะทึบแสง

สำหรับการแสดงที่ผมเคยใช้ภาพด้านล่าง (300x300) ที่มีพื้นหลังโปร่งใสและสองพิกเซลที่พิกัด(0,0)และ(150,150)

ใส่คำอธิบายภาพที่นี่

เอาต์พุตคอนโซล:

(0,0): โปร่งใส
(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>


1

ด้วย: 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);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.