Skip to content

Rasterize dvi files without dvipng. #30039

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 40 additions & 9 deletions lib/matplotlib/backends/backend_agg.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"""

from contextlib import nullcontext
import math
from math import radians, cos, sin

import numpy as np
Expand All @@ -30,8 +31,9 @@
from matplotlib import _api, cbook
from matplotlib.backend_bases import (
_Backend, FigureCanvasBase, FigureManagerBase, RendererBase)
from matplotlib.dviread import Dvi
from matplotlib.font_manager import fontManager as _fontManager, get_font
from matplotlib.ft2font import LoadFlags
from matplotlib.ft2font import FT2Image, LoadFlags
from matplotlib.mathtext import MathTextParser
from matplotlib.path import Path
from matplotlib.transforms import Bbox, BboxBase
Expand Down Expand Up @@ -208,7 +210,8 @@ def get_text_width_height_descent(self, s, prop, ismath):

_api.check_in_list(["TeX", True, False], ismath=ismath)
if ismath == "TeX":
return super().get_text_width_height_descent(s, prop, ismath)
return [*map(
math.ceil, super().get_text_width_height_descent(s, prop, ismath))]

if ismath:
ox, oy, width, height, descent, font_image = \
Expand All @@ -227,19 +230,47 @@ def get_text_width_height_descent(self, s, prop, ismath):
def draw_tex(self, gc, x, y, s, prop, angle, *, mtext=None):
# docstring inherited
# todo, handle props, angle, origins
size = prop.get_size_in_points()

texmanager = self.get_texmanager()

Z = texmanager.get_grey(s, size, self.dpi)
Z = np.array(Z * 255.0, np.uint8)
size = prop.get_size_in_points()
dvifile = self.get_texmanager().make_dvi(s, size)
with Dvi(dvifile, self.dpi) as dvi:
page, = dvi
w = math.ceil(page.width)
h = math.ceil(page.height)
d = math.ceil(page.descent)

image = FT2Image(w, h + d)

for text in page.text:
hf = mpl.rcParams["text.hinting_factor"]
font = get_font(text.font_path)
font.set_size(text.font_size, self.dpi)
slant = text.font_effects.get("slant", 0)
extend = text.font_effects.get("extend", 1)
matrix = [
[round(65536 * extend / hf), round(65536 * extend * slant)],
[0, 65536],
]
font._set_transform(matrix, [0, 0])
glyph = font.load_glyph(text.index)
# text.y is upwards from baseline, _draw_glyph_at wants upwards from bottom.
font._draw_glyph_at(image, text.x, d + text.y, glyph,
antialiased=gc.get_antialiased())

image = np.asarray(image)

for box in page.boxes:
x0 = round(box.x)
x1 = x0 + max(round(box.width), 1)
y1 = round(h - box.y)
y0 = y1 - max(round(box.height), 1)
image[y0:y1, x0:x1] = 0xff

w, h, d = self.get_text_width_height_descent(s, prop, ismath="TeX")
xd = d * sin(radians(angle))
yd = d * cos(radians(angle))
x = round(x + xd)
y = round(y + yd)
self._renderer.draw_text_image(Z, x, y, angle, gc)
self._renderer.draw_text_image(image, x, y, angle, gc)

def get_canvas_width_height(self):
# docstring inherited
Expand Down
Binary file modified lib/matplotlib/tests/baseline_images/test_usetex/eqnarray.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified lib/matplotlib/tests/baseline_images/test_usetex/rotation.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified lib/matplotlib/tests/baseline_images/test_usetex/test_usetex.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 30 additions & 0 deletions src/ft2font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,17 @@
}
}

void FT2Font::set_transform(
std::array<std::array<FT_Fixed, 2>, 2> matrix, std::array<FT_Fixed, 2> delta)
{
FT_Matrix m = {matrix[0][0], matrix[0][1], matrix[1][0], matrix[1][1]};
FT_Vector d = {delta[0], delta[1]};
FT_Set_Transform(face, &m, &d);
for (auto & fallback : fallbacks) {
fallback->set_transform(matrix, delta);
}
}

void FT2Font::set_charmap(int i)
{
if (i >= face->num_charmaps) {
Expand Down Expand Up @@ -721,6 +732,25 @@
im.draw_bitmap(&bitmap->bitmap, x + bitmap->left, y);
}

void FT2Font::draw_glyph_at(FT2Image &im, double x, double y, size_t glyphInd, bool antialiased)
{
if (glyphInd >= glyphs.size()) {
throw std::runtime_error("glyph num is out of range");
}
FT_Vector sub_offset = {FT_Fixed(x * 64 + .5), FT_Fixed(y * 64 + .5)};
FT_Error error = FT_Glyph_To_Bitmap(
&glyphs[glyphInd],
antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO,
&sub_offset, // additional translation
1 // destroy image
);
if (error) {
throw_ft_error("Could not convert glyph to bitmap", error);

Check warning on line 748 in src/ft2font.cpp

View check run for this annotation

Codecov / codecov/patch

src/ft2font.cpp#L748

Added line #L748 was not covered by tests
}
FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyphs[glyphInd];
im.draw_bitmap(&bitmap->bitmap, bitmap->left, im.get_height() - bitmap->top);
}

void FT2Font::get_glyph_name(unsigned int glyph_number, std::string &buffer,
bool fallback = false)
{
Expand Down
3 changes: 3 additions & 0 deletions src/ft2font.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ class FT2Font
virtual ~FT2Font();
void clear();
void set_size(double ptsize, double dpi);
void set_transform(
std::array<std::array<FT_Fixed, 2>, 2> matrix, std::array<FT_Fixed, 2> delta);
void set_charmap(int i);
void select_charmap(unsigned long i);
void set_text(std::u32string_view codepoints, double angle, FT_Int32 flags,
Expand All @@ -102,6 +104,7 @@ class FT2Font
long get_descent();
void draw_glyphs_to_bitmap(bool antialiased);
void draw_glyph_to_bitmap(FT2Image &im, int x, int y, size_t glyphInd, bool antialiased);
void draw_glyph_at(FT2Image &im, double x, double y, size_t glyphInd, bool antialiased);
void get_glyph_name(unsigned int glyph_number, std::string &buffer, bool fallback);
long get_name_index(char *name);
FT_UInt get_char_index(FT_ULong charcode, bool fallback);
Expand Down
53 changes: 52 additions & 1 deletion src/ft2font_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,25 @@ PyFT2Font_set_size(PyFT2Font *self, double ptsize, double dpi)
self->x->set_size(ptsize, dpi);
}

const char *PyFT2Font__set_transform__doc__ = R"""(
Set the transform of the text.

This is a low-level function directly taking inputs in 26.6 format. Refer
to the FreeType docs of FT_Set_Transform for further description.

Parameters
----------
matrix : (2, 2) array of int
delta : (2,) array of int
)""";

static void
PyFT2Font__set_transform(
PyFT2Font *self, std::array<std::array<FT_Fixed, 2>, 2> matrix, std::array<FT_Fixed, 2> delta)
{
self->x->set_transform(matrix, delta);
}

const char *PyFT2Font_set_charmap__doc__ = R"""(
Make the i-th charmap current.

Expand Down Expand Up @@ -971,7 +990,7 @@ const char *PyFT2Font_draw_glyph_to_bitmap__doc__ = R"""(
image : FT2Image
The image buffer on which to draw the glyph.
x, y : int
The pixel location at which to draw the glyph.
The position of the glyph's top left corner.
glyph : Glyph
The glyph to draw.
antialiased : bool, default: True
Expand All @@ -993,6 +1012,34 @@ PyFT2Font_draw_glyph_to_bitmap(PyFT2Font *self, FT2Image &image,
self->x->draw_glyph_to_bitmap(image, xd, yd, glyph->glyphInd, antialiased);
}

const char *PyFT2Font__draw_glyph_at__doc__ = R"""(
Draw a single glyph to the bitmap at pixel locations x, y.

Parameters
----------
image : FT2Image
The image buffer on which to draw the glyph. If the buffer is too
small, the glyph will be cropped.
x, y : float
The position of the glyph's origin.
glyph : Glyph
The glyph to draw.
antialiased : bool, default: True
Whether to render glyphs 8-bit antialiased or in pure black-and-white.

See Also
--------
.draw_glyphs_to_bitmap
)""";

static void
PyFT2Font__draw_glyph_at(PyFT2Font *self, FT2Image &image,
double x, double y,
PyGlyph *glyph, bool antialiased = true)
{
self->x->draw_glyph_at(image, x, y, glyph->glyphInd, antialiased);
}

const char *PyFT2Font_get_glyph_name__doc__ = R"""(
Retrieve the ASCII name of a given glyph *index* in a face.

Expand Down Expand Up @@ -1614,6 +1661,7 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used())
.def("clear", &PyFT2Font_clear, PyFT2Font_clear__doc__)
.def("set_size", &PyFT2Font_set_size, "ptsize"_a, "dpi"_a,
PyFT2Font_set_size__doc__)
.def("_set_transform", &PyFT2Font__set_transform, "matrix"_a, "delta"_a)
.def("set_charmap", &PyFT2Font_set_charmap, "i"_a,
PyFT2Font_set_charmap__doc__)
.def("select_charmap", &PyFT2Font_select_charmap, "i"_a,
Expand Down Expand Up @@ -1643,6 +1691,9 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used())
.def("draw_glyph_to_bitmap", &PyFT2Font_draw_glyph_to_bitmap,
"image"_a, "x"_a, "y"_a, "glyph"_a, py::kw_only(), "antialiased"_a=true,
PyFT2Font_draw_glyph_to_bitmap__doc__)
.def("_draw_glyph_at", &PyFT2Font__draw_glyph_at,
"image"_a, "x"_a, "y"_a, "glyph"_a, py::kw_only(), "antialiased"_a=true,
PyFT2Font__draw_glyph_at__doc__)
.def("get_glyph_name", &PyFT2Font_get_glyph_name, "index"_a,
PyFT2Font_get_glyph_name__doc__)
.def("get_charmap", &PyFT2Font_get_charmap, PyFT2Font_get_charmap__doc__)
Expand Down
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy