@@ -230,32 +230,66 @@ def _datetime_to_pdf(d):
230
230
return r
231
231
232
232
233
- def _calculate_quad_point_coordinates (x ,y ,width ,height ,angle = 0 ):
233
+ def _calculate_rotated_quad_point_coordinates (x ,y ,width ,height ,angle ):
234
234
"""
235
235
Calculate the coordinates of rectangle when rotated by angle around x, y
236
236
"""
237
237
238
- angle = math .radians (- angle )
238
+ angle = math .radians (angle )
239
239
sin_angle = math .sin (angle )
240
240
cos_angle = math .cos (angle )
241
- a = x + height * sin_angle
241
+ width_cos = width * cos_angle
242
+ width_sin = width * sin_angle
243
+ a = x - height * sin_angle
242
244
b = y + height * cos_angle
243
- c = x + width * cos_angle + height * sin_angle
244
- d = y - width * sin_angle + height * cos_angle
245
- e = x + width * cos_angle
246
- f = y - width * sin_angle
245
+ c = a + width_cos
246
+ d = b + width_sin
247
+ e = x + width_cos
248
+ f = y + width_sin
247
249
return ((x ,y ), (e ,f ), (c ,d ), (a ,b ))
248
250
249
251
250
- def _get_coordinates_of_block (x ,y ,width , height , angle = 0 ):
252
+ def _calculate_transformed_quad_point_coordinates (x ,y ,trans ):
251
253
"""
252
- Get the coordinates of rotated rectangle and rectangle that covers the
253
- rotated rectangle.
254
+ Calculate the coordinates of rectangle when transformed by trans
255
+ positioned at x, y
256
+ """
257
+ tr1 ,tr2 ,tr3 ,tr4 ,tr5 ,tr6 = trans
258
+ # Conceptual code
259
+ # width = 1
260
+ # height = 1
261
+ # a = x + 0 * tr1 + height * tr3 + tr5
262
+ # b = y + 0 * tr2 + height * tr4 + tr6
263
+ # c = x + width * tr1 + height * tr3 + tr5
264
+ # d = y + width * tr2 + height * tr4 + tr6
265
+ # e = x + width * tr1 + 0 * tr3 + tr5
266
+ # f = y + width * tr2 + 0 * tr4 + tr6
267
+ # x = x + 0 * tr1 + 0 * tr3 + tr5
268
+ # y = y + 0 * tr2 + 0 * tr4 + tr6
269
+ x = x + tr5
270
+ y = y + tr6
271
+ a = x + tr3
272
+ b = y + tr4
273
+ c = a + tr1
274
+ d = b + tr2
275
+ e = x + tr1
276
+ f = y + tr2
277
+ return (((x ,y ), (e ,f ), (c ,d ), (a ,b )),
278
+ (0 if math .isclose (tr2 ,0 )else 45 ))
279
+
280
+
281
+ def _get_coordinates_of_block (x ,y ,width ,height ,angle ,trans ):
282
+ """
283
+ Get the coordinates of rotated or transformed rectangle and rectangle
284
+ that covers the rotated or transformed rectangle.
254
285
"""
255
286
256
- vertices = _calculate_quad_point_coordinates (x ,y ,width ,
257
- height ,angle )
258
-
287
+ if trans is None :
288
+ vertices = _calculate_rotated_quad_point_coordinates (x ,y ,width ,
289
+ height ,angle )
290
+ else :
291
+ vertices ,angle = _calculate_transformed_quad_point_coordinates (x ,y ,
292
+ trans )
259
293
# Find min and max values for rectangle
260
294
# adjust so that QuadPoints is inside Rect
261
295
# PDF docs says that QuadPoints should be ignored if any point lies
@@ -268,27 +302,29 @@ def _get_coordinates_of_block(x, y, width, height, angle=0):
268
302
max_x = max (v [0 ]for v in vertices )+ pad
269
303
max_y = max (v [1 ]for v in vertices )+ pad
270
304
return (tuple (itertools .chain .from_iterable (vertices )),
271
- (min_x ,min_y ,max_x ,max_y ))
305
+ (min_x ,min_y ,max_x ,max_y ), angle )
272
306
273
307
274
- def _get_link_annotation (gc ,x ,y ,width ,height ,angle = 0 ):
308
+ def _get_link_annotation (gc ,x ,y ,width ,height ,angle = 0 , trans = None ):
275
309
"""
276
310
Create a link annotation object for embedding URLs.
277
311
"""
278
- quadpoints ,rect = _get_coordinates_of_block (x ,y ,width ,height ,angle )
279
312
link_annotation = {
280
313
'Type' :Name ('Annot' ),
281
314
'Subtype' :Name ('Link' ),
282
- 'Rect' :rect ,
283
315
'Border' : [0 ,0 ,0 ],
284
316
'A' : {
285
317
'S' :Name ('URI' ),
286
318
'URI' :gc .get_url (),
287
319
},
288
320
}
321
+ quadpoints ,rect ,angle = _get_coordinates_of_block (x ,y ,width ,height ,
322
+ angle ,trans )
323
+ link_annotation ['Rect' ]= rect
289
324
if angle % 90 :
290
325
# Add QuadPoints
291
326
link_annotation ['QuadPoints' ]= quadpoints
327
+
292
328
return link_annotation
293
329
294
330
@@ -2012,21 +2048,24 @@ def draw_image(self, gc, x, y, im, transform=None):
2012
2048
2013
2049
self .check_gc (gc )
2014
2050
2015
- w = 72.0 * w / self .image_dpi
2016
- h = 72.0 * h / self .image_dpi
2017
-
2018
2051
imob = self .file .imageObject (im )
2019
2052
2020
2053
if transform is None :
2054
+ w = 72.0 * w / self .image_dpi
2055
+ h = 72.0 * h / self .image_dpi
2056
+ if gc .get_url ()is not None :
2057
+ self ._add_link_annotation (gc ,x ,y ,w ,h )
2021
2058
self .file .output (Op .gsave ,
2022
2059
w ,0 ,0 ,h ,x ,y ,Op .concat_matrix ,
2023
2060
imob ,Op .use_xobject ,Op .grestore )
2024
2061
else :
2025
- tr1 ,tr2 ,tr3 ,tr4 ,tr5 ,tr6 = transform .frozen ().to_values ()
2062
+ trans = transform .frozen ().to_values ()
2063
+ if gc .get_url ()is not None :
2064
+ self ._add_link_annotation (gc ,x ,y ,w ,h ,trans = trans )
2026
2065
2027
2066
self .file .output (Op .gsave ,
2028
2067
1 ,0 ,0 ,1 ,x ,y ,Op .concat_matrix ,
2029
- tr1 , tr2 , tr3 , tr4 , tr5 , tr6 ,Op .concat_matrix ,
2068
+ * trans ,Op .concat_matrix ,
2030
2069
imob ,Op .use_xobject ,Op .grestore )
2031
2070
2032
2071
def draw_path (self ,gc ,path ,transform ,rgbFace = None ):
@@ -2038,6 +2077,11 @@ def draw_path(self, gc, path, transform, rgbFace=None):
2038
2077
gc .get_sketch_params ())
2039
2078
self .file .output (self .gc .paint ())
2040
2079
2080
+ def _add_link_annotation (self ,gc ,x ,y ,width ,height ,angle = 0 ,
2081
+ trans = None ):
2082
+ self .file ._annotations [- 1 ][1 ].append (
2083
+ _get_link_annotation (gc ,x ,y ,width ,height ,angle ,trans ))
2084
+
2041
2085
def draw_path_collection (self ,gc ,master_transform ,paths ,all_transforms ,
2042
2086
offsets ,offsetTrans ,facecolors ,edgecolors ,
2043
2087
linewidths ,linestyles ,antialiaseds ,urls ,
@@ -2206,8 +2250,7 @@ def draw_mathtext(self, gc, x, y, s, prop, angle):
2206
2250
self ._text2path .mathtext_parser .parse (s ,72 ,prop )
2207
2251
2208
2252
if gc .get_url ()is not None :
2209
- self .file ._annotations [- 1 ][1 ].append (_get_link_annotation (
2210
- gc ,x ,y ,width ,height ,angle ))
2253
+ self ._add_link_annotation (gc ,x ,y ,width ,height ,angle )
2211
2254
2212
2255
fonttype = mpl .rcParams ['pdf.fonttype' ]
2213
2256
@@ -2263,8 +2306,7 @@ def draw_tex(self, gc, x, y, s, prop, angle, *, mtext=None):
2263
2306
page ,= dvi
2264
2307
2265
2308
if gc .get_url ()is not None :
2266
- self .file ._annotations [- 1 ][1 ].append (_get_link_annotation (
2267
- gc ,x ,y ,page .width ,page .height ,angle ))
2309
+ self ._add_link_annotation (gc ,x ,y ,page .width ,page .height ,angle )
2268
2310
2269
2311
# Gather font information and do some setup for combining
2270
2312
# characters into strings. The variable seq will contain a
@@ -2364,8 +2406,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
2364
2406
if gc .get_url ()is not None :
2365
2407
font .set_text (s )
2366
2408
width ,height = font .get_width_height ()
2367
- self .file ._annotations [- 1 ][1 ].append (_get_link_annotation (
2368
- gc ,x ,y ,width / 64 ,height / 64 ,angle ))
2409
+ self ._add_link_annotation (gc ,x ,y ,width / 64 ,height / 64 ,angle )
2369
2410
2370
2411
# If fonttype is neither 3 nor 42, emit the whole string at once
2371
2412
# without manual kerning.