• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /macosx-10.10.1/pyobjc-45/2.6/pyobjc/pyobjc-framework-Quartz/Examples/Core Graphics/Quartz2DBasics/
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