如何将此UIImage
除以黑线分为两部分。上轮廓集UIBezierPath
。
我需要得到两个结果UIImage
。那有可能吗?
答案 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
将图像的顶部部分放在线上。这将如下所示:
现在,假设您的直线是直的,沿着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像素,其高度取决于您如何遍历它们。经过一些迭代后,您的图像看起来粗略(请原谅我糟糕的照片编辑技巧!),如:
有多种方法可以绘制清晰笔划,这只是解决问题的一种方法。如果它可以提供更好的结果,您也可以使用与给定路径平行的清晰笔划。
另一种方法是将线下像素的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;
}