More work on rendering complex glyphs
This commit is contained in:
parent
4bea6b7ad9
commit
8a049039ef
@ -193,8 +193,13 @@ 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)
|
||||
import pprint
|
||||
pprint.pprint(face.shape(text))
|
||||
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
|
||||
)
|
||||
|
||||
|
||||
def place_char_in_cell(bitmap_char):
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "data-types.h"
|
||||
#include <math.h>
|
||||
#include <structmember.h>
|
||||
#include <ft2build.h>
|
||||
#pragma GCC diagnostic push
|
||||
@ -181,12 +182,11 @@ static PyStructSequence_Field gm_fields[] = {
|
||||
static PyStructSequence_Desc gm_desc = {"GlpyhMetrics", NULL, gm_fields, 8};
|
||||
static PyTypeObject GlpyhMetricsType = {{{0}}};
|
||||
|
||||
static PyObject*
|
||||
glyph_metrics(Face *self) {
|
||||
#define glyph_metrics_doc ""
|
||||
static inline PyObject*
|
||||
gm_to_py(FT_Glyph_Metrics *gm) {
|
||||
PyObject *ans = PyStructSequence_New(&GlpyhMetricsType);
|
||||
if (ans != NULL) {
|
||||
#define SI(num, attr) PyStructSequence_SET_ITEM(ans, num, PyLong_FromLong(self->face->glyph->metrics.attr)); if (PyStructSequence_GET_ITEM(ans, num) == NULL) { Py_CLEAR(ans); return PyErr_NoMemory(); }
|
||||
#define SI(num, attr) PyStructSequence_SET_ITEM(ans, num, PyLong_FromLong(gm->attr)); if (PyStructSequence_GET_ITEM(ans, num) == NULL) { Py_CLEAR(ans); return PyErr_NoMemory(); }
|
||||
SI(0, width); SI(1, height);
|
||||
SI(2, horiBearingX); SI(3, horiBearingY); SI(4, horiAdvance);
|
||||
SI(5, vertBearingX); SI(6, vertBearingY); SI(7, vertAdvance);
|
||||
@ -195,6 +195,12 @@ glyph_metrics(Face *self) {
|
||||
return ans;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
glyph_metrics(Face *self) {
|
||||
#define glyph_metrics_doc ""
|
||||
return gm_to_py(&self->face->glyph->metrics);
|
||||
}
|
||||
|
||||
static PyStructSequence_Field bm_fields[] = {
|
||||
{"rows", NULL},
|
||||
{"width", NULL},
|
||||
@ -308,12 +314,30 @@ static inline bool
|
||||
ensure_space(GlyphBuffer *g, unsigned int width, unsigned int height) {
|
||||
if (g->width >= width && g->height >= height) return true;
|
||||
char *newbuf = calloc(width * height, sizeof(char));
|
||||
if (newbuf == NULL) return false;
|
||||
if (newbuf == NULL) { free(g->buf); g->buf = NULL; g->width = 0; g->height = 0; return false; }
|
||||
for (unsigned int r = 0; r < g->height; r++) memcpy(newbuf + r * width, g->buf + r * g->width, g->width);
|
||||
free(g->buf); g->buf = newbuf; g->width = width; g->height = height;
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
size_t x, y;
|
||||
} BitmapPoint;
|
||||
|
||||
|
||||
static inline void
|
||||
apply_bitmap(GlyphBuffer *dest, FT_Bitmap *bitmap, BitmapPoint src_start, BitmapPoint dest_start) {
|
||||
char *src = (char*)bitmap->buffer;
|
||||
size_t src_height = bitmap->rows, src_width = bitmap->pitch;
|
||||
#define ZERO_SUB(a, b) ((a) <= (b) ? 0 : (a) - (b))
|
||||
size_t width = MIN(ZERO_SUB(dest->width, dest_start.x), ZERO_SUB(src_width, src_start.x));
|
||||
#undef ZERO_SUB
|
||||
|
||||
for (size_t sy = src_start.y, dy = dest_start.y; sy < src_height && dy < dest->height; sy++, dy++) {
|
||||
memcpy(dest->buf + dest_start.x + dy * dest->width, src + sy * src_width, width);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
draw_complex_glyph(Face *self, PyObject *args) {
|
||||
@ -326,6 +350,7 @@ draw_complex_glyph(Face *self, PyObject *args) {
|
||||
ShapeData sd;
|
||||
_shape(self, string, len, &sd);
|
||||
GlyphBuffer g = {0};
|
||||
BitmapPoint src, dest;
|
||||
for (unsigned i = 0; i < sd.length; i++) {
|
||||
if (sd.info[i].codepoint == 0) continue;
|
||||
_load_char(self, sd.info[i].codepoint);
|
||||
@ -335,12 +360,26 @@ draw_complex_glyph(Face *self, PyObject *args) {
|
||||
width = MAX(width, (unsigned int)ceilf(x + self->face->glyph->bitmap.pitch));
|
||||
height = MAX(height, (unsigned int)ceilf(y + self->face->glyph->bitmap.rows));
|
||||
if (!ensure_space(&g, width, height)) return PyErr_NoMemory();
|
||||
|
||||
src.x = (size_t)(x < 0 ? ceilf(-x) : 0);
|
||||
src.y = (size_t)(y < 0 ? ceilf(-y) : 0);
|
||||
dest.x = (size_t)(x < 0 ? 0 : roundf(x));
|
||||
dest.y = (size_t)(y < 0 ? 0 : roundf(y));
|
||||
if (self->face->glyph->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY) {
|
||||
free(g.buf);
|
||||
PyErr_Format(PyExc_ValueError, "FreeType rendered a complex glyph with an unsupported pixel mode: %d", self->face->glyph->bitmap.pixel_mode);
|
||||
return NULL;
|
||||
}
|
||||
apply_bitmap(&g, &self->face->glyph->bitmap, src, dest);
|
||||
x += (float)sd.positions[i].x_advance / 64.0;
|
||||
y = 0;
|
||||
}
|
||||
if (!g.buf) {
|
||||
PyErr_Format(PyExc_ValueError, "No glpyhs found for string: %s", string);
|
||||
PyErr_Format(PyExc_ValueError, "No glyphs found for string: %s", string);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *t = PyByteArray_FromStringAndSize((const char*)g.buf, g.width * g.height);
|
||||
free(g.buf);
|
||||
return Py_BuildValue("NNII", t, gm_to_py(&g.metrics), g.width, g.height);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user