Photo button like in contacts and Facebook app - iphone

How can I create a "person photo" button like the one in contact info or in the Facebook app? (grey and rounded border with a small radius and an image that is cropped inside it)
Edit:
It must obviously work for all photos, not just one that I prerender in Photoshop.
I guess I could do it manually using masks etc., but Facebook app does it exactly like the contacts app, so I suspect there is some way to do it in the SDK.

Here you (I :P) go:
+ (UIImage *)imageWithBorderForImage:(UIImage *)image
{
CGFloat radius = 5;
CGSize size = image.size;
radius = MIN(radius, .5 * MIN(size.width, size.height));
CGRect interiorRect = CGRectInset(CGRectMake(0, 0, size.width, size.height), radius, radius);
UIGraphicsBeginImageContext(size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGMutablePathRef borderPath = CGPathCreateMutable();
CGPathAddArc(borderPath, NULL, CGRectGetMinX(interiorRect), CGRectGetMinY(interiorRect), radius, 1.0*M_PI, 1.5*M_PI, NO);
CGPathAddArc(borderPath, NULL, CGRectGetMaxX(interiorRect), CGRectGetMinY(interiorRect), radius, 1.5*M_PI, 0.0*M_PI, NO);
CGPathAddArc(borderPath, NULL, CGRectGetMaxX(interiorRect), CGRectGetMaxY(interiorRect), radius, 0.0*M_PI, 0.5*M_PI, NO);
CGPathAddArc(borderPath, NULL, CGRectGetMinX(interiorRect), CGRectGetMaxY(interiorRect), radius, 0.5*M_PI, 1.0*M_PI, NO);
CGContextBeginPath(context);
CGContextAddPath(context, borderPath);
CGContextClosePath(context);
CGContextClip(context);
[image drawAtPoint:CGPointMake(0,0)];
CGContextBeginPath(context);
CGContextAddPath(context, borderPath);
CGContextClosePath(context);
CGContextSetRGBStrokeColor(context, 0.5, 0.5, 0.5, 1.0);
CGContextSetLineWidth(context, 1.0);
CGContextStrokePath(context);
CGPathRelease(borderPath);
UIImage *borderedImage = UIGraphicsGetImageFromCurrentImageContext();
CGContextRestoreGState(context);
UIGraphicsEndImageContext();
return borderedImage;
}
Based largely on this question.
One problem is that the border is actually 2px wide (although 1px falls outside of the clip area) because of anti-aliasing. Ideally the border would have ~0.5 alpha, but since the antialiasing gives each of the 2 pixels some alpha, I set it to 1 and it comes out just about right. If I disable antialiasing, then the corners aren't rounded all the same :/

Create it as an image (like "person.png"), then load it up like this:
UIImage *personImage = [UIImage imageNamed:#"person.png"];
[[myButton imageView] setImage:personImage];
//where myButton is a UIButton of type UIButtonTypeCustom

Related

Multicolor line drawing

I am creating a drawing app. One of the features is multicolour line drawing. It should work like user touch up the screen and leads on it drawing a line. Colour of the line changes smoothly. Like that http://www.examples.pavelgatilov.com/Screen%20Shot%202013-09-22%20at%208.37.42%20PM.png
I tried several approaches, but haven't been lucky.
My line drawing method is below:
- (void) drawLineFrom:(CGPoint)from to:(CGPoint)to width:(CGFloat)width
{
self.drawColor = toolColor;
UIGraphicsBeginImageContext(self.frame.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextScaleCTM(ctx, 1.0f, -1.0f);
CGContextTranslateCTM(ctx, 0.0f, -self.frame.size.height);
if (drawImage != nil) {
CGRect rect = CGRectMake(0.0f, 0.0f, self.frame.size.width, self.frame.size.height);
CGContextDrawImage(ctx, rect, drawImage.CGImage);
}
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextSetLineWidth(ctx, width);
CGContextSetStrokeColorWithColor(ctx, self.drawColor.CGColor);
CGContextMoveToPoint(ctx, from.x, from.y);
CGContextAddLineToPoint(ctx, to.x, to.y);
CGContextStrokePath(ctx);
CGContextFlush(ctx);
drawImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
drawLayer.contents = (id)drawImage.CGImage;
}
Thanks for your help
Depending on exactly what colours, how they change and what effect you want / what happens with turns in the line, you may want to look at some combination of:
CGContextDrawLinearGradient with masking to the users drawn path.
colorWithPatternImage:
CGContextDrawLinearGradient drawn behind another layer and drawing transparency into the top layer with kCGBlendModeClear

How to fill the shapes with color

I am new to Objective-C and iOS development. I have a view with some figures drawn by core drawing. Now I want to fill those shapes with color and I don't know the path or context of shape. Does Objective-C have any function like flood-fill or put-pixel so that by having only the stroke color I can fill any shape inside my view.
-(void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 4.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {1.0, 0.0, 0.0, 1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, color);
CGContextMoveToPoint(context, 50, 0);
CGContextAddLineToPoint(context, 0,320);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
CGColorRelease(color);
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextSetRGBFillColor(context, 0, 255, 0, 1.0);
CGContextMoveToPoint(context, 100, 100);
CGContextAddLineToPoint(context, 150, 150);
CGContextAddLineToPoint(context, 100, 200);
CGContextAddLineToPoint(context, 50, 150);
CGContextAddLineToPoint(context, 100, 100);
CGContextStrokePath(context);
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGRect rectangle = CGRectMake(60,170,200,80);
CGContextAddEllipseInRect(context, rectangle);
CGContextStrokePath(context);
}
This will make a circle and a square with some common region. I want a particular region to fill with color when a user taps that region.
So you are looking for flood fill in Objective C.
This is my implementation of Scan Line Flood Fill Algorithm.
Github : UIImageScanlineFloodfill
If you want to learn basic of flood fill:
Lode's Computer Graphics Tutorial Flood Fill
I hope this will help you.
Put your drawing code in the question and I can give you a specific answer.
Normally you just need to set a fill color using
[[UIColor redColor] setFill];
And any shapes you draw your core graphics will be filled with that color automatically.
Try this command:-
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
Core Graphics is closely tied to UIView and its drawRect: method and has a C interface. As you point out, you always draw in the current graphics context. I can think of 2 approaches: (1) When the user taps myView, set a property like myView.pointTapped, and in drawRect: find the shape to fill, set a fill color, and fill the closed path using GGGeometry methods.
There is an objective-C alternative: (2) Take a look at UIBezierPath. It's not as comprehensive as drawing in Core Graphics but it can be used in your ViewController implementation.

Colourise CGContextRef But Preserve Alpha

I have a CGContextRef and can draw on it and specify the alpha, and if I try and use it it works perfectly. However, I am trying to colourise it (currently either red or green), but whatever blend mode I choose, the alpha is set to 1 (because I am drawing with alpha as 1). Drawing it the correct colour is not really a viable option, as I would like to be able to colour UIImages loaded from the filesystem as well, so how should I achieve this?
Edit: Example code (width and height are predefined floats, points is an array of CGPoints all of which lie inside the context and color is a UIColor with an opacity of 100%) -
UIGraphicsBeginImageContext(CGSizeMake(width,height));
CGContextRef contextRef = UIGraphicsGetCurrentContext();
CGContextClearRect(contextRef, CGRectMake(0.0f, 0.0f, width, height));
CGContextSetRGBStrokeColor(contextRef, 0.0f, 0.0f, 0.0f, 1.0f);
CGContextSetRGBFillColor(contextRef, 1.0f, 1.0f, 1.0f, 1.0f);
CGContextSetLineWidth(contextRef, lineWidth);
CGContextBeginPath(contextRef);
CGContextMoveToPoint(contextRef, points[0].x, points[0].y);
for (int i = 1; i < 4; i++) {
CGContextAddLineToPoint(contextRef, points[i].x, points[i].y);
}
CGContextAddLineToPoint(contextRef, points[0].x, points[0].y); // Encloses shape
CGContextDrawPath(contextRef, kCGPathFillStroke);
[color setFill];
CGContextBeginPath(contextRef);
CGContextSetBlendMode(contextRef, kCGBlendModeMultiply);
CGContextAddRect(contextRef, CGRectMake(0.0f, 0.0f, width, height));
CGContextDrawPath(contextRef, kCGPathFill);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Thank you in advance for your help,
jrtc27
The problem was I needed a CGContextClipToMask. This meant my code required the following:
CGContextTranslateCTM(contextRef, 0, height);
CGContextScaleCTM(contextRef, 1.0, -1.0);
to convert the coordinates and then
CGRect rect = CGRectMake(0.0f, 0.0f, width, height);
CGContextClipToMask(contextRef, rect, UIGraphicsGetImageFromCurrentImageContext().CGImage);
to fix it.

How to do a radar animation in the iPhone SDK?

Does anyone know how to animate a radar animation like the image below?
alt text http://img197.imageshack.us/img197/7124/circle0.png
With it growing outwards? I have to draw the circle using Quartz or some other way?
To draw a static circle in a UIView subclass:
- (void)drawRect:(CGRect)rect
{
CGRect rect = { 0.0f, 0.0f, 100.0f, 100.0f };
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextSetLineWidth(context, 2.0f);
CGContextAddEllipseInRect(context, rect);
CGContextStrokePath(context);
}
From there you just need to animate it with a timer, vary the size of the rect, and add more circles.

Flipped NSString drawing in CGContext

I try to draw a string in this texture:
http://picasaweb.google.it/lh/photo/LkYWBv_S_9v2d6BAfbrhag?feat=directlink
but the green numbers seem vertical flipped.
I've created my context in this way:
colorSpace = CGColorSpaceCreateDeviceRGB();
data = malloc(height * width * 4);
context = CGBitmapContextCreate(data, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
and i've draw the strings:
UIGraphicsPushContext(context);
for(int i=0;i<packs.size();++i)
{
CGPoint points[4] =
{
gltextures[i].texCoords[0] * size.width, //0
gltextures[i].texCoords[1] * size.height, //1
gltextures[i].texCoords[2] * size.width, //2
gltextures[i].texCoords[3] * size.height, //3
gltextures[i].texCoords[4] * size.width, //4
gltextures[i].texCoords[5] * size.height, //5
gltextures[i].texCoords[6] * size.width, //6
gltextures[i].texCoords[7] * size.height //7
};
CGRect debugRect = CGRectMake
(
gltextures[i].texCoords[0] * size.width,
gltextures[i].texCoords[1] * size.height,
gltextures[i].width,
gltextures[i].height
);
CGContextSetStrokeColorWithColor(context, [[UIColor redColor] CGColor]);
CGContextAddLines(context, points, 4);
CGContextClosePath(context);
CGContextDrawPath(context, kCGPathStroke);
NSString* s = [NSString stringWithFormat:#"%d",gltextures[i].texID];
UIFont* font = [UIFont fontWithName:#"Arial" size:12];
CGContextSetRGBFillColor(context, 0, 1, 0, 1);
[s drawAtPoint:points[0] withFont:font];
}
UIGraphicsPopContext();
The transformation matrix seems the Identity matrix... no CGAffineTransform is applied to THIS context.
If the string is flipped, maybe, all my images are flipped!
Any suggestion?
PS: sorry for my english ;)
As describe here, the coordinate system for a context within a UIView or its layer is inverted when compared to the normal Quartz drawing space. However, when using Quartz to draw to an image, this is no longer the case. The UIStringDrawing Cocoa Touch category on NSString that gives you the -drawAtPoint:withFont: method assumes an inverted layout, and that's why you're seeing the flipped text in your image.
One way to work around this would be to save the graphics state, apply an invert transform to the image, draw the text, and restore the old graphics state. This would look something like the following:
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0f, self.bounds.size.height);
CGContextScaleCTM(context, 1.0f, -1.0f);
[text drawAtPoint:CGPointMake(0.0f, 0.0f) withFont:font];
CGContextRestoreGState(context);
This is a fairly crude example, in that I believe it just draws the text at the bottom of the image, but you should be able to adjust the translation or the coordinate of the text to place it where it's needed.
Better save the text 's matrix before draw, otherwise it will affect other text draw by CoreGraphic:
CGContextSaveGState(ctx);
CGAffineTransform save = CGContextGetTextMatrix(ctx);
CGContextTranslateCTM(ctx, 0.0f, self.bounds.size.height);
CGContextScaleCTM(ctx, 1.0f, -1.0f);
[str drawAtPoint:point withFont:font];
CGContextSetTextMatrix(ctx, save);
CGContextRestoreGState(ctx);