|
31 | 31 | from matplotlib import _api, cbook |
32 | 32 | from matplotlib.backend_bases import ( |
33 | 33 | _Backend, FigureCanvasBase, FigureManagerBase, RendererBase) |
| 34 | +from matplotlib.dviread import Dvi |
34 | 35 | from matplotlib.font_manager import fontManager as _fontManager, get_font |
35 | 36 | from matplotlib.ft2font import LoadFlags, RenderMode |
36 | 37 | from matplotlib.mathtext import MathTextParser |
@@ -266,19 +267,84 @@ def get_text_width_height_descent(self, s, prop, ismath): |
266 | 267 | def draw_tex(self, gc, x, y, s, prop, angle, *, mtext=None): |
267 | 268 | # docstring inherited |
268 | 269 | # todo, handle props, angle, origins |
| 270 | + |
269 | 271 | size = prop.get_size_in_points() |
270 | 272 |
|
271 | | - texmanager = self.get_texmanager() |
| 273 | + if mpl.rcParams["text.latex.engine"] == "latex+dvipng": |
| 274 | + Z = self.get_texmanager().get_grey(s, size, self.dpi) |
| 275 | + Z = (Z * 0xff).astype(np.uint8) |
| 276 | + w, h, d = self.get_text_width_height_descent(s, prop, ismath="TeX") |
| 277 | + xd = d * math.sin(math.radians(angle)) |
| 278 | + yd = d * math.cos(math.radians(angle)) |
| 279 | + x = round(x + xd) |
| 280 | + y = round(y + yd) |
| 281 | + self._renderer.draw_text_image(Z, x, y, angle, gc) |
| 282 | + return |
| 283 | + |
| 284 | + dvifile = self.get_texmanager().make_dvi(s, size) |
| 285 | + with Dvi(dvifile, self.dpi) as dvi: |
| 286 | + page, = dvi |
272 | 287 |
|
273 | | - Z = texmanager.get_grey(s, size, self.dpi) |
274 | | - Z = np.array(Z * 255.0, np.uint8) |
| 288 | + cos = math.cos(math.radians(angle)) |
| 289 | + sin = math.sin(math.radians(angle)) |
275 | 290 |
|
276 | | - w, h, d = self.get_text_width_height_descent(s, prop, ismath="TeX") |
277 | | - xd = d * math.sin(math.radians(angle)) |
278 | | - yd = d * math.cos(math.radians(angle)) |
279 | | - x = round(x + xd) |
280 | | - y = round(y + yd) |
281 | | - self._renderer.draw_text_image(Z, x, y, angle, gc) |
| 291 | + for text in page.text: |
| 292 | + hf = mpl.rcParams["text.hinting_factor"] |
| 293 | + # Resolving text.index will implicitly call get_font(), which |
| 294 | + # resets the font transform, so it has to be done before explicitly |
| 295 | + # setting the font transform below. |
| 296 | + index = text.index |
| 297 | + font = get_font(text.font_path) |
| 298 | + font.set_size(text.font_size, self.dpi) |
| 299 | + slant = text.font_effects.get("slant", 0) |
| 300 | + extend = text.font_effects.get("extend", 1) |
| 301 | + font._set_transform( |
| 302 | + (0x10000 * np.array([[cos, -sin], [sin, cos]]) |
| 303 | + @ [[extend, extend * slant], [0, 1]] |
| 304 | + @ [[1 / hf, 0], [0, 1]]).round().astype(int), |
| 305 | + [round(0x40 * (x + text.x * cos - text.y * sin)), |
| 306 | + # FreeType's y is upwards. |
| 307 | + round(0x40 * (self.height - y + text.x * sin + text.y * cos))] |
| 308 | + ) |
| 309 | + bitmap = font._render_glyph( |
| 310 | + index, get_hinting_flag(), |
| 311 | + RenderMode.NORMAL if gc.get_antialiased() else RenderMode.MONO) |
| 312 | + buffer = np.asarray(bitmap.buffer) |
| 313 | + if not gc.get_antialiased(): |
| 314 | + buffer *= 0xff |
| 315 | + # draw_text_image's y is downwards & the bitmap bottom side. |
| 316 | + self._renderer.draw_text_image( |
| 317 | + buffer, |
| 318 | + bitmap.left, int(self.height) - bitmap.top + buffer.shape[0], |
| 319 | + 0, gc) |
| 320 | + |
| 321 | + rgba = gc.get_rgb() |
| 322 | + if len(rgba) == 3 or gc.get_forced_alpha(): |
| 323 | + rgba = rgba[:3] + (gc.get_alpha(),) |
| 324 | + gc1 = self.new_gc() |
| 325 | + gc1.set_linewidth(0) |
| 326 | + gc1.set_snap(gc.get_snap()) |
| 327 | + for box in page.boxes: |
| 328 | + bx = box.x |
| 329 | + by = box.y |
| 330 | + bw = box.width |
| 331 | + bh = box.height |
| 332 | + if gc1.get_snap() in [None, True]: |
| 333 | + # Prevent thin bars from disappearing by growing symmetrically. |
| 334 | + if bw < 1: |
| 335 | + bx -= (1 - bw) / 2 |
| 336 | + bw = 1 |
| 337 | + if bh < 1: |
| 338 | + by -= (1 - bh) / 2 |
| 339 | + bh = 1 |
| 340 | + path = Path._create_closed([ |
| 341 | + (bx, by), (bx + bw, by), (bx + bw, by + bh), (bx, by + bh)]) |
| 342 | + self._renderer.draw_path( |
| 343 | + gc1, path, |
| 344 | + mpl.transforms.Affine2D() |
| 345 | + .rotate_deg(angle).translate(x, self.height - y), |
| 346 | + rgba) |
| 347 | + gc1.restore() |
282 | 348 |
|
283 | 349 | def get_canvas_width_height(self): |
284 | 350 | # docstring inherited |
|
0 commit comments