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

145

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


1
图片能否以某种方式加载到画布元素上? - user166390
如果没有其他办法,那么就这样吧。 - Danny Fox
6个回答

227
建立在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(我认为,但一些浏览器可能已经解决了这个问题)脏画布,则此技术将失败。这可以防止某些网站为已登录用户提供自定义图像资产,并且攻击者想要读取该图像以获取信息的情况。您可以通过从同一服务器提供图像或实施跨域资源共享来解决这个问题。

为了使其正确,您需要设置画布的坐标空间,即将宽度和高度设置为与图像尺寸相匹配。 CSS 的宽度和高度只用于拉伸最终画布以进行布局,但当它是未显示元素时,这并没有帮助。尝试类似$('<canvas width=' + img.width + ' height=' + img.height + '/>'); 的东西。或者,离屏画布不适用于此? - fabspro
4
使用此链接 https://dev59.com/w2gu5IYBdhLWcg3wbGel 修复 Firefox 上的问题 http://jsfiddle.net/9SEMf/622/。 - benoît
Fiddle 中提供的示例未相应更新,无法正常工作。应该添加 this.canvas.width = img.width 和同样的 height。 - wilkas
8
你不能将此用于远程图片。 "由于画布已被跨域数据污染,无法从画布获取图像数据。 安全错误:试图突破用户代理的安全策略。" - Karl Glaser
1
还有一点需要注意:使用drawImage渲染的像素值可能与图像中的值不同,因为颜色空间校正的原因。好在只有当图像包含颜色空间信息时才会发生这种情况。 - ironic
显示剩余5条评论

21

如@pst所说,Canvas是实现这一目标的好方法。查看此答案以获取一个很好的例子:

从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循环转换为直接检查或运行条件语句。再次阅读您的问题,看起来您想能够获取人点击的点。这可以使用jQuery的click事件轻松完成。只需在点击处理程序中运行上述代码,如下所示:
$('el').click(function(e){
   console.log(e.clientX, e.clientY)
}

这些应该获取您的 x 和 y 值。


这不是评论者似乎所问的,也根本没有回答问题。被采纳的答案确实可行。我建议删除这个答案... - Agamemnus

8

在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;   
}

7

之前的两个答案演示了如何使用Canvas和ImageData。我想提供一个带有可运行示例并使用图像处理框架的答案,这样您就不需要手动处理像素数据。

MarvinJ提供了方法 image.getAlphaComponent(x,y),它简单地返回x,y坐标处像素的透明度值。如果该值为0,则像素完全透明,1到254之间的值是透明级别,最后255是不透明的。

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

输入图像描述

控制台输出:

(0,0): 透明
(150,150): 不透明

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>


2

With : 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); }
}

0
以下是几个答案的综合,可以运行片段,让您上传文件,悬停以预览每个像素的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>

参考资料:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接