Finish up harfbuzz based rendering
This commit is contained in:
parent
a5e6ab2bee
commit
0652fa1696
@ -193,13 +193,16 @@ def render_char(text, bold=False, italic=False, width=1):
|
||||
|
||||
def render_complex_char(text, bold=False, italic=False, width=1):
|
||||
font, face = face_for_text(text, bold, italic)
|
||||
buf, m, width, height = face.draw_complex_glyph(text)
|
||||
return CharBitmap(
|
||||
buf,
|
||||
ceil_int(abs(m.horiBearingX) / 64),
|
||||
ceil_int(abs(m.horiBearingY) / 64),
|
||||
ceil_int(m.horiAdvance / 64), height, width
|
||||
)
|
||||
if width == 1:
|
||||
buf = CharTexture()
|
||||
ans = (buf,)
|
||||
else:
|
||||
buf = (ctypes.c_ubyte * (cell_width * width * cell_height))()
|
||||
ans = tuple(CharTexture() for i in range(width))
|
||||
face.draw_complex_glyph(text, cell_width, cell_height, ctypes.addressof(buf), width, bold, italic, baseline)
|
||||
if width > 1:
|
||||
face.split_cells(cell_width, cell_height, ctypes.addressof(buf), *(ctypes.addressof(x) for x in ans))
|
||||
return ans
|
||||
|
||||
|
||||
def place_char_in_cell(bitmap_char):
|
||||
@ -273,26 +276,35 @@ def missing_glyph(width):
|
||||
def render_cell(text=' ', bold=False, italic=False):
|
||||
width = wcwidth(text[0])
|
||||
|
||||
try:
|
||||
if len(text) > 1:
|
||||
bitmap_char = render_complex_char(text, bold, italic, width)
|
||||
else:
|
||||
bitmap_char = render_char(text, bold, italic, width)
|
||||
except FontNotFound as err:
|
||||
safe_print('ERROR:', err, file=sys.stderr)
|
||||
return missing_glyph(width)
|
||||
except FreeTypeError as err:
|
||||
safe_print('Failed to render text:', repr(text), 'with error:', err, file=sys.stderr)
|
||||
return missing_glyph(width)
|
||||
second = None
|
||||
if width == 2:
|
||||
if bitmap_char.columns > cell_width:
|
||||
bitmap_char, second = split_char_bitmap(bitmap_char)
|
||||
second = place_char_in_cell(second)
|
||||
else:
|
||||
second = render_cell()[0]
|
||||
def safe_freetype(func):
|
||||
try:
|
||||
return func(text, bold, italic, width)
|
||||
except FontNotFound as err:
|
||||
safe_print('ERROR:', err, file=sys.stderr)
|
||||
except FreeTypeError as err:
|
||||
safe_print('Failed to render text:', repr(text), 'with error:', err, file=sys.stderr)
|
||||
|
||||
first = place_char_in_cell(bitmap_char)
|
||||
if len(text) > 1:
|
||||
ret = safe_freetype(render_complex_char)
|
||||
if ret is None:
|
||||
return missing_glyph(width)
|
||||
if width == 1:
|
||||
first, second = ret[0], None
|
||||
else:
|
||||
first, second = ret
|
||||
else:
|
||||
bitmap_char = safe_freetype(render_char)
|
||||
if bitmap_char is None:
|
||||
return missing_glyph(width)
|
||||
second = None
|
||||
if width == 2:
|
||||
if bitmap_char.columns > cell_width:
|
||||
bitmap_char, second = split_char_bitmap(bitmap_char)
|
||||
second = place_char_in_cell(second)
|
||||
else:
|
||||
second = render_cell()[0]
|
||||
|
||||
first = place_char_in_cell(bitmap_char)
|
||||
|
||||
return first, second
|
||||
|
||||
|
||||
@ -380,7 +380,7 @@ place_bitmap_in_cell(unsigned char *cell, ProcessedBitmap *bm, size_t cell_width
|
||||
ssize_t dy = (ssize_t)((float)metrics->horiBearingY / 64.f + y_offset);
|
||||
size_t src_start_row, dest_start_row;
|
||||
if (dy > 0 && (size_t)dy > baseline) {
|
||||
src_start_row = dy - baseline;
|
||||
src_start_row = 0;
|
||||
dest_start_row = 0;
|
||||
} else {
|
||||
src_start_row = 0;
|
||||
@ -405,7 +405,7 @@ draw_complex_glyph(Face *self, PyObject *args) {
|
||||
unsigned int cell_width, cell_height, num_cells, baseline;
|
||||
PyObject *addr;
|
||||
float x = 0.f, y = 0.f;
|
||||
if (!PyArg_ParseTuple(args, "s#IIO!Ipp", &text, &text_len, &cell_width, &cell_height, &PyLong_Type, &addr, &num_cells, &bold, &italic, &baseline)) return NULL;
|
||||
if (!PyArg_ParseTuple(args, "s#IIO!IppI", &text, &text_len, &cell_width, &cell_height, &PyLong_Type, &addr, &num_cells, &bold, &italic, &baseline)) return NULL;
|
||||
unsigned char *cell = PyLong_AsVoidPtr(addr);
|
||||
ShapeData sd;
|
||||
_shape(self, text, text_len, &sd);
|
||||
@ -423,6 +423,30 @@ draw_complex_glyph(Face *self, PyObject *args) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
split_cells(Face UNUSED *self, PyObject *args) {
|
||||
#define split_cells_doc "split_cells(cell_width, cell_height, src, *cells)"
|
||||
unsigned int cell_width, cell_height;
|
||||
unsigned char *cells[10], *src;
|
||||
size_t num_cells = PyTuple_GET_SIZE(args) - 3;
|
||||
if (num_cells > sizeof(cells)/sizeof(cells[0])) { PyErr_SetString(PyExc_ValueError, "Too many cells being split"); return NULL; }
|
||||
cell_width = PyLong_AsUnsignedLong(PyTuple_GET_ITEM(args, 0));
|
||||
cell_height = PyLong_AsUnsignedLong(PyTuple_GET_ITEM(args, 1));
|
||||
src = PyLong_AsVoidPtr(PyTuple_GET_ITEM(args, 2));
|
||||
for (size_t i = 3; i < num_cells + 3; i++) cells[i - 3] = PyLong_AsVoidPtr(PyTuple_GET_ITEM(args, i));
|
||||
|
||||
size_t stride = num_cells * cell_width;
|
||||
for (size_t y = 0; y < cell_height; y++) {
|
||||
for (size_t i = 0; i < num_cells; i++) {
|
||||
unsigned char *dest = cells[i] + y * cell_width;
|
||||
for (size_t x = 0; x < cell_width; x++) {
|
||||
dest[x] = src[y * stride + i * cell_width + x];
|
||||
}
|
||||
}
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
trim_to_width(Face UNUSED *self, PyObject *args) {
|
||||
@ -486,6 +510,7 @@ static PyMethodDef methods[] = {
|
||||
METHOD(load_char, METH_O)
|
||||
METHOD(shape, METH_VARARGS)
|
||||
METHOD(draw_complex_glyph, METH_VARARGS)
|
||||
METHOD(split_cells, METH_VARARGS)
|
||||
METHOD(get_char_index, METH_VARARGS)
|
||||
METHOD(glyph_metrics, METH_NOARGS)
|
||||
METHOD(bitmap, METH_NOARGS)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user