防止CALayer的renderInContext方法出现抗锯齿效果

7
我有一个非常简单的UIView,其中包含几个黑白UIImageView。如果我通过设备上的物理按钮截屏,生成的图像看起来与我所见完全相同(如预期一样)-如果我在像素级别检查图像,它只是黑白的。然而,如果我使用以下代码片段以编程方式执行相同的操作,则生成的图像似乎应用了反锯齿 - 所有黑色像素都被淡灰色的光环包围。我的原始场景中没有灰色 - 它是纯黑白的,"截屏"图像的尺寸与我以编程方式生成的图像相同,但我似乎无法弄清楚灰色光环来自何处。
UIView *printView = fullView;

UIGraphicsBeginImageContextWithOptions(printView.bounds.size, NO, 0.0);

CGContextRef ctx = UIGraphicsGetCurrentContext();
[printView.layer renderInContext:ctx];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
UIGraphicsEndImageContext();

我已经尝试在调用 renderInContext 之前添加以下内容,以尝试防止抗锯齿,但没有明显的效果:

CGContextSetShouldAntialias(ctx, NO);
CGContextSetAllowsAntialiasing(ctx, NO);
CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh);

这里是两个不同输出的示例 - 左侧是我的代码生成的内容,右侧是正常的iOS截图: enter image description here 由于我正在尝试将renderInContext的输出发送到单色打印机,因此灰色像素会导致一些丑陋的伪影,这是由于打印机的抖动算法造成的。
那么,如何让renderInContext产生与真实设备截图相同的像素级输出 - 即与我的原始场景中的黑白颜色相同?

该图层是否具有非恒等变换?该图层的内容是如何绘制的? - rob mayoff
视图布局非常简单 - 我有一个包含另一个UIView的UIView,而这个UIView又包含一个UIImageView。没有应用任何变换。内容使用UIView和UIImageView的所有默认iOS行为进行绘制。 - Brian Stormont
2个回答

3
原来的问题与使用UIImageView的底层UIImage的分辨率有关。UIImage是使用数据提供程序创建的CGImage,而且该CGImage的尺寸是以与父UIImageView相同的单位指定的,但我正在使用带视网膜显示器的iOS设备。因为CGImage的尺寸是非视网膜大小指定的,所以renderInContext会对其进行放大,而这种放大的行为与实际的屏幕渲染不同(由于某些原因,真实的屏幕渲染在不添加任何灰色像素的情况下进行了放大)。为了解决这个问题,我创建了一个双倍于UIImageView的尺寸的CGImage,然后我的renderInContext调用会生成一个更好的黑白图像。一些白色区域仍然存在一些灰色像素,但它比原来的问题有了很大的改善。
我最终通过将调用UIGraphicsBeginImageContextWithOptions()进行更改,迫使它进行1.0的缩放,并注意到UIImageView的黑色像素渲染不再有灰色光晕,从而弄清楚了这一点。当我强制UIGraphicsBeginImageContextWithOptions()缩放为2.0(这是由于视网膜显示器而默认)时,灰色光晕出现了。

1

我会尝试设置

 printView.layer.magnificationFilter

并且

 printView.layer.minificationFilter

 kCAFilterNearest

这些图片是在UIImageView实例中显示的吗?printView是它们的父视图吗?


我添加了由代码生成的有问题的屏幕截图图像,与我的iOS设备上的真实屏幕截图进行比较。是的,这些图像显示在UIImageView实例中。是的,printView是它们的父视图。由我的代码生成的输出看起来类似于当位图与包含UIImageView相同尺寸不匹配时发生的情况,但在这种情况下,大小完全匹配。在我的示例图像中,小块横跨8个像素,就像两个捕获的屏幕截图一样,但由于某种原因,我的代码会表现得好像它们处于1/2像素边界上。 - Brian Stormont
那么我猜kCAFilterNearest的技巧没有起作用?那么为每个图像视图的层设置这个值呢? - Baldoph
是的,kCAFilterNearest 没有产生任何明显的差异。我将为每个图像视图的层尝试它。我开始怀疑问题可能出在我使用的图像库中 - 它是一个 QRCode 编码器,它生成的 UIImage 使用了一个带有数据提供程序的 CGImage。我曾经假设它会生成一个与我请求的尺寸匹配的位图图像,但考虑到它使用了数据提供程序,我认为它正在进行一些额外的即时渲染。 - Brian Stormont
我注意到,如果我将图像视图层的shouldRasterize设置为YES,则在真实的iOS截图中会出现相同的问题,但是如果我对相同的图像视图层使用kCAFilterNearest作为mag/min过滤器,则屏幕上的对齐是正确的,iOS截图也是正确的。但是,不幸的是,这对我的renderInContext调用没有影响,该图像仍然显示灰色光晕。 - Brian Stormont

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