Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c9662b6

Browse files
anntzerQuLogic
authored andcommitted
Draw mathtext symbols from their baselines
1 parent 1688264 commit c9662b6

File tree

1,472 files changed

+53595
-69650
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,472 files changed

+53595
-69650
lines changed

lib/matplotlib/_mathtext.py

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import enum
1010
import functools
1111
import logging
12+
import math
1213
import os
1314
import re
1415
import types
@@ -128,50 +129,62 @@ def __init__(self, box: Box):
128129
def to_vector(self) -> VectorParse:
129130
w, h, d = map(
130131
np.ceil, [self.box.width, self.box.height, self.box.depth])
131-
gs = [(info.font, info.fontsize, info.num, ox, h - oy + info.offset)
132+
gs = [(info.font, info.fontsize, info.num, ox, -oy + info.offset)
132133
for ox, oy, info in self.glyphs]
133-
rs = [(x1, h - y2, x2 - x1, y2 - y1)
134+
rs = [(x1, -y2, x2 - x1, y2 - y1)
134135
for x1, y1, x2, y2 in self.rects]
135136
return VectorParse(w, h + d, d, gs, rs)
136137

137138
def to_raster(self, *, antialiased: bool) -> RasterParse:
138139
# Metrics y's and mathtext y's are oriented in opposite directions,
139140
# hence the switch between ymin and ymax.
140-
xmin = min([*[ox + info.metrics.xmin for ox, oy, info in self.glyphs],
141-
*[x1 for x1, y1, x2, y2 in self.rects], 0]) - 1
142-
ymin = min([*[oy - info.metrics.ymax for ox, oy, info in self.glyphs],
143-
*[y1 for x1, y1, x2, y2 in self.rects], 0]) - 1
144-
xmax = max([*[ox + info.metrics.xmax for ox, oy, info in self.glyphs],
145-
*[x2 for x1, y1, x2, y2 in self.rects], 0]) + 1
146-
ymax = max([*[oy - info.metrics.ymin for ox, oy, info in self.glyphs],
147-
*[y2 for x1, y1, x2, y2 in self.rects], 0]) + 1
141+
xmin0 = min([*[ox + info.metrics.xmin for ox, oy, info in self.glyphs],
142+
*[x1 for x1, y1, x2, y2 in self.rects], 0])
143+
ymin0 = min([*[oy - max(info.metrics.ymax, info.metrics.iceberg)
144+
for ox, oy, info in self.glyphs],
145+
*[y1 for x1, y1, x2, y2 in self.rects], 0])
146+
xmax0 = max([*[ox + info.metrics.xmax for ox, oy, info in self.glyphs],
147+
*[x2 for x1, y1, x2, y2 in self.rects], 0])
148+
ymax0 = max([*[oy - info.metrics.ymin for ox, oy, info in self.glyphs],
149+
*[y2 for x1, y1, x2, y2 in self.rects], 0])
150+
# Rasterizing can leak into the neighboring pixel, hence the +/-1; it
151+
# will be cropped at the end.
152+
xmin = math.floor(xmin0 - 1)
153+
ymin = math.floor(ymin0 - 1)
154+
xmax = math.ceil(xmax0 + 1)
155+
ymax = math.ceil(ymax0 + 1)
148156
w = xmax - xmin
149-
h = ymax - ymin - self.box.depth
150-
d = ymax - ymin - self.box.height
151-
image = FT2Image(int(np.ceil(w)), int(np.ceil(h + max(d, 0))))
157+
h = max(-ymin, 0)
158+
d = max(ymax, 0)
159+
image = FT2Image(w, h + d)
152160

153-
# Ideally, we could just use self.glyphs and self.rects here, shifting
154-
# their coordinates by (-xmin, -ymin), but this yields slightly
155-
# different results due to floating point slop; shipping twice is the
156-
# old approach and keeps baseline images backcompat.
157-
shifted = ship(self.box, (-xmin, -ymin))
158-
159-
for ox, oy, info in shifted.glyphs:
161+
for ox, oy, info in self.glyphs:
162+
ox -= xmin
163+
oy -= (-h + info.offset)
160164
info.font.draw_glyph_to_bitmap(
161-
image,
162-
int(ox),
163-
int(oy - np.ceil(info.metrics.iceberg)),
164-
info.glyph,
165-
antialiased=antialiased)
166-
for x1, y1, x2, y2 in shifted.rects:
165+
image, ox, oy, info.glyph, antialiased=antialiased)
166+
for x1, y1, x2, y2 in self.rects:
167+
x1 -= xmin
168+
x2 -= xmin
169+
y1 -= -h
170+
y2 -= -h
167171
height = max(int(y2 - y1) - 1, 0)
168172
if height == 0:
169173
center = (y2 + y1) / 2
170174
y = int(center - (height + 1) / 2)
171175
else:
172176
y = int(y1)
173-
image.draw_rect_filled(int(x1), y, int(np.ceil(x2)), y + height)
174-
return RasterParse(0, 0, w, h + d, d, image)
177+
image.draw_rect_filled(int(x1), y, math.ceil(x2), y + height)
178+
179+
image = np.asarray(image)
180+
while h and (image[0] == 0).all():
181+
image = image[1:]
182+
h -= 1
183+
while d and (image[-1] == 0).all():
184+
image = image[:-1]
185+
d -= 1
186+
return RasterParse(
187+
xmin - xmin0, d - ymax0, xmax0 - xmin0, ymax0 - ymin0, d, image)
175188

176189

177190
class FontMetrics(NamedTuple):
@@ -1607,7 +1620,7 @@ def ship(box: Box, xy: tuple[float, float] = (0, 0)) -> Output:
16071620
cur_v = 0.
16081621
cur_h = 0.
16091622
off_h = ox
1610-
off_v = oy + box.height
1623+
off_v = oy
16111624
output = Output(box)
16121625

16131626
def clamp(value: float) -> float:

lib/matplotlib/backends/backend_agg.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ def draw_mathtext(self, gc, x, y, s, prop, angle):
180180
yd = descent * cos(radians(angle))
181181
x = round(x + ox + xd)
182182
y = round(y - oy + yd)
183-
self._renderer.draw_text_image(font_image, x, y + 1, angle, gc)
183+
self._renderer.draw_text_image(font_image, x, y, angle, gc)
184184

185185
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
186186
# docstring inherited
Binary file not shown.

lib/matplotlib/tests/baseline_images/test_backend_ps/multi_font_type3.eps

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/matplotlib/tests/baseline_images/test_backend_ps/multi_font_type42.eps

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)