4848class ImageDraw :
4949 font = None
5050
51- def __init__ (self , im , mode = None ):
51+ def __init__ (self , im : Image . Image , mode : str | None = None ) -> None :
5252 """
5353 Create a drawing instance.
5454
@@ -115,7 +115,7 @@ def getfont(self):
115115 self .font = ImageFont .load_default ()
116116 return self .font
117117
118- def _getfont (self , font_size ):
118+ def _getfont (self , font_size : float | None ):
119119 if font_size is not None :
120120 from . import ImageFont
121121
@@ -124,7 +124,7 @@ def _getfont(self, font_size):
124124 font = self .getfont ()
125125 return font
126126
127- def _getink (self , ink , fill = None ):
127+ def _getink (self , ink , fill = None ) -> tuple [ int | None , int | None ] :
128128 if ink is None and fill is None :
129129 if self .fill :
130130 fill = self .ink
@@ -145,13 +145,13 @@ def _getink(self, ink, fill=None):
145145 fill = self .draw .draw_ink (fill )
146146 return ink , fill
147147
148- def arc (self , xy , start , end , fill = None , width = 1 ):
148+ def arc (self , xy , start , end , fill = None , width = 1 ) -> None :
149149 """Draw an arc."""
150150 ink , fill = self ._getink (fill )
151151 if ink is not None :
152152 self .draw .draw_arc (xy , start , end , ink , width )
153153
154- def bitmap (self , xy , bitmap , fill = None ):
154+ def bitmap (self , xy , bitmap , fill = None ) -> None :
155155 """Draw a bitmap."""
156156 bitmap .load ()
157157 ink , fill = self ._getink (fill )
@@ -160,23 +160,23 @@ def bitmap(self, xy, bitmap, fill=None):
160160 if ink is not None :
161161 self .draw .draw_bitmap (xy , bitmap .im , ink )
162162
163- def chord (self , xy , start , end , fill = None , outline = None , width = 1 ):
163+ def chord (self , xy , start , end , fill = None , outline = None , width = 1 ) -> None :
164164 """Draw a chord."""
165165 ink , fill = self ._getink (outline , fill )
166166 if fill is not None :
167167 self .draw .draw_chord (xy , start , end , fill , 1 )
168168 if ink is not None and ink != fill and width != 0 :
169169 self .draw .draw_chord (xy , start , end , ink , 0 , width )
170170
171- def ellipse (self , xy , fill = None , outline = None , width = 1 ):
171+ def ellipse (self , xy , fill = None , outline = None , width = 1 ) -> None :
172172 """Draw an ellipse."""
173173 ink , fill = self ._getink (outline , fill )
174174 if fill is not None :
175175 self .draw .draw_ellipse (xy , fill , 1 )
176176 if ink is not None and ink != fill and width != 0 :
177177 self .draw .draw_ellipse (xy , ink , 0 , width )
178178
179- def line (self , xy , fill = None , width = 0 , joint = None ):
179+ def line (self , xy , fill = None , width = 0 , joint = None ) -> None :
180180 """Draw a line, or a connected sequence of line segments."""
181181 ink = self ._getink (fill )[0 ]
182182 if ink is not None :
@@ -236,7 +236,7 @@ def coord_at_angle(coord, angle):
236236 ]
237237 self .line (gap_coords , fill , width = 3 )
238238
239- def shape (self , shape , fill = None , outline = None ):
239+ def shape (self , shape , fill = None , outline = None ) -> None :
240240 """(Experimental) Draw a shape."""
241241 shape .close ()
242242 ink , fill = self ._getink (outline , fill )
@@ -245,29 +245,29 @@ def shape(self, shape, fill=None, outline=None):
245245 if ink is not None and ink != fill :
246246 self .draw .draw_outline (shape , ink , 0 )
247247
248- def pieslice (self , xy , start , end , fill = None , outline = None , width = 1 ):
248+ def pieslice (self , xy , start , end , fill = None , outline = None , width = 1 ) -> None :
249249 """Draw a pieslice."""
250250 ink , fill = self ._getink (outline , fill )
251251 if fill is not None :
252252 self .draw .draw_pieslice (xy , start , end , fill , 1 )
253253 if ink is not None and ink != fill and width != 0 :
254254 self .draw .draw_pieslice (xy , start , end , ink , 0 , width )
255255
256- def point (self , xy , fill = None ):
256+ def point (self , xy , fill = None ) -> None :
257257 """Draw one or more individual pixels."""
258258 ink , fill = self ._getink (fill )
259259 if ink is not None :
260260 self .draw .draw_points (xy , ink )
261261
262- def polygon (self , xy , fill = None , outline = None , width = 1 ):
262+ def polygon (self , xy , fill = None , outline = None , width = 1 ) -> None :
263263 """Draw a polygon."""
264264 ink , fill = self ._getink (outline , fill )
265265 if fill is not None :
266266 self .draw .draw_polygon (xy , fill , 1 )
267267 if ink is not None and ink != fill and width != 0 :
268268 if width == 1 :
269269 self .draw .draw_polygon (xy , ink , 0 , width )
270- else :
270+ elif self . im is not None :
271271 # To avoid expanding the polygon outwards,
272272 # use the fill as a mask
273273 mask = Image .new ("1" , self .im .size )
@@ -291,12 +291,12 @@ def polygon(self, xy, fill=None, outline=None, width=1):
291291
292292 def regular_polygon (
293293 self , bounding_circle , n_sides , rotation = 0 , fill = None , outline = None , width = 1
294- ):
294+ ) -> None :
295295 """Draw a regular polygon."""
296296 xy = _compute_regular_polygon_vertices (bounding_circle , n_sides , rotation )
297297 self .polygon (xy , fill , outline , width )
298298
299- def rectangle (self , xy , fill = None , outline = None , width = 1 ):
299+ def rectangle (self , xy , fill = None , outline = None , width = 1 ) -> None :
300300 """Draw a rectangle."""
301301 ink , fill = self ._getink (outline , fill )
302302 if fill is not None :
@@ -306,7 +306,7 @@ def rectangle(self, xy, fill=None, outline=None, width=1):
306306
307307 def rounded_rectangle (
308308 self , xy , radius = 0 , fill = None , outline = None , width = 1 , * , corners = None
309- ):
309+ ) -> None :
310310 """Draw a rounded rectangle."""
311311 if isinstance (xy [0 ], (list , tuple )):
312312 (x0 , y0 ), (x1 , y1 ) = xy
@@ -346,7 +346,7 @@ def rounded_rectangle(
346346 r = d // 2
347347 ink , fill = self ._getink (outline , fill )
348348
349- def draw_corners (pieslice ):
349+ def draw_corners (pieslice ) -> None :
350350 if full_x :
351351 # Draw top and bottom halves
352352 parts = (
@@ -431,12 +431,12 @@ def draw_corners(pieslice):
431431 right [3 ] -= r + 1
432432 self .draw .draw_rectangle (right , ink , 1 )
433433
434- def _multiline_check (self , text ):
434+ def _multiline_check (self , text ) -> bool :
435435 split_character = "\n " if isinstance (text , str ) else b"\n "
436436
437437 return split_character in text
438438
439- def _multiline_split (self , text ):
439+ def _multiline_split (self , text ) -> list [ str | bytes ] :
440440 split_character = "\n " if isinstance (text , str ) else b"\n "
441441
442442 return text .split (split_character )
@@ -465,7 +465,7 @@ def text(
465465 embedded_color = False ,
466466 * args ,
467467 ** kwargs ,
468- ):
468+ ) -> None :
469469 """Draw text."""
470470 if embedded_color and self .mode not in ("RGB" , "RGBA" ):
471471 msg = "Embedded color supported only in RGB and RGBA modes"
@@ -497,7 +497,7 @@ def getink(fill):
497497 return fill
498498 return ink
499499
500- def draw_text (ink , stroke_width = 0 , stroke_offset = None ):
500+ def draw_text (ink , stroke_width = 0 , stroke_offset = None ) -> None :
501501 mode = self .fontmode
502502 if stroke_width == 0 and embedded_color :
503503 mode = "RGBA"
@@ -547,7 +547,8 @@ def draw_text(ink, stroke_width=0, stroke_offset=None):
547547 ink_alpha = struct .pack ("i" , ink )[3 ]
548548 color .fillband (3 , ink_alpha )
549549 x , y = coord
550- self .im .paste (color , (x , y , x + mask .size [0 ], y + mask .size [1 ]), mask )
550+ if self .im is not None :
551+ self .im .paste (color , (x , y , x + mask .size [0 ], y + mask .size [1 ]), mask )
551552 else :
552553 self .draw .draw_bitmap (coord , mask , ink )
553554
@@ -584,7 +585,7 @@ def multiline_text(
584585 embedded_color = False ,
585586 * ,
586587 font_size = None ,
587- ):
588+ ) -> None :
588589 if direction == "ttb" :
589590 msg = "ttb direction is unsupported for multiline text"
590591 raise ValueError (msg )
@@ -693,7 +694,7 @@ def textbbox(
693694 embedded_color = False ,
694695 * ,
695696 font_size = None ,
696- ):
697+ ) -> tuple [ int , int , int , int ] :
697698 """Get the bounding box of a given string, in pixels."""
698699 if embedded_color and self .mode not in ("RGB" , "RGBA" ):
699700 msg = "Embedded color supported only in RGB and RGBA modes"
@@ -738,7 +739,7 @@ def multiline_textbbox(
738739 embedded_color = False ,
739740 * ,
740741 font_size = None ,
741- ):
742+ ) -> tuple [ int , int , int , int ] :
742743 if direction == "ttb" :
743744 msg = "ttb direction is unsupported for multiline text"
744745 raise ValueError (msg )
@@ -777,7 +778,7 @@ def multiline_textbbox(
777778 elif anchor [1 ] == "d" :
778779 top -= (len (lines ) - 1 ) * line_spacing
779780
780- bbox = None
781+ bbox : tuple [ int , int , int , int ] | None = None
781782
782783 for idx , line in enumerate (lines ):
783784 left = xy [0 ]
@@ -828,7 +829,7 @@ def multiline_textbbox(
828829 return bbox
829830
830831
831- def Draw (im , mode = None ):
832+ def Draw (im : Image . Image , mode : str | None = None ) -> ImageDraw :
832833 """
833834 A simple 2D drawing interface for PIL images.
834835
@@ -876,7 +877,7 @@ def getdraw(im=None, hints=None):
876877 return im , handler
877878
878879
879- def floodfill (image , xy , value , border = None , thresh = 0 ):
880+ def floodfill (image : Image . Image , xy , value , border = None , thresh = 0 ) -> None :
880881 """
881882 (experimental) Fills a bounded region with a given color.
882883
@@ -932,7 +933,7 @@ def floodfill(image, xy, value, border=None, thresh=0):
932933 edge = new_edge
933934
934935
935- def _compute_regular_polygon_vertices (bounding_circle , n_sides , rotation ):
936+ def _compute_regular_polygon_vertices (bounding_circle , n_sides , rotation ) -> list [ tuple [ float , float ]] :
936937 """
937938 Generate a list of vertices for a 2D regular polygon.
938939
@@ -982,7 +983,7 @@ def _compute_regular_polygon_vertices(bounding_circle, n_sides, rotation):
982983
983984 # 1.2 Check `bounding_circle` has an appropriate value
984985 if not isinstance (bounding_circle , (list , tuple )):
985- msg = "bounding_circle should be a tuple "
986+ msg = "bounding_circle should be a sequence "
986987 raise TypeError (msg )
987988
988989 if len (bounding_circle ) == 3 :
@@ -1014,7 +1015,7 @@ def _compute_regular_polygon_vertices(bounding_circle, n_sides, rotation):
10141015 raise ValueError (msg )
10151016
10161017 # 2. Define Helper Functions
1017- def _apply_rotation (point , degrees , centroid ) :
1018+ def _apply_rotation (point : list [ float ] , degrees : float ) -> tuple [ int , int ] :
10181019 return (
10191020 round (
10201021 point [0 ] * math .cos (math .radians (360 - degrees ))
@@ -1030,11 +1031,11 @@ def _apply_rotation(point, degrees, centroid):
10301031 ),
10311032 )
10321033
1033- def _compute_polygon_vertex (centroid , polygon_radius , angle ) :
1034+ def _compute_polygon_vertex (angle : float ) -> tuple [ int , int ] :
10341035 start_point = [polygon_radius , 0 ]
1035- return _apply_rotation (start_point , angle , centroid )
1036+ return _apply_rotation (start_point , angle )
10361037
1037- def _get_angles (n_sides , rotation ) :
1038+ def _get_angles (n_sides : int , rotation : float ) -> list [ float ] :
10381039 angles = []
10391040 degrees = 360 / n_sides
10401041 # Start with the bottom left polygon vertex
@@ -1051,11 +1052,11 @@ def _get_angles(n_sides, rotation):
10511052
10521053 # 4. Compute Vertices
10531054 return [
1054- _compute_polygon_vertex (centroid , polygon_radius , angle ) for angle in angles
1055+ _compute_polygon_vertex (angle ) for angle in angles
10551056 ]
10561057
10571058
1058- def _color_diff (color1 , color2 ) :
1059+ def _color_diff (color1 , color2 : float | tuple [ int , ...]) -> float :
10591060 """
10601061 Uses 1-norm distance to calculate difference between two values.
10611062 """
0 commit comments