1from UIHandling import * 2from Quartz import * 3import math 4 5kOurImageFile = "ptlobos.tif" 6 7# For best performance make bytesPerRow a multiple of 16 bytes. 8BEST_BYTE_ALIGNMENT = 16 9def COMPUTE_BEST_BYTES_PER_ROW(bpr): 10 return ((bpr + (BEST_BYTE_ALIGNMENT-1)) & ~(BEST_BYTE_ALIGNMENT-1)) 11 12def DEGREES_TO_RADIANS(degrees): 13 return degrees * math.pi / 180 14 15_colorSpace = None 16def myGetGenericRGBSpace(): 17 global _colorSpace 18 19 if _colorSpace is None: 20 _colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB) 21 22 return _colorSpace 23 24_blue = None 25def myGetBlueColor(): 26 global _blue 27 28 if _blue is None: 29 _blue = CGColorCreate(myGetGenericRGBSpace(), (0, 0, 1, 1)) 30 31 return _blue 32 33_green = None 34def myGetGreenColor(): 35 global _green 36 37 if _green is None: 38 _green = CGColorCreate(myGetGenericRGBSpace(), (0, 1, 0, 1)) 39 40 return _green 41 42_red = None 43def myGetRedColor(): 44 global _red 45 46 if _red is None: 47 _red = CGColorCreate(myGetGenericRGBSpace(), (1, 0, 0, 1)) 48 49 return _red 50 51_ourImageURL = None 52def doDrawImageFile(context, doclip): 53 global _ourImageURL 54 55 if _ourImageURL is None: 56 mainBundle = CFBundleGetMainBundle() 57 if mainBundle: 58 _ourImageURL = CFBundleCopyResourceURL(mainBundle, kOurImageFile, None, None) 59 60 else: 61 print "Can't get the app bundle!" 62 63 if _ourImageURL: 64 if doclip: 65 clipImageToEllipse(context, _ourImageURL) 66 else: 67 drawCGImage(context, _ourImageURL) 68 69 else: 70 print "Couldn't create the URL for our Image file!" 71 72 73def myDispatchDrawing(context, drawingType): 74 if drawingType == kCommandStrokedAndFilledRects: 75 drawStrokedAndFilledRects(context) 76 77 elif drawingType == kCommandAlphaRects: 78 drawAlphaRects(context) 79 80 elif drawingType == kCommandSimpleClip: 81 doDrawImageFile(context, True) 82 83 elif drawingType == kCommandDrawImageFile: 84 doDrawImageFile(context, False) 85 86 elif drawingType == kCommandDoUncachedDrawing: 87 drawUncachedForLayer(context) 88 89 elif drawingType == kCommandDoCGLayer: 90 drawSimpleCGLayer(context) 91 92def drawStrokedAndFilledRects(context): 93 ourRect = CGRectMake(40, 40, 130, 100) 94 95 # Set the fill color to an opaque blue. 96 CGContextSetFillColorWithColor(context, myGetBlueColor()) 97 # Fill the rect. 98 CGContextFillRect(context, ourRect) 99 100 # Set the stroke color to an opaque green. 101 CGContextSetStrokeColorWithColor(context, myGetGreenColor()) 102 # Stroke the rect with a line width of 10 units. 103 CGContextStrokeRectWithWidth(context, ourRect, 10) 104 105 # Save the current graphics state. 106 CGContextSaveGState(context) 107 # Translate the coordinate system origin to the right 108 # by 200 units. 109 CGContextTranslateCTM(context, 200, 0) 110 # Stroke the rect with a line width of 10 units. 111 CGContextStrokeRectWithWidth(context, ourRect, 10) 112 # Fill the rect. 113 CGContextFillRect(context, ourRect) 114 # Restore the graphics state to the previously saved 115 # graphics state. This restores all graphics state 116 # parameters to those in effect during the last call 117 # to CGContextSaveGState. In this example that restores 118 # the coordinate system to that in effect prior to the 119 # call to CGContextTranslateCTM. 120 CGContextRestoreGState(context) 121 122# Create a mutable path object that represents 'rect'. 123# Note that this is for demonstrating how to create a simple 124# CGPath object. The Quartz function CGPathAddRect would normally 125# be a better choice for adding a rect to a CGPath object. 126def createRectPath(rect): 127 path = CGPathCreateMutable() 128 129 # Start a new subpath. 130 CGPathMoveToPoint(path, None, rect.origin.x, rect.origin.y) 131 132 # ***** Segment 1 ***** 133 CGPathAddLineToPoint(path, None, rect.origin.x + rect.size.width, rect.origin.y) 134 135 # ***** Segment 2 ***** 136 CGPathAddLineToPoint(path, None, rect.origin.x + rect.size.width, 137 rect.origin.y + rect.size.height) 138 139 # ***** Segment 3 ***** 140 CGPathAddLineToPoint(path, None, rect.origin.x, rect.origin.y + rect.size.height) 141 142 # ***** Segment 4 is created by closing the path ***** 143 CGPathCloseSubpath(path) 144 145 return path 146 147 148def drawAlphaRects(context): 149 ourRect = CGRectMake(0, 0, 130, 100) 150 numRects = 6 151 rotateAngle = 2*math.pi/numRects 152 tintAdjust = 1.0/numRects 153 154 # Create the path object representing our rectangle. This 155 # example is for demonstrating the use of a CGPath object. 156 # For a simple rectangular shape, you'd typically use 157 # CGContextFillRect or CGContextStrokeRect instead of this 158 # approach. 159 path = createRectPath(ourRect) 160 161 # Move the origin of coordinates to a location that allows 162 # the drawing to be within the window. 163 CGContextTranslateCTM(context, 2*ourRect.size.width, 164 2*ourRect.size.height) 165 166 # Set the fill color to a red color. 167 CGContextSetFillColorWithColor(context, myGetRedColor()) 168 169 tint = 1.0 170 while 0 < tint: 171 # Set the global alpha to the tint value. 172 CGContextSetAlpha(context, tint) 173 174 # For a CGPath object that is a simple rect, 175 # this is equivalent to CGContextFillRect. 176 CGContextBeginPath(context) 177 CGContextAddPath(context, path) 178 CGContextFillPath(context) 179 180 # These transformations are cummulative. 181 CGContextRotateCTM(context, rotateAngle) 182 183 tint -= tintAdjust 184 185def drawCGImage(context, url): 186 # Create a CGImageSource object from 'url'. 187 imageSource = CGImageSourceCreateWithURL(url, None) 188 189 # Create a CGImage object from the first image in the file. Image 190 # indexes are 0 based. 191 image = CGImageSourceCreateImageAtIndex(imageSource, 0, None) 192 193 # Create a rectangle that has its origin at (100, 100) with the width 194 # and height of the image itself. 195 imageRect = CGRectMake(100, 100, CGImageGetWidth(image), CGImageGetHeight(image)) 196 197 # Draw the image into the rect. 198 CGContextDrawImage(context, imageRect, image) 199 200def clipImageToEllipse(context, url): 201 # Create a CGImageSource object from 'url'. 202 imageSource = CGImageSourceCreateWithURL(url, None) 203 204 # Create a CGImage object from the first image in the file. Image 205 # indexes are 0 based. 206 image = CGImageSourceCreateImageAtIndex( imageSource, 0, None ) 207 208 # Create a rectangle that has its origin at (100, 100) with the width 209 # and height of the image itself. 210 imageRect = CGRectMake(100, 100, CGImageGetWidth(image), CGImageGetHeight(image)) 211 212 CGContextBeginPath(context) 213 # Create an elliptical path corresponding to the image width and height. 214 CGContextAddEllipseInRect(context, imageRect) 215 # Clip to the current path. 216 CGContextClip(context) 217 218 # Draw the image into the rect, clipped by the ellipse. 219 CGContextDrawImage(context, imageRect, image) 220 221def createRGBAImageFromQuartzDrawing(dpi, drawingCommand): 222 # For generating RGBA data from drawing. Use a Letter size page as the 223 # image dimensions. Typically this size would be the minimum necessary to 224 # capture the drawing of interest. We want 8 bits per component and for 225 # RGBA data there are 4 components. 226 width = 8.5*dpi 227 height = 11*dpi 228 bitsPerComponent = 8 229 numComps = 4 230 # Compute the minimum number of bytes in a given scanline. 231 bytesPerRow = width* bitsPerComponent/8 * numComps 232 233 # This bitmapInfo value specifies that we want the format where alpha is 234 # premultiplied and is the last of the components. We use this to produce 235 # RGBA data. 236 bitmapInfo = kCGImageAlphaPremultipliedLast 237 238 # Round to nearest multiple of BEST_BYTE_ALIGNMENT for optimal performance. 239 bytesPerRow = COMPUTE_BEST_BYTES_PER_ROW(bytesPerRow) 240 241 # Allocate the data for the bitmap. 242 data = array.array('c', '\0' * bytesPerRow * height) 243 244 # Create the bitmap context. Characterize the bitmap data with the 245 # Generic RGB color space. 246 bitmapContext = CGBitmapContextCreate( 247 data, width, height, bitsPerComponent, bytesPerRow, 248 myGetGenericRGBSpace(), bitmapInfo) 249 250 # Clear the destination bitmap so that it is completely transparent before 251 # performing any drawing. This is appropriate for exporting PNG data or 252 # other data formats that capture alpha data. If the destination output 253 # format doesn't support alpha then a better choice would be to paint 254 # to white. 255 CGContextClearRect(bitmapContext, CGRectMake(0, 0, width, height)) 256 257 # Scale the coordinate system so that 72 units are dpi pixels. 258 CGContextScaleCTM(bitmapContext, dpi/72, dpi/72) 259 260 # Perform the requested drawing. 261 myDispatchDrawing(bitmapContext, drawingCommand) 262 263 # Create a CGImage object from the drawing performed to the bitmapContext. 264 image = CGBitmapContextCreateImage(bitmapContext) 265 266 # Return the CGImage object this code created from the drawing. 267 return image 268 269def myExportCGDrawingAsPNG(url, drawingCommand): 270 dpi = 300 271 # Create an RGBA image from the Quartz drawing that corresponds to drawingCommand. 272 image = createRGBAImageFromQuartzDrawing(dpi, drawingCommand) 273 274 # Create a CGImageDestination object will write PNG data to URL. 275 # We specify that this object will hold 1 image. 276 imageDestination = CGImageDestinationCreateWithURL(url, kUTTypePNG, 1, None) 277 278 properties = { 279 kCGImagePropertyDPIWidth: dpi, 280 kCGImagePropertyDPIHeight: dpi, 281 } 282 283 # Add the image to the destination, characterizing the image with 284 # the properties dictionary. 285 CGImageDestinationAddImage(imageDestination, image, properties) 286 287 # When all the images (only 1 in this example) are added to the destination, 288 # finalize the CGImageDestination object. 289 CGImageDestinationFinalize(imageDestination) 290 291 292def createCachedContent(c): 293 # The cached content will be 50x50 units. 294 width = height = 50 295 296 # Create the layer to draw into. 297 layer = CGLayerCreateWithContext(c, CGSizeMake(width, height), None) 298 299 # Get the CG context corresponding to the layer. 300 layerContext = CGLayerGetContext(layer) 301 302 # Cache some very simple drawing just as an example. 303 CGContextFillRect(layerContext, CGRectMake(0, 0, width, height) ) 304 305 # The layer now contains cached drawing so return it. 306 return layer 307 308def drawSimpleCGLayer(context): 309 # Create a CGLayer object that represents some drawing. 310 layer = createCachedContent(context) 311 312 # Get the size of the layer created. 313 s = CGLayerGetSize(layer); 314 315 # Position the drawing to an appropriate location. 316 CGContextTranslateCTM(context, 40, 100) 317 318 # Paint 4 columns of layer objects. 319 for i in range(4): 320 # Draw the layer at the point that varies as the code loops. 321 CGContextDrawLayerAtPoint(context, 322 CGPointMake(2*(i+1)*s.width, 0), 323 layer) 324 325# The equivalent drawing as doSimpleCGLayer but without creating 326# a CGLayer object and caching that drawing to a layer. 327def drawUncachedForLayer(context): 328 r = CGRectMake(0, 0, 50, 50) 329 330 CGContextTranslateCTM(context, 40, 100) 331 332 for i in range(4): 333 # Adjust the origin as the code loops. Recall that 334 # transformations are cummulative. 335 CGContextTranslateCTM( context, 2*CGRectGetWidth(r), 0 ) 336 CGContextFillRect(context, r) # Do the uncached drawing. 337 338# Create a PDF document at 'url' from the drawing represented by drawingCommand. 339def myCreatePDFDocument(url, drawingCommand): 340 # mediaRect represents the media box for the PDF document the code is 341 # creating. The size here is that of a US Letter size sheet. 342 mediaRect = CGRectMake(0, 0, 8.5*72, 11*72) 343 344 # Create a CGContext object to capture the drawing as a PDF document located 345 # at 'url'. 346 pdfContext, mediaRect = CGPDFContextCreateWithURL(url, mediaRect, None) 347 348 # Start capturing drawing on a page. 349 mediaRect = CGContextBeginPage(pdfContext, mediaRect) 350 351 # Perform drawing for the first page. 352 myDispatchDrawing(pdfContext, drawingCommand) 353 354 # Tell the PDF context that drawing for the current page is finished. 355 CGContextEndPage(pdfContext) 356 357 # If there were more pages they would be captured as: 358 # 359 # mediaRect = CGContextBeginPage(pdfContext, None) 360 # 361 # DrawingForPage2(pdfContext) 362 # 363 # CGContextEndPage(pdfContext) 364 # 365 # mediaRect = CGContextBeginPage(pdfContext, None) 366 # 367