1 """PixMapWrapper - defines the PixMapWrapper class, which wraps an opaque
2 QuickDraw PixMap data structure in a handy Python class. Also provides
3 methods to convert to/from pixel data (from, e.g., the img module) or a
4 Python Imaging Library Image object.
6 J. Strout <joe@strout.net> February 1999"""
9 from warnings
import warnpy3k
10 warnpy3k("In 3.x, the PixMapWrapper module is removed.", stacklevel
=2)
13 from Carbon
import QuickDraw
19 # PixMap data structure element format (as used with struct)
21 'baseAddr':'l', # address of pixel data
22 'rowBytes':'H', # bytes per row, plus 0x8000
23 'bounds':'hhhh', # coordinates imposed over pixel data
28 'pmVersion':'h', # flags for Color QuickDraw
29 'packType':'h', # format of compression algorithm
30 'packSize':'l', # size after compression
31 'hRes':'l', # horizontal pixels per inch
32 'vRes':'l', # vertical pixels per inch
33 'pixelType':'h', # pixel format
34 'pixelSize':'h', # bits per pixel
35 'cmpCount':'h', # color components per pixel
36 'cmpSize':'h', # bits per component
37 'planeBytes':'l', # offset in bytes to next plane
38 'pmTable':'l', # handle to color table
39 'pmReserved':'l' # reserved for future use
42 # PixMap data structure element offset
66 """PixMapWrapper -- wraps the QD PixMap object in a Python class,
67 with methods to easily get/set various pixmap fields. Note: Use the
68 PixMap() method when passing to QD calls."""
71 self
.__dict
__['data'] = ''
72 self
._header
= struct
.pack("lhhhhhhhlllhhhhlll",
73 id(self
.data
)+MacOS
.string_id_to_buffer
,
77 0, 0, # packType, packSize
78 72<<16, 72<<16, # hRes, vRes
79 QuickDraw
.RGBDirect
, # pixelType
81 2, 5, # cmpCount, cmpSize,
82 0, 0, 0) # planeBytes, pmTable, pmReserved
83 self
.__dict
__['_pm'] = Qd
.RawBitMap(self
._header
)
85 def _stuff(self
, element
, bytes
):
86 offset
= _pmElemOffset
[element
]
87 fmt
= _pmElemFormat
[element
]
88 self
._header
= self
._header
[:offset
] \
89 + struct
.pack(fmt
, bytes
) \
90 + self
._header
[offset
+ struct
.calcsize(fmt
):]
91 self
.__dict
__['_pm'] = None
93 def _unstuff(self
, element
):
94 offset
= _pmElemOffset
[element
]
95 fmt
= _pmElemFormat
[element
]
96 return struct
.unpack(fmt
, self
._header
[offset
:offset
+struct
.calcsize(fmt
)])[0]
98 def __setattr__(self
, attr
, val
):
99 if attr
== 'baseAddr':
100 raise 'UseErr', "don't assign to .baseAddr -- assign to .data instead"
102 self
.__dict
__['data'] = val
103 self
._stuff
('baseAddr', id(self
.data
) + MacOS
.string_id_to_buffer
)
104 elif attr
== 'rowBytes':
105 # high bit is always set for some odd reason
106 self
._stuff
('rowBytes', val |
0x8000)
107 elif attr
== 'bounds':
108 # assume val is in official Left, Top, Right, Bottom order!
109 self
._stuff
('left',val
[0])
110 self
._stuff
('top',val
[1])
111 self
._stuff
('right',val
[2])
112 self
._stuff
('bottom',val
[3])
113 elif attr
== 'hRes' or attr
== 'vRes':
114 # 16.16 fixed format, so just shift 16 bits
115 self
._stuff
(attr
, int(val
) << 16)
116 elif attr
in _pmElemFormat
.keys():
117 # any other pm attribute -- just stuff
118 self
._stuff
(attr
, val
)
120 self
.__dict
__[attr
] = val
122 def __getattr__(self
, attr
):
123 if attr
== 'rowBytes':
124 # high bit is always set for some odd reason
125 return self
._unstuff
('rowBytes') & 0x7FFF
126 elif attr
== 'bounds':
127 # return bounds in official Left, Top, Right, Bottom order!
129 self
._unstuff
('left'),
130 self
._unstuff
('top'),
131 self
._unstuff
('right'),
132 self
._unstuff
('bottom') )
133 elif attr
== 'hRes' or attr
== 'vRes':
134 # 16.16 fixed format, so just shift 16 bits
135 return self
._unstuff
(attr
) >> 16
136 elif attr
in _pmElemFormat
.keys():
137 # any other pm attribute -- just unstuff
138 return self
._unstuff
(attr
)
140 return self
.__dict
__[attr
]
144 "Return a QuickDraw PixMap corresponding to this data."
145 if not self
.__dict
__['_pm']:
146 self
.__dict
__['_pm'] = Qd
.RawBitMap(self
._header
)
147 return self
.__dict
__['_pm']
149 def blit(self
, x1
=0,y1
=0,x2
=None,y2
=None, port
=None):
150 """Draw this pixmap into the given (default current) grafport."""
154 dest
[2] = x1
+ src
[2]-src
[0]
156 dest
[3] = y1
+ src
[3]-src
[1]
157 if not port
: port
= Qd
.GetPort()
158 Qd
.CopyBits(self
.PixMap(), port
.GetPortBitMapForCopyBits(), src
, tuple(dest
),
159 QuickDraw
.srcCopy
, None)
161 def fromstring(self
,s
,width
,height
,format
=imgformat
.macrgb
):
162 """Stuff this pixmap with raw pixel data from a string.
163 Supply width, height, and one of the imgformat specifiers."""
164 # we only support 16- and 32-bit mac rgb...
165 # so convert if necessary
166 if format
!= imgformat
.macrgb
and format
!= imgformat
.macrgb16
:
168 raise "NotImplementedError", "conversion to macrgb or macrgb16"
170 self
.bounds
= (0,0,width
,height
)
172 self
.pixelType
= QuickDraw
.RGBDirect
173 if format
== imgformat
.macrgb
:
179 self
.rowBytes
= width
*self
.pixelSize
/8
181 def tostring(self
, format
=imgformat
.macrgb
):
182 """Return raw data as a string in the specified format."""
183 # is the native format requested? if so, just return data
184 if (format
== imgformat
.macrgb
and self
.pixelSize
== 32) or \
185 (format
== imgformat
.macrgb16
and self
.pixelsize
== 16):
187 # otherwise, convert to the requested format
189 raise "NotImplementedError", "data format conversion"
191 def fromImage(self
,im
):
192 """Initialize this PixMap from a PIL Image object."""
193 # We need data in ARGB format; PIL can't currently do that,
194 # but it can do RGBA, which we can use by inserting one null
196 if im
.mode
!= 'RGBA': im
= im
.convert('RGBA')
197 data
= chr(0) + im
.tostring()
198 self
.fromstring(data
, im
.size
[0], im
.size
[1])
201 """Return the contents of this PixMap as a PIL Image object."""
203 # our tostring() method returns data in ARGB format,
204 # whereas Image uses RGBA; a bit of slicing fixes this...
205 data
= self
.tostring()[1:] + chr(0)
207 return Image
.fromstring('RGBA',(bounds
[2]-bounds
[0],bounds
[3]-bounds
[1]),data
)
213 path
= EasyDialogs
.AskFileForOpen("Image File:")
216 pm
.fromImage( Image
.open(path
) )