Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Replace FT2Image by plain numpy arrays.#30044

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
timhoffm merged 1 commit intomatplotlib:mainfromanntzer:ufi
May 24, 2025
Merged
Show file tree
Hide file tree
Changes fromall 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
12 changes: 12 additions & 0 deletionsdoc/api/next_api_changes/deprecations/30044-AL.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
``FT2Image``
~~~~~~~~~~~~
... is deprecated. Use 2D uint8 ndarrays instead. In particular:

- The ``FT2Image`` constructor took ``width, height`` as separate parameters
but the ndarray constructor takes ``(height, width)`` as single tuple
parameter.
- `.FT2Font.draw_glyph_to_bitmap` now (also) takes 2D uint8 arrays as input.
- ``FT2Image.draw_rect_filled`` should be replaced by directly setting pixel
values to black.
- The ``image`` attribute of the object returned by ``MathTextParser("agg").parse``
is now a 2D uint8 array.
14 changes: 9 additions & 5 deletionslib/matplotlib/_mathtext.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,7 @@
import enum
import functools
import logging
import math
import os
import re
import types
Expand All@@ -19,6 +20,7 @@
from typing import NamedTuple

import numpy as np
from numpy.typing import NDArray
from pyparsing import (
Empty, Forward, Literal, Group, NotAny, OneOrMore, Optional,
ParseBaseException, ParseException, ParseExpression, ParseFatalException,
Expand All@@ -30,7 +32,7 @@
from ._mathtext_data import (
latex_to_bakoma, stix_glyph_fixes, stix_virtual_fonts, tex2uni)
from .font_manager import FontProperties, findfont, get_font
from .ft2font import FT2Font,FT2Image,Kerning, LoadFlags
from .ft2font import FT2Font, Kerning, LoadFlags


if T.TYPE_CHECKING:
Expand DownExpand Up@@ -99,15 +101,15 @@ class RasterParse(NamedTuple):
The offsets are always zero.
width, height, depth : float
The global metrics.
image :FT2Image
image :2D array of uint8
A raster image.
"""
ox: float
oy: float
width: float
height: float
depth: float
image:FT2Image
image:NDArray[np.uint8]

RasterParse.__module__ = "matplotlib.mathtext"

Expand DownExpand Up@@ -148,7 +150,7 @@ def to_raster(self, *, antialiased: bool) -> RasterParse:
w = xmax - xmin
h = ymax - ymin - self.box.depth
d = ymax - ymin - self.box.height
image =FT2Image(int(np.ceil(w)), int(np.ceil(h + max(d, 0))))
image = np.zeros((math.ceil(h + max(d, 0)), math.ceil(w)), np.uint8)

# Ideally, we could just use self.glyphs and self.rects here, shifting
# their coordinates by (-xmin, -ymin), but this yields slightly
Expand All@@ -167,7 +169,9 @@ def to_raster(self, *, antialiased: bool) -> RasterParse:
y = int(center - (height + 1) / 2)
else:
y = int(y1)
image.draw_rect_filled(int(x1), y, int(np.ceil(x2)), y + height)
x1 = math.floor(x1)
x2 = math.ceil(x2)
image[y:y+height+1, x1:x2+1] = 0xff
return RasterParse(0, 0, w, h + d, d, image)


Expand Down
2 changes: 1 addition & 1 deletionlib/matplotlib/ft2font.pyi
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -198,7 +198,7 @@ class FT2Font(Buffer):
def _get_fontmap(self, string: str) -> dict[str, FT2Font]: ...
def clear(self) -> None: ...
def draw_glyph_to_bitmap(
self, image:FT2Image, x: int, y: int, glyph: Glyph, antialiased: bool = ...
self, image:NDArray[np.uint8], x: int, y: int, glyph: Glyph, antialiased: bool = ...
) -> None: ...
def draw_glyphs_to_bitmap(self, antialiased: bool = ...) -> None: ...
def get_bitmap_offset(self) -> tuple[int, int]: ...
Expand Down
5 changes: 3 additions & 2 deletionslib/matplotlib/tests/test_ft2font.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,7 +18,8 @@ def test_ft2image_draw_rect_filled():
width = 23
height = 42
for x0, y0, x1, y1 in itertools.product([1, 100], [2, 200], [4, 400], [8, 800]):
im = ft2font.FT2Image(width, height)
with pytest.warns(mpl.MatplotlibDeprecationWarning):
im = ft2font.FT2Image(width, height)
im.draw_rect_filled(x0, y0, x1, y1)
a = np.asarray(im)
assert a.dtype == np.uint8
Expand DownExpand Up@@ -823,7 +824,7 @@ def test_ft2font_drawing():
np.testing.assert_array_equal(image, expected)
font = ft2font.FT2Font(file, hinting_factor=1, _kerning_factor=0)
glyph = font.load_char(ord('M'))
image =ft2font.FT2Image(expected.shape[1], expected.shape[0])
image =np.zeros(expected.shape, np.uint8)
font.draw_glyph_to_bitmap(image, -1, 1, glyph, antialiased=False)
np.testing.assert_array_equal(image, expected)

Expand Down
59 changes: 17 additions & 42 deletionssrc/ft2font.cpp
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,51 +63,23 @@ void throw_ft_error(std::string message, FT_Error error) {
throw std::runtime_error(os.str());
}

FT2Image::FT2Image() : m_buffer(nullptr), m_width(0), m_height(0)
{
}

FT2Image::FT2Image(unsigned long width, unsigned long height)
: m_buffer(nullptr),m_width(0), m_height(0)
: m_buffer((unsigned char *)calloc(width * height, 1)),m_width(width), m_height(height)
{
resize(width, height);
}

FT2Image::~FT2Image()
{
delete[]m_buffer;
free(m_buffer);
}

void FT2Image::resize(long width, long height)
void draw_bitmap(
py::array_t<uint8_t, py::array::c_style> im, FT_Bitmap *bitmap, FT_Int x, FT_Int y)
{
if (width <= 0) {
width = 1;
}
if (height <= 0) {
height = 1;
}
size_t numBytes = width * height;

if ((unsigned long)width != m_width || (unsigned long)height != m_height) {
if (numBytes > m_width * m_height) {
delete[] m_buffer;
m_buffer = nullptr;
m_buffer = new unsigned char[numBytes];
}
auto buf = im.mutable_data(0);

m_width = (unsigned long)width;
m_height = (unsigned long)height;
}

if (numBytes && m_buffer) {
memset(m_buffer, 0, numBytes);
}
}

void FT2Image::draw_bitmap(FT_Bitmap *bitmap, FT_Int x, FT_Int y)
{
FT_Int image_width = (FT_Int)m_width;
FT_Int image_height = (FT_Int)m_height;
FT_Int image_width = (FT_Int)im.shape(1);
FT_Int image_height = (FT_Int)im.shape(0);
FT_Int char_width = bitmap->width;
FT_Int char_height = bitmap->rows;

Expand All@@ -121,14 +93,14 @@ void FT2Image::draw_bitmap(FT_Bitmap *bitmap, FT_Int x, FT_Int y)

if (bitmap->pixel_mode == FT_PIXEL_MODE_GRAY) {
for (FT_Int i = y1; i < y2; ++i) {
unsigned char *dst =m_buffer + (i * image_width + x1);
unsigned char *dst =buf + (i * image_width + x1);
unsigned char *src = bitmap->buffer + (((i - y_offset) * bitmap->pitch) + x_start);
for (FT_Int j = x1; j < x2; ++j, ++dst, ++src)
*dst |= *src;
}
} else if (bitmap->pixel_mode == FT_PIXEL_MODE_MONO) {
for (FT_Int i = y1; i < y2; ++i) {
unsigned char *dst =m_buffer + (i * image_width + x1);
unsigned char *dst =buf + (i * image_width + x1);
unsigned char *src = bitmap->buffer + ((i - y_offset) * bitmap->pitch);
for (FT_Int j = x1; j < x2; ++j, ++dst) {
int x = (j - x1 + x_start);
Expand DownExpand Up@@ -259,7 +231,7 @@ FT2Font::FT2Font(FT_Open_Args &open_args,
long hinting_factor_,
std::vector<FT2Font *> &fallback_list,
FT2Font::WarnFunc warn, bool warn_if_used)
: ft_glyph_warn(warn), warn_if_used(warn_if_used), image(), face(nullptr),
: ft_glyph_warn(warn), warn_if_used(warn_if_used), image({1, 1}), face(nullptr),
hinting_factor(hinting_factor_),
// set default kerning factor to 0, i.e., no kerning manipulation
kerning_factor(0)
Expand DownExpand Up@@ -676,7 +648,8 @@ void FT2Font::draw_glyphs_to_bitmap(bool antialiased)
long width = (bbox.xMax - bbox.xMin) / 64 + 2;
long height = (bbox.yMax - bbox.yMin) / 64 + 2;

image.resize(width, height);
image = py::array_t<uint8_t>{{height, width}};
std::memset(image.mutable_data(0), 0, image.nbytes());

for (auto & glyph : glyphs) {
FT_Error error = FT_Glyph_To_Bitmap(
Expand All@@ -692,11 +665,13 @@ void FT2Font::draw_glyphs_to_bitmap(bool antialiased)
FT_Int x = (FT_Int)(bitmap->left - (bbox.xMin * (1. / 64.)));
FT_Int y = (FT_Int)((bbox.yMax * (1. / 64.)) - bitmap->top + 1);

image.draw_bitmap(&bitmap->bitmap, x, y);
draw_bitmap(image,&bitmap->bitmap, x, y);
}
}

void FT2Font::draw_glyph_to_bitmap(FT2Image &im, int x, int y, size_t glyphInd, bool antialiased)
void FT2Font::draw_glyph_to_bitmap(
py::array_t<uint8_t, py::array::c_style> im,
int x, int y, size_t glyphInd, bool antialiased)
{
FT_Vector sub_offset;
sub_offset.x = 0; // int((xd - (double)x) * 64.0);
Expand All@@ -718,7 +693,7 @@ void FT2Font::draw_glyph_to_bitmap(FT2Image &im, int x, int y, size_t glyphInd,

FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyphs[glyphInd];

im.draw_bitmap(&bitmap->bitmap, x + bitmap->left, y);
draw_bitmap(im,&bitmap->bitmap, x + bitmap->left, y);
}

void FT2Font::get_glyph_name(unsigned int glyph_number, std::string &buffer,
Expand Down
13 changes: 9 additions & 4 deletionssrc/ft2font.h
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,10 @@ extern "C" {
#include FT_TRUETYPE_TABLES_H
}

#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
namespace py = pybind11;

/*
By definition, FT_FIXED as 2 16bit values stored in a single long.
*/
Expand All@@ -32,7 +36,6 @@ extern "C" {
class FT2Image
{
public:
FT2Image();
FT2Image(unsigned long width, unsigned long height);
virtual ~FT2Image();

Expand DownExpand Up@@ -101,7 +104,9 @@ class FT2Font
void get_bitmap_offset(long *x, long *y);
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_to_bitmap(
py::array_t<uint8_t, py::array::c_style> im,
int x, int 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 All@@ -113,7 +118,7 @@ class FT2Font
return face;
}

FT2Image &get_image()
py::array_t<uint8_t, py::array::c_style> &get_image()
{
return image;
}
Expand DownExpand Up@@ -141,7 +146,7 @@ class FT2Font
private:
WarnFunc ft_glyph_warn;
bool warn_if_used;
FT2Image image;
py::array_t<uint8_t, py::array::c_style> image;
FT_Face face;
FT_Vector pen; /* untransformed origin */
std::vector<FT_Glyph> glyphs;
Expand Down
46 changes: 27 additions & 19 deletionssrc/ft2font_wrapper.cpp
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -968,7 +968,7 @@ const char *PyFT2Font_draw_glyph_to_bitmap__doc__ = R"""(

Parameters
----------
image :FT2Image
image :2d array of uint8
The image buffer on which to draw the glyph.
x, y : int
The pixel location at which to draw the glyph.
Expand All@@ -983,14 +983,16 @@ const char *PyFT2Font_draw_glyph_to_bitmap__doc__ = R"""(
)""";

static void
PyFT2Font_draw_glyph_to_bitmap(PyFT2Font *self,FT2Image &image,
PyFT2Font_draw_glyph_to_bitmap(PyFT2Font *self,py::buffer &image,
double_or_<int> vxd, double_or_<int> vyd,
PyGlyph *glyph, bool antialiased = true)
{
auto xd = _double_to_<int>("x", vxd);
auto yd = _double_to_<int>("y", vyd);

self->x->draw_glyph_to_bitmap(image, xd, yd, glyph->glyphInd, antialiased);
self->x->draw_glyph_to_bitmap(
py::array_t<uint8_t, py::array::c_style>{image},
xd, yd, glyph->glyphInd, antialiased);
}

const char *PyFT2Font_get_glyph_name__doc__ = R"""(
Expand DownExpand Up@@ -1440,12 +1442,7 @@ const char *PyFT2Font_get_image__doc__ = R"""(
static py::array
PyFT2Font_get_image(PyFT2Font *self)
{
FT2Image &im = self->x->get_image();
py::ssize_t dims[] = {
static_cast<py::ssize_t>(im.get_height()),
static_cast<py::ssize_t>(im.get_width())
};
return py::array_t<unsigned char>(dims, im.get_buffer());
return self->x->get_image();
}

const char *PyFT2Font__get_type1_encoding_vector__doc__ = R"""(
Expand DownExpand Up@@ -1565,6 +1562,10 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used())
PyFT2Image__doc__)
.def(py::init(
[](double_or_<long> width, double_or_<long> height) {
auto warn =
py::module_::import("matplotlib._api").attr("warn_deprecated");
warn("since"_a="3.11", "name"_a="FT2Image", "obj_type"_a="class",
"alternative"_a="a 2D uint8 ndarray");
return new FT2Image(
_double_to_<long>("width", width),
_double_to_<long>("height", height)
Expand DownExpand Up@@ -1604,8 +1605,8 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used())
.def_property_readonly("bbox", &PyGlyph_get_bbox,
"The control box of the glyph.");

py::class_<PyFT2Font>(m, "FT2Font", py::is_final(), py::buffer_protocol(),
PyFT2Font__doc__)
auto cls =py::class_<PyFT2Font>(m, "FT2Font", py::is_final(), py::buffer_protocol(),
PyFT2Font__doc__)
.def(py::init(&PyFT2Font_init),
"filename"_a, "hinting_factor"_a=8, py::kw_only(),
"_fallback_list"_a=py::none(), "_kerning_factor"_a=0,
Expand DownExpand Up@@ -1639,10 +1640,20 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used())
.def("get_descent", &PyFT2Font_get_descent, PyFT2Font_get_descent__doc__)
.def("draw_glyphs_to_bitmap", &PyFT2Font_draw_glyphs_to_bitmap,
py::kw_only(), "antialiased"_a=true,
PyFT2Font_draw_glyphs_to_bitmap__doc__)
.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__)
PyFT2Font_draw_glyphs_to_bitmap__doc__);
// The generated docstring uses an unqualified "Buffer" as type hint,
// which causes an error in sphinx. This is fixed as of pybind11
// master (since #5566) which now uses "collections.abc.Buffer";
// restore the signature once that version is released.
{
py::options options{};
options.disable_function_signatures();
cls
.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__);
}
cls
.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 DownExpand Up@@ -1760,10 +1771,7 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used())
"The original filename for this object.")

.def_buffer([](PyFT2Font &self) -> py::buffer_info {
FT2Image &im = self.x->get_image();
std::vector<py::size_t> shape { im.get_height(), im.get_width() };
std::vector<py::size_t> strides { im.get_width(), 1 };
return py::buffer_info(im.get_buffer(), shape, strides);
return self.x->get_image().request();
});

m.attr("__freetype_version__") = version_string;
Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp