@@ -124,8 +124,98 @@ def __init__(self, text='', is_active=True):
124
124
self .is_active = is_active
125
125
self .size = None
126
126
127
+ def draw_grid_annotations (im , width , height , hor_texts , ver_texts , margin = 0 ):
128
+ def wrap (drawing , text , font , line_length ):
129
+ lines = ['' ]
130
+ for word in text .split ():
131
+ line = f'{ lines [- 1 ]} { word } ' .strip ()
132
+ if drawing .textlength (line , font = font ) <= line_length :
133
+ lines [- 1 ] = line
134
+ else :
135
+ lines .append (word )
136
+ return lines
137
+
138
+ def get_font (fontsize ):
139
+ try :
140
+ return ImageFont .truetype (opts .font or Roboto , fontsize )
141
+ except Exception :
142
+ return ImageFont .truetype (Roboto , fontsize )
143
+
144
+ def draw_texts (drawing , draw_x , draw_y , lines , initial_fnt , initial_fontsize ):
145
+ for i , line in enumerate (lines ):
146
+ fnt = initial_fnt
147
+ fontsize = initial_fontsize
148
+ while drawing .multiline_textsize (line .text , font = fnt )[0 ] > line .allowed_width and fontsize > 0 :
149
+ fontsize -= 1
150
+ fnt = get_font (fontsize )
151
+ drawing .multiline_text ((draw_x , draw_y + line .size [1 ] / 2 ), line .text , font = fnt , fill = color_active if line .is_active else color_inactive , anchor = "mm" , align = "center" )
152
+
153
+ if not line .is_active :
154
+ drawing .line ((draw_x - line .size [0 ] // 2 , draw_y + line .size [1 ] // 2 , draw_x + line .size [0 ] // 2 , draw_y + line .size [1 ] // 2 ), fill = color_inactive , width = 4 )
155
+
156
+ draw_y += line .size [1 ] + line_spacing
157
+
158
+ fontsize = (width + height ) // 25
159
+ line_spacing = fontsize // 2
160
+
161
+ fnt = get_font (fontsize )
162
+
163
+ color_active = (0 , 0 , 0 )
164
+ color_inactive = (153 , 153 , 153 )
165
+
166
+ pad_left = 0 if sum ([sum ([len (line .text ) for line in lines ]) for lines in ver_texts ]) == 0 else width * 3 // 4
167
+
168
+ cols = im .width // width
169
+ rows = im .height // height
170
+
171
+ assert cols == len (hor_texts ), f'bad number of horizontal texts: { len (hor_texts )} ; must be { cols } '
172
+ assert rows == len (ver_texts ), f'bad number of vertical texts: { len (ver_texts )} ; must be { rows } '
173
+
174
+ calc_img = Image .new ("RGB" , (1 , 1 ), "white" )
175
+ calc_d = ImageDraw .Draw (calc_img )
176
+
177
+ for texts , allowed_width in zip (hor_texts + ver_texts , [width ] * len (hor_texts ) + [pad_left ] * len (ver_texts )):
178
+ items = [] + texts
179
+ texts .clear ()
180
+
181
+ for line in items :
182
+ wrapped = wrap (calc_d , line .text , fnt , allowed_width )
183
+ texts += [GridAnnotation (x , line .is_active ) for x in wrapped ]
184
+
185
+ for line in texts :
186
+ bbox = calc_d .multiline_textbbox ((0 , 0 ), line .text , font = fnt )
187
+ line .size = (bbox [2 ] - bbox [0 ], bbox [3 ] - bbox [1 ])
188
+ line .allowed_width = allowed_width
189
+
190
+ hor_text_heights = [sum ([line .size [1 ] + line_spacing for line in lines ]) - line_spacing for lines in hor_texts ]
191
+ ver_text_heights = [sum ([line .size [1 ] + line_spacing for line in lines ]) - line_spacing * len (lines ) for lines in ver_texts ]
192
+
193
+ pad_top = 0 if sum (hor_text_heights ) == 0 else max (hor_text_heights ) + line_spacing * 2
194
+
195
+ result = Image .new ("RGB" , (im .width + pad_left + margin * (cols - 1 ), im .height + pad_top + margin * (rows - 1 )), "white" )
196
+
197
+ for row in range (rows ):
198
+ for col in range (cols ):
199
+ cell = im .crop ((width * col , height * row , width * (col + 1 ), height * (row + 1 )))
200
+ result .paste (cell , (pad_left + (width + margin ) * col , pad_top + (height + margin ) * row ))
201
+
202
+ d = ImageDraw .Draw (result )
203
+
204
+ for col in range (cols ):
205
+ x = pad_left + (width + margin ) * col + width / 2
206
+ y = pad_top / 2 - hor_text_heights [col ] / 2
207
+
208
+ draw_texts (d , x , y , hor_texts [col ], fnt , fontsize )
209
+
210
+ for row in range (rows ):
211
+ x = pad_left / 2
212
+ y = pad_top + (height + margin ) * row + height / 2 - ver_text_heights [row ] / 2
213
+
214
+ draw_texts (d , x , y , ver_texts [row ], fnt , fontsize )
215
+
216
+ return result
127
217
128
- def draw_grid_annotations (im , width , height , hor_texts , ver_texts ):
218
+ def draw_grid_annotations_old (im , width , height , hor_texts , ver_texts ):
129
219
def wrap (drawing , text , font , line_length ):
130
220
lines = ['' ]
131
221
for word in text .split ():
0 commit comments