Alpha 通道的图像映射
Posted
技术标签:
【中文标题】Alpha 通道的图像映射【英文标题】:Image map by alpha channel 【发布时间】:2012-06-29 01:10:42 【问题描述】:<img src="circle.png" onclick="alert('clicked')"/>
假设 circle.png 是一个 400x400 像素的透明背景图片,中间有一个圆圈。
我现在得到的是整个图像区域 (400x400px) 都是可点击的。我想要的是只有圆圈(非透明像素)是可点击的。
当然我知道在这个例子中我可以使用<map>
标签和一个圆形区域,但我正在寻找一个通用的解决方案,它会考虑到实际的图像透明度并适用于任何类型的图像(即非规则形状)。
我能看到的最复杂的方法是根据每个像素 alpha 跟踪图像的轮廓,转换为路径(也许简化)并作为地图应用。
有没有更有效/更直接的方法?
【问题讨论】:
您是否需要这样做,因为图像将动态生成?虽然我确信它可以在 javascript 中完成,但它可能会很慢。在 Photoshop 中使用过“魔术棒”之类的东西后,“把它做好”也不是一件容易的事。似乎如果您正在动态生成图像,请使用源数据创建图像映射。如果不是,那为什么不离线并使用图像地图呢? 是的,这将是动态的,因为图像也会动态加载...... 【参考方案1】:使用canvas
标签,您可以确定给定点下像素的颜色值。您可以使用事件数据来确定坐标,然后检查透明度。剩下的就是将图像加载到画布中。
首先,我们会解决这个问题:
var ctx = document.getElementById('canvas').getContext('2d');
var img = new Image();
img.onload = function()
ctx.drawImage(img,0,0);
;
img.src = [YOUR_URL_HERE];
第一个位抓取 canvas 元素,然后创建一个 Image
对象。当图像加载时,它被绘制在画布上。很简单!除了...如果图像与代码不在同一个域中,那么您将面临同域策略安全性。为了获取我们图像的数据,我们需要将图像托管在本地。您还可以对图像进行 base64 编码,这超出了此答案的范围。 (有关执行此操作的工具,请参阅 this url)。
接下来,将点击事件附加到画布上。当该点击进入时,我们将检查透明度并仅对不透明的点击区域采取行动:
if (isTransparentUnderMouse(this, e))
return;
// do whatever you need to do
alert('will do something!');
魔术发生在函数isTransparentUnderMouse
中,它需要两个参数:目标画布元素(点击处理程序范围内的this
)和事件数据(本例中为e)。现在我们来看看肉:
var isTransparentUnderMouse = function (target, evnt)
var l = 0, t = 0;
if (target.offsetParent)
var ele = target;
do
l += ele.offsetLeft;
t += ele.offsetTop;
while (ele = ele.offsetParent);
var x = evnt.page.x - l;
var y = evnt.page.y - t;
var imgdata = target.getContext('2d').getImageData(x, y, 1, 1).data;
if (
imgdata[0] == 0 &&
imgdata[1] == 0 &&
imgdata[2] == 0 &&
imgdata[3] == 0
)
return true;
return false;
;
首先,我们做一些跳舞来获得相关元素的精确位置。我们将使用该信息传递给 canvas 元素。 getImageData
将为我们提供一个 data
对象,其中包含我们指定位置的 RGBA。
如果所有这些值都是 0,那么我们正在查看透明度。如果不是,则存在一些颜色。 -edit- 如 cmets 中所述,我们真正需要查看的唯一值是最后一个值,即上例中的 imgdata[3]
。值是 r(0)g(1)b(2)a(3),透明度由 a, alpha 决定。您可以使用相同的方法来查找您知道 rgba 数据的任何不透明度的任何颜色。
在这里试试:http://jsfiddle.net/pJ3MD/1/
(注意:在我的示例中,由于我提到的域安全性,我使用了 base64 编码的图像。您可以忽略这部分代码,除非您也打算使用 base64 编码)
同样的例子,只是为了好玩而更改了鼠标光标:http://jsfiddle.net/pJ3MD/2/
文档
Image
MDN 上的对象 - https://developer.mozilla.org/en/DOM/Image
在 MDN - https://developer.mozilla.org/en/Canvas_tutorial/Using_images 上使用带有 canvas
的图像的教程
MDN 上的画布门户 - https://developer.mozilla.org/en/html/Canvas
HTML canvas
MDN 上的元素 (getContext
) - https://developer.mozilla.org/en/DOM/HTMLCanvasElement/
CanvasRenderingContext2D
在 MDN (getImageData
) - https://developer.mozilla.org/en/DOM/CanvasRenderingContext2D
MDN 上的像素操作 - https://developer.mozilla.org/En/HTML/Canvas/Pixel_manipulation_with_canvas/
【讨论】:
+1,感谢您在此答案中付出的努力。也 +1,因为这是一个很好的答案! isTransparentUnderMouse 的外观改进:return (imgdata[0] + imgdata[1] + imgdata[2] + imgdata[3] == 0) 当然!从技术上讲,您甚至只需要查看imgdata[3]
,因为那是 Alpha 通道,所以您可以让它变得更简单。
是的!为了让事情变得完美,我们也可以使用 isTransparentUnderMouse 方法来响应 mousemove 事件来相应地切换光标到指针(手)或箭头。
@Chris 和我今天实现了这种类型的解决方案并发现了一些注意事项: 1. 您必须使用 FlashCanvas Pro for IE flashcanvas.net,excanvas 不支持 getImageData() 也不支持 FlashCanvas免费【参考方案2】:
您可以使用 HTML5 画布做到这一点。将图像绘制到画布中,将单击处理程序附加到画布,然后在处理程序中检查被单击的像素是否透明。
【讨论】:
啊,我们对这个的想法很相似,我没有看到你的答案,因为花了一分钟时间才弄清楚!干杯!【参考方案3】:感谢克里斯的精彩回答
我在代码中添加了几行来处理画布的缩放
所以我现在要做的是创建一个画布,该画布的像素大小与在其上绘制的图像具有精确的像素大小。喜欢(对于 220px*120px 的图像):
<canvas id="mainMenu_item"></canvas>
并使用 css 缩放画布:
#mainMenu_item
width:110px;
调整后的 isTransparentUnderMouse 函数如下:
var isTransparentUnderMouse = function (target, evnt)
var l = 0, t = 0;
if (target.offsetParent)
var ele = target;
do
l += ele.offsetLeft;
t += ele.offsetTop;
while (ele = ele.offsetParent);
var x = evnt.pageX - l;
var y = evnt.pageY - t;
var initialWidth = $(evnt.target).attr('width');
var clientWidth = evnt.target.clientWidth;
x = x * (initialWidth/clientWidth);
var initialHeight = $(evnt.target).attr('height');;
var clientHeight = evnt.target.clientHeight;
y = y * (initialHeight/clientHeight);
var imgdata = target.getContext('2d').getImageData(x, y, 1, 1).data;
if (
imgdata[0] == 0 &&
imgdata[1] == 0 &&
imgdata[2] == 0 &&
imgdata[3] == 0
)
return true;
return false;
;
【讨论】:
以上是关于Alpha 通道的图像映射的主要内容,如果未能解决你的问题,请参考以下文章
JFrame 绘制带有 alpha 通道的动画 gif 图像