iOS 核心图形:仅绘制 CGPath 的阴影

发布于 2024-12-16 17:28:19 字数 1373 浏览 5 评论 0原文

我正在 iOS 5 中使用 Core Graphics 绘制一条简单的路径:

CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(   path, NULL, center.x   , topMargin   );
CGPathAddLineToPoint(path, NULL, center.x+20, topMargin+50);
CGPathAddLineToPoint(path, NULL, center.x   , topMargin+40);
CGPathAddLineToPoint(path, NULL, center.x-20, topMargin+50);
CGPathAddLineToPoint(path, NULL, center.x   , topMargin   );

现在我想以叠加模式填充它,如下所示:

[[UIColor colorWithRed:0 green:0 blue:0 alpha:0.4] setFill];
CGContextAddPath(context, path);
CGContextSetBlendMode (context, kCGBlendModeOverlay);
CGContextFillPath(context);

这给了我完全预期的结果。但接下来,我想创建浮雕效果。我想到使用白色和黑色阴影来实现这种效果,如下所示:

[[UIColor colorWithRed:0 green:0 blue:0 alpha:0] setFill];
CGContextAddPath(context, path);
CGContextSetShadowWithColor(context, CGSizeMake(1, 1), 1.0, highlightColor);
CGContextSetBlendMode (context, kCGBlendModeNormal);
CGContextFillPath(context);

[[UIColor colorWithRed:0 green:0 blue:0 alpha:0] setFill];
CGContextAddPath(context, path);
CGContextSetShadowWithColor(context, CGSizeMake(-1, -1), 1.0, shadowColor);
CGContextSetBlendMode (context, kCGBlendModeNormal);
CGContextFillPath(context);

问题是,当 alpha 设置为 0 时,不会绘制阴影。
现在的问题是:有没有一种方法可以绘制没有填充颜色但完整 Alpha 的阴影?我可以以某种方式阻止我的路径内部被绘制吗?或者是否有一种更简单的方法为一条路径绘制两个阴影?

I am drawing a simple path in iOS 5 with Core Graphics:

CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(   path, NULL, center.x   , topMargin   );
CGPathAddLineToPoint(path, NULL, center.x+20, topMargin+50);
CGPathAddLineToPoint(path, NULL, center.x   , topMargin+40);
CGPathAddLineToPoint(path, NULL, center.x-20, topMargin+50);
CGPathAddLineToPoint(path, NULL, center.x   , topMargin   );

Now i want to fill it in Overlay mode like so:

[[UIColor colorWithRed:0 green:0 blue:0 alpha:0.4] setFill];
CGContextAddPath(context, path);
CGContextSetBlendMode (context, kCGBlendModeOverlay);
CGContextFillPath(context);

Which gives me exactly the expected result. But next, i want to create an embossed effect. I thought of using a white and a black drop shadow in order to achieve this effect like so:

[[UIColor colorWithRed:0 green:0 blue:0 alpha:0] setFill];
CGContextAddPath(context, path);
CGContextSetShadowWithColor(context, CGSizeMake(1, 1), 1.0, highlightColor);
CGContextSetBlendMode (context, kCGBlendModeNormal);
CGContextFillPath(context);

[[UIColor colorWithRed:0 green:0 blue:0 alpha:0] setFill];
CGContextAddPath(context, path);
CGContextSetShadowWithColor(context, CGSizeMake(-1, -1), 1.0, shadowColor);
CGContextSetBlendMode (context, kCGBlendModeNormal);
CGContextFillPath(context);

The problem is, the shadows are not drawn when alpha is set to 0.
Now the question: Is there a way to draw only the shadows without the fill color but in full alpha? Can I somehow prevent the inside of my path from being drawn? Or is there perhaps a simpler way of drawing two shadows for one path?

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

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

发布评论

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

评论(2

安人多梦 2024-12-23 17:28:19

我建议您将上下文的剪切路径设置为形状路径的逆向,配置阴影,并以完全不透明度正常填充形状。剪切路径将遮盖填充颜色,仅保留阴影。

CGContextSaveGState(context);
CGRect boundingRect = CGContextGetClipBoundingBox(context);
CGContextAddRect(context, boundingRect);
CGContextAddPath(context, path);
CGContextEOClip(context);

[[UIColor blackColor] setFill];
CGContextAddPath(context, path);
CGContextSetShadowWithColor(context, CGSizeMake(1, 1), 1.0, highlightColor);
CGContextSetBlendMode (context, kCGBlendModeNormal);
CGContextFillPath(context);

CGContextAddPath(context, path);
CGContextSetShadowWithColor(context, CGSizeMake(-1, -1), 1.0, shadowColor);
CGContextSetBlendMode (context, kCGBlendModeNormal);
CGContextFillPath(context);

CGContextRestoreGState(context);

诀窍是使用 CGContextEOClip 和一个附加的矩形子路径将剪切区域设置为原始路径未覆盖的区域。这适用于任何不自相交的路径。

I suggest you set the context's clipping path to the inverse of the shape's path, configure the shadow, and fill the shape normally, with full opacity. The clipping path will mask out the fill color, and only the shadow would remain.

CGContextSaveGState(context);
CGRect boundingRect = CGContextGetClipBoundingBox(context);
CGContextAddRect(context, boundingRect);
CGContextAddPath(context, path);
CGContextEOClip(context);

[[UIColor blackColor] setFill];
CGContextAddPath(context, path);
CGContextSetShadowWithColor(context, CGSizeMake(1, 1), 1.0, highlightColor);
CGContextSetBlendMode (context, kCGBlendModeNormal);
CGContextFillPath(context);

CGContextAddPath(context, path);
CGContextSetShadowWithColor(context, CGSizeMake(-1, -1), 1.0, shadowColor);
CGContextSetBlendMode (context, kCGBlendModeNormal);
CGContextFillPath(context);

CGContextRestoreGState(context);

The trick is using CGContextEOClip and an additional rectangle subpath to set the clipping area to whatever is not covered by the original path. This will work for any path that is not self-intersecting.

拧巴小姐 2024-12-23 17:28:19

问题是,当 alpha 设置为 0 时,不会绘制阴影。

是的,阴影依赖于形状的 alpha 值来渲染。

现在的问题是:有没有办法只绘制阴影而不填充颜色,但以完整的 Alpha 形式绘制?我可以以某种方式阻止我的路径内部被绘制吗?或者是否有一种更简单的方法为一条路径绘制两个阴影?

您可以仅绘制阴影而不渲染主要形状。想法是:

  1. 为阴影添加额外的偏移宽度,偏移量应该足够大,即上下文/画布宽度。使阴影与主要形状分离。
  2. 使用负的相同水平偏移平移上下文,以便将主要形状移出渲染区域,并将阴影移回。

对于仅阴影图层,您可能需要使用 beginTransparencyLayer(auxiliaryInfo:)saveGState() 将绘图推送到单独的上下文中。

这是一个比较:

在此处输入图像描述
输入图片此处描述

对于代码片段,您可以在此处查看我对另一个问题的回答:https://stackoverflow.com/a/74844890/3164091

The problem is, the shadows are not drawn when alpha is set to 0.

Yes, the shadow relies on the shape's alpha value to render.

Now the question: Is there a way to draw only the shadows without the fill color but in full alpha? Can I somehow prevent the inside of my path from being drawn? Or is there perhaps a simpler way of drawing two shadows for one path?

You can draw the shadow only without rendering the main shape. The idea is:

  1. add extra offset width to the shadow, the offset should be big enough, i.e. the context/canvas width. So that the shadow is separated from the main shape.
  2. Translate the context with a negative same horizontal offset, so that the main shape is moved out of the rendering area, and the shadow is moved back.

For the shadow only layer, you probably want to use beginTransparencyLayer(auxiliaryInfo:) and saveGState() to push the drawing into a separated context.

Here is a comparison:

enter image description here
enter image description here

For code snippet, you can check my answer for another question here: https://stackoverflow.com/a/74844890/3164091

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