Browse Source

改进排版算法,增加描边宽度调整

master
jiangming1399 1 year ago
parent
commit
e5d4c5b879
5 changed files with 68 additions and 60 deletions
  1. +38
    -39
      fonts.c
  2. +2
    -2
      fonts.h
  3. +23
    -15
      fonts_border_renderer.c
  4. +1
    -1
      fonts_border_renderer.h
  5. +4
    -3
      main.c

+ 38
- 39
fonts.c View File

@@ -41,11 +41,10 @@ void fonts_make_render_buffer(struct font_render_buffer* buffer, int width, int
* 内部渲染方法,主要包含了排版方面的工作
* */
static struct font_error fonts_render_internal(struct font_lib* lib, wchar_t* str, int font_size, enum font_align align,
struct font_render_buffer* buffer, font_proccessor proccessor)
struct font_render_buffer* buffer, font_proccessor proccessor, void* arg)
{
struct font_error error;

FT_GlyphSlot slot = lib->face->glyph;
struct font_proccess_result* result = malloc(sizeof(struct font_proccess_result));
memset(result, 0, sizeof(struct font_proccess_result));

@@ -55,13 +54,14 @@ static struct font_error fonts_render_internal(struct font_lib* lib, wchar_t* st
return error;
}

memset(buffer->data, 0, buffer->width * buffer->height);

uint16_t line_height = lib->face->size->metrics.height >> 6;
uint16_t ascender = lib->face->size->metrics.ascender >> 6;

uint16_t x = 0, y = 0, width = 0;
wchar_t* lb = str;
unsigned char* line_buffer = malloc(buffer->width * line_height);
memset(line_buffer, 0, buffer->width * line_height);
memset(buffer->data, 0, buffer->width * buffer->height);

uint16_t x = 0, y = 0;
bool line_break = false;

do {
@@ -69,61 +69,59 @@ static struct font_error fonts_render_internal(struct font_lib* lib, wchar_t* st
line_break = true;
str++;
} else {
// first pass: 计算字体宽度和换行
FT_Load_Char(lib->face, *str, FT_LOAD_COMPUTE_METRICS);
if ((width + (slot->metrics.horiAdvance >> 6)) > buffer->width) {
proccessor(lib, *str, result, arg);
if ((x + (result->metrics.horiAdvance >> 6)) > buffer->width) {
line_break = true;
} else {
width += (slot->metrics.horiAdvance >> 6);
uint16_t x_start = x + (result->metrics.horiBearingX >> 6);
uint16_t y_start = (ascender - (result->metrics.horiBearingY >> 6));

for (int i = 0; i < result->bitmap.rows && y_start + i < line_height; i++) {
memcpy(&line_buffer[(y_start + i) * buffer->width + x_start],
&(result->bitmap.buffer[i * result->bitmap.width]),
result->bitmap.pitch);
}
x += (result->metrics.horiAdvance >> 6);
str++;
}

if (result->manual_free)
free(result->bitmap.buffer);
if (*str == 0)
line_break = true;
}

// two pass: 渲染字体
if (line_break) {
line_break = false;
// 计算本行偏移
int offset = 0;

switch (align) {
case FONT_ALIGN_LEFT:
x = 0;
offset = 0;
break;
case FONT_ALIGN_CENTER:
x = (buffer->width - width) / 2;
offset = (buffer->width - x) / 2;
break;
case FONT_ALIGN_RIGHT:
x = buffer->width - width;
offset = buffer->width - x;
break;
}

while (str != lb) {
if (*lb == '\n') {
lb++;
continue;
}
// FT_Load_Char(lib->face, *lb++, FT_LOAD_RENDER);
proccessor(lib, *lb++, result);

uint16_t x_start = x + (result->metrics.horiBearingX >> 6);
uint16_t y_start = y + (ascender - (result->metrics.horiBearingY >> 6));

for (int i = 0; i < result->bitmap.rows && y_start + i < buffer->height; i++) {
memcpy(&buffer->data[(y_start + i) * buffer->width + x_start],
&(result->bitmap.buffer[i * result->bitmap.width]),
result->bitmap.pitch);
}
if (result->manual_free)
free(result->bitmap.buffer);
x += (result->metrics.horiAdvance >> 6);
for (int i = 0; i < line_height; i++) {
memcpy(&buffer->data[(y + i) * buffer->width + offset], &line_buffer[i * buffer->width], x);
}
width = 0;

memset(line_buffer, 0, buffer->width * line_height);
x = 0;
y += line_height;

if (y > buffer->height)
break;
}
} while (*str);
free(line_buffer);

return error;
}
@@ -131,8 +129,9 @@ static struct font_error fonts_render_internal(struct font_lib* lib, wchar_t* st
/**
* 默认渲染处理器,使用内建的FT_Load_Char直接进行处理
* */
void font_default_proccessor(struct font_lib* lib, wchar_t ch, struct font_proccess_result* result)
void font_default_proccessor(struct font_lib* lib, wchar_t ch, struct font_proccess_result* result, void* arg)
{
FT_UNUSED(arg);
FT_Load_Char(lib->face, ch, FT_LOAD_RENDER);
result->metrics = lib->face->glyph->metrics;
result->bitmap = lib->face->glyph->bitmap;
@@ -145,11 +144,11 @@ void font_default_proccessor(struct font_lib* lib, wchar_t ch, struct font_procc
struct font_error fonts_render(struct font_lib* lib, wchar_t* str, int font_size, enum font_align align,
struct font_render_buffer* buffer)
{
return fonts_render_internal(lib, str, font_size, align, buffer, font_default_proccessor);
return fonts_render_internal(lib, str, font_size, align, buffer, font_default_proccessor, NULL);
}

struct font_error fonts_render_border(struct font_lib* lib, wchar_t* str, int font_size, enum font_align align,
struct font_error fonts_render_border(struct font_lib* lib, wchar_t* str, int font_size, int border_width, enum font_align align,
struct font_render_buffer* buffer)
{
return fonts_render_internal(lib, str, font_size, align, buffer, font_border_proccessor);
return fonts_render_internal(lib, str, font_size, align, buffer, font_border_proccessor, &border_width);
}

+ 2
- 2
fonts.h View File

@@ -35,12 +35,12 @@ struct font_proccess_result {
bool manual_free;
};

typedef void (*font_proccessor) (struct font_lib * lib, wchar_t ch, struct font_proccess_result * result);
typedef void (*font_proccessor) (struct font_lib * lib, wchar_t ch, struct font_proccess_result * result, void * arg);

struct font_error fonts_init(struct font_lib* lib, char* path);
struct font_error fonts_render(struct font_lib* lib, wchar_t* str, int font_size, enum font_align align,
struct font_render_buffer* buffer);
struct font_error fonts_render_border(struct font_lib* lib, wchar_t* str, int font_size, enum font_align align,
struct font_error fonts_render_border(struct font_lib* lib, wchar_t* str, int font_size, int border_width, enum font_align align,
struct font_render_buffer* buffer);
void fonts_make_render_buffer(struct font_render_buffer* buffer, int width, int height);



+ 23
- 15
fonts_border_renderer.c View File

@@ -25,11 +25,16 @@ struct box_aabb {
int yMax;
};

void box_aabb_add(struct box_aabb * box, int x, int y) {
if (x > box->xMax) box->xMax = x;
if (x < box->xMin) box->xMin = x;
if (y > box->yMax) box->yMax = y;
if (y < box->yMin) box->yMin = y;
void box_aabb_add(struct box_aabb* box, int x, int y)
{
if (x > box->xMax)
box->xMax = x;
if (x < box->xMin)
box->xMin = x;
if (y > box->yMax)
box->yMax = y;
if (y < box->yMin)
box->yMin = y;
}

void span_node_push(struct span_node* parent, struct span_node* node)
@@ -40,7 +45,8 @@ void span_node_push(struct span_node* parent, struct span_node* node)
parent->next = node;
}

void span_node_init(struct span_node* node) {
void span_node_init(struct span_node* node)
{
memset(node, 0, sizeof(struct span_node));
}

@@ -51,7 +57,8 @@ void span_free(struct span_node* node)
free(node);
}

void box_aabb_add_span_node(struct box_aabb * box, struct span_node* node) {
void box_aabb_add_span_node(struct box_aabb* box, struct span_node* node)
{
box_aabb_add(box, node->val.x, node->val.y);
box_aabb_add(box, node->val.x + node->val.width - 1, node->val.y);
if (node->next != NULL) {
@@ -86,11 +93,11 @@ void font_render_spans(FT_Library library, FT_Outline* const outline, struct spa
FT_Outline_Render(library, outline, &params);
}

void font_border_proccessor(struct font_lib* lib, wchar_t ch, struct font_proccess_result* result)
void font_border_proccessor(struct font_lib* lib, wchar_t ch, struct font_proccess_result* result, void* arg)
{
struct font_error err;

result->manual_free = false;
int border_width = *(int*)arg;
struct font_error err;

FT_UInt gindex = FT_Get_Char_Index(lib->face, ch);
err.code = FT_Load_Glyph(lib->face, gindex, FT_LOAD_NO_BITMAP);
@@ -108,7 +115,7 @@ void font_border_proccessor(struct font_lib* lib, wchar_t ch, struct font_procce

FT_Stroker stroker;
FT_Stroker_New(lib->library, &stroker);
FT_Stroker_Set(stroker, 1 << 6, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
FT_Stroker_Set(stroker, border_width, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);

FT_Glyph glyph;
err.code = FT_Get_Glyph(lib->face->glyph, &glyph);
@@ -123,7 +130,7 @@ void font_border_proccessor(struct font_lib* lib, wchar_t ch, struct font_procce
FT_Stroker_Done(stroker);
FT_Done_Glyph(glyph);

struct box_aabb box = {0,0,0,0};
struct box_aabb box = { 0, 0, 0, 0 };
box_aabb_add_span_node(&box, normal_spans);
box_aabb_add_span_node(&box, border_spans);

@@ -140,23 +147,24 @@ void font_border_proccessor(struct font_lib* lib, wchar_t ch, struct font_procce
result->bitmap.buffer = malloc(size);
result->manual_free = true;
memset(result->bitmap.buffer, 0, size);
result->metrics.horiAdvance += border_width;

struct span_node* node = border_spans;
do {
int y = height - 1 - node->val.y + box.yMin;
int x = node->val.x - box.xMin;
memset(&result->bitmap.buffer[y * width + x], (node->val.coverage) & 0xf0, node->val.width);
} while((node = node->next));
} while ((node = node->next));

node = normal_spans;
do {
int y = height - 1 - node->val.y + box.yMin;
int x = node->val.x - box.xMin;
int base_addr = y * width;
for (int i=0, w=x; i < node->val.width; i++, w++) {
for (int i = 0, w = x; i < node->val.width; i++, w++) {
result->bitmap.buffer[base_addr + w] += node->val.coverage >> 4;
}
} while((node = node->next));
} while ((node = node->next));

span_free(normal_spans);
span_free(border_spans);


+ 1
- 1
fonts_border_renderer.h View File

@@ -6,6 +6,6 @@

#include "fonts.h"

void font_border_proccessor(struct font_lib* lib, wchar_t ch, struct font_proccess_result* result);
void font_border_proccessor(struct font_lib* lib, wchar_t ch, struct font_proccess_result* result, void* border_width);

#endif // __FONTS_BORDER_RENDERER_

+ 4
- 3
main.c View File

@@ -108,17 +108,18 @@ int main(int argc, char* argv[])

struct _fbg_img* bb_font_img = fbg_loadPNG(fbg, "bbmode1_8x8.png");
struct _fbg_font* bbfont = fbg_createFont(fbg, bb_font_img, 8, 8, 33);
struct _fbg_img* bkg = fbg_loadPNG(fbg, "a.png");

time_t current_time;

wchar_t time_str[10];
struct font_render_buffer font_buffer;
struct _fbg_img* bkg = fbg_loadPNG(fbg, "a.png");
fonts_make_render_buffer(&font_buffer, 160, 32);

struct font_render_buffer font_buffer2;
// todo: 这个超过220好像在arm上会炸?
fonts_make_render_buffer(&font_buffer2, 200, 160);
fonts_render_border(&font2, L"测试字符串\nよーし\n\nいい加減そろそろ決着つけたい\nと思ってたし", 14, FONT_ALIGN_LEFT, &font_buffer2);
fonts_render_border(&font2, L"测试字符串\nよーし\n\nいい加減そろそろ決着つけたい\nと思ってたし", 14,1 << 6, FONT_ALIGN_LEFT, &font_buffer2);

do {
#ifdef GLFW
@@ -139,7 +140,7 @@ int main(int argc, char* argv[])
struct tm* lt = localtime(&current_time);
swprintf(time_str, 10, L"%02d:%02d:%02d", lt->tm_hour, lt->tm_min, lt->tm_sec);

fonts_render_border(&font1, time_str, 32, FONT_ALIGN_RIGHT, &font_buffer);
fonts_render_border(&font1, time_str, 32, 2 << 6, FONT_ALIGN_RIGHT, &font_buffer);

fbg_flip(fbg);
#ifdef GLFW


Loading…
Cancel
Save