iOS - Make UIImage inside Button Round - ios

Everybody loves them some round profile images these days. So I guess I do too. With that said...
I have a UIImage set as the background image of a UIButton. What I need to do is make the profile picture completely rounded. Here's my code ... can anyone point me in the right direction?
NSString* photoUrl = [NSString stringWithFormat:#"%#%#", URL_IMAGE_BASE, photoFileName];
NSURL *myurl2 = [NSURL URLWithString: photoUrl];
UIImage *image = [UIImage imageWithData: [NSData dataWithContentsOfURL:myurl2]];
[_goToProfileEditButton setImage:image forState:UIControlStateNormal];
[_goToProfileEditButton setBackgroundImage:image forState:UIControlStateNormal];

Make the button a perfect square (same width/height) and use the cornerRadius property of the button layer and set it to be exactly half its width/height. You need to import the QuartzCore header to be able to access the layer property.

What you could do is subclass UIView and override the drawRect: method like so:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, rect);
CGContextAddEllipseInRect(context, rect);
CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor);
CGContextFillPath(context);
}
Set the view's clipsToBounds property to YES and add your image view as a subview of your subclassed UIView. Otherwise you could look into masking with an image via CGImageMaskCreate.

bolivia's answer is the best if you are happy to mask the button itself.
If you want to create a circle image from a square, then you can do that with a clipping mask. It should be something like as follows:
// start with the square image, from a file, the network, or wherever...
UIImage * squareImage = [UIImage imageNamed:#"squareImage.png"];
CGRect imageRect = CGRectMake(0, 0, squareImage.size.width, squareImage.size.height);
UIGraphicsBeginImageContextWithOptions(imageRect.size,NO,0.0);
UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:imageRect cornerRadius:imageRect.size.width/2.0f];
[path addClip];
[squareImage drawInRect:imageRect];
UIImage *circleImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// now circleImage contains the circle in the center of squareImage

Related

create UIImage to be a border with color

I am using FSCalendar What I want to do is change the way of showing events. I want to put a coloured rectangle border around the cell with events. I did that by editing the cell background layer and worked fine, but now I realized that it is the wrong place to put my code as updating to the latest version of FSCalendar which will override my changes.
One of what I can access by the calendar delegates is to set image to the cell, So I want to create image as rectange border with the event colour.
Here is an image of what I want:
Any suggessions is appreicated.
Thanks in advance.
This method will draw a bordered rectangle. I would make it class method and put into UIImage category for convenient use.
- (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)imageSize andBorderWidth:(CGFloat)borderWidth fillWithColor:(BOOL)fillWithColor{
UIGraphicsBeginImageContext(imageSize);
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect rect = CGRectMake(0, 0, imageSize.width, imageSize.height);
if(fillWithColor) {
[color setFill];
CGContextFillRect(context, rect);
} else {
[color setStroke];
CGContextStrokeRectWithWidth(context, rect, borderWidth);
}
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
EDIT: Added fillWithColor parameter
You can set border for UIImageView instead of set image as rectange border
cell.imageView.layer.borderColor = [[UIColor redColor] CGColor];
cell.imageView.layer.borderWidth = 1.0f;

How to draw image inside a circular bezier path

I am trying to create a custom view to draw a music CD with the album artwork on the CD.
Currently I use core graphics to draw two circular disks inside the drawRect method. The inner disk's colour is set to the background colour of the view to make it look like the inner circle is a hollow circle.
My problem is that I can't draw the UIImage inside the the circular bezier path to get the result that I need.
Here's my drawRect code:
// Draw a CD like view using three drawing operations:
// 1st draw the main disk
// 2nd draw the image if it is set
// 3rd draw the inner disk over the image so that it looks like it is a hollow disk with the image painted on the disk.
// Note:) This view expects its aspect ratio to be set as 1:1
- (void)drawRect:(CGRect)rect
{
// Draw the main Circular CD disk
UIBezierPath* outerRing = [UIBezierPath bezierPathWithOvalInRect:self.bounds];
[self.mainColor setFill];
[outerRing fill];
[self.outerRingColor setStroke];
[outerRing stroke];
// Draw the album image if it is set
if(self.artwork){
[self.artwork drawInRect:self.bounds blendMode:kCGBlendModeNormal alpha:1.0];
}
// now draw another smaller disk inside
// this will be a percentage smaller than the whole disk's bounds and will be centered inside it
CGFloat sidePaddingCoord = ((1.0f - INNER_DISK_SIZE_PERCENTAGE) / 2) * self.bounds.size.height;
CGFloat side = INNER_DISK_SIZE_PERCENTAGE * self.bounds.size.width;
UIBezierPath* innerRing = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(sidePaddingCoord, sidePaddingCoord, side, side)];
[self.innerRingColor setFill];
[innerRing fill];
[innerRing stroke];
}
This fills the image as a square. I want the image to be clipped inside the outerRing bezier path so that it looks like a music CD.
I'm sure there is a way to use core graphics to achieve something else besides using the image's drawInRect method. Is there any way to 'clip' the image inside the circular bezier path or only draw inside the bezier path?
I've read really great posts by rob mayoff, UIBezierPath Subtract Path, iOS UIImage clip to paths, many thanks.
Here is an adoption of his code. Keep your creation code of outerRing and innerRing, add them to an array named paths.
[self.paths addObject:outerRing];
[self.paths addObject:innerRing];
Then use this help method.
- (UIImage *)maskedImage
{
CGRect rect = CGRectZero;
rect.size = self.originalImage.size;
UIGraphicsBeginImageContextWithOptions(rect.size, YES, 0.0);
UIBezierPath *clipPath = [UIBezierPath bezierPathWithRect:CGRectInfinite];
[clipPath appendPath:self.paths[1]];
clipPath.usesEvenOddFillRule = YES;
CGContextSaveGState(UIGraphicsGetCurrentContext()); {
[clipPath addClip];
[[UIColor orangeColor] setFill];
[self.paths[0] fill];
} CGContextRestoreGState(UIGraphicsGetCurrentContext());
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;
}
In drawRect,
UIImage *maskedImage = [self maskedImage];
[maskedImage drawInRect:self.bounds blendMode:kCGBlendModeNormal alpha:1.0];
Try below code:
UIImageView *userImageView= [[UIImageView alloc] initWithFrame:CGRectMake(85, 55.0, 90, 90)];
userImageView.layer.cornerRadius = 90/2;
userImageView.clipsToBounds = YES;
userImageView.layer.borderWidth = 1.0f;
userImageView.layer.borderColor = [UIColor blueColor];
[self.view addSubview:userImageView]; //or add it to the view you want
UIImage *userImage = [UIImage imageNamed:#"<image you want to set>"];
userImageView= [[UIImageView alloc] initWithFrame:CGRectMake(90, 60.0, 80, 80)];
userImageView.image = userImage;
userImageView.layer.cornerRadius = 80/2;
userImageView.clipsToBounds = YES;
userImageView.layer.borderWidth = 1.0f;
userImageView.layer.borderColor = [UIColor blueColor;
[self.view addSubview:userImageView]; //or add it to the view you want

Combining Multiple UI Images and UI Labels into 1 Image

Basically I have a main UIImage, which acts as a background/border. Within that UIImage I have 2 more UIImages, vertically split with a gap around them so you can still see a border of the main background UIImage. On each side I have a UILabel, to describe the images. Below is a picture of what I mean to help put into context.
What I want to achieve is to make this into 1 image, but keeping all of the current positions, layouts, image layouts (Aspect Fill) and label sizes and label background colours the same. I also want this image to be the same quality so it still looks good.
I have looked at many other stackoverflow questions and have so far come up with the follow, but it has the following problems:
Doesn't position the image labels to their correct places and sizes
Doesn't have the background colour for the labels or main image
Doesn't have the images as Aspect Fill (like the UIImageViews) so the outside of each picture is shown as well and isn't cropped properly, like in the above example.
Below is my code so far, can anyone help me achieve it like the image above please? I am fairly new to iOS development and am struggling a bit:
-(UIImage *)renderImagesForSharing{
CGSize newImageSize = CGSizeMake(640, 640);
NSLog(#"CGSize %#",NSStringFromCGSize(newImageSize));
UIGraphicsBeginImageContextWithOptions(newImageSize, NO, 0.0);
[self.mainImage.layer renderInContext:UIGraphicsGetCurrentContext()];
[self.beforeImageSide.image drawInRect:CGRectMake(0,0,(newImageSize.width/2),newImageSize.height)];
[self.afterImageSize.image drawInRect:CGRectMake(320,0,(newImageSize.width/2),newImageSize.height) blendMode:kCGBlendModeNormal alpha:1.0];
[self.beforeLabel drawTextInRect:CGRectMake(60.0f, 0.0f, 200.0f, 50.0f)];
[self.afterLabel drawTextInRect:CGRectMake(0.0f, 0.0f, 100.0f, 50.0f)];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
NSData *imgData = UIImageJPEGRepresentation(image, 0.9);
UIImage * imagePNG = [UIImage imageWithData:imgData]; //wrap UIImage around PNG representation
UIGraphicsEndImageContext();
return imagePNG;
}
Thank you in advance for any help guys!
I don't understand why you want use drawInRect: to accomplish this task.
Since you have the images and everything with you, you can easily create a view as you have shown in the image. Then take a screenshot of it like this:
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, self.view.opaque, 0.0);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage*theImage=UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData*theImageData=UIImageJPEGRepresentation(theImage, 1.0 ); //you can use PNG too
[theImageData writeToFile:#"example.jpeg" atomically:YES];
Change the self.view to the view just created
It will give some idea.
UIGraphicsBeginImageContextWithOptions(DiagnosisView.bounds.size, DiagnosisView.opaque, 0.0);
CGContextRef ctx = UIGraphicsGetCurrentContext();
[[UIColor redColor] set];
CGContextFillRect(ctx, DiagnosisView.frame);
[DiagnosisView.layer renderInContext:ctx];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSString *imagePath = [KdiagnosisFolderPath stringByAppendingPathComponent:FileName];
NSData *pngData = UIImagePNGRepresentation(img);
[pngData writeToFile:imagePath atomically:YES];
pngData = nil,imagePath = nil;

How to apply UIScrollView's transform to UIView?

In my app I have a scrollview with an added subview called allView.
In the scrollview delegate methods I am applying value of the current transformation of the scrollview's subview to another view called paint view
paintView.transform = allView.transform
and save it to the disk.
The image that is created in result of that process looks different than the one on the screen. Why? How can I fix it?
View Controller
- (void)scrollViewDidScroll:(UIScrollView *)scrollView; {
self.paintView.transform =self.allView.transform;
[self.paintView setNeedsDisplay];
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView{
self.backgroundView.transform = self.allView.transform;
[self.paintView setNeedsDisplay];
}
Paint View
Inside the PaintView's draw rect I am trying to apply transformation from the scroll view and
- (void)drawRect:(CGRect)rect
{
// Drawing code
// Draw on the screen
CGContextRef ctx1 =UIGraphicsGetCurrentContext();
CGContextConcatCTM(ctx1, self.transform);
CGColorRef wh = [[UIColor redColor]CGColor];
CGContextSetStrokeColorWithColor(ctx1, wh);
CGContextMoveToPoint(ctx1, 0, 0);
CGContextAddLineToPoint(ctx1, 200, 200);
CGContextStrokePath(ctx1);
// Apply scroll view's transformation
CGRect r = CGRectApplyAffineTransform(rect,self.transform );
//that gives a resized image
UIGraphicsBeginImageContextWithOptions(r.size, NO, 0.0);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextConcatCTM(ctx, self.transform);
// stroke and so on
CGContextSetStrokeColorWithColor(ctx, wh);
CGContextMoveToPoint(ctx, 0, 0);
CGContextAddLineToPoint(ctx, 200, 200);
CGContextStrokePath(ctx);
Getting image with entire content.
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
//Clipping the image
CGImageRef cgImg = CGImageCreateWithImageInRect(image.CGImage, rect);
UIImage *img = [UIImage imageWithCGImage:cgImg];
NSData * d = UIImageJPEGRepresentation(img, 0.8);
//saving the image (for debugging)
[self save:d];
UIGraphicsEndImageContext();
}
iOS Simulator
Image saved to the disk
It may be a little bit hard to diagnose the problem here without being able to have running code. However, I think the problem may be on these lines where you are clipping the image:
// Clipping the image
CGImageRef cgImg = CGImageCreateWithImageInRect(image.CGImage, rect);
UIImage *img = [UIImage imageWithCGImage:cgImg];
I think you actually just want to get the scroll view's visible rect, which would be scrollView.frame rather than the subview that fills the scroll view's entire contentSize. So, using some way (such as a property on paintView such as a visibleFrame), I would revise the lines to be something like this:
// Clipping the image
CGImageRef cgImg = CGImageCreateWithImageInRect(image.CGImage, self.visibleFrame);
UIImage *img = [UIImage imageWithCGImage:cgImg];
Hope this helps you get passed this issue!

CALayer containsPoint with mask not working

I have a UIView that have a CALayer mask:
// Getting the right mask image
UIImage *myimage = [UIImage imageNamed:[NSString stringWithFormat:#"img%d", imageIndex]];
// Scaling image to fit UIView
UIGraphicsBeginImageContextWithOptions(self.frame.size, NO, 0.0);
[myimage drawInRect:self.bounds];
myimage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self.layer setMasksToBounds:YES];
// Setting mask
UIImage *_maskingImage = myimage;
CALayer *_maskingLayer = [CALayer layer];
_maskingLayer.frame = self.bounds;
[_maskingLayer setContents:(id)[_maskingImage CGImage]];
[self.layer setMask:_maskingLayer];
When the user later short press (UILongPressGestureRecognizer *) the UIView I just want a action to happend if the user taps in the UIView layer mask (for now containsPoint always returns YES):
// Object is a UIView
CALayer *layer = [Object.layer mask];
// Sender is a UILongPressGestureRecognizer
location2 = [sender locationInView:Object];
// The position is correct
NSLog(#"%#", NSStringFromCGPoint(location2));
if ([layer containsPoint:location2]){
NSLog(#"HELLO WORLD!");
return;
}
Help, please?
My book gives two suggestions. If you know the bounding path of the mask drawing, you can use CGPathContainsPoint. Or, if the layer in question is transparent on the outside and opaque on the inside, you can examine the pixel at the tapped location to see if it is transparent or not.
http://www.apeth.com/iOSBook/ch18.html#_hit_testing
Scroll down to the section "Hit-testing for drawings".

Resources