使用缩放变换在CGContext中绘制平铺图像会产生精度错误

时间:2012-08-28 17:05:44

标签: objective-c core-graphics quartz-graphics

我想绘制平铺图像,然后使用通常的平移和缩放手势对其进行转换。这里带来的问题是,每当我对大量小数位进行缩放变换时,在瓷砖中间会出现一条细线像素(1或2)。我设法隔离了这样的问题:

CGContextSaveGState(UIGraphicsGetCurrentContext());

CGContextSetFillColor(UIGraphicsGetCurrentContext(), CGColorGetComponents([UIColor redColor].CGColor));
CGContextFillRect(UIGraphicsGetCurrentContext(), rect);//rect from drawRect:

float scale = 0.7;
CGContextScaleCTM(UIGraphicsGetCurrentContext(), scale, scale);
CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(50, 50, 100, 100), testImage);
CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(150, 50, 100, 100), testImage);
CGContextRestoreGState(UIGraphicsGetCurrentContext());

使用0.7比例,两个图像正确显示平铺: 0.7 scale

使用0.777777比例(将第6行更改为“float scale = 0.777777;”),会出现视觉工件:

0.777777 scale

有没有办法避免这个问题?这种情况发生在CGImage,CGLayer和原始形式(如矩形)中。它也发生在MacOSx上。

感谢您的帮助!

编辑:补充说,这也发生在原始形式,如CGContextFillRect

edit2:它也发生在MacOSx上!

2 个答案:

答案 0 :(得分:2)

Quartz具有浮点坐标系,因此缩放可能会导致值不在像素边界上,从而导致边缘处的可见抗锯齿。如果您不想这样,您有两种选择:

  1. 调整比例因子,使所有缩放坐标都是整数。这可能并不总是可行的,特别是如果你要抽取很多东西。

  2. 使用CGContextSetShouldAntialias(UIGraphicsGetCurrentContext(), false);禁用图形上下文的抗锯齿功能。这将导致清晰的像素边界,但除了直线之外的任何东西都可能看起来不太好。

答案 1 :(得分:0)

完成所有操作后,iOS正在处理整数边界上的离散像素。当您的帧减少0.7时,50将减少到35,就在像素边界上。在0.777777它不是 - 所以iOS适应和移动/收缩/混合任何东西。

你真的有两个选择。如果要使用上下文缩放,则向上或向下舍入所需的值,以便生成整数缩放的帧值(您的代码将50显示为标准乘法值。)

否则,您无法缩放上下文,而是逐个缩放内容,并根据需要使用CGIntegralRect向上或向下舍入所有维度。

编辑:如果我的怀疑是正确的,那么还有另一种选择。假设您希望比例因子为.77777,帧数为50,50,100,100。取50,然后乘以刻度,然后向上或向下舍入返回值。然后重新计算新帧,使用该值除以0.7777得到一些小数值,当缩放0.7777时返回一个整数。 Quartz非常擅长弄清楚你的意思是一个整数值,因此忽略了小的舍入误差。我敢打赌,这对你来说都很合适。