Implement rendering of ASCII char with FreeType
This commit is contained in:
parent
5796cbc040
commit
1b8978fede
@ -476,47 +476,64 @@ end:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t*
|
static uint8_t*
|
||||||
render_single_char_bitmap(const ProcessedBitmap *pbm, size_t *result_width, size_t *result_height) {
|
render_single_char_bitmap(const FT_Bitmap *bm, size_t *result_width, size_t *result_height) {
|
||||||
*result_width = pbm->width; *result_height = pbm->rows;
|
*result_width = bm->width; *result_height = bm->rows;
|
||||||
uint8_t *rendered = malloc(*result_width * *result_height);
|
uint8_t *rendered = malloc(*result_width * *result_height);
|
||||||
if (!rendered) { PyErr_NoMemory(); return NULL; }
|
if (!rendered) { PyErr_NoMemory(); return NULL; }
|
||||||
for (size_t r = 0; r < pbm->rows; r++) {
|
for (size_t r = 0; r < bm->rows; r++) {
|
||||||
uint8_t *src_row = pbm->buf + pbm->stride * r;
|
uint8_t *src_row = bm->buffer + bm->pitch * r;
|
||||||
uint8_t *dest_row = rendered + *result_width * r;
|
uint8_t *dest_row = rendered + *result_width * r;
|
||||||
memcpy(dest_row, src_row, MIN(*result_width, pbm->stride));
|
memcpy(dest_row, src_row, *result_width);
|
||||||
}
|
}
|
||||||
return rendered;
|
return rendered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct TempFontData {
|
||||||
|
Face *face;
|
||||||
|
FT_UInt orig_sz;
|
||||||
|
} TempFontData;
|
||||||
|
|
||||||
|
static void cleanup_resize(void *p) {
|
||||||
|
TempFontData *f = p;
|
||||||
|
if (f->face && f->face->freetype) {
|
||||||
|
f->face->pixel_size = f->orig_sz;
|
||||||
|
FT_Set_Pixel_Sizes(f->face->freetype, f->orig_sz, f->orig_sz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#define RESIZE_AFTER_FUNCTION __attribute__((cleanup(cleanup_resize)))
|
||||||
|
|
||||||
uint8_t*
|
uint8_t*
|
||||||
render_single_ascii_char_as_mask(FreeTypeRenderCtx ctx_, const char ch, size_t avail_height, size_t *result_width, size_t *result_height) {
|
render_single_ascii_char_as_mask(FreeTypeRenderCtx ctx_, const char ch, size_t *result_width, size_t *result_height) {
|
||||||
RenderCtx *ctx = (RenderCtx*)ctx_;
|
RenderCtx *ctx = (RenderCtx*)ctx_;
|
||||||
if (!ctx->created) { PyErr_SetString(PyExc_RuntimeError, "freetype render ctx not created"); return NULL; }
|
if (!ctx->created) { PyErr_SetString(PyExc_RuntimeError, "freetype render ctx not created"); return NULL; }
|
||||||
|
RESIZE_AFTER_FUNCTION TempFontData temp = {0};
|
||||||
Face *face = &main_face;
|
Face *face = &main_face;
|
||||||
int glyph_index = FT_Get_Char_Index(face->freetype, ch);
|
int glyph_index = FT_Get_Char_Index(face->freetype, ch);
|
||||||
if (!glyph_index) { PyErr_Format(PyExc_KeyError, "character %c not found in font", ch); return NULL; }
|
if (!glyph_index) { PyErr_Format(PyExc_KeyError, "character %c not found in font", ch); return NULL; }
|
||||||
unsigned int height = font_units_to_pixels_y(face->freetype, face->freetype->height);
|
unsigned int height = font_units_to_pixels_y(face->freetype, face->freetype->height);
|
||||||
|
size_t avail_height = *result_height;
|
||||||
|
if (avail_height < 4) { PyErr_Format(PyExc_ValueError, "Invalid available height: %zu", avail_height); return NULL; }
|
||||||
float ratio = ((float)height) / avail_height;
|
float ratio = ((float)height) / avail_height;
|
||||||
FT_UInt orig_sz = face->pixel_size;
|
temp.face = face; temp.orig_sz = face->pixel_size;
|
||||||
face->pixel_size = (FT_UInt)(face->pixel_size / ratio);
|
face->pixel_size = (FT_UInt)(face->pixel_size / ratio);
|
||||||
if (face->pixel_size != orig_sz) FT_Set_Pixel_Sizes(face->freetype, avail_height, avail_height);
|
if (face->pixel_size != temp.orig_sz) FT_Set_Pixel_Sizes(face->freetype, avail_height, avail_height);
|
||||||
int error = FT_Load_Glyph(face->freetype, glyph_index, get_load_flags(face->hinting, face->hintstyle, FT_LOAD_DEFAULT));
|
int error = FT_Load_Glyph(face->freetype, glyph_index, get_load_flags(face->hinting, face->hintstyle, FT_LOAD_DEFAULT));
|
||||||
FT_Set_Pixel_Sizes(face->freetype, orig_sz, orig_sz); face->pixel_size = orig_sz;
|
|
||||||
if (error) { PyErr_Format(PyExc_Exception, "failed to load glyph for character: %c", ch); return NULL;}
|
if (error) { PyErr_Format(PyExc_Exception, "failed to load glyph for character: %c", ch); return NULL;}
|
||||||
ProcessedBitmap pbm = {0};
|
if (face->freetype->glyph->format != FT_GLYPH_FORMAT_BITMAP) {
|
||||||
|
error = FT_Render_Glyph(face->freetype->glyph, FT_RENDER_MODE_NORMAL);
|
||||||
|
if (error) { PyErr_Format(PyExc_Exception, "failed to render glyph for character: %c", ch); return NULL;}
|
||||||
|
}
|
||||||
uint8_t *rendered = NULL;
|
uint8_t *rendered = NULL;
|
||||||
switch(face->freetype->glyph->bitmap.pixel_mode) {
|
switch(face->freetype->glyph->bitmap.pixel_mode) {
|
||||||
case FT_PIXEL_MODE_MONO: {
|
case FT_PIXEL_MODE_MONO: {
|
||||||
FT_Bitmap bitmap;
|
FT_Bitmap bitmap;
|
||||||
if (!freetype_convert_mono_bitmap(&face->freetype->glyph->bitmap, &bitmap)) return NULL;
|
if (!freetype_convert_mono_bitmap(&face->freetype->glyph->bitmap, &bitmap)) return NULL;
|
||||||
populate_processed_bitmap(face->freetype->glyph, &bitmap, &pbm);
|
rendered = render_single_char_bitmap(&bitmap, result_width, result_height);
|
||||||
rendered = render_single_char_bitmap(&pbm, result_width, result_height);
|
|
||||||
FT_Bitmap_Done(freetype_library(), &bitmap);
|
FT_Bitmap_Done(freetype_library(), &bitmap);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FT_PIXEL_MODE_GRAY:
|
case FT_PIXEL_MODE_GRAY:
|
||||||
populate_processed_bitmap(face->freetype->glyph, &face->freetype->glyph->bitmap, &pbm);
|
rendered = render_single_char_bitmap(&face->freetype->glyph->bitmap, result_width, result_height);
|
||||||
rendered = render_single_char_bitmap(&pbm, result_width, result_height);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PyErr_Format(PyExc_TypeError, "Unknown FreeType bitmap type: 0x%x", face->freetype->glyph->bitmap.pixel_mode);
|
PyErr_Format(PyExc_TypeError, "Unknown FreeType bitmap type: 0x%x", face->freetype->glyph->bitmap.pixel_mode);
|
||||||
|
|||||||
@ -14,6 +14,7 @@ typedef struct {bool created;} *FreeTypeRenderCtx;
|
|||||||
FreeTypeRenderCtx create_freetype_render_context(const char *family, bool bold, bool italic);
|
FreeTypeRenderCtx create_freetype_render_context(const char *family, bool bold, bool italic);
|
||||||
void set_main_face_family(FreeTypeRenderCtx ctx, const char *family, bool bold, bool italic);
|
void set_main_face_family(FreeTypeRenderCtx ctx, const char *family, bool bold, bool italic);
|
||||||
bool render_single_line(FreeTypeRenderCtx ctx, const char *text, unsigned sz_px, uint32_t fg, uint32_t bg, uint8_t *output_buf, size_t width, size_t height, float x_offset, float y_offset, size_t right_margin);
|
bool render_single_line(FreeTypeRenderCtx ctx, const char *text, unsigned sz_px, uint32_t fg, uint32_t bg, uint8_t *output_buf, size_t width, size_t height, float x_offset, float y_offset, size_t right_margin);
|
||||||
|
uint8_t* render_single_ascii_char_as_mask(FreeTypeRenderCtx ctx_, const char ch, size_t *result_width, size_t *result_height);
|
||||||
void release_freetype_render_context(FreeTypeRenderCtx ctx);
|
void release_freetype_render_context(FreeTypeRenderCtx ctx);
|
||||||
|
|
||||||
typedef struct FontConfigFace {
|
typedef struct FontConfigFace {
|
||||||
|
|||||||
@ -460,6 +460,14 @@ draw_window_title(OSWindow *window, const char *text, color_type fg, color_type
|
|||||||
if (!ok && PyErr_Occurred()) PyErr_Print();
|
if (!ok && PyErr_Occurred()) PyErr_Print();
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t*
|
||||||
|
draw_single_ascii_char(const char ch, size_t *result_width, size_t *result_height) {
|
||||||
|
if (!ensure_csd_title_render_ctx()) return NULL;
|
||||||
|
uint8_t *ans = render_single_ascii_char_as_mask(csd_title_render_ctx, ch, result_width, result_height);
|
||||||
|
if (PyErr_Occurred()) PyErr_Print();
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
|
|||||||
@ -593,13 +593,10 @@ draw_window_number(OSWindow *os_window, Screen *screen, GLfloat xstart, GLfloat
|
|||||||
ystart -= dy / 2.f; height -= dy; // top and bottom margins
|
ystart -= dy / 2.f; height -= dy; // top and bottom margins
|
||||||
xstart += dx / 2.f; width -= dx; // left and right margins
|
xstart += dx / 2.f; width -= dx; // left and right margins
|
||||||
GLfloat height_gl = MIN(MIN(12 * dy, height), width);
|
GLfloat height_gl = MIN(MIN(12 * dy, height), width);
|
||||||
unsigned height_px = (unsigned)(os_window->viewport_height * height_gl / 2.f);
|
size_t height_px = (unsigned)(os_window->viewport_height * height_gl / 2.f), width_px = 0;
|
||||||
if (height_px < 4) return;
|
if (height_px < 4) return;
|
||||||
unsigned width_px = height_px;
|
FREE_AFTER_FUNCTION uint8_t *canvas = draw_single_ascii_char('a', &width_px, &height_px);
|
||||||
if (height_px < 4 || width_px < 4) return;
|
if (height_px < 4 || width_px < 4 || !canvas) return;
|
||||||
FREE_AFTER_FUNCTION uint8_t *canvas = malloc(height_px * width_px);
|
|
||||||
if (!canvas) return;
|
|
||||||
memset(canvas, 255, height_px * width_px);
|
|
||||||
GLfloat width_gl = 2.f * ((float)width_px) / os_window->viewport_width;
|
GLfloat width_gl = 2.f * ((float)width_px) / os_window->viewport_width;
|
||||||
left = xstart + (width - width_gl) / 2.f;
|
left = xstart + (width - width_gl) / 2.f;
|
||||||
right = left + width_gl;
|
right = left + width_gl;
|
||||||
|
|||||||
@ -320,3 +320,4 @@ void send_pending_click_to_window_id(id_type, void*);
|
|||||||
void send_pending_click_to_window(Window*, void*);
|
void send_pending_click_to_window(Window*, void*);
|
||||||
void get_platform_dependent_config_values(void *glfw_window);
|
void get_platform_dependent_config_values(void *glfw_window);
|
||||||
bool draw_window_title(OSWindow *window, const char *text, color_type fg, color_type bg, uint8_t *output_buf, size_t width, size_t height);
|
bool draw_window_title(OSWindow *window, const char *text, color_type fg, color_type bg, uint8_t *output_buf, size_t width, size_t height);
|
||||||
|
uint8_t* draw_single_ascii_char(const char ch, size_t *result_width, size_t *result_height);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user