yaft/tools/mkfont_bdf.c
2018-10-15 07:40:24 +09:00

205 lines
5.7 KiB
C

#include "mkfont_bdf.h"
#include "../conf.h"
#include "util.h"
#include "bdf.h"
/* mkfont_bdf functions */
bool map_glyph(struct glyph_t *font[],
struct glyph_list_t *glist_head, struct glyph_t *default_glyph)
{
int width, cell_width = 0, cell_height = 0;
struct glyph_t *glyph;
struct glyph_list_t *listp;
if (default_glyph->width == 0 || default_glyph->height == 0) {
logging(ERROR, "default glyph(U+%.4X) not found\n", DEFAULT_CHAR);
return false;
}
cell_width = default_glyph->width;
cell_height = default_glyph->height;
logging(DEBUG, "default glyph width:%d height:%d\n",
default_glyph->width, default_glyph->height);
for (listp = glist_head; listp != NULL; listp = listp->next) {
if (listp->code >= UCS2_CHARS)
continue;
width = wcwidth(listp->code);
glyph = listp->glyph;
if ((width <= 0) /* not printable */
|| (glyph->height != cell_height) /* invalid font height */
|| (glyph->width != (cell_width * width))) /* invalid font width */
continue;
font[listp->code] = glyph;
}
return true;
}
bool load_alias(struct glyph_t *font[], char *alias)
{
unsigned int dst, src;
char buf[BUFSIZE];
FILE *fp;
if ((fp = efopen(alias, "r")) == NULL)
return false;
while (fgets(buf, BUFSIZE, fp) != NULL) {
if (strlen(buf) == 0 || buf[0] == '#')
continue;
sscanf(buf, "%X %X", &dst, &src);
if ((dst >= UCS2_CHARS) || (src >= UCS2_CHARS))
continue;
//if (font[src] != NULL && font[dst] != NULL) {
if (font[src] != NULL) {
logging(DEBUG, "swapped: use U+%.4X for U+%.4X\n", src, dst);
font[dst] = font[src];
//free(font[dst]->bitmap);
//font[dst]->width = font[src]->width;
//font[dst]->height = font[src]->height;
//font[dst]->bitmap = font[src]->bitmap;
//memcpy(font[dst]->bitmap, font[src]->bitmap, sizeof(bitmap_width_t) * font[src]->height);
}
}
efclose(fp);
return true;
}
bool check_font(struct glyph_t **font, struct glyph_t *empty_half, struct glyph_t *empty_wide)
{
empty_half->bitmap = (bitmap_width_t *) ecalloc(font[DEFAULT_CHAR]->height, sizeof(bitmap_width_t));
empty_wide->bitmap = (bitmap_width_t *) ecalloc(font[DEFAULT_CHAR]->height, sizeof(bitmap_width_t));
if (!empty_half->bitmap || !empty_wide->bitmap)
return false;
empty_half->width = font[DEFAULT_CHAR]->width;
empty_wide->width = font[DEFAULT_CHAR]->width * WIDE;
empty_half->height = font[DEFAULT_CHAR]->height;
empty_wide->height = font[DEFAULT_CHAR]->height;
if (font[SUBSTITUTE_HALF] == NULL) {
logging(WARN, "half substitute glyph(U+%.4X) not found, use empty glyph\n", SUBSTITUTE_HALF);
font[SUBSTITUTE_HALF] = empty_half;
}
if (font[SUBSTITUTE_WIDE] == NULL) {
logging(WARN, "wide substitute glyph(U+%.4X) not found, use empty glyph\n", SUBSTITUTE_WIDE);
font[SUBSTITUTE_WIDE] = empty_wide;
}
if (font[REPLACEMENT_CHAR] == NULL) {
logging(WARN, "replacement glyph(U+%.4X) not found, use empty glyph\n", REPLACEMENT_CHAR);
font[REPLACEMENT_CHAR] = empty_half;
}
return true;
}
bool dump_font(struct glyph_t *font[])
{
int i, j, width, int_type;
uint8_t cell_width, cell_height;
cell_width = font[DEFAULT_CHAR]->width;
cell_height = font[DEFAULT_CHAR]->height;
int_type = my_ceil(cell_width, BITS_PER_BYTE) /* minimum byte for containing half glyph */
* 2 /* minimum byte for containing wide glyph */
* BITS_PER_BYTE; /* minimum bits for containing wide glyph */
/* int_type: 16, 32, 48, 64, 80... */
if (int_type == 48) { /* uint48_t does not exist */
int_type = 64;
} else if (int_type >= 80) {
logging(ERROR, "BDF width too large (uint%d_t does not exist)\n", int_type);
return false;
}
fprintf(stdout,
"struct glyph_t {\n"
"\tuint32_t code;\n"
"\tuint8_t width;\n"
"\tuint%d_t bitmap[%d];\n"
"};\n\n", int_type, cell_height);
fprintf(stdout, "enum {\n\tCELL_WIDTH = %d,\n\tCELL_HEIGHT = %d\n};\n\n",
cell_width, cell_height);
fprintf(stdout, "static const struct glyph_t glyphs[] = {\n");
for (i = 0; i < UCS2_CHARS; i++) {
width = wcwidth(i);
if (font[i] == NULL) /* glyph not found */
continue;
fprintf(stdout, "\t{%d, %d, {", i, width);
for (j = 0; j < cell_height; j++)
fprintf(stdout, "0x%X%s", (unsigned int) font[i]->bitmap[j], (j == (cell_height - 1)) ? "": ", ");
fprintf(stdout, "}},\n");
}
fprintf(stdout, "};\n");
return true;
}
void cleanup(struct glyph_list_t *glist_head, struct glyph_t *empty_half, struct glyph_t *empty_wide)
{
struct glyph_list_t *listp, *next;
for (listp = glist_head; listp != NULL; listp = next) {
next = listp->next;
free(listp->glyph->bitmap);
free(listp->glyph);
free(listp);
}
free(empty_half->bitmap);
free(empty_wide->bitmap);
}
int main(int argc, char *argv[])
{
struct glyph_list_t *glist_head = NULL;
struct glyph_t *font[UCS2_CHARS], default_glyph, empty_wide, empty_half;
if (!setlocale(LC_ALL, "")) /* set current locale for wcwidth() */
logging(WARN, "setlocale() failed\n");
if (argc < 3) {
logging(FATAL, "usage: ./mkfont ALIAS BDF1 [BDF2] [BDF3] ...\n");
return EXIT_FAILURE;
}
for (int i = 0; i < UCS2_CHARS; i++)
font[i] = NULL;
for (int i = 2; i < argc; i++)
load_bdf_glyph(&glist_head, &default_glyph, argv[i]);
if (!map_glyph(font, glist_head, &default_glyph)) {
logging(FATAL, "map_glyph() failed\n");
goto err_occurred;
}
if (!load_alias(font, argv[1]))
logging(WARN, "font alias does not work\n");
if (!check_font(font, &empty_half, &empty_wide)) {
logging(FATAL, "check_font() failed\n");
goto err_occurred;
}
if (!dump_font(font)) {
logging(FATAL, "dump_font() failed\n");
goto err_occurred;
}
cleanup(glist_head, &empty_half, &empty_wide);
return EXIT_SUCCESS;
err_occurred:
cleanup(glist_head, &empty_half, &empty_wide);
return EXIT_FAILURE;
}