• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /macosx-10.10.1/pyobjc-45/pyobjc/pyobjc-framework-Quartz-2.5.1/Examples/Programming with Quartz/BasicDrawing/
1from Quartz import *
2import Quartz
3import objc
4
5import Utilities
6import BitmapContext
7
8import sys
9
10# We're using a function that isn't made available through a wrapper, just
11# load it manually:
12if not hasattr(Quartz, 'PMCGImageCreateWithEPSDataProvider'):
13    functions = [
14        ('PMCGImageCreateWithEPSDataProvider', '@@@'),
15    ]
16    import AppKit
17    d = {}
18    objc.loadBundleFunctions(AppKit.__bundle__, d, functions)
19
20    if 'PMCGImageCreateWithEPSDataProvider' in d:
21        PMCGImageCreateWithEPSDataProvider=d['PMCGImageCreateWithEPSDataProvider']
22    else:
23        print >>sys.stderr, "PMCGImageCreateWithEPSDataProvider doesn't exist"
24
25def getEPSBBox(epspath):
26    try:
27        fp = open(epspath, 'rU')
28    except IOError, msg:
29        return CGRectZero
30
31    try:
32        #  This is a VERY poor man's EPS DSC parser, here just so that
33        #  this sample code can handle simple EPS files. It is
34        #  simple but very inefficient. In addition it does not ensure
35        #  that the DSC comments are at the beginning of a line,
36        #  nor does it handle (atend) style comments at all.
37        #  It will simply find the first occurance of a
38        #  %%BoundingBox comment and if it is of the typical
39        # form, it will obtain the bounding box data.
40        #
41        for ln in fp:
42            if ln.startswith("%%BoundingBox:"):
43                fields = ln.split()[1:]
44                if len(fields) >= 4:
45                    llx = int(fields[0])
46                    lly = int(fields[1])
47                    urx = int(fields[2])
48                    ury = int(fields[3])
49                    return CGRectMake(llx, lly, urx - llx, ury - lly)
50    finally:
51        fp.close()
52
53    return CGRectZero
54
55def createEPSPreviewImage(url):
56    # The CGImage used as the preview needs to have the
57    # same width and height as the EPS data it will
58    # be associated with. This sample code doesn't attempt
59    # to use any preview image associated with the EPS
60    # data but instead simply draws a box of an appropriate
61    # size. Your code would most likely create an image
62    # that reflects a PICT or TIFF preview present in the
63    # EPS data.
64    result, path = CFURLGetFileSystemRepresentation(url, True, None, 1024)
65    if not result:
66        print >>sys.stderr, "Couldn't get the path for EPS file!"
67        return None
68
69    path = path.rstrip('\0')
70
71    epsRect = getEPSBBox(path)
72    # Check whether the EPS bounding box is empty.
73    if epsRect == CGRectZero:
74        print >>sys.stderr, "Couldn't find BoundingBox comment!"
75        return None
76
77    wantDisplayColorSpace = False
78    needsTransparentBitmap = True
79    # Create a bitmap context to draw to in order to
80    # create the preview image. Use the routine
81    # createRGBBitmapContext from the earlier chapter.
82    bitmapContext = BitmapContext.createRGBBitmapContext(
83                                    epsRect.size.width,
84                                    epsRect.size.height,
85                                    wantDisplayColorSpace,
86                                    needsTransparentBitmap)
87    if bitmapContext is None:
88        print >>sys.stderr, "Couldn't create bitmap context"
89        return None
90
91    epsRect.origin.x = epsRect.origin.y = 0
92    # Draw the contents of the preview. The preview consists
93    # of two lines and a stroke around the bounding box. One
94    # of the two lines is drawn from the lower-left corner to
95    # the upper-right corner of the bounding box and the other
96    # line is from the lower-right corner to the upper-left
97    # corner of the bounding box.
98    CGContextBeginPath(bitmapContext)
99    CGContextMoveToPoint(bitmapContext, 0, 0)
100    CGContextAddLineToPoint(bitmapContext, epsRect.size.width, epsRect.size.height)
101    CGContextMoveToPoint(bitmapContext, epsRect.size.width, 0)
102    CGContextAddLineToPoint(bitmapContext, 0, epsRect.size.height)
103    CGContextStrokePath(bitmapContext)
104    # Stroke the bounding rectangle, inset so that the stroke is
105    # completely contained in the EPS bounding rect.
106    CGContextStrokeRect(bitmapContext, CGRectInset(epsRect, 0.5, 0.5))
107
108    # Now create an image from the bitmap raster data. This image
109    # has a data provider that releases the image raster data when
110    # the image is released. Use the createImageFromBitmapContext
111    # from Chapter 12. Calling createImageFromBitmapContext
112    # gives up ownership of the raster data used by the context.
113    epsPreviewImage = BitmapContext.createImageFromBitmapContext(bitmapContext)
114
115    if epsPreviewImage is None:
116        print >>sys.stderr, "Couldn't create preview image!"
117        return None
118
119    return epsPreviewImage
120
121# This technique of handling EPS data is available in
122# Mac OS X v10.1 and later and is one alternative method
123# of supporting EPS data during printing as compared to
124# converting EPS data to PDF data using CGPSConverter which
125# is only available in Panther and later.
126def createCGEPSImage(url):
127    previewImage = createEPSPreviewImage(url)
128    if previewImage is None:
129        print >>sys.stderr, "Couldn't create EPS preview!"
130        return None
131
132    # It is important that the data provider supplying the
133    # EPS data conform to the Quartz guidelines for data providers
134    # and is able to provide the data until the data releaser function
135    # is called. If you have a custom data provider, you need
136    # to follow these guidelines since your data provider
137    # is not necessarily called before you release the image
138    # that uses the provider.
139    epsDataProvider = CGDataProviderCreateWithURL(url)
140    if epsDataProvider is None:
141        print >>sys.stderr, "Couldn't create EPS data provider!"
142        return None
143
144    # Create the hybrid CGImage that contains the preview image
145    # and the EPS data. Note that the data provider isn't
146    # called during image creation but at some later point in time.
147
148
149    epsImage = PMCGImageCreateWithEPSDataProvider(epsDataProvider, previewImage)
150    # The preview image and data provider are no longer needed
151    # because Quartz retains them and this code doesn't
152    # require them further.
153    del previewImage
154    del epsDataProvider
155
156    if epsImage is None:
157        print >>sys.stderr, "Couldn't create EPS hybrid image!"
158        return None
159
160    return epsImage
161
162def drawEPSDataImage(context, url):
163    # Create the a CGImage that has EPS data associated with it.
164    epsDataImage = createCGEPSImage(url)
165    if epsDataImage is None:
166        return
167
168    # Create a destination rectangle at the location
169    # to draw the EPS document. The size of the rect is scaled
170    # down to 1/2 the size of the EPS graphic.
171    destinationRect = CGRectMake(100, 100,
172                        CGImageGetWidth(epsDataImage),
173                        CGImageGetHeight(epsDataImage))
174    # Draw the image to the destination. When the EPS
175    # data associated with the image is sent to a PostScript
176    # printer, the EPS bounding box is mapped to this
177    # destination rectangle, translated and scaled as necessary.
178    CGContextDrawImage(context, destinationRect, epsDataImage)
179
180    # Draw the image a second time. This time the image is
181    # rotated by 45 degrees and scaled by an additional scaling factor
182    # of 0.5 in the x dimension. The center point of this image coincides
183    # with the center point of the earlier drawing.
184    CGContextTranslateCTM(context,
185            destinationRect.origin.x + destinationRect.size.width/2,
186            destinationRect.origin.y + destinationRect.size.height/2)
187    CGContextRotateCTM(context, Utilities.DEGREES_TO_RADIANS(45))
188    CGContextScaleCTM(context, 0.5, 1)
189    CGContextTranslateCTM(context,
190            -(destinationRect.origin.x + destinationRect.size.width/2),
191            -(destinationRect.origin.y + destinationRect.size.height/2) )
192    CGContextDrawImage(context, destinationRect, epsDataImage)
193