iOS UIImage clip to paths - ios

I'm working with an image where the user has selected part of it using UIBezierPath. How can I delete/clear out/make transparent everything that is not part of that selection?

With one path it's very easy. Just set the path as the clipping path:
- (UIImage *)maskImage:(UIImage *)originalImage toPath:(UIBezierPath *)path {
UIGraphicsBeginImageContextWithOptions(originalImage.size, NO, 0);
[path addClip];
[originalImage drawAtPoint:CGPointZero];
UIImage *maskedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return maskedImage;
}
If you want to use the union of multiple paths, it's harder, because Quartz doesn't have any functions that directly compute the union of two paths. One way is to fill each path one by one into a mask, and then draw the image through the mask:
- (UIImage *)maskedImage
{
CGRect rect = CGRectZero;
rect.size = self.originalImage.size;
UIGraphicsBeginImageContextWithOptions(rect.size, YES, 0.0); {
[[UIColor blackColor] setFill];
UIRectFill(rect);
[[UIColor whiteColor] setFill];
for (UIBezierPath *path in self.paths)
[path fill];
}
UIImage *mask = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0.0); {
CGContextClipToMask(UIGraphicsGetCurrentContext(), rect, mask.CGImage);
[self.originalImage drawAtPoint:CGPointZero];
}
UIImage *maskedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return maskedImage;
}

I tried the code of union multiple paths, and it doesn't work.
Actually, if the union of paths don't overlap with each other, we append one path to another and crop with the final path.
UIGraphicsBeginImageContextWithOptions(originalImg.size, NO, 0);
[path1 appendPath:path2]; // append path2 to path1
[path1 addClip];
[originalImg drawAtPoint:CGPointZero];
result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

Related

CGImageCreateWithImageInRect with MZCroppableView rect issue

I am using this library to crop image form appropriate path.
Seems it works perfect, but after modification the image has another size, that I can't understand how to control.
I have added image with the same size as a container. Sizes = 320 x 524
There is an method in the sources that return cropping image:
- (UIImage *)deleteBackgroundOfImage:(UIImageView *)image
{
NSArray *points = [self.croppingPath points];
CGRect rect = CGRectZero;
rect.size = image.image.size;
UIBezierPath *aPath;
UIGraphicsBeginImageContextWithOptions(rect.size, YES, 0.0);
{
[[UIColor blackColor] setFill];
UIRectFill(rect);
[[UIColor whiteColor] setFill];
aPath = [UIBezierPath bezierPath];
// Set the starting point of the shape.
CGPoint p1 = [MZCroppableView convertCGPoint:[[points objectAtIndex:0] CGPointValue] fromRect1:image.frame.size toRect2:image.image.size];
[aPath moveToPoint:CGPointMake(p1.x, p1.y)];
for (uint i=1; i<points.count; i++)
{
CGPoint p = [MZCroppableView convertCGPoint:[[points objectAtIndex:i] CGPointValue] fromRect1:image.frame.size toRect2:image.image.size];
[aPath addLineToPoint:CGPointMake(p.x, p.y)];
}
[aPath closePath];
[aPath fill];
}
UIImage *mask = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0.0);
{
CGContextClipToMask(UIGraphicsGetCurrentContext(), rect, mask.CGImage);
[image.image drawAtPoint:CGPointZero];
}
UIImage *maskedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGRect croppedRect = aPath.bounds;
croppedRect.origin.y = rect.size.height - CGRectGetMaxY(aPath.bounds);//This because mask become inverse of the actual image;
croppedRect.origin.x = croppedRect.origin.x*2;
croppedRect.origin.y = croppedRect.origin.y*2;
croppedRect.size.width = croppedRect.size.width*2;
croppedRect.size.height = croppedRect.size.height*2;
CGImageRef imageRef = CGImageCreateWithImageInRect(maskedImage.CGImage, croppedRect);
maskedImage = [UIImage imageWithCGImage:imageRef];
return maskedImage;
}
When I debug maskedImage before maskedImage = [UIImage imageWithCGImage:imageRef]; line it seems the method remove background correct, but by some reason after the method CGImageCreateWithImageInRect(maskedImage.CGImage, croppedRect); modify frame of cropped image. I tried to set cropped rect manually in CGImageCreateWithImageInRect to crop just needed frame.
CGImageRef imageRef = CGImageCreateWithImageInRect(maskedImage.CGImage, CGRectMake(0, 0, 320, 100));
But it return nothing for me.
How can I extract appropriate rect?
Also this lines multiply rect x2:
croppedRect.origin.x = croppedRect.origin.x*2;
croppedRect.origin.y = croppedRect.origin.y*2;
croppedRect.size.width = croppedRect.size.width*2;
croppedRect.size.height = croppedRect.size.height*2;
So when I debug it:
origin=(x=242, y=874) size=(width=191, height=164)
So as you can see the Y point out of my image height size 524, but by some reason it works.

iphone - Tinting/shading/glowing an animated UIImage

I'm currently using [UIImage animatedImageNamed:#"..." duration:1.0f] to animate a series of PNG images in my iOS 7 app.
When the image is still, I use UIGraphicsGetImageFromCurrentImageContext() as follows:
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, [UIScreen mainScreen].scale);
{
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIBezierPath* path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)];
[color setFill];
[path fillWithBlendMode:kCGBlendModeSourceAtop alpha:1.0];
image = UIGraphicsGetImageFromCurrentImageContext();
} UIGraphicsEndImageContext();
...and then CAAnimation to glow/tint/shade the image mask. For the animated image, though, is there a way to animate the mask so that it follows the animated PNG? (By "mask" I mean shape or silhouette of the image content that I'm animating.)

Make part of UIImage transparent, or crop that region

I have a UIImage like so:
I want to remove a rect in the middle to leave it like so:
The easiest way to punch a hole through would be to add a layer mask.
#import <QuartzCore/QuartzCore.h>
Create the path you want to clip (the rect you want to punch through)
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRect:yourView.bounds];
[maskPath appendPath:[UIBezierPath bezierPathWithRect:rectToPunchThroughTheView]];
Then create a mask layer and add it to your view - CAShapeLayer will allow you to define any path
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.fillRule = kCAFillRuleEvenOdd;
maskLayer.fillColor = [UIColor blackColor].CGColor;
maskLayer.path = maskPath.CGPath;
yourView.layer.mask = maskLayer;
I would create a UIImage category and crop the image two times with different rects.
Here is the method I added yo my UIImage category a while ago that suited my needs good:
- (UIImage *)cropWithRect:(CGRect)rect {
// If run on a retina device scale is 2 else 1
rect = CGRectMake(rect.origin.x * self.scale,
rect.origin.y * self.scale,
rect.size.width * self.scale,
rect.size.height * self.scale);
CGImageRef imgRf = CGImageCreateWithImageInRect(self.CGImage, rect);
UIImage *croppedImage = [UIImage imageWithCGImage:imageRef
scale:self.scale
orientation:self.imageOrientation];
CGImageRelease(imageRef);
return croppedImage;
}
You can do this way
CGRect fullimageRect;
CGRect upperRect;
CGRect lowerRect;
UIImage *upperImage;
UIImage *lowerImage;
UIImage *finalImage;
UIGraphicsBeginImageContext(upperRect.size);
[[UIImage imageNamed:#"yourimage.png"] drawInRect:lowerRect];
upperImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIGraphicsBeginImageContext(lowerRect.size);
[[UIImage imageNamed:#"yourimage.png"] drawInRect:lowerRect];
lowerImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSLog(#"%#",upperImage);
NSLog(#"%#",lowerImage);
UIGraphicsBeginImageContext(fullimageRect.size);
[upperImage drawInRect:upperRect];
[lowerImage drawInRect:lowerRect];
finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSLog(#"%#",finalImage);

Draw UIImage on a custom color canvas

I want to draw a image for example on black canvas, but the the result is always white, here is my code
-(UIImage*) renderImage
{
UIGraphicsBeginImageContext(CGSizeMake(300, 300));
[[UIColor blackColor] setFill];
UIImage*resultImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return resultImage;
}
for the future i will draw an image inside the canvas, but right now i just want a black filled canvas. why this code is not working
You need to be using CGContextSetFillColorWithColor() to fill the current context with a color. Try this sample code, you give it a color and a size and it will return you a UIImage meeting your criteria.
- (UIImage *)renderImageWithColor:(UIColor *)color inSize:(CGSize)size
{
CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}

How to crop an uiimageView from a rectangle overlay?

I want to crop a part of an uiimageview that on my view controller. I'm creating a rectangle on top of it:
UIGraphicsBeginImageContext(self.view.bounds.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(context, newPoint1.x, newPoint1.y);
CGContextAddLineToPoint(context, newPoint1.x, newPoint2.y);
CGContextAddLineToPoint(context, newPoint2.x, newPoint2.y);
CGContextAddLineToPoint(context, newPoint2.x, newPoint1.y);
CGContextAddLineToPoint(context, newPoint1.x, newPoint1.y);
CGContextClosePath(context);
UIColor *blue = [UIColor colorWithRed: (0.0/255.0 ) green: (0.0/255.0) blue: (255.0/255.0) alpha:0.4];
CGContextSetFillColorWithColor(context, blue.CGColor);
CGContextDrawPath(context, kCGPathFillStroke);
I can't figure out how to crop it right. I'm able to retrieve a capture of the screen : entirely blank with my rectangle on it:
UIImage *cropImage = UIGraphicsGetImageFromCurrentImageContext();
rectImage = cropImage;
UIGraphicsEndImageContext();
UIImageCrop *rectImageView = [[UIImageCrop alloc]initWithImage:rectImage];
[self.view addSubview:rectImageView];
So I'm aware that there is something I've missed about it, any help?
- (UIImage *)captureScreenInRect:(CGRect)captureFrame
{
CALayer *layer;
layer = self.view.layer;
UIGraphicsBeginImageContext(self.view.frame.size);
CGContextClipToRect (UIGraphicsGetCurrentContext(),captureFrame);
[layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screenImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return screenImage;
}
this is just for reference change this code according to your requirement
hope this will help you
You can get cropped image using :
- (UIImage*) getCroppedImage {
CGRect rect = PASS_YOUR_RECT;
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
// translated rectangle for drawing sub image
CGRect drawRect = CGRectMake(-rect.origin.x, -rect.origin.y, your_image.size.width, your_image.size.height);
// clip to the bounds of the image context
// not strictly necessary as it will get clipped anyway?
CGContextClipToRect(context, CGRectMake(0, 0, rect.size.width, rect.size.height));
// draw image
[your_image drawInRect:drawRect];
// grab image
UIImage* croppedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return croppedImage;
}
Hope it helps you.

Resources