CALayer 和 CGGradientRef 抗锯齿?

发布于 2024-07-16 19:05:21 字数 1705 浏览 11 评论 0原文

我在 iPhone 上的 CALayer 绘图方面遇到了一个奇怪的问题。 我有一个根层,它添加了一堆代表“气泡”的子层。 最终结果应该看起来像这样:

http://www.expectivedna.com/IMG_0018.PNG http://www.expensedna.com/IMG_0018.PNG

问题是我似乎无法使图层抗锯齿(注意气泡上的锯齿)。 我为气泡 CALayer 覆盖 drawInContext 的代码如下:

- (void)drawInContext:(CGContextRef)theContext{
CGContextSetAllowsAntialiasing(theContext, true);
CGContextSetShouldAntialias(theContext, true);

size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 1.0, 1.0, 1.0, 0.5,  // Start color
                          1.0, 1.0, 1.0, 0.0 }; // End color
CGColorSpaceRef rgbColorspace = CGColorSpaceCreateDeviceRGB();
CGGradientRef glossGradient = 
CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations);

CGPoint topCenter = CGPointMake(25, 20);
CGPoint midCenter = CGPointMake(25, 25);
CGContextDrawRadialGradient(theContext, glossGradient, midCenter, 20, topCenter, 10, kCGGradientDrawsAfterEndLocation); 

}

现在真正奇怪的是,如果我稍微改变绘图代码以仅绘制正常的红色圆圈,如下所示:

- (void)drawInContext:(CGContextRef)theContext{
CGContextSetAllowsAntialiasing(theContext, true);
CGContextSetShouldAntialias(theContext, true);

CGContextSetFillColorWithColor(theContext, [UIColor redColor].CGColor);
CGContextFillEllipseInRect(theContext, CGRectMake(0, 0, 40,40));
}

一切似乎都抗锯齿正常:

http://www.expectivedna.com/IMG_0017.PNG http://www.expectivedna.com/IMG_0017.PNG

我可以似乎没有弄清楚这种看似奇怪的行为。 我是否遗漏了抗锯齿渐变和普通圆之间的一些区别?

多谢你们。

I'm having an odd issue with CALayer drawing for the iPhone. I have a root layer which adds a bunch of sublayers representing "bubbles". The end result is supposed to look something like this:

http://www.expensivedna.com/IMG_0018.PNG http://www.expensivedna.com/IMG_0018.PNG

The problem is that I can't seem to get the layer to anti-alias (notice the jaggies on the bubbles). My code overwriting drawInContext for the bubble CALayer is as follows:

- (void)drawInContext:(CGContextRef)theContext{
CGContextSetAllowsAntialiasing(theContext, true);
CGContextSetShouldAntialias(theContext, true);

size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 1.0, 1.0, 1.0, 0.5,  // Start color
                          1.0, 1.0, 1.0, 0.0 }; // End color
CGColorSpaceRef rgbColorspace = CGColorSpaceCreateDeviceRGB();
CGGradientRef glossGradient = 
CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations);

CGPoint topCenter = CGPointMake(25, 20);
CGPoint midCenter = CGPointMake(25, 25);
CGContextDrawRadialGradient(theContext, glossGradient, midCenter, 20, topCenter, 10, kCGGradientDrawsAfterEndLocation); 

}

Now the really odd thing is that if I slightly alter the drawing code to only draw normal red circles as follows:

- (void)drawInContext:(CGContextRef)theContext{
CGContextSetAllowsAntialiasing(theContext, true);
CGContextSetShouldAntialias(theContext, true);

CGContextSetFillColorWithColor(theContext, [UIColor redColor].CGColor);
CGContextFillEllipseInRect(theContext, CGRectMake(0, 0, 40,40));
}

Everything seems to antialias OK:

http://www.expensivedna.com/IMG_0017.PNG http://www.expensivedna.com/IMG_0017.PNG

I can't seem to figure out this seemingly odd behavior. Am I missing some difference between antialiasing gradients and normal circles?

Thanks guys.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

jJeQQOZ5 2024-07-23 19:05:21

多谢你们。 所以事实证明答案是你的两个答案(coob 和 Alex)的组合。 基本上,CGDrawRadialGradient 函数似乎只在起始圆处有锯齿,而在结束圆处没有。 由于我想要在两者上使用别名“边缘”,因此我首先将函数设置为从内向外绘制,该函数负责第一个“边缘”,但会产生以下结果:

第 1 步

然后,我按照 coob 的建议剪辑图像,这在气泡的最终边缘周围产生了漂亮的锯齿:

第 2 步

对我来说看起来足够好了!

- (void)drawInContext:(CGContextRef)theContext{
CGContextSetAllowsAntialiasing(theContext, true);
CGContextSetShouldAntialias(theContext, true);

size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 1.0, 1.0, 1.0, 0.0,  // Start color
              1.0, 1.0, 1.0, 0.5 }; // End color
CGColorSpaceRef rgbColorspace = CGColorSpaceCreateDeviceRGB();
CGGradientRef glossGradient = 
CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations);

CGContextAddEllipseInRect(theContext, CGRectMake(5, 5, 40, 40));
CGContextClip(theContext);

CGPoint topCenter = CGPointMake(25, 20);
CGPoint midCenter = CGPointMake(25, 25);
CGContextDrawRadialGradient(theContext, glossGradient, topCenter, 10, midCenter, 20, kCGGradientDrawsAfterEndLocation);

}

Thanks guys. So it turns out that the answer is a combination of your two answers (coob and Alex). Basically it seems like the CGDrawRadialGradient function only has aliasing at the starting circle, not the ending one. Since I want aliased "edges" on both, I first set the function to draw from the inside out which takes care of the first "edge", but produces the following:

Step 1

Then, I clip the image as suggested by coob and that gives a nice aliasing around the final edge of the bubble:

Step 2

Looks good enough for me!

- (void)drawInContext:(CGContextRef)theContext{
CGContextSetAllowsAntialiasing(theContext, true);
CGContextSetShouldAntialias(theContext, true);

size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 1.0, 1.0, 1.0, 0.0,  // Start color
              1.0, 1.0, 1.0, 0.5 }; // End color
CGColorSpaceRef rgbColorspace = CGColorSpaceCreateDeviceRGB();
CGGradientRef glossGradient = 
CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations);

CGContextAddEllipseInRect(theContext, CGRectMake(5, 5, 40, 40));
CGContextClip(theContext);

CGPoint topCenter = CGPointMake(25, 20);
CGPoint midCenter = CGPointMake(25, 25);
CGContextDrawRadialGradient(theContext, glossGradient, topCenter, 10, midCenter, 20, kCGGradientDrawsAfterEndLocation);

}

℉服软 2024-07-23 19:05:21

Jeff - 让 topCenter 稍微远一点,并使用带有圆形遮罩的 CGContextClipToMask。

编辑:实际上,更好的方法是使用 CGContextClip 使用矢量剪切路径。

编辑 2:示例代码:

CGContextAddEllipseInRect(theContext, CGRectMake(20, 20, 10, 10));
CGContextClip(theContext);

在绘制渐变之前添加此代码,并将其绘制得更远一些。

Jeff - make topCenter a bit further out and use CGContextClipToMask with a circular mask.

Edit: Actually a much much better way to do it is to use a vector clipping path using CGContextClip.

Edit 2: Sample code:

CGContextAddEllipseInRect(theContext, CGRectMake(20, 20, 10, 10));
CGContextClip(theContext);

Add this before you draw your gradient, and draw it a bit further out.

做个少女永远怀春 2024-07-23 19:05:21

也许尝试删除 kCGGradientDrawsAfterEndLocation ? 它可能对 alpha 做了一些奇怪的事情

maybe try dropping out the kCGGradientDrawsAfterEndLocation? It might be doing something weird with the alpha

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文