沿着UIBezierPath将UIImage分成两部分

时间:2012-04-10 12:16:20

标签: objective-c ios uiimage uibezierpath

如何将此UIImage除以黑线分为两部分。上轮廓集UIBezierPath

我需要得到两个结果UIImage。那有可能吗?

3 个答案:

答案 0 :(得分:7)

以下一组例程创建UIImage的版本,其中只有内容内部路径,或者只有内容之外的路径。

两者都使用compositeImage方法,该方法使用CGBlendMode。 CGBlendMode非常强大,可以屏蔽任何你可以绘制的东西。调用compositeImage:使用其他混合模式可以有趣(如果不是总是有用的)效果。有关所有模式,请参阅CGContext Reference

我在对你的OP的评论中描述的裁剪方法确实有效,但可能更快,但只有你有UIBezierPaths定义你想要剪辑的所有区域。

- (UIImage*) compositeImage:(UIImage*) sourceImage onPath:(UIBezierPath*) path usingBlendMode:(CGBlendMode) blend;
{
    // Create a new image of the same size as the source.
    UIGraphicsBeginImageContext([sourceImage size]);

    // First draw an opaque path...
    [path fill];
    // ...then composite with the image.
    [sourceImage drawAtPoint:CGPointZero blendMode:blend alpha:1.0];

    // With drawing complete, store the composited image for later use.
    UIImage *maskedImage = UIGraphicsGetImageFromCurrentImageContext();

    // Graphics contexts must be ended manually.
    UIGraphicsEndImageContext();

    return maskedImage;
}

- (UIImage*) maskImage:(UIImage*) sourceImage toAreaInsidePath:(UIBezierPath*) maskPath;
{
    return [self compositeImage:sourceImage onPath:maskPath usingBlendMode:kCGBlendModeSourceIn];
}

- (UIImage*) maskImage:(UIImage*) sourceImage toAreaOutsidePath:(UIBezierPath*) maskPath;
{
    return [self compositeImage:sourceImage onPath:maskPath usingBlendMode:kCGBlendModeSourceOut];
}

答案 1 :(得分:2)

这可以完成,但需要一些三角法。让我们考虑上图的情况。首先,确定UIBezierPath的最低端点,并使用UIGraphicsBeginImageContext将图像的顶部部分放在线上。这将如下所示:

Top portion

现在,假设您的直线是直的,沿着stroke的垂直clearColor的线绘制逐像素移动(顶部循环。在底部的类似线上继续):

for(int currentPixel_x=0;currentPixel_x<your_ui_image_top.size.width)
    UIGraphicsBeginImageContext(your_ui_image_top.size);
    [your_ui_image_top drawInRect:CGRectMake(0, 0, your_ui_image_top.size.width, your_ui_image_top.size.height)];
    CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
    CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 1.0);
    CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeClear); 
    CGContextSetStrokeColorWithColor(UIGraphicsGetCurrentContext(),[UIColor clearColor].CGColor);
    CGContextBeginPath(UIGraphicsGetCurrentContext());
    CGContextMoveToPoint(UIGraphicsGetCurrentContext(), currentPixel_x, m*currentPixel_x + c);
    CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPixel_x, your_ui_image_top.size.height);
    CGContextStrokePath(UIGraphicsGetCurrentContext());
    your_ui_image_top = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
}

您的UIBezierPath必须转换为y = m*x + c形式的直线。此等式中的x将高于currentPixel_x。迭代图像的宽度,每次将currentPixel_x增加1。 next_y_point_on_your_line将按以下方式计算:

next_y_point_on_your_line = m*currentPixel_x + c

每个垂直stroke的宽度为1像素,其高度取决于您如何遍历它们。经过一些迭代后,您的图像看起来粗略(请原谅我糟糕的照片编辑技巧!),如:

enter image description here

有多种方法可以绘制清晰笔划,这只是解决问题的一种方法。如果它可以提供更好的结果,您也可以使用与给定路径平行的清晰笔划。

另一种方法是将线下像素的alpha设置为0.

答案 2 :(得分:2)

我测试了剪辑,并且在一些不同的测试中,它比屏蔽<强>慢25%以获得与我在其他答案中的[maskImage: toAreaInsidePath:]方法相同的结果。为了完整起见,我将其包含在此处,但请不要在没有充分理由的情况下使用它。

- (UIImage*) clipImage:(UIImage*) sourceImage toPath:(UIBezierPath*) path;
{
    // Create a new image of the same size as the source.
    UIGraphicsBeginImageContext([sourceImage size]);

    // Clipping means drawing only happens within the path.
    [path addClip];

    // Draw the image to the context.
    [sourceImage drawAtPoint:CGPointZero];

    // With drawing complete, store the composited image for later use.
    UIImage *clippedImage = UIGraphicsGetImageFromCurrentImageContext();

    // Graphics contexts must be ended manually.
    UIGraphicsEndImageContext();

    return clippedImage;
}