有没有办法检查 PNG 图像的选定(x,y)点是否透明?
Canvas 将是一个很好的方法,正如@pst 上面所说。下面是一个很好的例子:
从 HTML 画布中获取像素?
一些特别适合您的代码:
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 循环转换为直接检查或在其中运行条件。
再读一遍你的问题,看起来你想要得到那个人点击的点。这可以通过 jquery 的 click 事件轻松实现。只需在单击处理程序中运行以上代码:
$('el').click(function(e){ console.log(e.clientX, e.clientY) }
这些应该可以获取 x 和 y 值。
基于 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获取位置。这可以用来获取像素:
event.offsetX
event.offsetY
var pixelData = canvas.getContext('2d').getImageData(event.offsetX, event.offsetY, 1, 1).data;
因为只抓取一个像素,所以 pixelData 是一个包含像素的 R、 G、 B 和 A 值的四个入口数组。对于 alpha,小于255表示某种程度的透明度,0表示完全透明。
下面是一个 jsFiddle 示例: http://jsfiddle.net/thirtydot/9SEMf/869/,我在所有这些中使用 jQuery 是为了方便,但它并不是必需的。
注意: 为了防止数据泄漏,getImageData属于浏览器的同源策略,这意味着如果你用来自其他域的图片或者(我相信,但是一些浏览器可能已经解决了这个问题)来自任何域的 SVG 弄脏了画布,这项技术就会失败。这可以防止这样的情况: 站点为登录用户提供自定义图像资产,而攻击者希望通过读取图像来获取信息。您可以通过从同一台服务器提供映像或实现 跨来源资源共享来解决这个问题。
getImageData
前两个答案演示了如何使用 Canvas 和 ImageData。我想提出一个可运行的例子和使用图像处理框架的答案,所以您不需要手动处理像素数据。
MarvinJ 提供了方法 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>
配图: i << 2
i << 2
const pixels = context.getImageData(x, y, width, height).data; for (let i = 0, dx = 0; dx < data.length; i++, dx = i << 2) { if (pixels[dx+3] <= 8) { console.log("transparent x= " + i); } }
基于 Brian Nickel 的答案,只有源图像的单个像素被绘制到1 * 1像素的画布上,这比仅仅为了得到一个像素而绘制整个图像更有效率:
function getPixel(img, x, y) { let canvas = document.createElement('canvas'); canvas.width = 1; canvas.height = 1; canvas.getContext('2d').drawImage(img, x, y, 1, 1, 0, 0, 1, 1);; let pixelData = canvas.getContext('2d').getImageData(0, 0, 1, 1).data; return pixelData; }
下面是将一些答案合并到一个可运行的代码片段中,该代码片段允许您上传一个文件,鼠标悬停预览每个像素的 RGB 值,然后单击以将 RGB 放入 div 中。
与最初的问题相关,最后一个值(alpha)是透明度。0是完全透明的,255是完全不透明的。
const canvas = document.querySelector("canvas"); const ctx = canvas.getContext("2d"); const input = document .querySelector('input[type="file"]'); input.addEventListener("change", e => { const image = new Image(); image.addEventListener("load", e => { const {width, height} = image; canvas.width = width; canvas.height = height; ctx.drawImage(image, 0, 0); const {data} = ctx.getImageData( 0, 0, width, height ); const rgb = (x, y) => { const i = (x + y * width) * 4; return data.slice(i, i + 4).join(", "); }; canvas.addEventListener("mousemove", event => { const {offsetX: x, offsetY: y} = event; console.log(rgb(x, y)); }); canvas.addEventListener("click", event => { const {offsetX: x, offsetY: y} = event; document.querySelector("div") .textContent = rgb(x, y); }); }); image.addEventListener("error", () => console.error("failed") ); image.src = URL .createObjectURL(event.target.files[0]); });
.as-console-wrapper { height: 21px !important; }
<div> Upload image and mouseover to preview RGB. Click to select a value. </div> <form> <input type="file"> </form> <canvas></canvas>
参考文献: