Drawing with Quartz on iOS

43,661 views

Published on

Presentation by Bob McCune of TapHarmonic detailing how to use the Quartz framework to perform 2D drawing on the iOS platform. Quartz Demos: https://github.com/tapharmonic/QuartzDemos

Published in: Technology, Education
2 Comments
70 Likes
Statistics
Notes
No Downloads
Views
Total views
43,661
On SlideShare
0
From Embeds
0
Number of Embeds
7,319
Actions
Shares
0
Downloads
653
Comments
2
Likes
70
Embeds 0
No embeds

No notes for slide

Drawing with Quartz on iOS

  1. 1. Drawing withQuartz on iOS http://bobmccune.com http://tapharmonic.com
  2. 2. Agenda• Overview of the Quartz framework • What is it? • When do you need it?• Key framework functionality: • Contexts and Paths • Drawing lines, curves, and images • Applying transformations• Recipes and Examples
  3. 3. What is Quartz?
  4. 4. What is Quartz?Wasn’t this talk supposed to be about Core Graphics? • 2D drawing engine for Mac and iOS based on the PDF imaging model • Graphics API to produce lines, curves, transformations, gradients, etc. • Uses painters model for drawing operations Drawing Order Result
  5. 5. When do I need it?Isn’t this what graphic designers are for? • Always build your UI from images • Better performance and caching • Easier to create and maintain • Keeps your graphic designers employed • Always, always, always use images... ...until you can’t
  6. 6. Getting Started
  7. 7. Understanding the SyntaxDude, where’s my objects?Objective-CCGContext *context = [[CGContext alloc] init];[context moveToPoint:CGPointMake(12.0f, 12.0f)];[context addLineToPoint:CGPointMake(24.0f, 24.0f)];[context fill];
  8. 8. Understanding the SyntaxDude, where’s my objects?Objective-CCGContext *context = [[CGContext alloc] init]; Quartz is not an Objective-C API[context moveToPoint:CGPointMake(12.0f, 12.0f)];[context addLineToPoint:CGPointMake(24.0f, 24.0f)];[context fill];Standard CCGContextRef context = UIGraphicsGetCurrentContext();CGContextMoveToPoint(context, 12.0f, 12.0f);CGContextAddLineToPoint(context, 24.0f, 24.0f);CGContextFillPath(context);
  9. 9. Quartz is ConsistentNaming ConventionsFunctions always use the following convention: <Type><Action>(<Object>, <Arguments);CGContextMoveToPoint(context, 12.0f, 12.0f);CGPathAddLineToPoint(path, NULL, 22.0f, 100.0f);CGPDFContextClose(context);
  10. 10. Graphics Contexts
  11. 11. Quartz Graphics ContextsThe Canvas • Graphics context provides the drawing area • Manages core drawing states: • Colors, line widths, transforms, etc. • It’s a state machine • Key Quartz Contexts: • CGContext • CGBitmapContext • CGPDFContext
  12. 12. Quartz Coordinate SystemDrawing Orientation • Current Transformation Matrix (CTM) defines the coordinate system • Coordinate system varies on Mac and iOS y Positive 0, 0 x x 0, 0 y Positive Mac OS X iOS
  13. 13. CGContext DrawingQuartz Points • Drawing is p0 defined in terms of points • Points are abstract, infinitely thin • Points live in p1 User Space
  14. 14. Points are Device-IndependentThink in points not pixels p0 p1
  15. 15. CGContext DrawingCGContextRef • CGContextRef is the drawing context • Created by UIKit and AppKit • Get a pointer reference to it: iOS CGContextRef context = UIGraphicsGetCurrentContext(); Mac NSGraphicsContext *current = [NSGraphicsContext currentContext]; CGContextRef context = (CGContextRef)[current graphicsPort];
  16. 16. Getting StartedWhere do I draw?
  17. 17. Getting StartedWhere do I draw?@implementation HelloQuartzViewController- (void)drawBackground:(UIGestureRecognizer *)recognizer { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(context, THRandomColor()); CGContextFillRect(context, self.view.bounds); }@end
  18. 18. Getting StartedWhere do I draw?@implementation HelloQuartzViewController- (void)drawBackground:(UIGestureRecognizer *)recognizer { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(context, THRandomColor()); CGContextFillRect(context, self.view.bounds); }@end@implementation HelloQuartzView- (void)drawRect:(CGRect)rect {}@end
  19. 19. Getting StartedWhere do I draw?@implementation HelloQuartzViewController- (void)drawBackground:(UIGestureRecognizer *)recognizer { // Trigger call to HelloQuartzViews drawRect method (if needed) [self.helloView setNeedsDisplay];}@end@implementation HelloQuartzView- (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(context, THRandomColor()); CGContextFillRect(context, rect); }@end
  20. 20. Basic Paths
  21. 21. CGContext DrawingDefining Paths (0, 0) (100, 100) CGRect rect = CGRectMake(0, 0, 100, 100); CGContextAddRect(context, rect);
  22. 22. CGContext DrawingDefining Paths (0, 0) (100, 100) CGRect rect = CGRectMake(0, 0, 100, 100); CGContextAddEllipseInRect(context, rect);
  23. 23. CGContext DrawingDefining Paths (0, 0) (100, 100) CGContextSetStrokeColorWithColor(context, white); CGContextDrawPath(context, kCGPathStroke);
  24. 24. CGContext DrawingDefining Paths (0, 0) (100, 100) CGContextSetFillColorWithColor(context, yellow); CGContextDrawPath(context, kCGPathFill);
  25. 25. CGContext DrawingDefining Paths (0, 0) (100, 100) CGContextDrawPath(context, kCGPathFillStroke);
  26. 26. Defining ColorsCGColorRef • Colors must be defined before drawing • Fill Colors • CGContextSetFillColor • CGContextSetFillColorWithColor • CGContextSetRGBFillColor • Stroke Colors • CGContextSetStrokeColor • CGContextSetStrokeColorWithColor • CGContextSetRGBStrokeColor
  27. 27. Defining ColorsCGColor vs UIColor • CGColor is the native Quartz color type • UIColor is the native UIKit color type • Use UIColor in almost all cases • Easier to create • Autoreleased convenience initializers • Named color initializers • Easy to convert to and from CGColorCGColorRef redColor = [UIColor redColor].CGColor;CGContextSetFillColorWithColor(context, redColor);
  28. 28. Drawing LinesDefining Paths • Lines are the most essential primitive • Lines are always defined by their endpoints • Basic Recipe: 1.Begin a new path 2.Move to initial starting point 3.Add lines defining shape 4.Optionally close the path 5.Draw Path
  29. 29. CGContext DrawingDefining Paths CGContextBeginPath(context); CGContextMoveToPoint(context, 0.0f, 0.0f);
  30. 30. CGContext DrawingDefining Paths CGContextAddLineToPoint(context, 0.0f, 4.0f);
  31. 31. CGContext DrawingDefining Paths CGContextAddLineToPoint(context, 4.0f, 4.0f);
  32. 32. CGContext DrawingDefining Paths CGContextAddLineToPoint(context, 4.0f, 0.0f);
  33. 33. CGContext DrawingDefining Paths CGContextClosePath(context);
  34. 34. CGContext DrawingDefining Paths CGColorRef color = [UIColor whiteColor].CGColor; CGContextSetFillColorWithColor(context, color);
  35. 35. CGContext DrawingDefining Paths CGContextDrawPath(context, kCGPathFill);
  36. 36. Advanced Paths
  37. 37. Drawing ArcsDefining Paths • Arcs define circle segments • Arcs are defined with the following: • Center point x, y coordinates • Radius • Start and stop angles (in radians) • Direction (clockwise or counter-clockwise) • Created using: • CGContextAddArc • CGContextAddArcToPoint
  38. 38. UIBezierPathMore iOS-friendly solution • Arc functions are not aware of flipped coordinate system • Need to think upside down • Transform coordinate system before using • UIBezierPath provides a lightweight wrapper over Quartz path functionality • Access to underlying path with CGPath property • Easier to use UIBezierPath on iOS
  39. 39. Drawing Arcs Defining PathsUIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:centerPoint radius:radius startAngle:0 endAngle:DEGREES(90) clockwise:NO];CGContextAddPath(context, path.CGPath);
  40. 40. Quadratic Bézier CurvesSingle Control Point p0 CGContextBeginPath(context); CGContextMoveToPoint(context, startPoint.x, startPoint.y);
  41. 41. Quadratic Bézier CurvesSingle Control Point p0 cp p1CGContextAddQuadCurveToPoint(context, cp.x, cp.y, endPoint.x, endPoint.y);
  42. 42. Quadratic Bézier CurvesSingle Control Point p0 cp p1 CGColorRef greenColor = [UIColor greenColor].CGColor; CGContextSetStrokeColorWithColor(context, greenColor); CGContextStrokePath(context);
  43. 43. Cubic Bézier CurvesTwo Control Points p0 CGContextBeginPath(context); CGContextMoveToPoint(context, startPoint.x, startPoint.y);
  44. 44. Cubic Bézier CurvesTwo Control Points cp1 p0 cp2 p1 CGContextAddCurveToPoint(context, cp1.x, cp1.y, cp2.x, cp2.y, endPoint.x, endPoint.y);
  45. 45. Cubic Bézier CurvesTwo Control Points -cp1 cp1 p0 -cp2 cp2 p1 CGContextAddCurveToPoint(context, -cp2.x, cp2.y, -cp1.x, cp1.y, endPoint.x, endPoint.y);
  46. 46. Cubic Bézier CurvesTwo Control Points -cp1 cp1 p0 -cp2 cp2 p1 CGColorRef fillColor = [UIColor redColor].CGColor; CGContextSetFillColorWithColor(context, fillColor); CGContextClosePath(context); CGContextDrawPath(context, kCGPathFillStroke);
  47. 47. Fill RulesTo fill, or not to fill • Quartz uses fill rules to determine what’s inside and outside of a path. • Uses one of the following: • Non-Zero Winding Rule (Default) • Even Odd Rule
  48. 48. Reusable PathsCGPathRef and UIBezierPath • Paths are flushed from context when drawn • CGPath or UIBezierPath should be used when you need a reusable path CGMutablePathRef path = CGPathCreateMutable(); CGPathMoveToPoint(path, NULL, 0, 55); CGPathAddQuadCurveToPoint(path, NULL, -50, 155, 0, 155); CGPathAddQuadCurveToPoint(path, NULL, 50, 155, 0, 55); CGContextAddPath(context, path); CGContextDrawPath(context, kCGPathFillStroke); CGPathRelease(path);
  49. 49. Transformations
  50. 50. Affine TransformationsTransforming the Coordinate System • Affine transformations are essential to all graphics programming regardless of platform • Allow you to manipulate the coordinate system to translate, scale, skew, and rotate • Transform preserves collinearity of lines X
  51. 51. Current Transformation MatrixModifying the CTM • CTM can be modified with the following: • CGContextTranslateCTM • CGContextScaleCTM • CGContextRotateCTM • Additionally can create a CGAffineTransform
  52. 52. CGContextTranslateCTMMoving the Origin Point(0, 0) (100, 100)
  53. 53. CGContextTranslateCTMMoving the Origin Point (0, 0) (0, 0)CGContextTranslateCTM(context, 100.0f, 100.0f);
  54. 54. CGContextScaleCTMScaling the Coordinates(0, 0) (200, 200)
  55. 55. CGContextScaleCTMScaling the Unit Size(0, 0) (200, 200) CGContextScaleCTM(context, 2.0f, 2.0f);
  56. 56. CGContextRotateCTM
  57. 57. CGContextRotateCTM CGContextRotateCTM(context, DEGREES(15));
  58. 58. Gradients
  59. 59. GradientsDrawing Gradients • A gradient is a fill that varies from one color to another • Quartz supports two different gradient types • Linear varies between two endpoints • Radial varies between two radial endpoints Linear Radial
  60. 60. Creating a CGGradientCGGradientRef • Gradients can be created using either: • CGGradientCreateWithColors • CGGradientCreateWithColorComponents • Both functions require the following: • CGColorSpace • Colors (components or array of CGColorRef) • CGFloat[] defining gradient color stops
  61. 61. CGGradientRefBuilding the gradient code// Define ColorsCGColorRef startColor = [UIColor greenColor].CGColor;CGColorRef endColor = [UIColor yellowColor].CGColor;NSMutableArray *colors = [NSMutableArray array];[colors addObject:(id)startColor];[colors addObject:(id)endColor]; // Define Color LocationsCGFloat locations[] = {0.0, 1.0}; // Create GradientCGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (CFArrayRef)colors, locations); // Define start and end points and draw gradientCGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect)); CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
  62. 62. Gradient Examples
  63. 63. Images
  64. 64. Working with ImagesCGImageRef • Quartz has broad support for images • Represented as CGImageRef • Can be drawn using: • CGContextDrawImage • CGContextDrawTiledImage • CGBitmapContext allows for dynamically building image data
  65. 65. CGImage vs UIImageWhich should I use? • Don’t draw in Quartz. Use UIImageView. • Choose UIImage over CGImage • Easier to load and cache image content • Provides methods for drawing • Is aware of flipped coordinate system • Easy to convert to and from CGImage • Use CGImage for more advanced cases • Cropping, scaling, masking • Dynamic image creation
  66. 66. Using Image MasksHiding behind a mask
  67. 67. Using Image Masks Hiding behind a mask UIImage *maskImage = [UIImage imageNamed:@"round_mask"]; UIImage *jeffersonImage = [UIImage imageNamed:@"jefferson"]; CGImageRef maskRef = maskImage.CGImage; CGImageRef imageMask = CGImageMaskCreate(CGImageGetWidth(maskRef), CGImageGetHeight(maskRef), CGImageGetBitsPerComponent(maskRef), CGImageGetBitsPerPixel(maskRef), CGImageGetBytesPerRow(maskRef), CGImageGetDataProvider(maskRef), NULL, false); CGImageRef masked = CGImageCreateWithMask(jeffersonImage, imageMask); UIImage *maskedImage = [UIImage imageWithCGImage:masked];
  68. 68. Cropping ImagesCGImageCreateWithImageInRectUIImage *albumImage = [UIImage imageNamed:@"vh1"];CGRect cropRect = CGRectMake(20.0f, 20.0f, 200.0f, 200.0f);CGImageRef image = CGImageCreateWithImageInRect(albumImage.CGImage, cropRect); CGRect imageRect = CGRectMake(0.0f, 0.0f, 200.0f, 200.0f); // Draw image in current context[[UIImage imageWithCGImage:image] drawInRect:imageRect]; CGImageRelease(image);
  69. 69. Summary• Quartz is a powerful, comprehensive drawing engine and API for Apple platforms• Fairly steep learning curve, but consistent interface helps considerably• Understanding is essential to building beautiful apps on Mac and iOS
  70. 70. ResourcesQuartz 2D Programming Guidehttp://developer.apple.com/Quartz Demoshttps://github.com/tapharmonic/QuartzDemosProgramming with QuartzDavid GelphmanBunny Laden

×