我有一个应用程序,要求在部分透明UIImage
周围绘制纯黑色轮廓。不是在图像的框架周围,而是围绕图像本身的所有不透明部分。即,想到一个透明的PNG,上面有一个不透明的白色“X” - 我需要用黑色勾勒出“X”。
为了使问题变得棘手,在绘制轮廓之后,将调整原始图像的不透明度,但轮廓必须保持不透明 - 因此我生成的轮廓必须仅包含 轮廓,而不是原始图像。
我目前的技术是:
UIView
。UIImage
4次,并将重复项添加为UIView
的子视图,每个UIImage
从原始位置沿对角线偏移几个像素。UIView
转换为图片(通过典型的UIGraphicsGetImageFromCurrentImageContext
方法)。CGImageMaskCreate
和CGImageCreateWithMask
,从此新图片中减去原始图像,只剩下轮廓。有效。即使只有4个偏移图像,结果看起来也很不错。然而,它非常低效,并且在iPhone 4上造成了4秒的稳定延迟。
所以我需要的是一个很好,快速,有效的方法来实现同样的东西,iOS 4.0完全支持。
有什么好主意吗? :)
答案 0 :(得分:3)
我想指出的是,虽然有些人建议进行边缘检测,但这不是一个合适的解决方案。边缘检测用于在图像数据中查找边缘,其中数据中没有明显的精确边缘表示。
对于你来说,边缘定义得更好,你正在寻找定义明确的轮廓。在您的情况下,边缘是任何像素,它位于完全透明的像素上,旁边是一个不完全透明的像素,简单就是这样!迭代图像中的每个像素,如果它们满足这些条件,则将它们设置为黑色。
或者,对于抗锯齿结果,获取图像的布尔表示,并将一个小的抗锯齿圆内核传递给它。我知道你说不支持自定义过滤器,但是如果你可以直接访问图像数据,那么手动实现就不会太难了......
干杯,希望这会有所帮助。
答案 1 :(得分:2)
为了提出新的想法:
当前实现的一个变体将使用CALayer
对阴影的支持,它根据图层的实际像素内容计算,而不仅仅是它的边界矩形,并且它使用GPU。您可以尝试将shadowOpacity
放大到一些巨大的值,以试图消除羽化;如果你无法渲染到合适的CGContext,只取出alpha图层并手动处理它以对alpha值应用阈值测试,将它们推到完全不透明或完全透明。
即使在ES 1下,您也可以通过各种方式在GPU上实现最终处理步骤。您可以使用alpha测试来应用实际阈值,然后,您可以将深度缓冲区填充为1.0,禁用颜色输出和深度测试,使用深度为0.5的阴影绘制版本,绘制没有深度为1.0的阴影然后启用颜色输出和深度测试,并在0.75的深度绘制纯黑色全屏四边形。所以就像使用深度缓冲区来模拟模板一样(因为在使用ES 2的设备之前使用的Apple Apple不支持模板缓冲区)。
当然,假设CALayer
阴影出现在合成器之外,我没有检查过。
或者,如果您愿意限制对ES 2设备(所有3GS +)的支持,那么您可以将图像上传为纹理并在GPU上完成整个过程。但这在技术上会使一些支持iOS 4的设备不受支持,所以我认为不是一种选择。
答案 2 :(得分:1)
您只需要实现edge detection算法,但不要使用亮度或颜色来确定边缘的位置,而是使用不透明度。有许多不同的方法可以解决这个问题。例如,您可以查看每个像素及其邻居,以确定不透明度超过您设置的阈值的区域。每当您需要在MacOS X或iOS中查看图像的每个像素时,请考虑Core Image。有一系列有用的博客文章starting with this one着眼于实现自定义核心图像过滤器 - 我将从那里开始构建边缘检测过滤器。
答案 3 :(得分:0)
而是使用UIView,我建议只按下面的上下文:
UIGraphicsBeginImageContextWithOptions(image.size,NO,0.0);
//draw your image 4 times and mask it whatever you like, you can just copy & paste
//current drawing code here.
....
outlinedimage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
这比你的UIView要快得多。