2
# The Python Imaging Library
5
# drawing interface operations
8
# 1996-04-13 fl Created (experimental)
9
# 1996-08-07 fl Filled polygons, ellipses.
10
# 1996-08-13 fl Added text support
11
# 1998-06-28 fl Handle I and F images
12
# 1998-12-29 fl Added arc; use arc primitive to draw ellipses
13
# 1999-01-10 fl Added shape stuff (experimental)
14
# 1999-02-06 fl Added bitmap support
15
# 1999-02-11 fl Changed all primitives to take options
16
# 1999-02-20 fl Fixed backwards compatibility
17
# 2000-10-12 fl Copy on write, when necessary
18
# 2001-02-18 fl Use default ink for bitmap/text also in fill mode
19
# 2002-10-24 fl Added support for CSS-style color strings
20
# 2002-12-10 fl Added experimental support for RGBA-on-RGB drawing
21
# 2002-12-11 fl Refactored low-level drawing API (work in progress)
22
# 2004-08-26 fl Made Draw() a factory function, added getdraw() support
23
# 2004-09-04 fl Added width support to line primitive
24
# 2004-09-10 fl Added font mode handling
25
# 2006-06-19 fl Added font bearing support (getmask2)
27
# Copyright (c) 1997-2006 by Secret Labs AB
28
# Copyright (c) 1996-2006 by Fredrik Lundh
30
# See the README file for information on usage and redistribution.
33
import Image, ImageColor
41
# A simple 2D drawing interface for PIL images.
43
# Application code should use the <b>Draw</b> factory, instead of
49
# Create a drawing instance.
51
# @param im The image to draw in.
52
# @param mode Optional mode to use for color values. For RGB
53
# images, this argument can be RGB or RGBA (to blend the
54
# drawing into the image). For all other modes, this argument
55
# must be the same as the image mode. If omitted, the mode
56
# defaults to the mode of the image.
58
def __init__(self, im, mode=None):
61
im._copy() # make it writable
66
if mode == "RGBA" and im.mode == "RGB":
69
raise ValueError("mode mismatch")
71
self.palette = im.palette
75
self.draw = Image.core.draw(self.im, blend)
77
if mode in ("I", "F"):
78
self.ink = self.draw.draw_ink(1, mode)
80
self.ink = self.draw.draw_ink(-1, mode)
81
if mode in ("1", "P", "I", "F"):
82
# FIXME: fix Fill2 to properly support matte for I+F images
85
self.fontmode = "L" # aliasing is okay for other modes
90
# Set the default pen color.
92
def setink(self, ink):
96
"'setink' is deprecated; use keyword arguments instead",
97
DeprecationWarning, stacklevel=2
99
if Image.isStringType(ink):
100
ink = ImageColor.getcolor(ink, self.mode)
101
if self.palette and not Image.isNumberType(ink):
102
ink = self.palette.getcolor(ink)
103
self.ink = self.draw.draw_ink(ink, self.mode)
106
# Set the default background color.
108
def setfill(self, onoff):
112
"'setfill' is deprecated; use keyword arguments instead",
113
DeprecationWarning, stacklevel=2
118
# Set the default font.
120
def setfont(self, font):
125
# Get the current default font.
129
# FIXME: should add a font repository
131
self.font = ImageFont.load_default()
134
def _getink(self, ink, fill=None):
135
if ink is None and fill is None:
142
if Image.isStringType(ink):
143
ink = ImageColor.getcolor(ink, self.mode)
144
if self.palette and not Image.isNumberType(ink):
145
ink = self.palette.getcolor(ink)
146
ink = self.draw.draw_ink(ink, self.mode)
148
if Image.isStringType(fill):
149
fill = ImageColor.getcolor(fill, self.mode)
150
if self.palette and not Image.isNumberType(fill):
151
fill = self.palette.getcolor(fill)
152
fill = self.draw.draw_ink(fill, self.mode)
158
def arc(self, xy, start, end, fill=None):
159
ink, fill = self._getink(fill)
161
self.draw.draw_arc(xy, start, end, ink)
166
def bitmap(self, xy, bitmap, fill=None):
168
ink, fill = self._getink(fill)
172
self.draw.draw_bitmap(xy, bitmap.im, ink)
177
def chord(self, xy, start, end, fill=None, outline=None):
178
ink, fill = self._getink(outline, fill)
180
self.draw.draw_chord(xy, start, end, fill, 1)
182
self.draw.draw_chord(xy, start, end, ink, 0)
187
def ellipse(self, xy, fill=None, outline=None):
188
ink, fill = self._getink(outline, fill)
190
self.draw.draw_ellipse(xy, fill, 1)
192
self.draw.draw_ellipse(xy, ink, 0)
195
# Draw a line, or a connected sequence of line segments.
197
def line(self, xy, fill=None, width=0):
198
ink, fill = self._getink(fill)
200
self.draw.draw_lines(xy, ink, width)
203
# (Experimental) Draw a shape.
205
def shape(self, shape, fill=None, outline=None):
208
ink, fill = self._getink(outline, fill)
210
self.draw.draw_outline(shape, fill, 1)
212
self.draw.draw_outline(shape, ink, 0)
217
def pieslice(self, xy, start, end, fill=None, outline=None):
218
ink, fill = self._getink(outline, fill)
220
self.draw.draw_pieslice(xy, start, end, fill, 1)
222
self.draw.draw_pieslice(xy, start, end, ink, 0)
225
# Draw one or more individual pixels.
227
def point(self, xy, fill=None):
228
ink, fill = self._getink(fill)
230
self.draw.draw_points(xy, ink)
235
def polygon(self, xy, fill=None, outline=None):
236
ink, fill = self._getink(outline, fill)
238
self.draw.draw_polygon(xy, fill, 1)
240
self.draw.draw_polygon(xy, ink, 0)
245
def rectangle(self, xy, fill=None, outline=None):
246
ink, fill = self._getink(outline, fill)
248
self.draw.draw_rectangle(xy, fill, 1)
250
self.draw.draw_rectangle(xy, ink, 0)
255
def text(self, xy, text, fill=None, font=None, anchor=None):
256
ink, fill = self._getink(fill)
258
font = self.getfont()
263
mask, offset = font.getmask2(text, self.fontmode)
264
xy = xy[0] + offset[0], xy[1] + offset[1]
265
except AttributeError:
267
mask = font.getmask(text, self.fontmode)
269
mask = font.getmask(text)
270
self.draw.draw_bitmap(xy, mask, ink)
273
# Get the size of a given string, in pixels.
275
def textsize(self, text, font=None):
277
font = self.getfont()
278
return font.getsize(text)
281
# A simple 2D drawing interface for PIL images.
283
# @param im The image to draw in.
284
# @param mode Optional mode to use for color values. For RGB
285
# images, this argument can be RGB or RGBA (to blend the
286
# drawing into the image). For all other modes, this argument
287
# must be the same as the image mode. If omitted, the mode
288
# defaults to the mode of the image.
290
def Draw(im, mode=None):
292
return im.getdraw(mode)
293
except AttributeError:
294
return ImageDraw(im, mode)
296
# experimental access to the outline API
298
Outline = Image.core.outline
303
# (Experimental) A more advanced 2D drawing interface for PIL images,
304
# based on the WCK interface.
306
# @param im The image to draw in.
307
# @param hints An optional list of hints.
308
# @return A (drawing context, drawing resource factory) tuple.
310
def getdraw(im=None, hints=None):
311
# FIXME: this needs more work!
312
# FIXME: come up with a better 'hints' scheme.
314
if not hints or "nicest" in hints:
317
handler = _imagingagg
324
im = handler.Draw(im)
328
# (experimental) Fills a bounded region with a given color.
330
# @param image Target image.
331
# @param xy Seed position (a 2-item coordinate tuple).
332
# @param value Fill color.
333
# @param border Optional border value. If given, the region consists of
334
# pixels with a color different from the border color. If not given,
335
# the region consists of pixels having the same color as the seed
338
def floodfill(image, xy, value, border=None):
339
"Fill bounded region."
340
# based on an implementation by Eric S. Raymond
344
background = pixel[x, y]
345
if background == value:
346
return # seed point already has fill color
349
return # seed point outside image
355
for (s, t) in ((x+1, y), (x-1, y), (x, y+1), (x, y-1)):
363
newedge.append((s, t))
369
for (s, t) in ((x+1, y), (x-1, y), (x, y+1), (x, y-1)):
375
if p != value and p != border:
377
newedge.append((s, t))