1from __future__ import with_statement
2
3from PyObjCTools.TestSupport import *
4from Quartz import *
5import Quartz
6import os
7import sys
8
9if sys.version_info[0] != 2:
10    def buffer(value):
11        if isinstance(value, bytes):
12            return value
13        return value.encode('latin1')
14
15
16class TestCGContext (TestCase):
17    def testTypes(self):
18        self.assertIsCFType(CGContextRef)
19
20    def testConstants(self):
21        self.assertEqual(kCGLineJoinMiter, 0)
22        self.assertEqual(kCGLineJoinRound, 1)
23        self.assertEqual(kCGLineJoinBevel, 2)
24
25        self.assertEqual(kCGLineCapButt, 0)
26        self.assertEqual(kCGLineCapRound, 1)
27        self.assertEqual(kCGLineCapSquare, 2)
28
29        self.assertEqual(kCGPathFill, 0)
30        self.assertEqual(kCGPathEOFill, 1)
31        self.assertEqual(kCGPathStroke, 2)
32        self.assertEqual(kCGPathFillStroke, 3)
33        self.assertEqual(kCGPathEOFillStroke, 4)
34
35        self.assertEqual(kCGTextFill, 0)
36        self.assertEqual(kCGTextStroke, 1)
37        self.assertEqual(kCGTextFillStroke, 2)
38        self.assertEqual(kCGTextInvisible, 3)
39        self.assertEqual(kCGTextFillClip, 4)
40        self.assertEqual(kCGTextStrokeClip, 5)
41        self.assertEqual(kCGTextFillStrokeClip, 6)
42        self.assertEqual(kCGTextClip, 7)
43
44        self.assertEqual(kCGEncodingFontSpecific, 0)
45        self.assertEqual(kCGEncodingMacRoman, 1)
46
47        self.assertEqual(kCGInterpolationDefault, 0)
48        self.assertEqual(kCGInterpolationNone, 1)
49        self.assertEqual(kCGInterpolationLow, 2)
50        self.assertEqual(kCGInterpolationHigh, 3)
51
52        self.assertEqual(kCGBlendModeNormal, 0)
53        self.assertEqual(kCGBlendModeMultiply, 1)
54        self.assertEqual(kCGBlendModeScreen, 2)
55        self.assertEqual(kCGBlendModeOverlay, 3)
56        self.assertEqual(kCGBlendModeDarken, 4)
57        self.assertEqual(kCGBlendModeLighten, 5)
58        self.assertEqual(kCGBlendModeColorDodge, 6)
59        self.assertEqual(kCGBlendModeColorBurn, 7)
60        self.assertEqual(kCGBlendModeSoftLight, 8)
61        self.assertEqual(kCGBlendModeHardLight, 9)
62        self.assertEqual(kCGBlendModeDifference, 10)
63        self.assertEqual(kCGBlendModeExclusion, 11)
64        self.assertEqual(kCGBlendModeHue, 12)
65        self.assertEqual(kCGBlendModeSaturation, 13)
66        self.assertEqual(kCGBlendModeColor, 14)
67        self.assertEqual(kCGBlendModeLuminosity, 15)
68        self.assertEqual(kCGBlendModeClear, 16)
69        self.assertEqual(kCGBlendModeCopy, 17)
70        self.assertEqual(kCGBlendModeSourceIn, 18)
71        self.assertEqual(kCGBlendModeSourceOut, 19)
72        self.assertEqual(kCGBlendModeSourceAtop, 20)
73        self.assertEqual(kCGBlendModeDestinationOver, 21)
74        self.assertEqual(kCGBlendModeDestinationIn, 22)
75        self.assertEqual(kCGBlendModeDestinationOut, 23)
76        self.assertEqual(kCGBlendModeDestinationAtop, 24)
77        self.assertEqual(kCGBlendModeXOR, 25)
78        self.assertEqual(kCGBlendModePlusDarker, 26)
79        self.assertEqual(kCGBlendModePlusLighter, 27)
80
81    @min_os_level('10.5')
82    def testFunctions10_5(self):
83
84        url = CFURLCreateWithFileSystemPath(None,
85                "/tmp/pyobjc.test.pdf", kCFURLPOSIXPathStyle, False)
86        self.assertIsInstance(url, CFURLRef)
87        context = CGPDFContextCreateWithURL(url,
88                ((0, 0), (1000, 1000)), None)
89        self.assertIsInstance(context, CGContextRef)
90        CGContextBeginPage(context, objc.NULL)
91        try:
92            fn = '/System/Library/CoreServices/DefaultDesktop.jpg'
93            if not os.path.exists(fn):
94                fn = '/System/Library/Automator/Apply ColorSync Profile to Images.action/Contents/Resources/A-1075-normal.jpg'
95
96            provider = CGDataProviderCreateWithCFData(buffer(open(fn, 'rb').read()))
97            image = CGImageCreateWithJPEGDataProvider(provider, None, True, kCGRenderingIntentDefault)
98            self.assertIsInstance(image, CGImageRef)
99
100            CGContextDrawTiledImage(context, ((0, 0), (10, 10)), image)
101
102            font =  CGFontCreateWithFontName("Helvetica")
103            self.assertIsInstance(font, CGFontRef)
104            CGContextSetFont(context, font)
105
106            CGContextBeginTransparencyLayerWithRect(context,
107                    ((10, 10), (500, 100)), None)
108            CGContextEndTransparencyLayer(context)
109
110            color = CGColorCreateGenericRGB(1.0, 0.5, 0.5, 1.0)
111            self.assertIsInstance(color, CGColorRef)
112            CGContextSetFillColorWithColor(context, color)
113            CGContextSetStrokeColorWithColor(context, color)
114
115            gradient = CGGradientCreateWithColorComponents(
116                CGColorSpaceCreateDeviceGray(),
117                (0.25, 0.8), (0.95, 0.99), 2)
118            self.assertIsInstance(gradient, CGGradientRef)
119
120            CGContextDrawRadialGradient(context, gradient, (10, 15),
121                    30, (50, 70), 99.5, kCGGradientDrawsAfterEndLocation)
122
123            def evaluate(info, input, output):
124                return input * 4
125
126            func = CGFunctionCreate(None, 1, (0, 1), 2, (0, 1, 0, 1), evaluate)
127            self.assertIsInstance(func, CGFunctionRef)
128            shading = CGShadingCreateAxial(
129                    CGColorSpaceCreateDeviceGray(),
130                    (0, 0), (30,90), func, False, False)
131            self.assertIsInstance(shading, CGShadingRef)
132
133            self.assertArgHasType(CGContextSetShouldSubpixelPositionFonts, 1, objc._C_BOOL)
134            self.assertArgHasType(CGContextSetAllowsFontSubpixelPositioning, 1, objc._C_BOOL)
135            self.assertArgHasType(CGContextSetShouldSubpixelQuantizeFonts, 1, objc._C_BOOL)
136
137            gradient = CGGradientCreateWithColorComponents(
138                    CGColorSpaceCreateDeviceGray(),
139                    (0.25, 0.8), (0.95, 0.99), 2)
140            self.assertIsInstance(gradient, CGGradientRef)
141
142            CGContextDrawLinearGradient(context, gradient, (0, 10), (50, 60),
143                    kCGGradientDrawsAfterEndLocation)
144
145        finally:
146            CGContextEndPage(context)
147            if hasattr(Quartz, 'CGPDFContextClose'): CGPDFContextClose(context)
148            if os.path.exists("/tmp/pyobjc.test.pdf"):
149                os.unlink("/tmp/pyobjc.test.pdf")
150
151
152
153    def testFunctions(self):
154        self.assertIsInstance(CGContextGetTypeID(), (int, long))
155
156        url = CFURLCreateWithFileSystemPath(None,
157                "/tmp/pyobjc.test.pdf", kCFURLPOSIXPathStyle, False)
158        self.assertIsInstance(url, CFURLRef)
159        context = CGPDFContextCreateWithURL(url,
160                ((0, 0), (1000, 1000)), None)
161        self.assertIsInstance(context, CGContextRef)
162        CGContextBeginPage(context, objc.NULL)
163
164        self.assertTrue(CGContextIsPathEmpty(context) is True)
165        try:
166            CGContextBeginPath(context)
167            CGContextAddEllipseInRect(context, ((0, 10), (50, 30)))
168            CGContextDrawPath(context, kCGPathStroke)
169
170            CGContextSaveGState(context)
171            CGContextRestoreGState(context)
172
173            CGContextScaleCTM(context, 5.5, 9.5)
174            CGContextTranslateCTM(context, 4.5, 3.5)
175            CGContextRotateCTM(context, 0.79)
176            CGContextConcatCTM(context, CGAffineTransformIdentity)
177
178            tf = CGContextGetCTM(context)
179            self.assertIsInstance(tf, CGAffineTransform)
180
181            CGContextSetLineWidth(context, 2.5)
182            CGContextSetLineCap(context, kCGLineCapRound)
183            CGContextSetLineJoin(context, kCGLineJoinMiter)
184            CGContextSetMiterLimit(context, 9.5)
185
186            CGContextSetLineDash(context, 0.5, [0.4, 0.2, 0.8, 0.1], 4)
187
188            self.assertRaises(ValueError, CGContextSetLineDash,
189                    context, 0.5, [0.4, 0.2, 0.8, 0.1], 8)
190
191            CGContextSetFlatness(context, 0.8)
192            CGContextSetAlpha(context, 0.5)
193            CGContextSetBlendMode(context, kCGBlendModeLighten)
194
195
196            CGContextMoveToPoint(context, 10.5, 50.8)
197            CGContextAddLineToPoint(context, 0.5, 0.7)
198            CGContextAddCurveToPoint(context, 7.5, 8.7, 9.10, 9.10, 99.5, 80.5)
199            CGContextAddQuadCurveToPoint(context, 50.5, 50.5, 75.9, 78.4)
200            CGContextClosePath(context)
201
202            CGContextAddRect(context, CGRect(CGPoint(10, 10), CGSize(50, 50)))
203            CGContextAddRects(context, [
204                ( (8, 8), (7, 7) ),
205                ( (90, 80), (6, 6) ),
206                ( (50, 80), (60, 6) ),
207            ], 3)
208            self.assertRaises(ValueError,
209                CGContextAddRects, context, [
210                    ( (8, 8), (7, 7) ),
211                    ( (90, 80), (6, 6) ),
212                    ( (50, 80), (60, 6) ),
213                ], 8)
214
215
216            CGContextAddLines(context, [ (0, 10), (50, 7), (50, 90), (90.5, 8)],
217                    4)
218            self.assertRaises(ValueError,
219                CGContextAddLines, context, [ (0, 10), (50, 7), (50, 90), (90.5, 8)],
220                    7)
221
222            CGContextAddEllipseInRect(context, ((0, 10), (50, 30)))
223
224            CGContextAddArc(context, 50, 50, 70.5, 0.5, 1.3, 0)
225
226            CGContextAddArcToPoint(context, 20, 30, 70, 20, 55)
227
228            path = CGPathCreateMutable()
229            CGPathAddEllipseInRect(path, None, ((10, 50), (33, 33)))
230            self.assertIsInstance(path, CGPathRef)
231            CGContextAddPath(context, path)
232
233            self.assertResultHasType(CGContextIsPathEmpty, objc._C_BOOL)
234            self.assertTrue(CGContextIsPathEmpty(context) is False)
235
236            pt = CGContextGetPathCurrentPoint(context)
237            self.assertIsInstance(pt, CGPoint)
238
239            box = CGContextGetPathBoundingBox(context)
240            self.assertIsInstance(box, CGRect)
241
242            self.assertResultHasType(CGContextPathContainsPoint, objc._C_BOOL)
243            self.assertIsInstance(CGContextPathContainsPoint(context, pt, kCGPathStroke), bool)
244
245            CGContextFillPath(context)
246            CGContextEOFillPath(context)
247            CGContextStrokePath(context)
248            CGContextFillRect(context, ((10, 10), (50, 30)))
249
250            CGContextFillRects(context, [
251                ((10, 10), (50, 30)),
252                ((90, 10), (50, 30)),
253                ((30, 50), (50, 30))], 3)
254            self.assertRaises(ValueError, CGContextFillRects, context, [
255                ((10, 10), (50, 30)),
256                ((90, 10), (50, 30)),
257                ((30, 50), (50, 30))], 6)
258
259            CGContextStrokeRect(context, ((10, 10), (50, 30)))
260            CGContextStrokeRectWithWidth(context, ((10, 10), (50, 30)), 8.0)
261            CGContextClearRect(context, ((10, 10), (50, 30)))
262
263            CGContextFillEllipseInRect(context, ((10, 10), (50, 30)))
264            CGContextStrokeEllipseInRect(context, ((10, 10), (50, 30)))
265
266            CGContextStrokeLineSegments(context,
267                    [ (0, 0), (10, 15), (15, 10) ], 3)
268            self.assertRaises(ValueError, CGContextStrokeLineSegments, context,
269                    [ (0, 0), (10, 15), (15, 10) ], 4)
270
271            CGContextAddRect(context, CGRect(CGPoint(10, 10), CGSize(50, 50)))
272            CGContextClip(context)
273
274            CGContextAddRect(context, CGRect(CGPoint(10, 10), CGSize(50, 50)))
275            CGContextEOClip(context)
276
277            box = CGContextGetClipBoundingBox(context)
278            self.assertIsInstance(box, CGRect)
279
280            CGContextClipToRect(context, ((0, 0), (40, 50)))
281            CGContextClipToRects(context,
282                    [ ((0, 0), (40, 50)), ((60, 50), (90, 100))], 2)
283            self.assertRaises(ValueError, CGContextClipToRects, context,
284                    [ ((0, 0), (40, 50)), ((60, 50), (90, 100))], 3)
285
286
287            CGContextSetFillColorSpace(context, CGColorSpaceCreateDeviceGray())
288            CGContextSetStrokeColorSpace(context, CGColorSpaceCreateDeviceGray())
289
290            CGContextSetFillColor(context, [0.5, 1.0])
291            CGContextSetStrokeColor(context, [0.5, 1.0])
292
293            CGContextSetPatternPhase(context, CGSize(10.0, 50.0))
294
295            CGContextSetGrayFillColor(context, 0.8, 1.0)
296            CGContextSetGrayStrokeColor(context, 0.8, 1.0)
297
298            CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0)
299            CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0)
300
301            CGContextSetCMYKFillColor(context, 1.0, 1.0, 1.0, 0.5, 0.8)
302            CGContextSetCMYKStrokeColor(context, 1.0, 1.0, 1.0, 0.5, 0.8)
303
304            CGContextSetRenderingIntent(context, kCGRenderingIntentPerceptual)
305
306            v = CGContextGetInterpolationQuality(context)
307            self.assertIsInstance(v, (int, long))
308
309            CGContextSetInterpolationQuality(context, kCGInterpolationHigh)
310
311            color = CGColorCreate(CGColorSpaceCreateDeviceRGB(), (1,1,1,1))
312
313            CGContextSetShadowWithColor(context, (2, 3), 0.5, color)
314            CGContextSetShadow(context, (5, 6), 0.6)
315
316
317            CGContextSetCharacterSpacing(context, 0.1)
318            CGContextSetTextPosition(context, 10, 50)
319            p = CGContextGetTextPosition(context)
320            self.assertIsInstance(pt, CGPoint)
321
322            CGContextSetTextMatrix(context, CGAffineTransformIdentity)
323
324            tr = CGContextGetTextMatrix(context)
325            self.assertIsInstance(tr, CGAffineTransform)
326
327            CGContextSetTextDrawingMode(context, kCGTextStroke)
328
329
330            CGContextSetFontSize(context, 11.5)
331
332            CGContextSelectFont(context, b"Helvetica", 10.5, kCGEncodingMacRoman)
333
334            CGContextShowText(context, b"value", 5)
335            CGContextShowTextAtPoint(context, 50, 60, b"value", 5)
336
337
338            v = CGContextRetain(context)
339            self.assertTrue(v is context)
340            CGContextRelease(context)
341
342            CGContextFlush(context)
343            CGContextSynchronize(context)
344
345            self.assertArgHasType(CGContextSetShouldAntialias, 1, objc._C_BOOL)
346            CGContextSetShouldAntialias(context, True)
347
348            self.assertArgHasType(CGContextSetAllowsAntialiasing, 1, objc._C_BOOL)
349            CGContextSetAllowsAntialiasing(context, True)
350
351            self.assertArgHasType(CGContextSetShouldSmoothFonts, 1, objc._C_BOOL)
352            CGContextSetShouldSmoothFonts(context, True)
353
354
355            CGContextBeginTransparencyLayer(context, None)
356            CGContextEndTransparencyLayer(context)
357
358
359            tf = CGContextGetUserSpaceToDeviceSpaceTransform(context)
360            self.assertIsInstance(tf, CGAffineTransform)
361
362            pt = CGContextConvertPointToDeviceSpace(context, (10.5, 11.9))
363            self.assertIsInstance(pt, CGPoint)
364
365            pt = CGContextConvertPointToUserSpace(context, (10.5, 11.9))
366            self.assertIsInstance(pt, CGPoint)
367
368            sz = CGContextConvertSizeToDeviceSpace(context, (10.5, 11.9))
369            self.assertIsInstance(sz, CGSize)
370
371            sz = CGContextConvertSizeToUserSpace(context, (10.5, 11.9))
372            self.assertIsInstance(sz, CGSize)
373
374            box = CGContextConvertRectToDeviceSpace(context,
375                    ((10.5, 11.9), (55.6, 39.3)))
376            self.assertIsInstance(box, CGRect)
377            box = CGContextConvertRectToUserSpace(context,
378                    ((10.5, 11.9), (55.6, 39.3)))
379            self.assertIsInstance(box, CGRect)
380
381            myInfo = object()
382            def drawPattern(info, context):
383                pass
384
385            pattern = CGPatternCreate(myInfo, CGRectMake(0, 0, 10, 10), CGAffineTransformIdentity, 10.0, 10.0,
386                            kCGPatternTilingConstantSpacing, True, drawPattern)
387            self.assertIsInstance(pattern, CGPatternRef)
388
389            CGContextSetFillColorSpace(context, CGColorSpaceCreatePattern(None))
390            CGContextSetStrokeColorSpace(context, CGColorSpaceCreatePattern(None))
391            CGContextSetFillPattern(context, pattern, (1.0,1.0,1.0,1.0))
392            CGContextSetStrokePattern(context, pattern, (1.0,1.0,1.0,1.0))
393
394            fn = '/System/Library/CoreServices/DefaultDesktop.jpg'
395            if not os.path.exists(fn):
396                fn = '/System/Library/Automator/Apply ColorSync Profile to Images.action/Contents/Resources/A-1075-normal.jpg'
397
398            provider = CGDataProviderCreateWithCFData(buffer(open(fn, 'rb').read()))
399            image = CGImageCreateWithJPEGDataProvider(provider, None, True, kCGRenderingIntentDefault)
400            self.assertIsInstance(image, CGImageRef)
401
402            CGContextDrawImage(context, ((0, 0), (70, 50)), image)
403
404            provider = CGDataProviderCreateWithCFData(buffer("1" * 4 * 20 * 10))
405            mask = CGImageMaskCreate(20, 10, 8, 32, 80, provider, None, True)
406            self.assertIsInstance(mask, CGImageRef)
407
408            CGContextClipToMask(context, CGRectMake(0, 0, 50, 90), mask)
409
410        finally:
411            CGContextEndPage(context)
412            if hasattr(Quartz, 'CGPDFContextClose'): CGPDFContextClose(context)
413            if os.path.exists("/tmp/pyobjc.test.pdf"):
414                os.unlink("/tmp/pyobjc.test.pdf")
415
416    def testGlyphFunctions(self):
417        self.assertArgHasType(CGContextShowGlyphsAtPositions, 1, 'n^S')
418        self.assertArgSizeInArg(CGContextShowGlyphsAtPositions, 1, 3)
419        self.assertArgHasType(CGContextShowGlyphsAtPositions, 2, 'n^' + CGPoint.__typestr__)
420        self.assertArgSizeInArg(CGContextShowGlyphsAtPositions, 2, 3)
421
422        self.assertArgHasType(CGContextShowGlyphs, 1, 'n^S')
423        self.assertArgSizeInArg(CGContextShowGlyphs, 1, 2)
424
425        self.assertArgHasType(CGContextShowGlyphsAtPoint, 1, objc._C_CGFloat)
426        self.assertArgHasType(CGContextShowGlyphsAtPoint, 2, objc._C_CGFloat)
427        self.assertArgHasType(CGContextShowGlyphsAtPoint, 3, 'n^S')
428        self.assertArgSizeInArg(CGContextShowGlyphsAtPoint, 3, 4)
429
430        self.assertArgHasType(CGContextShowGlyphsWithAdvances, 1, 'n^S')
431        self.assertArgSizeInArg(CGContextShowGlyphsWithAdvances, 1, 3)
432        self.assertArgHasType(CGContextShowGlyphsWithAdvances, 2, 'n^' + CGSize.__typestr__)
433        self.assertArgSizeInArg(CGContextShowGlyphsWithAdvances, 2, 3)
434
435        self.assertArgHasType(CGContextDrawPDFPage, 0, '^{CGContext=}')
436        self.assertArgHasType(CGContextDrawPDFPage, 1, '^{CGPDFPage=}')
437
438        self.assertArgHasType(CGContextDrawPDFDocument, 0, '^{CGContext=}')
439        self.assertArgHasType(CGContextDrawPDFDocument, 1, CGRect.__typestr__)
440        self.assertArgHasType(CGContextDrawPDFDocument, 2, '^{CGPDFDocument=}')
441        self.assertArgHasType(CGContextDrawPDFDocument, 3, objc._C_INT)
442
443
444    @min_os_level('10.5')
445    def testContextManager10_5(self):
446        url = CFURLCreateWithFileSystemPath(None,
447                "/tmp/pyobjc.test.pdf", kCFURLPOSIXPathStyle, False)
448        self.assertIsInstance(url, CFURLRef)
449        context = CGPDFContextCreateWithURL(url,
450                ((0, 0), (1000, 1000)), None)
451        self.assertIsInstance(context, CGContextRef)
452        try:
453            CGContextBeginPage(context, objc.NULL)
454
455            # XXX: This need actual tests, this at least tests that
456            # the contextmanagers can be used
457            with CGTransparencyLayer(context, None):
458                pass
459
460            with CGTransparencyLayer(context, None, ((10, 10), (200, 200))):
461                pass
462
463        finally:
464            CGContextEndPage(context)
465            if hasattr(Quartz, 'CGPDFContextClose'): CGPDFContextClose(context)
466            if os.path.exists("/tmp/pyobjc.test.pdf"):
467                os.unlink("/tmp/pyobjc.test.pdf")
468
469    def testContextManager(self):
470        """
471        Tests for some additional functionality
472        """
473        url = CFURLCreateWithFileSystemPath(None,
474                "/tmp/pyobjc.test.pdf", kCFURLPOSIXPathStyle, False)
475        self.assertIsInstance(url, CFURLRef)
476        context = CGPDFContextCreateWithURL(url,
477                ((0, 0), (1000, 1000)), None)
478        self.assertIsInstance(context, CGContextRef)
479        try:
480            CGContextBeginPage(context, objc.NULL)
481            transform = CGContextGetCTM(context)
482            newTransform = CGAffineTransformMake(1.5, 2.5, 3.5, 4.5, 5.5, 6.5)
483
484            with CGSavedGState(context):
485                CGContextConcatCTM(context, newTransform)
486                tf = CGContextGetCTM(context)
487                self.assertNotEqual(tf, transform)
488
489
490            tf = CGContextGetCTM(context)
491            self.assertEqual(tf, transform)
492
493
494
495
496            CGContextEndPage(context)
497            with CGContextPage(context):
498                pass
499
500            with CGContextPage(context, CGRectMake(0, 0, 500, 500)):
501                pass
502
503            CGContextBeginPage(context, None)
504
505
506
507        finally:
508            CGContextEndPage(context)
509            if hasattr(Quartz, 'CGPDFContextClose'): CGPDFContextClose(context)
510            if os.path.exists("/tmp/pyobjc.test.pdf"):
511                os.unlink("/tmp/pyobjc.test.pdf")
512
513if __name__ == "__main__":
514    main()
515