How to position and crop UIImage in a circle - iphone

I have an interface that lets you position an image within a circle and then when the you decide that it is in the right place, press a crop button and crop the visible area of the image.
Structurally I have a view that contains a scrollview that contains a UIImageView.
The first views layer has a shape layer as a mask that is shaped as a circle. this is my initialization code.
- (void)viewDidLoad
{
[super viewDidLoad];
_buttonView = [[UIView alloc]initWithFrame:CGRectMake(0, self.view.height - 136, 320, 136)];
[_buttonView setBackgroundColor:[UIColor whiteColor]];
_saveButton = [UIButton buttonWithType:UIButtonTypeCustom];
[_saveButton setTitle:#"Save image" forState:UIControlStateNormal];
[_saveButton setBackgroundImage:[[UIImage imageNamed:#"cntnt-button-defult-dark-grey.png"] resizableImageWithNormalCapInsets] forState:UIControlStateNormal];
[_saveButton addTarget:self action:#selector(saveImageWasPressed:) forControlEvents:UIControlEventTouchUpInside];
[_saveButton setBackgroundImage:[[UIImage imageNamed:#"cntnt-button-pressed-dark-grey.png"] resizableImageWithNormalCapInsets] forState:UIControlStateHighlighted];
[_saveButton setFrame:CGRectMake(10, 11, 300, 50)];
[_buttonView addSubview:_saveButton];
_cancelButton = [UIButton buttonWithType:UIButtonTypeCustom];
[_cancelButton setTitle:#"CANCEL" forState:UIControlStateNormal];
[_cancelButton setBackgroundImage:[[UIImage imageNamed:#"btm-button-defult-grey.png"] resizableImageWithNormalCapInsets] forState:UIControlStateNormal];
[_cancelButton setBackgroundImage:[[UIImage imageNamed:#"btm-button-pressed-grey.png"] resizableImageWithNormalCapInsets] forState:UIControlStateHighlighted];
[_cancelButton setFrame:CGRectMake(10, _saveButton.bottom+7, 300, 50)];
[_buttonView addSubview:_cancelButton];
[self.view addSubview:_buttonView];
_topView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, _buttonView.yOrigin)];
[self.view addSubview:_topView];
_scrollView = [[UIScrollView alloc]initWithFrame:_topView.bounds];
[self.topView addSubview:_scrollView];
[_scrollView setDecelerationRate:0.0];
_imageView = [[UIImageView alloc]initWithFrame:CGRectZero];
[_scrollView addSubview:_imageView];
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, (self.topView.height - 300)/2, 300, 300)];
_imageOverlay = [CAShapeLayer layer];
[_imageOverlay setPath:path.CGPath];
[_imageOverlay setFrame:CGRectMake(0, 0, 320, 320)];
[_topView.layer setMask:_imageOverlay];
[_imageView setImage:[UIImage imageNamed:#"portrait.jpg"]];
[_imageView setSize:_imageView.image.size];
[_scrollView setContentOffset:_imageView.center];
[_scrollView setContentSize:_imageView.image.size];
}
When the "_saveButton" is pressed I want the image to be cropped where the visible part of the _imageOverlay is.
If you have any questions for the above, please feel free to ask.
Can you please help me?

Once you crop your view to a circle (renderingView below):
-(UIImage *)retrieveSingletonImage:(UIView *)renderingView
{
UIGraphicsBeginImageContextWithOptions(renderingView.bounds.size, renderingView.opaque, 0.0);
[renderingView.layer renderInContext: UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return viewImage;
}
Use QuartzCore layer corner radius on the renderingView to make it a circle (diameter/2 = corner)

I found some snippets online that do the work.
First I crop the image in the rectangle that represents my circular overlay
- (UIImage *)getCroppedImage
{
float zoomScale = 1.0 / [_scrollView zoomScale];
CGRect rect;
rect.origin.x = [_scrollView contentOffset].x * zoomScale;
rect.origin.y = [_scrollView contentOffset].y * zoomScale;
rect.size.width =_imageOverlay.bounds.size.width *zoomScale;
rect.size.height =_imageOverlay.bounds.size.height *zoomScale;
CGImageRef cr = CGImageCreateWithImageInRect([[_imageView image] CGImage], rect);
UIImage *cropped = [UIImage imageWithCGImage:cr];
CGImageRelease(cr);
return [cropped roundedCornerImage:150 borderSize:0];
}
Then before the return I round the corners of the image and crop it again.
#implementation UIImage (RoundedCorner)
// Creates a copy of this image with rounded corners
// If borderSize is non-zero, a transparent border of the given size will also be added
// Original author: Björn Sållarp. Used with permission. See: http://blog.sallarp.com/iphone-uiimage-round-corners/
- (UIImage *)roundedCornerImage:(NSInteger)cornerSize borderSize:(NSInteger)borderSize {
// If the image does not have an alpha layer, add one
UIImage *image = [self imageWithAlpha];
CGFloat scale = [[UIScreen mainScreen] scale];
UIGraphicsBeginImageContextWithOptions(image.size, !image.hasAlpha, 0);
// Build a context that's the same dimensions as the new size
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0, image.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// Create a clipping path with rounded corners
CGContextBeginPath(context);
[self addRoundedRectToPath:CGRectMake(borderSize, borderSize, image.size.width - borderSize * 2, image.size.height - borderSize * 2)
context:context
ovalWidth:cornerSize * scale
ovalHeight:cornerSize * scale];
CGContextClosePath(context);
CGContextClip(context);
// Draw the image to the context; the clipping path will make anything outside the rounded rect transparent
CGContextDrawImage(context, CGRectMake(0, 0, image.size.width, image.size.height), image.CGImage);
// Create a CGImage from the context
UIImage *roundedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return roundedImage;
}
#end

Related

iOS7 custom button become transparent when highlighted

I just create my own custom button that seem like iOS6 and earlier buttons but on iOS7 my CustomButton turn transparent when highlighted.
I have try to set property adjustsImageWhenHighlighted at NO but nothing change, [self setAlpha:1.f] doesn't work either.
Following, my init method:
-(void) baseInit:(CGRect)frame :(CGFloat *)colorsNormal :(CGFloat *)colorsHighlighted :(CGFloat *)colorsDisabled
{
self.layer.borderWidth=1.0f;
self.layer.borderColor=[[UIColor colorWithRed:0.67f green:0.67f blue:0.67f alpha:1.0f] CGColor];
self.layer.cornerRadius=7.0f;
self.clipsToBounds = YES;
UIImage *image = [self generateUIImageWithGradient:frame :colorsNormal];
[self setBackgroundImage:image forState:UIControlStateNormal];
[self setTitleColor:[UIColor colorWithRed:0.22f green:0.33f blue:0.53f alpha:1.0f] forState:UIControlStateNormal];
UIImage *image2 = [self generateUIImageWithGradient:frame :colorsHighlighted];
[self setBackgroundImage:image2 forState:UIControlStateHighlighted];
[self setTitleColor:[UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:1.0f] forState:UIControlStateHighlighted];
UIImage *image3 = [self generateUIImageWithGradient:frame :colorsDisabled];
[self setBackgroundImage:image3 forState:UIControlStateDisabled];
}
-(id) generateUIImageWithGradient:(CGRect)frame :(CGFloat *)colors
{
CGSize size = CGSizeMake(frame.size.width, frame.size.height);
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
size_t gradientNumberOfLocations = 2;
CGFloat gradientLocations[2] = {0.0, 1.0};
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorspace, colors, gradientLocations, gradientNumberOfLocations);
CGContextDrawLinearGradient(context, gradient, CGPointMake(0, 0), CGPointMake(0, size.height), 0);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
CGGradientRelease(gradient);
CGColorSpaceRelease(colorspace);
UIGraphicsEndImageContext();
return image;
}
And my method call :
CGFloat colorsNormal [] = {1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f};
CGFloat colorsHighlighted [] = {0.03f,0.55f,0.97f,1.0f,0.0f,0.37f,0.90f,1.0f};
CGFloat colorsDisabled [] = {1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f};
[self baseInit:rect :colorsNormal :colorsHighlighted :colorsDisabled];
That work like a charm on iOS6 and NormalState work on iOS7.
Thanks for your help
Set the button type property to UIButtonTypeCustom seem to work. Problem solved.

iPhone:-simplest way to crop image of desired shape and size

i am trying to crop image according to my desire....for my cinemagram type app.....and use it in my application
i have tried a lot of options but none of tham is...usefull for me
i read answers on stack over flow but of no use
plzz help me out
image = [UIImage imageNamed:#"images2.jpg"];
imageView = [[UIImageView alloc] initWithImage:image];
CGSize size = [image size];
[imageView setFrame:CGRectMake(0, 0, size.width, size.height)];
[[self view] addSubview:imageView];
[imageView release];
thanks
Here is the exact code to resize your image to desired size
CGSize itemSize = CGSizeMake(320,480); // give any size you want to give
UIGraphicsBeginImageContext(itemSize);
CGRect imageRect = CGRectMake(0.0, 0.0, itemSize.width, itemSize.height);
[myimage drawInRect:imageRect];
myimage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Now my image is of your desired size
Please find the code below to the crop the image.
// Create the image from a png file
UIImage *image = [UIImage imageNamed:#"prgBinary.jpg"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
// Get size of current image
CGSize size = [image size];
// Frame location in view to show original image
[imageView setFrame:CGRectMake(0, 0, size.width, size.height)];
[[self view] addSubview:imageView];
[imageView release];
// Create rectangle that represents a cropped image
// from the middle of the existing image
CGRect rect = CGRectMake(size.width / 4, size.height / 4 ,
(size.width / 2), (size.height / 2));
// Create bitmap image from original image data,
// using rectangle to specify desired crop area
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], rect);
UIImage *img = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
// Create and show the new image from bitmap data
imageView = [[UIImageView alloc] initWithImage:img];
[imageView setFrame:CGRectMake(0, 200, (size.width / 2), (size.height / 2))];
[[self view] addSubview:imageView];
[imageView release];
Referred from How to Crop an Image
I think this is the most simple way:
CGRect rect = CGRectMake(0.0, 0.0, 320.0, 430.0);
CGImageRef tempImage = CGImageCreateWithImageInRect([originalImage CGImage], rect);
UIImage *newImage = [UIImage imageWithCGImage:tempImage];
CGImageRelease(tempImage);
But don't forget to clear imageOrientation BEFORE cropping, otherwise you will get rotated image after cropping:
-(UIImage *)normalizeImage:(UIImage *)raw {
if (raw.imageOrientation == UIImageOrientationUp) return raw;
UIGraphicsBeginImageContextWithOptions(raw.size, NO, raw.scale);
[raw drawInRect:(CGRect){0, 0, raw.size}];
UIImage *normalizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return normalizedImage;
}
Here is a class using Dinesh's answer to get a square thumbnail of an image
class func returnSquareCroppedImage(theImage:UIImage)->UIImage{
var mySize:CGFloat = 100.0
var imageRect:CGRect
if theImage.size.width > theImage.size.height {
mySize = theImage.size.height
let xAdjust = 0-((theImage.size.width - theImage.size.height)/2)
imageRect = CGRectMake(xAdjust, 0, theImage.size.width, theImage.size.height)
}else{
mySize = theImage.size.width
let yAdjust = 0-((theImage.size.height - theImage.size.width)/2)
imageRect = CGRectMake(0, yAdjust, theImage.size.width, theImage.size.height)
}
UIGraphicsBeginImageContext(CGSizeMake(mySize, mySize))
theImage.drawInRect(imageRect)
let returnImage = UIGraphicsGetImageFromCurrentImageContext()
return returnImage
}

Iphone, how to add outline on an image?

I want to add outline on an image, do you have any idea?
Note: I don't need the border of imageview, not imageview.layer.borderColor nor image.layer.borderWidth;
Try this :
- (UIImage*)imageWithBorderFromImage:(UIImage*)source;
{
CGSize size = [source size];
UIGraphicsBeginImageContext(size);
CGRect rect = CGRectMake(0, 0, size.width, size.height);
[source drawInRect:rect blendMode:kCGBlendModeNormal alpha:1.0];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 0.5, 1.0, 1.0);
CGContextStrokeRect(context, rect);
UIImage *testImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return testImg;
}
source : http://www.icodesnip.com/snippet/objective-c/add-image-border-to-uiimage
This may not be a very clean way but may work and is simple.
//Make a UIView instance with required coords and size
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(...)];
//Set a backgroundColor, that will be the color of your border
view.backgroundColor = [UIColor ...];
// Make a UIImageView instance with the frame just leaving enough
// space around for the border.
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(...)];
imageView.image = yourImage;
// Add the imageView to the view.
[view addSubview:imageView];
[imageView release];
// Release view accordingly after adding to some other view.
The sizes of the view and imageView will what give your image a border.
eg. (0, 0, 10, 10) -> view frame
(1, 1, 8, 8) -> imageView frame
This will give border of "1" to the image.

rounded corner in UIImageView

I have the following code:
[avatar.layer setBorderColor:[[UIColor whiteColor] CGColor]];
[avatar.layer setBorderWidth:2.0];
[avatar.layer setShadowOffset:CGSizeMake(-1.0, -1.0)];
[avatar.layer setCornerRadius:8];
It does give me a rounded white border surrounding the UIImage, however there is that extra tip around the 4 corners.. is there a way to cut it off?
setMasksToBounds is probably what you are looking for.
[avatar.layer setMasksToBounds:YES];
-(UIImage *)makeRoundedImage:(UIImage *) image
radius: (float) radius;
{
CALayer *imageLayer = [CALayer layer];
imageLayer.frame = CGRectMake(0, 0, image.size.width, image.size.height);
imageLayer.contents = (id) image.CGImage;
imageLayer.masksToBounds = YES;
imageLayer.cornerRadius = radius;
UIGraphicsBeginImageContext(image.size);
[imageLayer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *roundedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return roundedImage;
}

iPhone SDK: Rendering a CGLayer into an image object

I am trying to add a curved border around an image downloaded and to be displayed in a UITableViewCell.
In the large view (ie one image on the screen) I have the following:
productImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:product.image]];
[productImageView setAlpha:0.4];
productImageView.frame = CGRectMake(10.0, 30.0, 128.0, 128.0);
CALayer *roundedlayer = [productImageView layer];
[roundedlayer setMasksToBounds:YES];
[roundedlayer setCornerRadius:7.0];
[roundedlayer setBorderWidth:2.0];
[roundedlayer setBorderColor:[[UIColor darkGrayColor] CGColor]];
[self addSubview:productImageView];
In the table view cell, to get it to scroll fast, an image needs to be drawn in the drawRect method of a UIView which is then added to a custom cell.
so in drawRect
- (void)drawRect:(CGRect)rect {
...
point = CGPointMake(boundsX + LEFT_COLUMN_OFFSET, UPPER_ROW_TOP);
//CALayer *roundedlayer = [productImageView layer];
//[roundedlayer setMasksToBounds:YES];
//[roundedlayer setCornerRadius:7.0];
//[roundedlayer setBorderWidth:2.0];
//[roundedlayer setBorderColor:[[UIColor darkGrayColor] CGColor]];
//[productImageView drawRect:CGRectMake(boundsX + LEFT_COLUMN_OFFSET, UPPER_ROW_TOP, IMAGE_WIDTH, IMAGE_HEIGHT)];
//
[productImageView.image drawInRect:CGRectMake(boundsX + LEFT_COLUMN_OFFSET, UPPER_ROW_TOP, IMAGE_WIDTH, IMAGE_HEIGHT)];
So this works well, but if I remove the comment and try to show the rounded CA layer the scrolling goes really slow.
To fix this I suppose I would have to render this image context into a different image object, and store this in an array, then set this image as something like:
productImageView.image = (UIImage*)[imageArray objectAtIndex:indexPath.row];
My question is "How do I render this layer into an image?"
TIA.
This is what I got to work well.
- (UIImage *)roundedImage:(UIImage*)originalImage
{
CGRect bounds = CGRectMake(0.0, 0.0, originalImage.size.width, originalImage.size.height);
UIImageView *imageView = [[UIImageView alloc] initWithImage:originalImage];
CALayer *layer = imageView.layer;
imageView.frame = bounds;
[layer setMasksToBounds:YES];
[layer setCornerRadius:7.0];
[layer setBorderWidth:2.0];
[layer setBorderColor:[[UIColor darkGrayColor] CGColor]];
UIGraphicsBeginImageContext(bounds.size);
[layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *anImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[imageView release];
return anImage;
}
Then to scale the image, I found this in the lazy loading example:
#define kAppIconHeight 48
CGSize itemSize = CGSizeMake(kAppIconHeight, kAppIconHeight);
UIGraphicsBeginImageContext(itemSize);
CGRect imageRect = CGRectMake(0.0, 0.0, itemSize.width, itemSize.height);
[image drawInRect:imageRect];
self.appRecord.appIcon = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
You are on the right track with your own comment.
- (UIImage *)roundedImage:(UIImage*)originalImage;
{
CGRect bounds = originalImage.bounds;
CGImageRef theImage = originalImage.CGImage;
CALayer *roundedlayer = [CALayer layer];
roundedlayer.position = CGPointMake(0.0f,0.0f);
roundedlayer.bounds = bounds;
[roundedlayer setMasksToBounds:YES];
[roundedlayer setCornerRadius:7.0];
[roundedlayer setBorderWidth:2.0];
[roundedlayer setBorderColor:[[UIColor darkGrayColor] CGColor]];
roundedlayer.contents = theImage;
UIGraphicsBeginImageContext(bounds.size); // creates a new context and pushes it on the stack
CGContextBeginTransparencyLayerWithRect(UIGraphicsGetCurrentContext(), bounds, NULL);
CGContextClearRect(UIGraphicsGetCurrentContext(), bounds);
[roundedlayer drawInContext:UIGraphicsGetCurrentContext()];
UIImage *anImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext(); //releases new context and removes from stack
return anImage;
}
I would pre-render these and store them in your image array so they are not calculated during your drawRect, but set in your
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
method.