• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /macosx-10.10.1/pyobjc-45/2.6/pyobjc/pyobjc-framework-Quartz/Examples/Programming with Quartz/BasicDrawing/
1from Quartz import *
2import Utilities
3
4import sys
5
6def scalePatternPhase(phase):
7    # Adjust the pattern phase if scaling to export as bits. This is equivalent to scaling base
8    # space by the scaling factor.
9    patternScaling = Utilities.getScalingFactor()
10    if patternScaling != 1.0:
11        phase = CGSizeApplyAffineTransform(phase,
12            CGAffineTransformMakeScale(patternScaling, patternScaling))
13
14    return phase
15
16def scalePatternMatrix(patternTransform):
17    # Scale the pattern by the scaling factor when exporting to bits. This is equivalent to
18    # scaling base space by the scaling factor.
19    patternScaling = Utilities.getScalingFactor()
20    if patternScaling != 1.0:
21        patternTransform = CGAffineTransformConcat(patternTransform,
22                CGAffineTransformMakeScale(patternScaling, patternScaling))
23
24    return patternTransform
25
26
27def myDrawRedBlackCheckerBoardPattern(info, patternCellContext):
28    # This pattern proc draws a red and a black rectangle
29    # patch representing the minimum cell needed to paint a
30    # checkerboard with that pattern.
31    #
32    # Each 'cell' of the checkerboard is 2 units on a side.
33    #
34    # This code uses CGColorRefs which are available in Panther
35    # and later only. Patterns are available in all versions of
36    # Mac OS X but this code uses CGColorRefs for convenience
37    # and efficiency.
38
39    # Paint a black checkerboard box.
40    CGContextSetFillColorWithColor(patternCellContext,
41            Utilities.getRGBOpaqueBlackColor())
42    # This is a 1x1 unit rect whose origin is at 0,0 in pattern space.
43    CGContextFillRect(patternCellContext, CGRectMake(0.0, 0.0, 1.0, 1.0))
44    # This is a 1x1 unit rect whose origin is at 1,1 in pattern space.
45    CGContextFillRect(patternCellContext, CGRectMake(1.0, 1.0, 1.0, 1.0))
46
47    # Paint a red checkerboard box.
48    CGContextSetFillColorWithColor(patternCellContext,
49            Utilities.getRGBOpaqueRedColor())
50    # This is a 1x1 unit rect whose origin is at 1,0 in pattern space,
51    # that is, immediately to the right of first black checkerboard box.
52    CGContextFillRect(patternCellContext, CGRectMake(1.0, 0.0, 1.0, 1.0))
53    # This is a 1x1 unit rect whose origin is at 0,1 in pattern space,
54    # that is, immediately above the first black checkerboard box.
55    CGContextFillRect(patternCellContext, CGRectMake(0.0, 1.0, 1.0, 1.0))
56
57def createRedBlackCheckerBoardPattern(patternTransform):
58    pattern = CGPatternCreate(None,
59        # The pattern cell origin is at (0,0) with a
60        # width of 2 units and a height of 2 units.
61        CGRectMake(0, 0, 2, 2),
62        # Use the pattern transform supplied to this routine.
63        scalePatternMatrix(patternTransform),
64        # In pattern space the xStep is 2 units to the next cell in x
65        # and the yStep is 2 units to the next row of cells in y.
66        2, 2,
67        # This value is a good choice for this type of pattern and it
68        # avoids seams between tiles.
69        kCGPatternTilingConstantSpacingMinimalDistortion,
70        # This pattern has intrinsic color.
71        True,
72        (
73            myDrawRedBlackCheckerBoardPattern,
74            None
75        ))
76    return pattern
77
78def doRedBlackCheckerboard(context):
79    dash = [4]
80    pattern = createRedBlackCheckerBoardPattern(
81			    CGAffineTransformMakeScale(20, 20))
82    if pattern is None:
83        print >>sys.stderr, "Couldn't create pattern!"
84        return
85
86    # Create the pattern color space. Since the pattern
87    # itself has intrinsic color, the 'baseColorSpace' parameter
88    # to CGColorSpaceCreatePattern must be None.
89    patternColorSpace = CGColorSpaceCreatePattern(None)
90    CGContextSetFillColorSpace(context, patternColorSpace)
91
92    # The pattern has intrinsic color so the color components array
93    # passed to CGContextSetFillPattern is just the alpha value used
94    # to composite the pattern cell.
95
96    # Paint the pattern with alpha = 1.
97    color = [1.0]
98
99    # Set the fill color to the checkerboard pattern.
100    CGContextSetFillPattern(context, pattern, color)
101
102    # Fill a 100x100 unit rect at (20,20).
103    CGContextFillRect(context, CGRectMake(20, 20, 100, 100))
104
105    # Save the graphics state before changing the stroke color.
106    CGContextSaveGState(context)
107    if 1:
108	# Set the stroke color space and color to the pattern.
109	CGContextSetStrokeColorSpace(context, patternColorSpace)
110	CGContextSetStrokePattern(context, pattern, color)
111
112	# Stroke an ellipse with the pattern.
113	CGContextSetLineWidth(context, 8)
114	CGContextBeginPath(context)
115	Utilities.myCGContextAddEllipseInRect(context, CGRectMake(120, 20, 50, 100))
116	CGContextStrokePath(context)
117
118    # Restore to the graphics state without the
119    # pattern stroke color.
120    CGContextRestoreGState(context)
121
122    # Now draw text.
123    CGContextSetTextMatrix(context, CGAffineTransformIdentity)
124    # Choose the font with the PostScript name "Times-Roman",
125    # size 80 points, with the encoding MacRoman encoding.
126    CGContextSelectFont(context, "Times-Roman", 80, kCGEncodingMacRoman)
127
128    # Using the fill text drawing mode.
129    CGContextSetTextDrawingMode(context, kCGTextFill)
130
131    # Draw text with the pattern.
132    CGContextShowTextAtPoint(context, 20, 120, "Text", 4)
133
134    # Rectangle 1, filled.
135    CGContextFillRect(context, CGRectMake(200, 20, 90, 90))
136
137    # Rectangle 2, filled and stroked with a dash.
138    CGContextSetLineWidth(context, 2)
139    CGContextSetLineDash(context, 0, dash, 1)
140    CGContextBeginPath(context)
141    CGContextAddRect(context, CGRectMake(200, 70, 90, 90))
142    CGContextDrawPath(context, kCGPathFillStroke)
143
144def doPatternMatrix(context):
145    basePatternMatrix = CGAffineTransformMakeScale(20, 20)
146    pattern = createRedBlackCheckerBoardPattern(basePatternMatrix)
147    if pattern is None:
148        print >>sys.stderr, "Couldn't create pattern!"
149        return
150
151    # Create the pattern color space. Since the pattern
152    # itself has intrinsic color, the 'baseColorSpace' parameter
153    # to CGColorSpaceCreatePattern must be None.
154    patternColorSpace = CGColorSpaceCreatePattern(None)
155
156    CGContextSetFillColorSpace(context, patternColorSpace)
157    del patternColorSpace
158
159    CGContextTranslateCTM(context, 40, 40)
160    CGContextSetPatternPhase(context, scalePatternPhase(CGSize(40, 40)))
161
162    # The pattern has intrinsic color so the color components array
163    # passed to CGContextSetFillPattern is the alpha value used
164    # to composite the pattern cell.
165
166    # Paint the pattern first with alpha = 1.
167    color = [1]
168    CGContextSetFillPattern(context, pattern, color)
169
170    # Rectangle 1.
171    CGContextFillRect(context, CGRectMake(0, 0, 100, 100))
172
173    CGContextSaveGState(context)
174    if 1:
175	# Rectangle 2.
176	# Paint the pattern with 65% alpha.
177	color = [0.65]
178	CGContextSetFillPattern(context, pattern, color)
179	# Rotate 45 degrees about the point (150, 50).
180	CGContextTranslateCTM(context, 150.0, 50.0)
181	CGContextRotateCTM(context, Utilities.DEGREES_TO_RADIANS(45.0))
182	CGContextTranslateCTM(context, -50.0, -50.0)
183	# Rectangle 2. Patterns do not translate, scale or
184	# rotate with the CTM. You can see that the pattern
185	# tile of this filled rectangle is that of Rectangle
186	# 1.
187	CGContextFillRect(context, CGRectMake(0, 0, 100, 100))
188	# Release the pattern.
189	del pattern
190    CGContextRestoreGState(context)
191
192    CGContextSaveGState(context)
193    if 1:
194	# Rectangle 3. The pattern is rotated with the object.
195	# Rotate 45 degrees about the point 250, 50.
196	t = CGAffineTransformMakeTranslation(250.0, 50.0)
197	t = CGAffineTransformRotate(t, Utilities.DEGREES_TO_RADIANS(45.0))
198	# Translate back to -50, -50.
199	t = CGAffineTransformTranslate(t, -50.0, -50.0)
200	CGContextConcatCTM(context, t)
201	# Make a new pattern that is equivalent to
202	# the old pattern but transformed to current user
203	# space. The order of transformations is crucial.
204	# This ordering is equivalent to using the same pattern
205	# matrix as before but transforming base space by t.
206	patTransform = CGAffineTransformConcat(basePatternMatrix, t)
207	pattern = createRedBlackCheckerBoardPattern(patTransform)
208	color = [1]
209	CGContextSetFillPattern(context, pattern, color)
210	# Release the pattern.
211	del pattern
212	CGContextFillRect(context, CGRectMake(0, 0, 100, 100))
213    CGContextRestoreGState(context)
214
215    CGContextSaveGState(context)
216    if 1:
217	# Rectangle 4. The pattern is scaled with the object.
218	# Translate and scale.
219	t = CGAffineTransformMakeTranslation(320, 0)
220	t = CGAffineTransformScale(t, 2, 2)
221	CGContextConcatCTM(context, t)
222	# Make a new pattern that is equivalent to
223	# the old pattern but transformed to current user
224	# space. The order of transformations is crucial.
225	# This ordering is equivalent to using the same pattern
226	# matrix as before but transforming base space by t.
227	patTransform = CGAffineTransformConcat(basePatternMatrix, t)
228	pattern = createRedBlackCheckerBoardPattern(patTransform)
229	color = [1]
230	CGContextSetFillPattern(context, pattern, color)
231	# Release the pattern.
232	del pattern
233	CGContextFillRect(context, CGRectMake(0, 0, 100, 100))
234    CGContextRestoreGState(context)
235
236
237def doPatternPhase(context):
238    pattern = createRedBlackCheckerBoardPattern(
239			    CGAffineTransformMakeScale(20, 20))
240    if pattern is None:
241        print >>sys.stderr, "Couldn't create pattern!"
242        return
243
244    # Create the pattern color space for a colored pattern.
245    patternColorSpace = CGColorSpaceCreatePattern(None)
246    CGContextSetFillColorSpace(context, patternColorSpace)
247
248    # Paint the pattern with alpha = 1.
249    color = (1,)
250    CGContextSetFillPattern(context, pattern, color)
251
252    # Rectangle 1
253    CGContextFillRect(context, CGRectMake(20, 150, 100, 100))
254
255    # Rectangle 2
256    CGContextFillRect(context, CGRectMake(130, 150, 100, 100))
257
258    # Rectangle 3
259    # Set the pattern phase so that the pattern origin
260    # is at the lower-left of the shape.
261    CGContextSetPatternPhase(context, scalePatternPhase( CGSizeMake(20, 20) ))
262    CGContextFillRect(context, CGRectMake(20, 20, 100, 100))
263
264    # Rectangle 4
265    # Set the pattern phase so that the pattern origin
266    # is at the lower-left corner of the shape.
267    CGContextSetPatternPhase(context, scalePatternPhase( CGSizeMake(130, 20) ))
268    CGContextTranslateCTM(context, 130, 20)
269    CGContextFillRect(context, CGRectMake(0, 0, 100, 100))
270
271def drawRotatedRect(c, p):
272    r = CGRectMake(0, 0, 1, 1)
273    CGContextSaveGState(c)
274    if 1:
275	CGContextTranslateCTM(c, p.x, p.y)
276	CGContextRotateCTM(c, Utilities.DEGREES_TO_RADIANS(45))
277	CGContextTranslateCTM(c, -r.size.width/2, -r.size.height/2)
278	CGContextFillRect(c, r)
279    CGContextRestoreGState(c)
280
281def myStencilPatternProc(info, patternCellContext):
282    drawRotatedRect(patternCellContext, CGPointMake(1, 1))
283    drawRotatedRect(patternCellContext, CGPointMake(1.75, 1))
284
285def createStencilPattern(patternTransform):
286    pattern = CGPatternCreate(None,
287		# The pattern cell origin is at (0,0) with a
288		# width of 2.5 units and a height of 2 units. This
289		# pattern cell has transparent areas since
290		# the pattern proc only marks a portion of the cell.
291		CGRectMake(0, 0, 2.5, 2),
292		# Use the pattern transform supplied to this routine.
293		scalePatternMatrix(patternTransform),
294		# Use the width and height of the pattern cell for
295		# the xStep and yStep.
296		2.5, 2,
297		# This value is a good choice for this type of pattern and it
298		# avoids seams between tiles.
299		kCGPatternTilingConstantSpacingMinimalDistortion,
300		# This pattern does not have intrinsic color.
301		False,   # Must be False for a stencil pattern.
302		(
303                    myStencilPatternProc,
304                    None,
305                ))
306    return pattern
307
308def doStencilPattern(context):
309    pattern = createStencilPattern(CGAffineTransformMakeScale(20, 20))
310    if pattern is None:
311        print >>sys.stderr, "Couldn't create pattern!"
312        return
313
314    # Create the pattern color space. This pattern is a stencil
315    # pattern so when the code sets the pattern it also sets the
316    # color it will paint the pattern with. In order to
317    # set the pattern color space in this case we also have
318    # to say what underlying color space should be used when
319    # the pattern proc is called.
320    baseColorSpace = Utilities.getTheCalibratedRGBColorSpace()
321    patternColorSpace = CGColorSpaceCreatePattern(baseColorSpace)
322
323    CGContextSetFillColorSpace(context, patternColorSpace)
324    # This code is finished with the pattern color space and can release
325    # it because Quartz retains it while it is the current color space.
326    del patternColorSpace
327
328    # The pattern has no intrinsic color so the color components array
329    # passed to CGContextSetFillPattern contains the colors to paint
330    # the pattern with in the baseColorSpace. In the case here,
331    # first paint the pattern with opaque blue.
332    color = (0.11, 0.208, 0.451, 1.0)
333    CGContextSetFillPattern(context, pattern, color)
334
335    # Rectangle 1.
336    CGContextSetPatternPhase(context, scalePatternPhase( CGSizeMake(20, 160) ))
337    CGContextBeginPath(context)
338    CGContextAddRect(context, CGRectMake(20, 160, 105, 80))
339    CGContextDrawPath(context, kCGPathFillStroke)
340
341    # Rectangle 2.
342    # Set the pattern color so the stencil pattern
343    # is painted in a yellow shade.
344    color = (1.0, 0.816, 0.0, 1.0)
345    CGContextSetFillPattern(context, pattern, color)
346    # Set the pattern phase to the origin of the next object.
347    CGContextSetPatternPhase(context, scalePatternPhase( CGSizeMake(140, 160) ))
348    CGContextBeginPath(context)
349    CGContextAddRect(context, CGRectMake(140, 160, 105, 80))
350    CGContextDrawPath(context, kCGPathFillStroke)
351
352    CGContextSaveGState(context)
353    if 1:
354        CGContextSetFillColorWithColor(context,
355                Utilities.getRGBOpaqueBlueColor())
356        # Fill color is now blue. Paint two blue rectangles
357        # that will be underneath the drawing which follows.
358        CGContextFillRect(context, CGRectMake(20, 40, 105, 80))
359        CGContextFillRect(context, CGRectMake(140, 40, 105, 80))
360    CGContextRestoreGState(context)
361
362    # The fill color is again the stencil pattern with
363    # the underlying fill color an opaque yellow.
364
365    # Rectangle 3.
366    # This paints over the blue rect just painted at 20,40
367    # and the blue underneath is visible where the pattern has
368    # transparent areas.
369    CGContextSetPatternPhase(context, scalePatternPhase( CGSizeMake(20, 40) ))
370    CGContextFillRect(context, CGRectMake(20, 40, 105, 80))
371
372    # Rectangle 4.
373    # Change the alpha value of the underlying color used
374    # to paint the stencil pattern.
375    color = list(color)
376    color[3] = 0.75
377    CGContextSetFillPattern(context, pattern, color)
378    CGContextSetPatternPhase(context, scalePatternPhase( CGSizeMake(140, 40) ))
379    CGContextFillRect(context, CGRectMake(140, 40, 105, 80))
380
381class MyPDFPatternInfo (object):
382    rect = None
383    pdfDoc = None
384
385def myDrawPDFPattern(info, patternCellContext):
386    # This pattern proc draws the first page of a PDF document to
387    # a destination rect.
388    CGContextSaveGState(patternCellContext)
389    CGContextClipToRect(patternCellContext, info.rect)
390    CGContextDrawPDFDocument(patternCellContext, info.rect, info.pdfDoc, 1)
391    CGContextRestoreGState(patternCellContext)
392
393# Versions of Tiger prior to 10.4.3 have a bug such that use of an xStep that
394# doesn't match the width of pattern bounding box or a yStep that doesn't match the
395# height of the pattern bounding box produces incorrect results when drawn
396# to a bit-based context. Setting TIGERSTEPWORKAROUND works around this bug.
397
398
399TIGERSTEPWORKAROUND=1
400SCALEPATTERN=1
401OPTIMIZEDPERF=0
402
403
404def createPDFPatternPattern(additionalTransformP, url):
405    patternInfoP = MyPDFPatternInfo()
406
407    patternInfoP.pdfDoc = CGPDFDocumentCreateWithURL(url)
408    if patternInfoP.pdfDoc is None:
409        print >>sys.stderr, "Couldn't create PDF document reference!"
410        return
411
412    patternInfoP.rect = CGPDFDocumentGetMediaBox(patternInfoP.pdfDoc, 1)
413    # Set the origin of the media rect for the PDF document to (0,0).
414    patternInfoP.rect.origin = CGPointZero
415
416    if additionalTransformP is not None:
417        patternTransform = additionalTransformP
418    else:
419        patternTransform = CGAffineTransformIdentity
420
421    # To emulate the example from the bitmap context drawing chapter,
422    # the tile offset in each dimension is the tile size in that
423    # dimension, plus 6 units.
424    if SCALEPATTERN:
425        tileOffsetX = 6. + patternInfoP.rect.size.width
426        tileOffsetY = 6. + patternInfoP.rect.size.height
427    else:
428        tileOffsetX = 2. + patternInfoP.rect.size.width
429        tileOffsetY = 2. + patternInfoP.rect.size.height
430
431    # Tiger versions 10.4.0 - 10.4.2 have a bug such that the bounds
432    # width and height is incorrectly used as the xstep,ystep.
433    # To workaround this bug, we can make the bounds rect incorporate
434    # the xstep,ystep since xstep,ystep are larger than the bounds.
435    if OPTIMIZEDPERF or TIGERSTEPWORKAROUND:
436        patternRect = CGRectMake(0, 0, tileOffsetX, tileOffsetY)
437    else:
438        patternRect = patternInfoP.rect
439
440    if OPTIMIZEDPERF:
441        # Produces best performance if bbox == xstep/ystep
442        spacing = kCGPatternTilingConstantSpacing
443    else:
444        spacing = kCGPatternTilingConstantSpacingMinimalDistortion
445
446    pattern = CGPatternCreate(patternInfoP,
447	    # The pattern cell size is the size
448	    # of the media rect of the PDF document.
449            patternRect,
450	    scalePatternMatrix(patternTransform),
451	    tileOffsetX, tileOffsetY,
452	    # This value is a good choice for this type of pattern and
453	    #  it avoids seams between tiles.
454            spacing,
455	    # This pattern has intrinsic color.
456	    True,
457	    (
458                myDrawPDFPattern,
459                None,
460            ))
461    # If the pattern can't be created then release the
462    # pattern resources and info parameter.
463    if pattern is None:
464        patternInfoP = None
465
466    return pattern
467
468
469def drawWithPDFPattern(context, url):
470    if SCALEPATTERN:
471        patternMatrix = CGAffineTransformMakeScale(1.0/3, 1.0/3)
472    else:
473        patternMatrix = CGAffineTransformMakeScale(1, 1)
474
475    # Scale the PDF pattern down to 1/3 its original size.
476    pdfPattern = createPDFPatternPattern(patternMatrix, url)
477    if pdfPattern is None:
478        print >>sys.stderr, "Couldn't create pattern!"
479        return
480
481    # Create the pattern color space. Since the pattern
482    # itself has intrinsic color, the 'baseColorSpace' parameter
483    # to CGColorSpaceCreatePattern must be None.
484    patternColorSpace = CGColorSpaceCreatePattern(None)
485    CGContextSetFillColorSpace(context, patternColorSpace)
486    # Quartz retains the color space so this code
487    # can now release it since it no longer needs it.
488    del patternColorSpace
489
490    # Paint the pattern with an alpha of 1.
491    color = (1,)
492    CGContextSetFillPattern(context, pdfPattern, color)
493    # Quartz retains the pattern so this code
494    # can now release it since it no longer needs it.
495    del pdfPattern
496
497    # Fill a US Letter size rect with the pattern.
498    CGContextFillRect(context, CGRectMake(0, 0, 612, 792))
499