diff --git a/lib/matplotlib/backends/backend_ps.py b/lib/matplotlib/backends/backend_ps.py index d95d6ea60f2b..d0102dd45238 100644 --- a/lib/matplotlib/backends/backend_ps.py +++ b/lib/matplotlib/backends/backend_ps.py @@ -484,8 +484,7 @@ def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!', mtext=None): r'\psfrag{%s}[Bl][Bl][1][%f]{\fontsize{%f}{%f}%s}' % ( thetext, angle, fontsize, fontsize*1.25, tex)) else: - # Stick to the bottom alignment, but this may give incorrect - # baseline some times. + # Stick to the bottom alignment. pos = _nums_to_str(x-corr, y-bl) self.psfrag.append( r'\psfrag{%s}[bl][bl][1][%f]{\fontsize{%f}{%f}%s}' % ( diff --git a/lib/matplotlib/dviread.py b/lib/matplotlib/dviread.py index d96dfb8a7f21..dcaba415a7b2 100644 --- a/lib/matplotlib/dviread.py +++ b/lib/matplotlib/dviread.py @@ -274,6 +274,12 @@ def _output(self): maxx = max(maxx, x + w) maxy = max(maxy, y + e) maxy_pure = max(maxy_pure, y) + if self._baseline_v is not None: + maxy_pure = self._baseline_v # This should normally be the case. + self._baseline_v = None + + if not self.text and not self.boxes: # Avoid infs/nans from inf+/-inf. + return Page(text=[], boxes=[], width=0, height=0, descent=0) if self.dpi is None: # special case for ease of debugging: output raw dvi coordinates @@ -301,9 +307,24 @@ def _read(self): Read one page from the file. Return True if successful, False if there were no more pages. """ + # Pages appear to start with the sequence + # bop (begin of page) + # xxx comment + # down + # push + # down, down + # push + # down (possibly multiple) + # push <= here, v is the baseline position. + # etc. + # (dviasm is useful to explore this structure.) + self._baseline_v = None while True: byte = self.file.read(1)[0] self._dtable[byte](self, byte) + if (self._baseline_v is None + and len(getattr(self, "stack", [])) == 3): + self._baseline_v = self.v if byte == 140: # end of page return True if self.state is _dvistate.post_post: # end of file diff --git a/lib/matplotlib/tests/baseline_images/test_usetex/test_usetex.pdf b/lib/matplotlib/tests/baseline_images/test_usetex/test_usetex.pdf index 8041641f9827..4ef375771d38 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_usetex/test_usetex.pdf and b/lib/matplotlib/tests/baseline_images/test_usetex/test_usetex.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_usetex/test_usetex.png b/lib/matplotlib/tests/baseline_images/test_usetex/test_usetex.png index 9a92f45e1e18..e4a9183612f5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_usetex/test_usetex.png and b/lib/matplotlib/tests/baseline_images/test_usetex/test_usetex.png differ diff --git a/lib/matplotlib/tests/test_usetex.py b/lib/matplotlib/tests/test_usetex.py index d13ff30060f5..8fccfe4a18b9 100644 --- a/lib/matplotlib/tests/test_usetex.py +++ b/lib/matplotlib/tests/test_usetex.py @@ -1,5 +1,3 @@ -import platform - import numpy as np import pytest @@ -12,24 +10,38 @@ pytestmark = pytest.mark.skip('Missing TeX of Ghostscript or dvipng') -@image_comparison(baseline_images=['test_usetex'], - extensions=['pdf', 'png'], - tol={'aarch64': 2.868, 'x86_64': 2.868}.get( - platform.machine(), 0.3 - )) +@image_comparison( + baseline_images=['test_usetex'], + extensions=['pdf', 'png'], + style="mpl20") def test_usetex(): mpl.rcParams['text.usetex'] = True fig = plt.figure() ax = fig.add_subplot(111) - ax.text(0.1, 0.2, + kwargs = {"verticalalignment": "baseline", "size": 24, + "bbox": dict(pad=0, edgecolor="k", facecolor="none")} + ax.text(0.2, 0.7, # the \LaTeX macro exercises character sizing and placement, # \left[ ... \right\} draw some variable-height characters, # \sqrt and \frac draw horizontal rules, \mathrm changes the font r'\LaTeX\ $\left[\int\limits_e^{2e}' r'\sqrt\frac{\log^3 x}{x}\,\mathrm{d}x \right\}$', - fontsize=24) - ax.set_xticks([]) - ax.set_yticks([]) + **kwargs) + ax.text(0.2, 0.3, "lg", **kwargs) + ax.text(0.4, 0.3, r"$\frac{1}{2}\pi$", **kwargs) + ax.text(0.6, 0.3, "$p^{3^A}$", **kwargs) + ax.text(0.8, 0.3, "$p_{3_2}$", **kwargs) + for x in {t.get_position()[0] for t in ax.texts}: + ax.axvline(x) + for y in {t.get_position()[1] for t in ax.texts}: + ax.axhline(y) + ax.set_axis_off() + + +@check_figures_equal() +def test_empty(fig_test, fig_ref): + mpl.rcParams['text.usetex'] = True + fig_test.text(.5, .5, "% a comment") @check_figures_equal() diff --git a/lib/matplotlib/texmanager.py b/lib/matplotlib/texmanager.py index f954254adc9e..1685b955352a 100644 --- a/lib/matplotlib/texmanager.py +++ b/lib/matplotlib/texmanager.py @@ -207,7 +207,8 @@ def make_tex(self, tex, fontsize): \usepackage[papersize={72in,72in},body={70in,70in},margin={1in,1in}]{geometry} \pagestyle{empty} \begin{document} -\fontsize{%f}{%f}%s +%% The empty hbox ensures that a page is printed even for empty inputs. +\fontsize{%f}{%f}\hbox{}%s \end{document} """ % (self._get_preamble(), fontsize, fontsize * 1.25, fontcmd % tex), encoding='utf-8') @@ -350,9 +351,16 @@ def make_png(self, tex, fontsize, dpi): # see get_rgba for a discussion of the background if not os.path.exists(pngfile): dvifile = self.make_dvi(tex, fontsize) - self._run_checked_subprocess( - ["dvipng", "-bg", "Transparent", "-D", str(dpi), - "-T", "tight", "-o", pngfile, dvifile], tex) + cmd = ["dvipng", "-bg", "Transparent", "-D", str(dpi), + "-T", "tight", "-o", pngfile, dvifile] + # When testing, disable FreeType rendering for reproducibility; but + # dvipng 1.16 has a bug (fixed in f3ff241) that breaks --freetype0 + # mode, so for it we keep FreeType enabled; the image will be + # slightly off. + if (getattr(mpl, "_called_from_pytest", False) + and mpl._get_executable_info("dvipng").version != "1.16"): + cmd.insert(1, "--freetype0") + self._run_checked_subprocess(cmd, tex) return pngfile def get_grey(self, tex, fontsize=None, dpi=None): @@ -403,7 +411,7 @@ def get_text_width_height_descent(self, tex, fontsize, renderer=None): return width, height + depth, depth else: - # use dviread. It sometimes returns a wrong descent. + # use dviread. dvifile = self.make_dvi(tex, fontsize) with dviread.Dvi(dvifile, 72 * dpi_fraction) as dvi: page, = dvi