Improve rendering of italic fonts in linux
Now rather than down-size characters from italic fonts that do not fit into the cell width, trim the left and right margins to make them fit, instead.
This commit is contained in:
parent
b4bf0eb794
commit
0427f30c2a
@ -100,7 +100,11 @@ def render_char(text, bold=False, italic=False, width=1):
|
|||||||
face = alt_face_cache[font] = Face(font.face)
|
face = alt_face_cache[font] = Face(font.face)
|
||||||
set_char_size(face, **cff_size)
|
set_char_size(face, **cff_size)
|
||||||
bitmap = render_to_bitmap(font, face, text)
|
bitmap = render_to_bitmap(font, face, text)
|
||||||
if width == 1 and bitmap.width > cell_width * 1.1:
|
if width == 1 and bitmap.width > cell_width:
|
||||||
|
extra = bitmap.width - cell_width
|
||||||
|
if italic and extra < cell_width // 2:
|
||||||
|
bitmap = face.trim_to_width(bitmap, cell_width)
|
||||||
|
elif extra > max(2, 0.1 * cell_width):
|
||||||
# rescale the font size so that the glyph is visible in a single
|
# rescale the font size so that the glyph is visible in a single
|
||||||
# cell and hope somebody updates libc's wcwidth
|
# cell and hope somebody updates libc's wcwidth
|
||||||
sz = cff_size.copy()
|
sz = cff_size.copy()
|
||||||
@ -117,10 +121,6 @@ def render_char(text, bold=False, italic=False, width=1):
|
|||||||
ceil_int(abs(m.horiBearingY) / 64), ceil_int(m.horiAdvance / 64), bitmap.rows, bitmap.width)
|
ceil_int(abs(m.horiBearingY) / 64), ceil_int(m.horiAdvance / 64), bitmap.rows, bitmap.width)
|
||||||
|
|
||||||
|
|
||||||
def is_wide_char(bitmap_char):
|
|
||||||
return min(bitmap_char.advance, bitmap_char.columns) > cell_width * 1.1
|
|
||||||
|
|
||||||
|
|
||||||
def place_char_in_cell(bitmap_char):
|
def place_char_in_cell(bitmap_char):
|
||||||
# We want the glyph to be positioned inside the cell based on the bearingX
|
# We want the glyph to be positioned inside the cell based on the bearingX
|
||||||
# and bearingY values, making sure that it does not overflow the cell.
|
# and bearingY values, making sure that it does not overflow the cell.
|
||||||
|
|||||||
@ -184,6 +184,46 @@ bitmap(Face *self) {
|
|||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
trim_to_width(Face UNUSED *self, PyObject *args) {
|
||||||
|
#define trim_to_width_doc "Trim edges from the supplied bitmap to make it fit in the specified cell-width"
|
||||||
|
PyObject *bitmap, *t;
|
||||||
|
unsigned long cell_width, rows, width, rtrim = 0, extra, ltrim;
|
||||||
|
unsigned char *src, *dest;
|
||||||
|
bool column_has_text = false;
|
||||||
|
if (!PyArg_ParseTuple(args, "O!k", &BitmapType, &bitmap, &cell_width)) return NULL;
|
||||||
|
rows = PyLong_AsUnsignedLong(PyStructSequence_GET_ITEM(bitmap, 0));
|
||||||
|
width = PyLong_AsUnsignedLong(PyStructSequence_GET_ITEM(bitmap, 1));
|
||||||
|
extra = width - cell_width;
|
||||||
|
if (extra >= cell_width) { PyErr_SetString(PyExc_ValueError, "Too large for trimming"); return NULL; }
|
||||||
|
PyObject *ans = PyStructSequence_New(&BitmapType);
|
||||||
|
if (ans == NULL) return PyErr_NoMemory();
|
||||||
|
src = (unsigned char*)PyByteArray_AS_STRING(PyStructSequence_GET_ITEM(bitmap, 3));
|
||||||
|
PyObject *abuf = PyByteArray_FromStringAndSize(NULL, cell_width * rows);
|
||||||
|
if (abuf == NULL) { Py_CLEAR(ans); return PyErr_NoMemory(); }
|
||||||
|
dest = (unsigned char*)PyByteArray_AS_STRING(abuf);
|
||||||
|
PyStructSequence_SET_ITEM(ans, 1, PyLong_FromUnsignedLong(cell_width));
|
||||||
|
PyStructSequence_SET_ITEM(ans, 2, PyLong_FromUnsignedLong(cell_width));
|
||||||
|
PyStructSequence_SET_ITEM(ans, 3, abuf);
|
||||||
|
#define COPY(which) t = PyStructSequence_GET_ITEM(bitmap, which); Py_INCREF(t); PyStructSequence_SET_ITEM(ans, which, t);
|
||||||
|
COPY(0); COPY(4); COPY(5); COPY(6);
|
||||||
|
#undef COPY
|
||||||
|
|
||||||
|
for (long x = width - 1; !column_has_text && x > -1 && rtrim < extra; x--) {
|
||||||
|
for (unsigned long y = 0; y < rows * width; y += width) {
|
||||||
|
if (src[x + y] > 200) { column_has_text = true; break; }
|
||||||
|
}
|
||||||
|
if (!column_has_text) rtrim++;
|
||||||
|
}
|
||||||
|
rtrim = MIN(extra, rtrim);
|
||||||
|
ltrim = extra - rtrim;
|
||||||
|
for (unsigned long y = 0; y < rows; y++) {
|
||||||
|
memcpy(dest + y*cell_width, src + ltrim + y*width, cell_width);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
// Boilerplate {{{
|
// Boilerplate {{{
|
||||||
|
|
||||||
static PyMemberDef members[] = {
|
static PyMemberDef members[] = {
|
||||||
@ -205,6 +245,7 @@ static PyMethodDef methods[] = {
|
|||||||
METHOD(get_char_index, METH_VARARGS)
|
METHOD(get_char_index, METH_VARARGS)
|
||||||
METHOD(glyph_metrics, METH_NOARGS)
|
METHOD(glyph_metrics, METH_NOARGS)
|
||||||
METHOD(bitmap, METH_NOARGS)
|
METHOD(bitmap, METH_NOARGS)
|
||||||
|
METHOD(trim_to_width, METH_VARARGS)
|
||||||
{NULL} /* Sentinel */
|
{NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -234,6 +275,7 @@ init_freetype_library(PyObject *m) {
|
|||||||
if (PyStructSequence_InitType2(&GlpyhMetricsType, &gm_desc) != 0) return false;
|
if (PyStructSequence_InitType2(&GlpyhMetricsType, &gm_desc) != 0) return false;
|
||||||
if (PyStructSequence_InitType2(&BitmapType, &bm_desc) != 0) return false;
|
if (PyStructSequence_InitType2(&BitmapType, &bm_desc) != 0) return false;
|
||||||
PyModule_AddObject(m, "GlyphMetrics", (PyObject*)&GlpyhMetricsType);
|
PyModule_AddObject(m, "GlyphMetrics", (PyObject*)&GlpyhMetricsType);
|
||||||
|
PyModule_AddObject(m, "Bitmap", (PyObject*)&BitmapType);
|
||||||
PyModule_AddIntMacro(m, FT_LOAD_RENDER);
|
PyModule_AddIntMacro(m, FT_LOAD_RENDER);
|
||||||
PyModule_AddIntMacro(m, FT_LOAD_TARGET_NORMAL);
|
PyModule_AddIntMacro(m, FT_LOAD_TARGET_NORMAL);
|
||||||
PyModule_AddIntMacro(m, FT_LOAD_TARGET_LIGHT);
|
PyModule_AddIntMacro(m, FT_LOAD_TARGET_LIGHT);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user