如何检查图像的特定像素是否透明?

有没有办法检查 PNG 图像的选定(x,y)点是否透明?

197175 次浏览

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.offsetXevent.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 弄脏了画布,这项技术就会失败。这可以防止这样的情况: 站点为登录用户提供自定义图像资产,而攻击者希望通过读取图像来获取信息。您可以通过从同一台服务器提供映像或实现 跨来源资源共享来解决这个问题。

前两个答案演示了如何使用 Canvas 和 ImageData。我想提出一个可运行的例子和使用图像处理框架的答案,所以您不需要手动处理像素数据。

MarvinJ 提供了方法 GetAlphaComponent (x,y),它只返回 x,y 坐标中像素的透明度值。如果该值为0,则像素为完全透明,1到254之间的值为透明级别,最后255为不透明级别。

为了演示,我使用了下面的图像(300x300) ,背景是透明的,坐标 (0,0)(150,150)处有两个像素。

enter image description here

控制台输出:

(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

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>

参考文献: