mirror of
https://gitee.com/zlgopen/awtk.git
synced 2024-12-02 03:58:33 +08:00
209 lines
5.8 KiB
C
209 lines
5.8 KiB
C
/**
|
|
* File: font_gen.c
|
|
* Author: AWTK Develop Team
|
|
* Brief: bitmap font generator
|
|
*
|
|
* Copyright (c) 2018 - 2024 Guangzhou ZHIYUAN Electronics Co.,Ltd.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* License file for more details.
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* History:
|
|
* ================================================================
|
|
* 2018-01-21 Li XianJing <xianjimli@hotmail.com> created
|
|
*
|
|
*/
|
|
|
|
#include <wctype.h>
|
|
#include "tkc/mem.h"
|
|
#include "tkc/utf8.h"
|
|
#include "tkc/fs.h"
|
|
#include "tkc/path.h"
|
|
#include "base/bitmap.h"
|
|
#include "common/utils.h"
|
|
#include "font_gen/font_gen.h"
|
|
#include "font_gen/preprocess_text.inc"
|
|
#include "base/assets_manager.h"
|
|
#include "font_loader/font_loader_stb.h"
|
|
#include "font_loader/font_loader_bitmap.h"
|
|
|
|
#define MAX_CHARS 100 * 1024
|
|
#define MAX_BUFF_SIZE 1 * 1024 * 1024
|
|
|
|
static int char_cmp(const void* a, const void* b) {
|
|
wchar_t c1 = *(wchar_t*)a;
|
|
wchar_t c2 = *(wchar_t*)b;
|
|
|
|
return c1 - c2;
|
|
}
|
|
|
|
ret_t font_gen(font_t* font, uint16_t font_size, glyph_format_t format, const char* str,
|
|
const char* output_filename, const char* theme, const char* res_dir) {
|
|
str_t tstr;
|
|
str_t name;
|
|
wbuffer_t wbuffer;
|
|
uint32_t size = 0;
|
|
str_init(&name, 0);
|
|
str_init(&tstr, 100000);
|
|
wbuffer_init_extendable(&wbuffer);
|
|
|
|
str = font_gen_expand_text(str, &tstr);
|
|
size = font_gen_buff(font, font_size, format, str, &wbuffer);
|
|
|
|
if (strstr(output_filename, ".bin") != NULL) {
|
|
file_write(output_filename, wbuffer.data, size);
|
|
} else {
|
|
char path[MAX_PATH + 1] = {0};
|
|
if (TK_STR_IS_NOT_EMPTY(res_dir)) {
|
|
str_append(&name, res_dir);
|
|
str_append(&name, "/");
|
|
}
|
|
path_basename_ex(output_filename, TRUE, path, sizeof(path));
|
|
str_append(&name, path);
|
|
|
|
output_res_c_source_ex(output_filename, theme, ASSET_TYPE_FONT, ASSET_TYPE_FONT_BMP,
|
|
wbuffer.data, size, name.str);
|
|
}
|
|
|
|
str_reset(&tstr);
|
|
str_reset(&name);
|
|
wbuffer_deinit(&wbuffer);
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
static ret_t fong_convert_alpha8_to_alpha4(glyph_t* from, glyph_t* to) {
|
|
uint32_t x = 0;
|
|
uint32_t y = 0;
|
|
const uint8_t* pfrom = from->data;
|
|
uint8_t* p = (uint8_t*)(to->data);
|
|
|
|
for (y = 0; y < from->h; y++) {
|
|
for (x = 0; x < from->w; x++) {
|
|
uint32_t i = x / 2;
|
|
if ((x % 2) == 0) {
|
|
p[i] = (pfrom[x] >> 4) & 0x0f;
|
|
} else {
|
|
p[i] |= pfrom[x] & 0xf0;
|
|
}
|
|
}
|
|
p += to->pitch;
|
|
pfrom += from->pitch;
|
|
}
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
static ret_t font_gen_glyph(font_t* font, glyph_format_t format, wchar_t c, font_size_t font_size,
|
|
glyph_t* g) {
|
|
static glyph_t gg;
|
|
static uint8_t buff[200 * 200];
|
|
|
|
memset(&gg, 0x00, sizeof(gg));
|
|
memset(buff, 0x00, sizeof(buff));
|
|
|
|
if (font_get_glyph(font, c, font_size, &gg) == RET_OK) {
|
|
if (!gg.pitch) {
|
|
gg.pitch = gg.w;
|
|
}
|
|
*g = gg;
|
|
|
|
if (format != gg.format) {
|
|
g->data = buff;
|
|
g->format = format;
|
|
log_debug("convert %d => %d\n", (int)(gg.format), (int)(format));
|
|
if (format == GLYPH_FMT_ALPHA4 && gg.format == GLYPH_FMT_ALPHA) {
|
|
g->pitch = (gg.pitch + 1) / 2;
|
|
|
|
return fong_convert_alpha8_to_alpha4(&gg, g);
|
|
} else if (c != ' ') {
|
|
assert(!"not supported format yet");
|
|
return RET_FAIL;
|
|
}
|
|
}
|
|
return RET_OK;
|
|
} else {
|
|
return RET_FAIL;
|
|
}
|
|
}
|
|
|
|
uint32_t font_gen_buff(font_t* font, uint16_t font_size, glyph_format_t format, const char* str,
|
|
wbuffer_t* wbuffer) {
|
|
int i = 0;
|
|
glyph_t g;
|
|
int size = 0;
|
|
wchar_t wstr[MAX_CHARS];
|
|
font_vmetrics_t vmetrics = font_get_vmetrics(font, font_size);
|
|
|
|
tk_utf8_to_utf16(str, wstr, MAX_CHARS);
|
|
size = wcslen(wstr);
|
|
|
|
qsort(wstr, size, sizeof(wchar_t), char_cmp);
|
|
size = unique(wstr, size);
|
|
|
|
int32_t header_size = sizeof(font_bitmap_header_t) + (size - 1) * sizeof(font_bitmap_index_t);
|
|
font_bitmap_header_t* header = (font_bitmap_header_t*)TKMEM_ALLOC(header_size);
|
|
memset(header, 0, header_size);
|
|
wbuffer_write_binary(wbuffer, header, header_size);
|
|
|
|
header->format = format;
|
|
header->char_nr = size;
|
|
header->font_size = (uint8_t)font_size;
|
|
header->ascent = vmetrics.ascent;
|
|
header->descent = vmetrics.descent;
|
|
header->line_gap = vmetrics.line_gap;
|
|
|
|
memset(&g, 0x00, sizeof(g));
|
|
for (i = 0; i < size; i++) {
|
|
wchar_t c = wstr[i];
|
|
|
|
header->index[i].c = c;
|
|
header->index[i].size = 0;
|
|
header->index[i].offset = wbuffer->cursor;
|
|
|
|
printf("%d/%d: 0x%04x format=%d w=%d h=%d pitch=%d\n", i, size, c, (int)format, (int)(g.w),
|
|
(int)(g.h), (int)(g.pitch));
|
|
if (font_gen_glyph(font, format, c, font_size, &g) == RET_OK) {
|
|
uint32_t data_size = g.pitch * g.h;
|
|
|
|
wbuffer_write_uint16(wbuffer, g.x);
|
|
wbuffer_write_uint16(wbuffer, g.y);
|
|
wbuffer_write_uint16(wbuffer, g.w);
|
|
wbuffer_write_uint16(wbuffer, g.h);
|
|
wbuffer_write_uint16(wbuffer, g.advance);
|
|
wbuffer_write_uint8(wbuffer, g.format);
|
|
wbuffer_write_uint8(wbuffer, g.pitch);
|
|
|
|
if (g.data != NULL) {
|
|
header->index[i].size = data_size;
|
|
wbuffer_write_binary(wbuffer, g.data, data_size);
|
|
}
|
|
|
|
if (g.format == GLYPH_FMT_MONO) {
|
|
bitmap_mono_dump(g.data, g.w, g.h);
|
|
}
|
|
} else if (c > 32 && c != 0xfeff) {
|
|
wchar_t arr[] = {c};
|
|
char utf8_arr[32] = {0};
|
|
memset(utf8_arr, 0x00, sizeof(utf8_arr));
|
|
tk_utf8_from_utf16(arr, utf8_arr, sizeof(utf8_arr));
|
|
printf("Warnning: not find char 0x%04x('%s') in TTF\n", c, utf8_arr);
|
|
header->index[i].offset = 0;
|
|
} else {
|
|
header->index[i].offset = 0;
|
|
}
|
|
}
|
|
size = wbuffer->cursor;
|
|
wbuffer->cursor = 0;
|
|
wbuffer_write_binary(wbuffer, header, header_size);
|
|
wbuffer->cursor = size;
|
|
TKMEM_FREE(header);
|
|
|
|
return size;
|
|
}
|