2

如何UIImage通过黑线将其分为两部分。的上等高线集UIBezierPath

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

4

3 回答 3

7

以下一组例程创建 UIImage 的版本,其中要么仅包含路径内的内容,要么仅包含路径的内容。

两者都使用了compositeImage使用 CGBlendMode 的方法。CGBlendMode 非常强大,可以将您可以绘制的任何内容与您可以绘制的任何其他内容进行屏蔽。调用 compositeImage: 与其他混合模式可以产生有趣的(如果不是总是有用的)效果。有关所有模式,请参阅CGContext 参考

我在对您的 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];
}
于 2012-04-10T13:28:15.050 回答
2

这可以做到,但它需要一些三角函数。让我们考虑上图的情况。首先,确定最底端的端点,UIBezierPath并使用它UIGraphicsBeginImageContext来获取图像的顶部线以上。这将如下所示:

顶部

现在,假设您的线是直的,沿着绘制垂直strokes 的线逐个像素移动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 像素,其高度取决于您穿过它们的方式。经过一些迭代后,您的图像将大致看起来(请原谅我糟糕的照片编辑技能!),例如:

在此处输入图像描述

有多种方法可以绘制清晰的笔触,这只是其中一种方法。如果效果更好,您还可以使用与给定路径平行的清晰笔划。

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

于 2012-04-10T12:53:10.050 回答
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;
}
于 2012-04-10T22:24:41.780 回答