Performing custom bitmap drawing in an iOS application - iphone-sdk-3.0

I am new to iOS/Mac programming. I am trying to create an iOS application that performs custom bitmap drawing, and blits it to screen.
I have looked at some examples that use CGImage, but I haven't been able to able to follow them to create an iOS application that performs custom drawing on the application window.
I am now looking for examples/tutorials related to this, written specifically for iOS. Please post any you know of.

Create a subclass of UIView and implement the drawRect: method. Drawing to a Graphics Context in iOS
Drawing a red rectangle:
...with Quartz
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(context, 1.0,0.0,0.0,1.0);
CGRect rectangle = CGRectMake(10, 10, 50, 50);
CGContextFillRect(context, rectangle);
}
...with UIKit
- (void)drawRect:(CGRect)rect {
[[UIColor redColor] set];
CGRect rectangle = CGRectMake(10, 10, 50, 50);
UIRectFill(rectangle);
}

Related

drawRect doesn't draw rect - Objective-C

I just want to draw a rect on a view. This is my code in my UIView subclass:
- (void)drawRect:(CGRect)rect
{
context = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(context, 255.0/255.0, 0.0/255.0, 0.0/255.0, 1);
CGContextAddRect(context, (CGRectMake(20, 20, 20, 20)));
}
When I run it no rect is drawn. What's wrong?
CGContextAddRect just adds a rectangular path to the context. You need to stroke or fill the path as well using CGContextFillPath or CGContextStrokePath.
You can also fill a rect directly with UIRectFill or CGContextFillRect.

CGContextFillRect not working

This code appears to do nothing. Build successful, no errors. No rectangle drawn on screen.
- (void)viewDidLoad
{
[super viewDidLoad];
UIColor *reliantMagenta = [UIColor colorWithRed:208.0f / 255.0f green:27.0f / 255.0f blue:124.0f / 255.0f alpha:1];
CALayer *reliantCanvasLayer = [CALayer layer];
reliantCanvasLayer.frame = CGRectMake(0, 0, 640, 960);
[[[self view] layer] addSublayer:reliantCanvasLayer];
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGRect leftRect = CGRectMake(0, 0, 200, 300);
CGContextSaveGState(ctx);
CGContextSetFillColorWithColor(ctx, reliantMagenta.CGColor);
CGContextFillRect(ctx, leftRect);
CGContextRestoreGState(ctx);
}
I am just learning Quartz and really thrashing with it. If you want to explain the relationship between UIViews, CALayers, CGLayers, and context that would be a big help too, but not required, just having trouble understanding what is going on.
If you're starting out with Quartz, then you should start with the Quartz 2D Programming Guide, which walks through all of this. Your key mistake here is that there is no context available in viewDidLoad. Drawing of this kind is generally done in drawRect:. Your call to UIGraphicsGetCurrentContext() returns NULL at this point.
After reading through the Programming Guide, you may have more questions, but that's where you should start to learn about custom drawing.

Is it possible to draw Graphics with CGContext and save them into a NSMutableArray?

At first I draw graphics:
-(void)drawRect: (CGRect)rect{
//Circle
circle = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(circle, [UIColor darkGrayColor].CGColor);
CGContextFillRect(circle,CGRectMake(10,10, 50, 50));
//rectangle
rectangle = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(rectangle, [UIColor darkGrayColor].CGColor);
CGContextFillRect(rectangle, CGRectMake(10, 10, 50, 50));
//square
square = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(square, [UIColor darkGrayColor].CGColor);
CGContextFillRect(square, CGRectMake(100, 100, 25, 25));
//triangle
triangle = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(triangle, [UIColor darkGrayColor].CGColor);
CGPoint points[6] = { CGPointMake(100, 200), CGPointMake(150, 250),
CGPointMake(150, 250), CGPointMake(50, 250),
CGPointMake(50, 250), CGPointMake(100, 200) };
CGContextStrokeLineSegments(triangle, points, 6);
}
And now I want to put the graphics into an Array:
-(void)viewDidLoad {
grafics = [[NSMutableArray alloc]initWithObjects: circle,rectangle,square,triangle];
[self.navigationItem.title = #"Shape"];
[super viewDidLoad];
}
The problem is, that I have to make a cast thereby the objects fit into this array. Another problem is that the UITableViewController does not load the array into the rows. There is nothing wrong with the tableview, but a failure with handling CGContext. What I am doing wrong?
drawRect: is a method on UIView used to draw the view itself, not to pre-create graphic objects.
Since it seems that you want to create shapes to store them and draw later, it appears reasonable to create the shapes as UIImage and draw them using UIImageView. UIImage can be stored directly in an NSArray.
To create the images, do the following (on the main queue; not in drawRect:):
1) create a bitmap context
UIGraphicsBeginImageContextWithOptions(size, opaque, scale);
2) get the context
CGContextRef context = UIGraphicsGetCurrentContext();
3) draw whatever you need
4) export the context into an image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
5) destroy the context
UIGraphicsEndImageContext();
6) store the reference to the image
[yourArray addObject:image];
Repeat for each shape you want to create.
For details see the documentation for the above mentioned functions. To get a better understanding of the difference between drawing in drawRect: and in arbitrary place in your program and of working with contexts in general, I would recommend you read the Quartz2D Programming Guide, especially the section on Graphics Contexts.
First, UIGraphicsGetCurrentContext returns CGContextRef, which is not an object and cannot be stored directly in a collection (edit: this is not really true, see the comments). Technically speaking you could wrap the context in an NSValue or turn it into an UIImage:
CGImageRef imageRef = CGBitmapContextCreateImage(context);
UIImage *img = [UIImage imageWithCGImage:imageRef];
The resulting UIImage is an object and can be stored in a collection just fine. But the code sample does not make sense in the big picture. The -drawRect: method is meant to draw your component, not create some graphics to be used later. And -viewDidLoad is a UIViewController method, not a UIView one. Could you edit the question and describe what you are trying to do?

drawRect is not being called

I need to draw an image in a rectangle so for that am using drawRect method.i observed that it is not being called.The output i can see only the blank screen.Am using MAC OS and i need to test the App in Iphone OS 3+.Please can anyone solve my problem.Here is my code:
-(IBAction)calling
{
int a=0;
a=a+1;
[self.view setNeedsDisplay]; //InRect:CGRectMake(78, 43, 200, 138)];
}
- (void)drawRect:(CGRect)rect {
UIImage *myImage = [UIImage imageNamed:#"btbp.jpg"];
CGRect imageRect = CGRectMake(10, 10, 300, 400);
[myImage drawInRect:imageRect];
[self.view setNeedsDisplay];
[myImage release];
}
i donno where i was wrong:(
Is your drawRect method on an actual view? Or is it on the view controller, which is what it seems like? drawRect is something you write/override on the view itself.
You should not call release on the myImage object, since you didn't alloc it yourself.
If this isn't making 100% sense, I'd recommend you start with the iOS Cocoa Views documentation to understand how this all fits together.

Create a colored bubble/circle programmatically in ObjectiveC and Cocoa

Can anyone guide me in the correct way to build a colored bubble/circle programmatically?
I can't use images as I need it to be able to be any color depending on user interaction.
My thought was maybe to make a white circle image and then overlay a color on top of it.
However I am not sure if this would work, or how to really go about it.
If someone could point me the right direction I would appreciate it.
There are a couple steps to drawing something in Cocoa.
First you need a path that will be used to define the object that you are going to be drawing. Take a look here Drawing Fundamental Shapes for a guide on creating paths in Cocoa. You will be most interested in sending the "appendBezierPathWithOvalInRect" message to an "NSBezierPath" object, this takes a rectangle that bounds the circle you want to draw.
This code will create a 10x10 circle at coordinates 10,10:
NSRect rect = NSMakeRect(10, 10, 10, 10);
NSBezierPath* circlePath = [NSBezierPath bezierPath];
[circlePath appendBezierPathWithOvalInRect: rect];
Once you have your path you want to set the color for the current drawing context. There are two colors, stroke and fill; stroke is the outline of the path and the fill is the interior color. To set a color you send "set" to an "NSColor" object.
This sets the stroke to black and the fill to red:
[[NSColor blackColor] setStroke];
[[NSColor redColor] setFill];
Now that you have your path and you have your colors set just fill the path and then draw it:
[path stroke];
[path fill];
All of this will need to be done in a graphics context like in drawRect of a view perhaps. All of this together with a graphics context would look like this:
- (void)drawRect:(NSRect)rect
{
// Get the graphics context that we are currently executing under
NSGraphicsContext* gc = [NSGraphicsContext currentContext];
// Save the current graphics context settings
[gc saveGraphicsState];
// Set the color in the current graphics context for future draw operations
[[NSColor blackColor] setStroke];
[[NSColor redColor] setFill];
// Create our circle path
NSRect rect = NSMakeRect(10, 10, 10, 10);
NSBezierPath* circlePath = [NSBezierPath bezierPath];
[circlePath appendBezierPathWithOvalInRect: rect];
// Outline and fill the path
[circlePath stroke];
[circlePath fill];
// Restore the context to what it was before we messed with it
[gc restoreGraphicsState];
}
You may use simple UIView to create perfect circle with only parameter radius:
// Add framework CoreGraphics.framework
#import <QuartzCore/QuartzCore.h>
-(UIView *)circleWithColor:(UIColor *)color radius:(int)radius {
UIView *circle = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 2 * radius, 2 * radius)];
circle.backgroundColor = color;
circle.layer.cornerRadius = radius;
circle.layer.masksToBounds = YES;
return circle;
}
Create an NSView subclass that holds an NSColor as an ivar. In the drawRect method, create an NSBezierPath of the appropriate size, using the view's bounds. Then set the color [myColor set] and fill the path [myPath fill]. There's a lot more you can do, such as set transparency, a border, and so on and so on, but I'll leave that to the docs unless you have a specific question.
To use the NSView subclass, just drag a view object onto your nib, and choose the name of your subclass in custom class in IB's inspector. You'll need to also set an outlet to it in your controller, so you can change the color as needed.
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(c, 40, 0, 255, 0.1);
CGContextSetRGBStrokeColor(c, 0, 40, 255, 0.5);
// Draw a green solid circle
CGContextSetRGBFillColor(c, 0, 255, 0, 1);
CGContextFillEllipseInRect(c, CGRectMake(100, 100, 25, 25));
Download sketch from apple. http://developer.apple.com/library/mac/#samplecode/Sketch
It can do a lot more, but one of the things is draw circles.