iOS:从 UIBezierPath 创建图像剪切路径

Posted

技术标签:

【中文标题】iOS:从 UIBezierPath 创建图像剪切路径【英文标题】:iOS: Create image clipping path from a UIBezierPath 【发布时间】:2011-10-15 05:12:13 【问题描述】:

我正在创建一个允许用户剪切图像的一部分的应用。为了做到这一点,他们将创建一堆 UIBezierPaths 来形成剪切路径。我目前的设置如下:

UIImageView 显示他们正在剪切的图像。 以上 UIImageView 是 UIImageView 的自定义子类, 执行自定义 drawRect: 显示/更新 用户正在添加的 UIBezierPaths。 当用户单击“完成”按钮时,将创建一个新的 UIBezierPath 对象,该对象包含用户创建的所有单独路径,方法是遍历它们存储在其中的数组并在其自身上调用 appendPath:。这个新的 UIBezierPath 然后关闭它的路径。

就我所知。我知道 UIBezierPath 有一个 addClip 方法,但我无法从文档中弄清楚如何使用它。

一般来说,我看到的所有裁剪示例都直接使用 Core Graphics 而不是 UIBezierPath 包装器。我意识到 UIBezierPath 有一个 CGPath 属性。那么我应该在剪辑时使用它而不是完整的 UIBezierPath 对象吗?

【问题讨论】:

你是如何检测你想要剪辑的部分的?通过手势? 【参考方案1】:

根据UIImageView class reference,Apple 说不要继承 UIImageView。感谢@rob mayoff 指出这一点。

但是,如果您要实现自己的 drawRect,请从您自己的 UIView 子类开始。而且,您在 drawRect 中使用addClip。您可以使用 UIBezierPath 执行此操作,而无需将其转换为 CGPath。

- (void)drawRect:(CGRect)rect

    // This assumes the clippingPath and image may be drawn in the current coordinate space.
    [[self clippingPath] addClip];
    [[self image] drawAtPoint:CGPointZero];

如果要放大或缩小以填充边界,则需要缩放图形上下文。 (您也可以将CGAffineTransform 应用于clippingPath,但这是永久性的,因此您需要先复制clippingPath。)

- (void)drawRect:(CGRect)rect

    // This assumes the clippingPath and image are in the same coordinate space, and scales both to fill the view bounds.
    if ([self image])
    
        CGSize imageSize = [[self image] size];
        CGRect bounds = [self bounds];

        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextScaleCTM(context, bounds.size.width/imageSize.width, bounds.size.height/imageSize.height);

        [[self clippingPath] addClip];
        [[self image] drawAtPoint:CGPointZero];
    

这将在每个轴上分别缩放图像。如果您想保留其纵横比,则需要计算出整体缩放比例,并可能将其平移以使其居中或以其他方式对齐。

最后,如果你的路径被大量绘制,所有这些都会相对缓慢。您可能会发现将图像存储在 CALayer 中更快,mask 与包含路径的CAShapeLayer 一起存储。 除测试外,请勿使用以下方法。您需要分别缩放图像层和蒙版以使它们对齐。优点是您可以在不渲染底层图像的情况下更改遮罩。

- (void) setImage:(UIImage *)image;

    // This method should also store the image for later retrieval.
    // Putting an image directly into a CALayer will stretch the image to fill the layer.
    [[self layer] setContents:(id) [image CGImage]];


- (void) setClippingPath:(UIBezierPath *)clippingPath;

    // This method should also store the clippingPath for later retrieval.
    if (![[self layer] mask])
        [[self layer] setMask:[CAShapeLayer layer]];

    [(CAShapeLayer*) [[self layer] mask] setPath:[clippingPath CGPath]];

如果您确实使用图层蒙版进行图像剪辑,则不再需要 drawRect 方法。删除它以提高效率。

【讨论】:

以上是关于iOS:从 UIBezierPath 创建图像剪切路径的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 UIBezierPath 保存裁剪的图像

iOS UIImage 剪辑到路径

为图像创建复杂的剪切路径?

如何在不同颜色的ios中使用uibezierpath创建堆叠条形图

iOS关于CAShapeLayer与UIBezierPath的知识内容

iOS 绘图-UIBezierPath