This commit is contained in:
olikraus
2015-11-07 13:00:10 +01:00
parent ae801fc34a
commit aacb58afef
12 changed files with 4008 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
# works within ubuntu and min-gw (win7) environment
# win7 exe uploaded on google drive
CFLAGS = -g -Wall
#CFLAGS = -O4 -Wall
SRC = main.c bdf_font.c bdf_glyph.c bdf_parser.c bdf_map.c bdf_rle.c bdf_tga.c fd.c bdf_8x8.c
OBJ = $(SRC:.c=.o)
ASM = $(SRC:.c=.s)
.c.s:
$(CC) $(CFLAGS) -S -o $@ $<
bdfconv: $(OBJ) $(ASM)
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJ) -o bdfconv
clean:
-rm $(OBJ) $(ASM) bdfconv
test:
./bdfconv
+180
View File
@@ -0,0 +1,180 @@
/*
bdf_8x8.c
unencoded font format for 8x8 pixel font
offset bytes desc
0 1 first char
1 2 last char
2 n font data, n = (last char - first char + 1)*8
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "bdf_font.h"
int bg_8x8_convert(bg_t *bg, bbx_t *bbx)
{
int x;
int y;
int d;
if ( bbx == NULL )
bbx = &(bg->bbx);
bg_ClearTargetData(bg);
if ( bbx->w != 8 )
return 0;
if ( bbx->h != 8 )
return 0;
/*
for( y = bbx->y+bbx->h-1; y >= bbx->y; y--)
{
d = 0;
for( x = bbx->x; x < bbx->x + bbx->w; x++)
{
d <<= 1;
if ( bg_GetBBXPixel(bg, x, y) != 0 )
{
d++;
}
}
if ( bg_AddTargetData(bg, d) < 0 )
return 0;
}
*/
for( x = bbx->x; x < bbx->x + bbx->w; x++)
{
d = 0;
for( y = bbx->y+bbx->h-1; y >= bbx->y; y--)
{
d >>= 1;
if ( bg_GetBBXPixel(bg, x, y) != 0 )
{
d |= 128;
}
}
if ( bg_AddTargetData(bg, d) < 0 )
return 0;
}
return 1;
}
void bf_Generate8x8Font(bf_t *bf)
{
int i, j, k;
bg_t *bg;
int first, last;
bbx_t local_bbx;
int is_glyph_written;
/* Step 1: Generate 8x8 bitmap data */
for( i = 0; i < bf->glyph_cnt; i++ )
{
bg = bf->glyph_list[i];
if ( bg->map_to >= 0 )
{
bf_copy_bbx_and_update_shift(bf, &local_bbx, bg);
if ( local_bbx.w != 8 )
{
bf_Log(bf, "Generate8x8Font: Error, glyph width is not 8, width=%d, encoding=%d", local_bbx.w, bg->encoding);
}
else
{
if ( local_bbx.h != 8 )
{
bf_Log(bf, "Generate8x8Font: Error, glyph height is not 8, height=%d, encoding=%d", local_bbx.h, bg->encoding);
}
else
{
if ( bg_8x8_convert(bg, &local_bbx) == 0 )
{
bf_Log(bf, "Generate8x8Font: Error, 8x8 conversion, encoding=%d", bg->target_cnt, bg->encoding);
}
}
}
}
}
/* Step 2: Calculate first and last char */
first = -1;
last = -1;
for( j = 0; j < 256; j++ )
{
for( i = 0; i < bf->glyph_cnt; i++ )
{
bg = bf->glyph_list[i];
if ( bg->map_to == j )
{
if ( bg->target_data != NULL )
{
if ( bg->target_cnt != 8)
{
bf_Log(bf, "Generate8x8Font: Error, glyph size is not 8, size=%d, encoding=%d", bg->target_cnt, bg->encoding);
}
else
{
if ( first < 0 )
first = j;
last = j;
}
}
}
}
}
/* Step 3: Write font data */
bf_AddTargetData(bf, first);
bf_AddTargetData(bf, last);
for( j = first; j <= last; j++ )
{
is_glyph_written = 0;
for( i = 0; i < bf->glyph_cnt; i++ )
{
bg = bf->glyph_list[i];
if ( bg->map_to == j )
{
if ( bg->target_data != NULL )
{
if ( bg->target_cnt == 8)
{
for( k = 0; k < bg->target_cnt; k++ )
{
bf_AddTargetData(bf, bg->target_data[k]);
}
is_glyph_written = 1;
}
}
}
}
if ( is_glyph_written == 0 )
{
for( k = 0; k < 8; k++ )
{
bf_AddTargetData(bf, 0);
}
}
}
bf_Log(bf, "Generate8x8Font: Font size %d", bf->target_cnt);
}
+685
View File
@@ -0,0 +1,685 @@
#include <stdlib.h>
#include <stdarg.h>
#include "bdf_font.h"
void bf_Error(bf_t *bf, char *fmt, ...)
{
va_list va;
va_start(va, fmt);
vprintf(fmt, va);
printf("\n");
va_end(va);
}
void bf_Log(bf_t *bf, char *fmt, ...)
{
va_list va;
va_start(va, fmt);
if ( bf->is_verbose != 0 )
{
vprintf(fmt, va);
printf("\n");
}
va_end(va);
}
/*
bf_Open(0, BDF_BBX_MODE_MINIMAL)
*/
bf_t *bf_Open(int is_verbose, int bbx_mode)
{
bf_t *bf;
bf = (bf_t *)malloc(sizeof(bf_t));
if ( bf != NULL )
{
bf->is_verbose = is_verbose;
bf->glyph_list = NULL;
bf->glyph_cnt = 0;
bf->glyph_max = 0;
bf->str_font = NULL; /* argument for FONT in bdf file */
bf->str_copyright = NULL; /* argument for COPYRIGHT in bdf file */
bf->target_data = NULL;
bf->target_max = 0;
bf->target_cnt = 0;
bf->selected_glyphs = 0;
bf->enc_w = 0;
bf->enc_h = 0;
bf->enc_x = 0;
bf->enc_y = 0;
bf->bbx_mode = bbx_mode;
return bf;
}
return NULL;
}
void bf_Clear(bf_t *bf)
{
int i;
for( i = 0; i < bf->glyph_cnt; i++ )
{
free( bf->glyph_list[i] );
}
bf->glyph_cnt = 0;
if ( bf->str_font != NULL )
free(bf->str_font);
bf->str_font = NULL;
if ( bf->str_copyright != NULL )
free(bf->str_copyright);
bf->str_copyright = NULL;
}
void bf_Close(bf_t *bf)
{
bf_Clear(bf);
if ( bf->glyph_list != NULL )
free(bf->glyph_list);
if ( bf->target_data != NULL )
free(bf->target_data);
bf->glyph_list = NULL;
bf->glyph_max = 0;
free(bf);
}
static int bf_extend(bf_t *bf)
{
int extend = 16;
void *ptr;
if ( bf->glyph_list == NULL )
{
ptr = malloc(extend*sizeof(bg_t *));
bf->glyph_max = 0;
}
else
{
ptr = realloc(bf->glyph_list, (bf->glyph_max + extend)*sizeof(bg_t *));
}
if ( ptr == NULL )
return 0;
bf->glyph_max += extend;
bf->glyph_list = (bg_t **)ptr;
return 1;
}
/* returns glyph position or -1 */
int bf_AddGlyph(bf_t *bf)
{
while( bf->glyph_max <= bf->glyph_cnt )
if ( bf_extend(bf) == 0 )
return -1;
bf->glyph_list[bf->glyph_cnt] = bg_Open();
if ( bf->glyph_list[bf->glyph_cnt] == NULL )
return -1;
bf->glyph_list[bf->glyph_cnt]->bf = bf;
bf->glyph_cnt++;
return bf->glyph_cnt-1;
}
static int bf_extend_target_data(bf_t *bf)
{
int extend = 16;
int i;
void *ptr;
if ( bf->target_data == NULL )
{
ptr = malloc(extend*sizeof(uint8_t));
bf->target_max = 0;
}
else
{
ptr = realloc(bf->target_data, (bf->target_max + extend)*sizeof(uint8_t));
}
if ( ptr == NULL )
return 0;
bf->target_data = (uint8_t *)ptr;
for( i = bf->target_max; i < bf->target_max + extend; i++ )
bf->target_data[i] = 0;
bf->target_max += extend;
return 1;
}
int bf_AddTargetData(bf_t *bf, uint8_t data)
{
while( bf->target_max <= bf->target_cnt )
if ( bf_extend_target_data(bf) == 0 )
return -1;
bf->target_data[bf->target_cnt] = data;
bf->target_cnt++;
return bf->target_cnt-1;
}
void bf_ClearTargetData(bf_t *bf)
{
int i;
for( i = 0; i < bf->target_max; i++ )
bf->target_data[i] = 0;
bf->target_cnt = 0;
}
void bf_CalculateSelectedNumberOfGlyphs(bf_t *bf)
{
int i;
bg_t *bg;
bf->selected_glyphs = 0;
for( i = 0; i < bf->glyph_cnt; i++ )
{
bg = bf->glyph_list[i];
if ( bg->map_to >= 0 )
{
bf->selected_glyphs++;
}
}
}
void bf_ReduceAllGlyph(bf_t *bf)
{
int i;
bg_t *bg;
int red_x, red_y;
bf_Log(bf, "Reduce: Start");
for( i = 0; i < bf->glyph_cnt; i++ )
{
bg = bf->glyph_list[i];
if ( bg->map_to >= 0 )
{
bg_ReduceGlyph(bg);
//bg_ShowBitmap(bg, &(bg->bbx));
red_x = bg->bitmap_width - bg->bbx.w;
red_y = bg->bitmap_height - bg->bbx.h;
if ( red_x > 0 || red_y > 0 )
{
//bf_Log(bf, "Reduce: Encoding %ld, x by %d, y by %d", bg->encoding, red_x, red_y);
}
}
}
bf_Log(bf, "Reduce: End");
}
void bf_ShowAllGlyphs(bf_t *bf, bbx_t *bbx)
{
int i;
bg_t *bg;
for( i = 0; i < bf->glyph_cnt; i++ )
{
bg = bf->glyph_list[i];
if ( bg->map_to >= 0 )
{
bg_ShowBitmap(bg, bbx);
}
}
}
int bf_GetIndexByEncoding(bf_t *bf, long encoding)
{
int i;
bg_t *bg;
for( i = 0; i < bf->glyph_cnt; i++ )
{
bg = bf->glyph_list[i];
if ( bg->encoding == encoding )
return i;
}
return -1;
}
void bf_CalculateMaxBBX(bf_t *bf)
{
int i;
int is_first = 1;
int enc_idx;
bg_t *bg;
for( i = 0; i < bf->glyph_cnt; i++ )
{
bg = bf->glyph_list[i];
if ( bg->map_to >= 0 )
{
if ( is_first != 0 )
{
bf->max = bg->bbx;
bf->enc_x = bg->encoding;
bf->enc_y = bg->encoding;
bf->enc_w = bg->encoding;
bf->enc_h = bg->encoding;
is_first = 0;
}
else
{
enc_idx = bg_Max(bg, &(bf->max));
switch(enc_idx)
{
case 1:
bf->enc_w = bg->encoding;
break;
case 2:
bf->enc_h = bg->encoding;
break;
case 3:
bf->enc_x = bg->encoding;
break;
case 4:
bf->enc_y = bg->encoding;
break;
}
}
}
}
if ( bf->bbx_mode == BDF_BBX_MODE_M8 )
{
bf->max.w = ( bf->max.w + 7 ) & ~7;
bf->max.h = ( bf->max.h + 7 ) & ~7;
}
bf_Log(bf, "CalculateMaxBBX: x=%ld, y=%ld, w=%ld, h=%ld", bf->max.x, bf->max.y, bf->max.w, bf->max.h);
bf_Log(bf, "CalculateMaxBBX: Encodings x=%ld, y=%ld, w=%ld, h=%ld", bf->enc_x, bf->enc_y, bf->enc_w, bf->enc_h);
}
void bf_CalculateMinMaxDWidth(bf_t *bf)
{
int i;
bg_t *bg;
bf->dx_min = 0x07fff;
bf->dx_max = -0x07fff;
bf->x_min = 0x07fff;
bf->x_max = -0x07fff;
for( i = 0; i < bf->glyph_cnt; i++ )
{
bg = bf->glyph_list[i];
if ( bg->map_to >= 0 )
{
if ( bf->dx_min > bg->dwidth_x )
bf->dx_min = bg->dwidth_x;
if ( bf->dx_max < bg->dwidth_x )
bf->dx_max = bg->dwidth_x;
if ( bf->x_min > bg->bbx.x )
bf->x_min = bg->bbx.x;
if ( bf->x_max < bg->bbx.x )
bf->x_max = bg->bbx.x;
}
}
bf_Log(bf, "bf_CalculateMinMaxDWidth: dx_min=%ld, dx_max=%ld", bf->dx_min, bf->dx_max);
bf_Log(bf, "bf_CalculateMinMaxDWidth: x_min=%ld, x_max=%ld", bf->x_min, bf->x_max);
if ( bf->dx_min == bf->dx_max && bf->x_min >= 0 )
{
bf_Log(bf, "bf_CalculateMinMaxDWidth: Monospaced font."); /* not sufficient: also bbx.x must be >= 0 for all glyphs */
/* for a monospaced font, dx must be identical to bbx.w */
}
}
int get_unsigned_bit_size(unsigned long v)
{
int i = 0;
while( v != 0 )
{
v = v / 2;
i++;
}
return i;
}
int get_signed_bit_size(long v)
{
if ( v < 0 )
return get_unsigned_bit_size(-v-1) + 1;
return get_unsigned_bit_size(v) + 1;
}
void bf_copy_bbx_and_update_shift(bf_t *bf, bbx_t *target_bbx, bg_t *bg)
{
/* modifing the following code requires update ind bdf_rle.c also */
if ( bf->bbx_mode == BDF_BBX_MODE_MINIMAL )
{
*target_bbx = bg->bbx;
}
else if ( bf->bbx_mode == BDF_BBX_MODE_MAX )
{
*target_bbx = bf->max;
target_bbx->x = 0;
if ( bg->bbx.x < 0 )
bg->shift_x = bg->bbx.x;
if ( target_bbx->w < bg->dwidth_x )
target_bbx->w = bg->dwidth_x;
}
else if ( bf->bbx_mode == BDF_BBX_MODE_M8 )
{
target_bbx->w = bf->max.w;
if ( target_bbx->w < bg->dwidth_x )
target_bbx->w = bg->dwidth_x;
target_bbx->w = (target_bbx->w+7) & ~7;
target_bbx->h = (bf->max.h+7) & ~7;
target_bbx->x = bf->max.x;
target_bbx->y = bf->max.y;
target_bbx->x = 0;
if ( bg->bbx.x < 0 )
bg->shift_x = bg->bbx.x;
}
else
{
*target_bbx = bf->max;
target_bbx->w = bg->bbx.w;
target_bbx->x = bg->bbx.x;
target_bbx->x = 0;
if ( bg->bbx.x < 0 )
{
/* e.g. "j" */
target_bbx->w -= bg->bbx.x;
bg->shift_x = bg->bbx.x;
}
else
{
/* e.g. "B" */
target_bbx->w += bg->bbx.x;
//bg->shift_x = bg->bbx.x;
}
if ( target_bbx->w < bg->dwidth_x )
target_bbx->w = bg->dwidth_x;
}
bg->width_deviation = target_bbx->w - bg->bbx.w;
}
void bf_CalculateMaxBitFieldSize(bf_t *bf)
{
int i;
bg_t *bg;
int bs;
bbx_t local_bbx;
bf->bbx_x_max_bit_size = 0;
bf->bbx_y_max_bit_size = 0;
bf->bbx_w_max_bit_size = 0;
bf->bbx_h_max_bit_size = 0;
bf->dx_max_bit_size = 0;
for( i = 0; i < bf->glyph_cnt; i++ )
{
bg = bf->glyph_list[i];
if ( bg->map_to >= 0 )
{
bf_copy_bbx_and_update_shift(bf, &local_bbx, bg);
#ifdef OLD_CLODE
/* modifing the following code requires update ind bdf_rle.c also */
if ( bf->bbx_mode == BDF_BBX_MODE_MINIMAL )
{
local_bbx = bg->bbx;
}
else if ( bf->bbx_mode == BDF_BBX_MODE_MAX )
{
local_bbx = bf->max;
local_bbx.x = 0;
if ( bg->bbx.x < 0 )
bg->shift_x = bg->bbx.x;
if ( local_bbx.w < bg->dwidth_x )
local_bbx.w = bg->dwidth_x;
}
else if ( bf->bbx_mode == BDF_BBX_MODE_M8 )
{
local_bbx.w = bf->max.w;
if ( local_bbx.w < bg->dwidth_x )
local_bbx.w = bg->dwidth_x;
local_bbx.w = (local_bbx.w+7) & ~7;
local_bbx.h = (bf->max.h+7) & ~7;
local_bbx.x = bf->max.x;
local_bbx.y = bf->max.y;
local_bbx.x = 0;
if ( bg->bbx.x < 0 )
bg->shift_x = bg->bbx.x;
}
else
{
local_bbx = bf->max;
local_bbx.w = bg->bbx.w;
local_bbx.x = bg->bbx.x;
local_bbx.x = 0;
if ( bg->bbx.x < 0 )
{
/* e.g. "j" */
local_bbx.w -= bg->bbx.x;
bg->shift_x = bg->bbx.x;
}
else
{
/* e.g. "B" */
local_bbx.w += bg->bbx.x;
//bg->shift_x = bg->bbx.x;
}
if ( local_bbx.w < bg->dwidth_x )
local_bbx.w = bg->dwidth_x;
}
#endif
bs = get_unsigned_bit_size(local_bbx.w);
if ( bf->bbx_w_max_bit_size < bs )
bf->bbx_w_max_bit_size = bs;
bs = get_unsigned_bit_size(local_bbx.h);
if ( bf->bbx_h_max_bit_size < bs )
bf->bbx_h_max_bit_size = bs;
//printf("%ld ", local_bbx.x);
bs = get_signed_bit_size(local_bbx.x);
if ( bf->bbx_x_max_bit_size < bs )
bf->bbx_x_max_bit_size = bs;
//printf("%d:%d ",(int)local_bbx->x, (int)bs);
bs = get_signed_bit_size(local_bbx.y);
if ( bf->bbx_y_max_bit_size < bs )
bf->bbx_y_max_bit_size = bs;
if ( bf->bbx_mode == BDF_BBX_MODE_MINIMAL )
{
bs = get_signed_bit_size(bg->dwidth_x);
}
else if ( bf->bbx_mode == BDF_BBX_MODE_MAX )
{
bs = get_signed_bit_size(local_bbx.w);
}
else
{
bs = get_signed_bit_size(local_bbx.w);
}
if ( bf->dx_max_bit_size < bs )
bf->dx_max_bit_size = bs;
}
}
bf_Log(bf, "bf_CalculateMaxBitFieldSize: bbx.x=%d, bbx.y=%d, bbx.w=%d, bbx.h=%d, dwidth=%d",
bf->bbx_x_max_bit_size, bf->bbx_y_max_bit_size, bf->bbx_w_max_bit_size, bf->bbx_h_max_bit_size, bf->dx_max_bit_size);
}
void bf_ShowMonospaceStatistics(bf_t *bf)
{
int i;
bg_t *bg;
long cnt = 0;
long max = 0;
long sum = 0;
for( i = 0; i < bf->glyph_cnt; i++ )
{
bg = bf->glyph_list[i];
if ( bg->map_to >= 0 )
{
if ( max < bg->width_deviation )
max = bg->width_deviation;
sum += bg->width_deviation;
cnt++;
}
}
if ( cnt == 0 )
cnt++;
bf_Log(bf, "Monospace Statistics: Max width extention %ld, average width extention %ld.%ld", max, sum/cnt, (sum*10/cnt) % 10 );
/*
Monospaced font: average width extention does not differ much between -b 1 and --b 2
Variable width font: big difference for the average width extention between modes 1 and 2.
Examples:
./bdfconv -b 1 -v ../bdf/profont12.bdf
Monospace Statistics: Max width extention 6, average width extention 1.7
./bdfconv -b 2 -v ../bdf/profont12.bdf
Monospace Statistics: Max width extention 6, average width extention 1.7
--> profont12.bdf is a monospaced font
./bdfconv -b 1 -v ../bdf/helvR12.bdf
Monospace Statistics: Max width extention 6, average width extention 1.9
./bdfconv -b 2 -v ../bdf/helvR12.bdf
Monospace Statistics: Max width extention 15, average width extention 8.0
--> helvR12.bdf is not a monospaced font
*/
}
int bf_WriteUCGCByFP(bf_t *bf, FILE *out_fp, const char *fontname, const char *indent)
{
int i;
int bytes_per_line = 16;
fprintf(out_fp, "/*\n");
fprintf(out_fp, " Fontname: %s\n", bf->str_font);
fprintf(out_fp, " Copyright: %s\n", bf->str_copyright);
fprintf(out_fp, " Glyphs: %d/%d\n", (int)bf->selected_glyphs, (int)bf->glyph_cnt );
fprintf(out_fp, " BBX Build Mode: %d\n", (int)bf->bbx_mode);
fprintf(out_fp, "*/\n");
fprintf(out_fp, "#include \"ucg.h\"\n");
fprintf(out_fp, "const ucg_fntpgm_uint8_t %s[%d] UCG_FONT_SECTION(\"%s\") = {\n", fontname, bf->target_cnt, fontname);
fprintf(out_fp, " ");
for( i = 0; i < bf->target_cnt; i++ )
{
fprintf(out_fp, "%d", bf->target_data[i]);
if ( i+1 != bf->target_cnt )
fprintf(out_fp, ",");
if ( (i+1) % bytes_per_line == 0 )
fprintf(out_fp, "\n%s", indent);
}
fprintf(out_fp, "};\n");
return 1;
}
int bf_WriteU8G2CByFP(bf_t *bf, FILE *out_fp, const char *fontname, const char *indent)
{
int i;
int bytes_per_line = 16;
fprintf(out_fp, "/*\n");
fprintf(out_fp, " Fontname: %s\n", bf->str_font);
fprintf(out_fp, " Copyright: %s\n", bf->str_copyright);
fprintf(out_fp, " Glyphs: %d/%d\n", (int)bf->selected_glyphs, (int)bf->glyph_cnt );
fprintf(out_fp, " BBX Build Mode: %d\n", (int)bf->bbx_mode);
fprintf(out_fp, "*/\n");
fprintf(out_fp, "#include \"u8g2.h\"\n");
fprintf(out_fp, "const uint8_t %s[%d] U8G2_FONT_SECTION(\"%s\") = {\n", fontname, bf->target_cnt, fontname);
fprintf(out_fp, " ");
for( i = 0; i < bf->target_cnt; i++ )
{
fprintf(out_fp, "%d", bf->target_data[i]);
if ( i+1 != bf->target_cnt )
fprintf(out_fp, ",");
if ( (i+1) % bytes_per_line == 0 )
fprintf(out_fp, "\n%s", indent);
}
fprintf(out_fp, "};\n");
return 1;
}
int bf_WriteUCGCByFilename(bf_t *bf, const char *filename, const char *fontname, const char *indent)
{
FILE *fp;
fp = fopen(filename, "wb");
if ( fp == NULL )
{
bf_Log(bf, "bf_WriteUCGCByFilename: Open error '%s'", filename);
return 0;
}
bf_WriteUCGCByFP(bf, fp, fontname, indent);
bf_Log(bf, "bf_WriteUCGCByFilename: Write file '%s'", filename);
fclose(fp);
return 1;
}
int bf_WriteU8G2CByFilename(bf_t *bf, const char *filename, const char *fontname, const char *indent)
{
FILE *fp;
fp = fopen(filename, "wb");
if ( fp == NULL )
{
bf_Log(bf, "bf_WriteU8G2CByFilename: Open error '%s'", filename);
return 0;
}
bf_WriteU8G2CByFP(bf, fp, fontname, indent);
bf_Log(bf, "bf_WriteU8G2CByFilename: Write file '%s'", filename);
fclose(fp);
return 1;
}
bf_t *bf_OpenFromFile(const char *bdf_filename, int is_verbose, int bbx_mode, const char *map_str, int font_format)
{
bf_t *bf;
bf = bf_Open(is_verbose, bbx_mode);
if ( bf != NULL )
{
if ( bf_ParseFile(bf, bdf_filename) != 0 )
{
bf_Map(bf, map_str);
bf_CalculateSelectedNumberOfGlyphs(bf);
bf_ReduceAllGlyph(bf);
bf_CalculateMaxBBX(bf);
//bf_ShowAllGlyphs(bf, &(bf->max));
bf_CalculateMinMaxDWidth(bf);
bf_CalculateMaxBitFieldSize(bf);
if ( font_format == 0 || font_format == 1 )
{
bf_RLECompressAllGlyphs(bf);
}
else
{
bf_Generate8x8Font(bf);
}
if ( bf->bbx_mode != BDF_BBX_MODE_MINIMAL )
bf_ShowMonospaceStatistics(bf); /* Show stats only for none minimal mode. For minimal mode it will always be zero */
return bf;
}
bf_Close(bf);
}
return NULL;
}
+146
View File
@@ -0,0 +1,146 @@
#ifndef _BDF_FONT_H
#define _BDF_FONT_H
#include <stdio.h>
#include "bdf_glyph.h"
#define BDF_LINE_LEN 1024
#define BDF_BBX_MODE_MINIMAL 0
#define BDF_BBX_MODE_HEIGHT 1
#define BDF_BBX_MODE_MAX 2
#define BDF_BBX_MODE_M8 3
struct _bdf_font_struct
{
int is_verbose;
bg_t **glyph_list;
int glyph_cnt;
int glyph_max;
/* variables for the parser */
char line_buf[BDF_LINE_LEN];
int line_pos;
int is_bitmap_parsing;
long encoding;
long dwidth_x;
long dwidth_y;
long bbx_w;
long bbx_h;
long bbx_x;
long bbx_y;
int bitmap_x; /* x position within bitmap parsing */
int bitmap_y; /* y position within bitmap parsing */
int glyph_pos; /* the position to which the glyph has been added in the list */
FILE *fp;
char *str_font; /* argument for FONT in bdf file */
char *str_copyright; /* argument for COPYRIGHT in bdf file */
long selected_glyphs; /* number of mapped glyphs */
int bbx_mode; /* bounding box mode, one of BDF_BBX_MODE_xxx */
/* bf_CalculateMaxBBX */
bbx_t max; /* max bbx, calculated from the mapped glyphs by bf_CalculateMaxBBX */
/* remember which encoding has caused the max value */
long enc_w;
long enc_h;
long enc_x;
long enc_y;
/* bf_CalculateMinMaxDWidth */
long dx_min; /* calculated minimum and maximum dwidth value from the mapped glyphs by bf_CalculateMinMaxDWidth */
long dx_max; /* it is a monospaced font if max and min values are identical */
/* bf_CalculateMinMaxDWidth */
long x_min; /* calculated minimum and maximum bbx.x value from the mapped glyphs by bf_CalculateMinMaxDWidth */
long x_max; /* it is a monospaced font if x_min >= 0 */
/* bf_CalculateMaxBitFieldSize */
int bbx_x_max_bit_size;
int bbx_y_max_bit_size;
int bbx_w_max_bit_size;
int bbx_h_max_bit_size;
int dx_max_bit_size;
/* font target data */
uint8_t *target_data;
int target_max;
int target_cnt;
};
/* bdf_font.c */
/* output error & log messages */
void bf_Error(bf_t *bf, char *fmt, ...);
void bf_Log(bf_t *bf, char *fmt, ...);
/* constructor/destructor */
bf_t *bf_Open(int is_verbose, int bbx_mode);
void bf_Close(bf_t *bf);
/* returns glyph position or -1 */
int bf_AddGlyph(bf_t *bf);
/* add binary data */
void bf_ClearTargetData(bf_t *bf);
int bf_AddTargetData(bf_t *bf, uint8_t data);
void bf_CalculateSelectedNumberOfGlyphs(bf_t *bf);
void bf_ReduceAllGlyph(bf_t *bf);
int bf_GetIndexByEncoding(bf_t *bf, long encoding);
/* only shows glyphs, which will be mapped (call bf_Map() first) */
void bf_ShowAllGlyphs(bf_t *bf, bbx_t *bbx);
void bf_ShowMonospaceStatistics(bf_t *bf);
/* calculate the max bbx for all mapped glyphs (call bf_Map() first) */
void bf_CalculateMaxBBX(bf_t *bf);
void bf_CalculateMinMaxDWidth(bf_t *bf);
void bf_copy_bbx_and_update_shift(bf_t *bf, bbx_t *target_bbx, bg_t *bg);
void bf_CalculateMaxBitFieldSize(bf_t *bf);
void bf_RLECompressAllGlyphs(bf_t *bf);
void bf_Generate8x8Font(bf_t *bf);
int bf_WriteUCGCByFilename(bf_t *bf, const char *filename, const char *fontname, const char *indent);
int bf_WriteU8G2CByFilename(bf_t *bf, const char *filename, const char *fontname, const char *indent);
bf_t *bf_OpenFromFile(const char *bdf_filename, int is_verbose, int bbx_mode, const char *map_str, int font_format);
/* bdf_parser.c */
int bf_ParseFile(bf_t *bf, const char *name);
/* bdf_map.c */
void bf_Map(bf_t *bf, const char *map_cmd_list);
/* bdf_tga.c */
int tga_init(uint16_t w, uint16_t h);
void tga_set_pixel(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b);
void tga_save(const char *name);
void tga_set_font(uint8_t *font);
uint8_t *tga_get_glyph_data(uint8_t encoding);
int tga_get_char_width(void);
int tga_get_char_height(void);
unsigned tga_draw_glyph(unsigned x, unsigned y, uint8_t encoding, int is_hints);
unsigned tga_draw_string(unsigned x, unsigned y, const char *s, int is_hints, unsigned max_dx);
#endif
+392
View File
@@ -0,0 +1,392 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "bdf_glyph.h"
bg_t *bg_Open(void)
{
bg_t *bg;
bg = (bg_t *)malloc(sizeof(bg_t));
if ( bg != NULL )
{
bg->encoding = 0;
bg->map_to = -1;
bg->bitmap_data = NULL;
bg->target_data = NULL;
bg->target_max = 0;
bg->target_cnt = 0;
bg->shift_x = 0;
return bg;
}
return NULL;
}
void bg_Close(bg_t *bg)
{
if ( bg->bitmap_data != NULL )
free(bg->bitmap_data);
if ( bg->target_data != NULL )
free(bg->target_data);
bg->bitmap_data = NULL;
bg->target_data =NULL;
bg->target_max = 0;
bg->target_cnt = 0;
bg->target_bit_pos = 0;
bg->encoding = 0;
free(bg);
}
static int bg_extend_target_data(bg_t *bg)
{
int extend = 16;
int i;
void *ptr;
if ( bg->target_data == NULL )
{
ptr = malloc(extend*sizeof(uint8_t));
bg->target_max = 0;
}
else
{
ptr = realloc(bg->target_data, (bg->target_max + extend)*sizeof(uint8_t));
}
if ( ptr == NULL )
return 0;
bg->target_data = (uint8_t *)ptr;
for( i = bg->target_max; i < bg->target_max + extend; i++ )
bg->target_data[i] = 0;
bg->target_max += extend;
return 1;
}
int bg_AddTargetData(bg_t *bg, uint8_t data)
{
while( bg->target_max <= bg->target_cnt )
if ( bg_extend_target_data(bg) == 0 )
return -1;
bg->target_data[bg->target_cnt] = data;
bg->target_cnt++;
return bg->target_cnt-1;
}
void bg_ClearTargetData(bg_t *bg)
{
int i;
for( i = 0; i < bg->target_max; i++ )
bg->target_data[i] = 0;
bg->target_cnt = 0;
bg->target_bit_pos = 0;
}
/*
Desc:
Output a field to the target bitstream. The field size in bits is given by "cnt" and
the value of the field is "val".
Args:
cnt: Fieldsize in bits, must be lower or equal to 8
val: The value (content) of the field. Side condition: val < (1<<cnt) && val >= 0
*/
int bg_AddTargetBits(bg_t *bg, unsigned cnt, unsigned val)
{
assert( val < (1<<cnt) );
while( bg->target_max <= bg->target_cnt+1 )
if ( bg_extend_target_data(bg) == 0 )
return 0;
bg->target_data[bg->target_cnt] |= (val << bg->target_bit_pos);
if ( bg->target_bit_pos+cnt >= 8 )
{
bg->target_cnt++;
val >>= 8-bg->target_bit_pos;
bg->target_data[bg->target_cnt] = val;
bg->target_bit_pos+=cnt;
bg->target_bit_pos-=8;
}
else
{
bg->target_bit_pos+=cnt;
}
return 1;
}
int bg_FlushTargetBits(bg_t *bg)
{
while( bg->target_bit_pos != 0 )
if ( bg_AddTargetBits(bg, 1, 0) == 0 )
return 0;
return 1;
}
int bg_SetBitmapSizeInBytes(bg_t *bg, size_t bytes)
{
if ( bg->bitmap_data != NULL )
free(bg->bitmap_data);
bg->bitmap_data = (uint8_t *)malloc(bytes);
if ( bg->bitmap_data == NULL )
return 0;
memset(bg->bitmap_data, 0, bytes);
return 1;
}
int bg_SetBitmapSize(bg_t *bg, int w, int h)
{
return bg_SetBitmapSizeInBytes(bg, w*h);
}
void bg_SetBitmapPixel(bg_t *bg, int x, int y, int value)
{
assert( x < bg->bitmap_width );
assert( y < bg->bitmap_height );
assert( x >= 0 );
assert( y >= 0 );
bg->bitmap_data[y*bg->bitmap_width + x] = value;
}
int bg_GetBitmapPixel(bg_t *bg, int x, int y)
{
if ( x >= bg->bitmap_width )
return 0;
if ( y >= bg->bitmap_height )
return 0;
if ( x < 0 )
return 0;
if ( y < 0 )
return 0;
return bg->bitmap_data[y*bg->bitmap_width + x];
}
/*
Return a pixel with the provided bbx
Coordinates are within the bbx.
*/
int bg_GetBBXPixel(bg_t *bg, int x, int y)
{
/* glyph rectangle */
long glyph_x0, glyph_x1, glyph_y0, glyph_y1;
/* local bitmap coordinates */
long bitmap_x, bitmap_y;
/* perform x offset alignment (used in BDF_BBX_MODE_HEIGHT mode only)*/
x += bg->shift_x;
/* calculate the rectangle for the glyph */
glyph_x0 = bg->bbx.x;
glyph_y0 = bg->bbx.y;
glyph_x1 = bg->bbx.x+bg->bbx.w;
glyph_y1 = bg->bbx.y+bg->bbx.h;
if ( x < glyph_x0 )
return 0;
if ( x >= glyph_x1 )
return 0;
if ( y < glyph_y0 )
return 0;
if ( y >= glyph_y1 )
return 0;
bitmap_x = x - glyph_x0;
bitmap_y = bg->bbx.h - 1 - ( y - glyph_y0);
return bg_GetBitmapPixel( bg, bitmap_x, bitmap_y );
}
void bg_ShowBitmap(bg_t *bg, bbx_t *bbx)
{
int x, y;
if ( bbx == NULL )
bbx = &(bg->bbx);
printf("Encoding %ld, mapped to %ld, w=%ld, h=%ld, x=%ld, y=%ld\n", bg->encoding, bg->map_to, bg->bbx.w, bg->bbx.h, bg->bbx.x, bg->bbx.y);
for( y = bbx->y+bbx->h-1; y >= bbx->y; y--)
{
printf("%03d ", y);
for( x = bbx->x; x < bbx->x + bbx->w; x++)
{
if ( bg_GetBBXPixel(bg, x, y) == 0 )
{
printf(" .");
}
else
{
printf(" #");
}
}
printf("\n");
}
}
int bg_IsColZero(bg_t *bg, int x)
{
int y;
for( y = 0; y < bg->bitmap_height; y++ )
{
if ( bg_GetBitmapPixel(bg, x, y) != 0 )
return 0;
}
return 1;
}
int bg_IsRowZero(bg_t *bg, int y)
{
int x;
for( x = 0; x < bg->bitmap_width; x++ )
{
if ( bg_GetBitmapPixel(bg, x, y) != 0 )
return 0;
}
return 1;
}
void bg_DeleteFirstCol(bg_t *bg)
{
int x,y;
for( y = 0; y < bg->bitmap_height; y++ )
for( x = 0; x+1 < bg->bitmap_width; x++ )
{
bg_SetBitmapPixel(bg, x, y, bg_GetBitmapPixel(bg, x+1, y));
}
}
void bg_DeleteFirstRow(bg_t *bg)
{
int x,y;
for( y = 0; y+1 < bg->bitmap_height; y++ )
for( x = 0; x < bg->bitmap_width; x++ )
{
bg_SetBitmapPixel(bg, x, y, bg_GetBitmapPixel(bg, x, y+1));
}
}
void bg_ReduceGlyph(bg_t *bg)
{
/* assign bitmap dimension (should be done already) */
//bg->bbx.w = bg->bitmap_width;
//bg->bbx.h = bg->bitmap_height;
/* do not assign x,y because they are already set correctly */
while( bg->bbx.w > 0 )
{
if ( bg_IsColZero(bg, bg->bbx.w-1) == 0 )
break;
bg->bbx.w--;
}
while( bg->bbx.h > 0 )
{
if ( bg_IsRowZero(bg, bg->bbx.h-1) == 0 )
break;
bg->bbx.y++;
bg->bbx.h--;
}
while( bg->bbx.w > 0)
{
if ( bg_IsColZero(bg, 0) == 0 )
break;
bg_DeleteFirstCol(bg);
bg->bbx.x++;
bg->bbx.w--;
}
while( bg->bbx.h > 0 )
{
if ( bg_IsRowZero(bg, 0) == 0 )
break;
bg_DeleteFirstRow(bg);
bg->bbx.h--;
}
}
/*
maximize the provided bbx so that the bbxof the glyph completly is covered by the max bbx
*/
int bg_Max(bg_t *bg, bbx_t *max)
{
int r = 0;
/* glyph rectangle */
long glyph_x0, glyph_x1, glyph_y0, glyph_y1;
/* max rectangle */
long max_x0, max_x1, max_y0, max_y1;
// printf("Encoding %ld, mapped to %ld, w=%ld, h=%ld, x=%ld, y=%ld\n", bg->encoding, bg->map_to, bg->bbx.w, bg->bbx.h, bg->bbx.x, bg->bbx.y);
/* calculate the rectangle for the glyph */
glyph_x0 = bg->bbx.x;
glyph_y0 = bg->bbx.y;
glyph_x1 = bg->bbx.x+bg->bbx.w;
glyph_y1 = bg->bbx.y+bg->bbx.h;
/* calculate the rectangle for the max bbx */
max_x0 = max->x;
max_y0 = max->y;
max_x1 = max->x+max->w;
max_y1 = max->y+max->h;
/* maximize the max rectrangle so that the glyph rectangle full fits inside */
if ( max_x0 > glyph_x0 )
{
max_x0 = glyph_x0;
r = 3;
}
/* 28 Mar dwidth_x and x0???? */
if ( max_x0 > bg->dwidth_x ) /* include dwidth_x into the box */
{
max_x0 = bg->dwidth_x; /* is this correct??? */
r = 3;
}
if ( max_x1 < glyph_x1 )
{
r = 1;
max_x1 = glyph_x1;
}
if ( max_y0 > glyph_y0 )
{
r = 4;
max_y0 = glyph_y0;
}
if ( max_y1 < glyph_y1 )
{
r = 2;
max_y1 = glyph_y1;
}
/* reconstruct the max bbx from the max rectangle */
max->x = max_x0;
max->y = max_y0;
max->w = max_x1 - max->x;
max->h = max_y1 - max->y;
return r;
}
+84
View File
@@ -0,0 +1,84 @@
#ifndef _BDF_GLYPH_H
#define _BDF_GLYPH_H
#include <stdint.h>
#include <stddef.h>
/* forward def */
typedef struct _bdf_font_struct bf_t;
struct _bbx_struct
{
long w;
long h;
long x;
long y;
};
typedef struct _bbx_struct bbx_t;
struct _bdf_glyph_struct
{
bf_t *bf;
long encoding;
long map_to;
long dwidth_x;
long dwidth_y;
bbx_t bbx; /* x,y are delta x,y from glyph, w,h start wth bitmap dimension, but may be reduced */
long shift_x; /* extra shift for BDF_BBX_MODE_HEIGHT alignment */
uint8_t *bitmap_data;
int bitmap_width; /* the physical width within "bitmap_data", will be larger than or equal to bbx.w */
int bitmap_height;
//int actual_bitmap_width; /* identical to bbx.w, maybe replace actual_bitmap_width by bbx.w */
//int actual_bitmap_height; /* identical to bbx.h, maybe replace actual_bitmap_height by bbx.h */
uint8_t *target_data;
int target_max;
int target_cnt;
int target_bit_pos;
/* rle data */
unsigned rle_bits_per_0;
unsigned rle_bits_per_1;
int rle_is_first;
unsigned rle_bitcnt;
unsigned rle_last_0;
unsigned rle_last_1;
long width_deviation; /* filled by bf_copy_bbx_and_update_shift for statistics */
};
typedef struct _bdf_glyph_struct bg_t;
bg_t *bg_Open(void);
void bg_Close(bg_t *bg);
int bg_AddTargetData(bg_t *bg, uint8_t data);
void bg_ClearTargetData(bg_t *bg);
int bg_AddTargetBits(bg_t *bg, unsigned cnt, unsigned val);
int bg_FlushTargetBits(bg_t *bg);
int bg_SetBitmapSizeInBytes(bg_t *bg, size_t bytes);
int bg_SetBitmapSize(bg_t *bg, int w, int h);
void bg_SetBitmapPixel(bg_t *bg, int x, int y, int value);
int bg_GetBitmapPixel(bg_t *bg, int x, int y);
int bg_GetBBXPixel(bg_t *bg, int x, int y);
void bg_ShowBitmap(bg_t *bg, bbx_t *bbx);
void bg_ReduceGlyph(bg_t *bg);
int bg_Max(bg_t *bg, bbx_t *max); /* returns idx which describes glyph expansion */
/* bdf_rle.c */
int bg_rle_compress(bg_t *bg, bbx_t *bbx, unsigned rle_bits_per_0, unsigned rle_bits_per_1, int is_output);
#endif
+239
View File
@@ -0,0 +1,239 @@
/*
bdf_map.c
select and map glyphs
Syntax:
maplist := <mapcmd> { "," <mapcmd> }
mapcmd := <default> | <maprange> | <exclude>
default := "*"
maprange := <range> [ ">" <num> ]
exclude := "~" <range>
range := <num> [ "-" <num> ]
num := <hexnum> | <decnum>
hexnum := "$" <hexdigit> { <hexdigit> }
decnum := <decdigit> { <decdigit> }
decdigit := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
hexdigit := "a" | "b" | "c" | "d" | "e" | "f" | "A" | "B" | "C" | "D" | "E" | "F" | <decdigit>
{ }: zero, one ore more
[ ]: zero or once
|: alternative
*/
#include "bdf_font.h"
static long range_from;
static long range_to;
static int is_exclude;
static long map_to;
static void skip_space(const char **s)
{
for(;;)
{
if ( **s == '\0' )
break;
if ( **s > ' ' )
break;
(*s)++;
}
}
static long get_dec(const char **s)
{
long v = 0;
for(;;)
{
if ( (**s) >= '0' && (**s) <= '9' )
{
v*=10;
v+= (**s)-'0';
(*s)++;
}
else
{
break;
}
}
skip_space(s);
return v;
}
static long get_hex(const char **s)
{
long v = 0;
for(;;)
{
if ( (**s) >= '0' && (**s) <= '9' )
{
v*=16;
v+= (**s)-'0';
(*s)++;
}
else if ( (**s) >= 'a' && (**s) <= 'f' )
{
v*=16;
v+= (**s)-'a'+10;
(*s)++;
}
else if ( (**s) >= 'A' && (**s) <= 'F' )
{
v*=16;
v+= (**s)-'A'+10;
(*s)++;
}
else
{
break;
}
}
skip_space(s);
return v;
}
static long get_num(const char **s)
{
if ( (**s) != '$' )
return get_dec(s);
(*s)++;
skip_space(s);
return get_hex(s);
}
static long get_mul(const char **s)
{
long v;
v = get_num(s);
if ( (**s) == '*' )
{
(*s)++;
skip_space(s);
v *= get_num(s);
}
return v;
}
static long get_add(const char **s)
{
long v;
v = get_mul(s);
if ( (**s) == '+' )
{
(*s)++;
skip_space(s);
v += get_mul(s);
}
return v;
}
static void get_range(const char **s)
{
range_from = get_add(s);
if ( **s != '-' )
{
range_to = range_from;
}
else
{
(*s)++;
skip_space(s);
range_to = get_add(s);
}
}
static void map_cmd(const char **s)
{
if ( **s == '*' )
{
range_from = 32;
range_to = 255;
map_to = 32;
is_exclude = 0;
(*s)++;
skip_space(s);
}
else if ( **s == '~' )
{
is_exclude = 1;
map_to = 0; /*will be ignored */
(*s)++;
skip_space(s);
get_range(s);
}
else
{
is_exclude = 0;
get_range(s);
map_to = range_from;
if ( **s == '>')
{
(*s)++;
skip_space(s);
map_to = get_add(s);
}
}
}
void bf_map_cmd(bf_t *bf, const char **s)
{
int i;
bg_t *bg;
map_cmd(s);
bf_Log(bf, "Map: exclude=%d from=%ld to=%ld map=%ld", is_exclude, range_from, range_to, map_to);
for( i = 0; i < bf->glyph_cnt; i++ )
{
bg = bf->glyph_list[i];
if ( bg->encoding >= range_from && bg->encoding <= range_to )
{
if ( is_exclude != 0 )
{
bg->map_to = -1;
}
else
{
bg->map_to = bg->encoding - range_from + map_to;
}
}
}
}
void bf_map_list(bf_t *bf, const char **s)
{
int i;
bg_t *bg;
/* exclude everything first */
for( i = 0; i < bf->glyph_cnt; i++ )
{
bg = bf->glyph_list[i];
bg->map_to = -1;
}
/* process the mapping list list */
skip_space(s);
for(;;)
{
bf_map_cmd(bf, s);
if ( **s != ',' )
break;
(*s)++;
skip_space(s);
}
}
void bf_Map(bf_t *bf, const char *map_cmd_list)
{
bf_Log(bf, "Map: map_cmd_list='%s'", map_cmd_list);
bf_map_list(bf, &map_cmd_list);
}
+472
View File
@@ -0,0 +1,472 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "bdf_font.h"
static int bf_curr(bf_t * bf)
{
if ( bf->line_pos >= BDF_LINE_LEN )
return '\0';
return bf->line_buf[bf->line_pos];
}
static void bf_next(bf_t *bf)
{
if ( bf_curr(bf) == '\0' )
return;
if ( bf->line_pos >= BDF_LINE_LEN )
return;
bf->line_pos++;
}
static void bf_skipspace(bf_t *bf)
{
int c;
for(;;)
{
c = bf_curr(bf);
if ( c == '\0' )
return;
if ( c > ' ' )
return;
bf_next(bf);
}
}
static const char *bf_get_identifier(bf_t *bf)
{
static char buf[BDF_LINE_LEN];
int c;
int i = 0;
buf[0] = '\0';
for(;;)
{
c = bf_curr(bf);
if ( c <= ' ' )
break;
if ( i >= BDF_LINE_LEN-2 )
break;
buf[i++] = c;
buf[i] = '\0';
bf_next(bf);
}
bf_skipspace(bf);
return buf;
}
static const char *bf_get_string(bf_t *bf)
{
static char buf[BDF_LINE_LEN];
int i = 0;
int c;
buf[0] = '\0';
if ( bf_curr(bf) != '\"' )
return bf_get_identifier(bf);
bf_next(bf);
for(;;)
{
c = bf_curr(bf);
if ( c == '\0' )
break;
if ( c == '\"' )
break;
if ( i >= BDF_LINE_LEN-2 )
break;
buf[i++] = c;
buf[i] = '\0';
bf_next(bf);
}
if ( bf_curr(bf) == '\"' )
bf_next(bf);
bf_skipspace(bf);
return buf;
}
static const char *bf_get_eol_string(bf_t *bf)
{
static char buf[BDF_LINE_LEN];
int i = 0;
int c;
buf[0] = '\0';
if ( bf_curr(bf) == '\"' )
return bf_get_string(bf);
bf_next(bf);
for(;;)
{
c = bf_curr(bf);
if ( c == '\0' )
break;
if ( c == '\n' || c == '\r' )
break;
if ( i >= BDF_LINE_LEN-2 )
break;
buf[i++] = c;
buf[i] = '\0';
bf_next(bf);
}
bf_skipspace(bf);
return buf;
}
static long bf_get_long(bf_t *bf)
{
int c;
long v = 0;
long sign = 1;
if ( bf_curr(bf) == '-' )
{
sign = -1;
bf_next(bf);
bf_skipspace(bf);
}
for(;;)
{
c = bf_curr(bf);
if ( c < '0' )
break;
if ( c > '9' )
break;
v *= 10L;
v += (long)(c-'0');
bf_next(bf);
}
bf_skipspace(bf);
return v*sign;
}
/*
static long bf_get_mul(bf_t *bf)
{
long v;
v = bf_get_long(bf);
if ( bf_curr(bf) == '*' )
{
bf_next(bf);
bf_skipspace(bf);
v *= bf_get_long(bf);
}
return v;
}
static long bf_get_add(bf_t *bf)
{
long v;
v = bf_get_mul(bf);
if ( bf_curr(bf) == '+' )
{
bf_next(bf);
bf_skipspace(bf);
v += bf_get_mul(bf);
}
return v;
}
*/
static int bf_add_glyph_to_list(bf_t *bf)
{
bg_t *bg;
bf->glyph_pos = bf_AddGlyph(bf);
if ( bf->glyph_pos < 0 )
{
bf_Error(bf, "Can not add glyph (memory error?)");
return 0;
}
bg = bf->glyph_list[bf->glyph_pos];
/* copy the values from the parser to the glyph record */
bg->encoding = bf->encoding;
bg->dwidth_x = bf->dwidth_x;
bg->dwidth_y = bf->dwidth_y;
bg->bbx.w = bf->bbx_w;
bg->bbx.h = bf->bbx_h;
bg->bbx.x = bf->bbx_x;
bg->bbx.y = bf->bbx_y;
if ( bg_SetBitmapSize(bg, bf->bbx_w, bf->bbx_h) == 0 )
{
bf_Error(bf, "Can not create bitmap (memory error?)");
return 0;
}
bg->bitmap_width = bf->bbx_w;
bg->bitmap_height = bf->bbx_h;
// bg->actual_bitmap_width = bf->bbx_w;
// bg->actual_bitmap_height = bf->bbx_h;
//bf_Log(bf, "BDF File: Create glyph glyph_pos=%d bbx_w=%d bbx_h=%d bbx_x=%d bbx_y=%d", bf->glyph_pos, bf->bbx_w, bf->bbx_h, bf->bbx_x, bf->bbx_y);
return 1;
}
static void bf_set_pixel_by_halfbyte(bf_t *bf, int halfbyte)
{
int i;
bg_t *bg;
assert( bf->glyph_list != NULL );
bg = bf->glyph_list[bf->glyph_pos];
for ( i = 0; i < 4; i++ )
{
if ( (halfbyte & 8) != 0 )
{
bg_SetBitmapPixel(bg, bf->bitmap_x, bf->bitmap_y, 1);
}
halfbyte<<=1;
bf->bitmap_x++;
}
}
static void bf_set_pixel_by_hex_char(bf_t *bf, int hex)
{
if ( hex >= '0' && hex <= '9' )
return bf_set_pixel_by_halfbyte(bf, hex-'0');
if ( hex >= 'a' && hex <= 'f' )
return bf_set_pixel_by_halfbyte(bf, hex-'a'+10);
if ( hex >= 'A' && hex <= 'F' )
return bf_set_pixel_by_halfbyte(bf, hex-'A'+10);
return bf_set_pixel_by_halfbyte(bf, 0);
}
static int bf_parse_line(bf_t *bf)
{
static char cmd[BDF_LINE_LEN];
bf->line_pos = 0;
bf_skipspace(bf);
if ( bf->is_bitmap_parsing == 0 )
{
/* regular command */
bf->bitmap_y = 0;
strcpy(cmd, bf_get_string(bf));
if ( strcmp(cmd, "" ) == 0 )
{
return 1;
}
else if ( strcmp(cmd, "STARTFONT" ) == 0 ) /* args: s */
{
}
else if ( strcmp(cmd, "FONT" ) == 0 ) /* args: s */
{
if ( bf->str_font != NULL )
free(bf->str_font);
bf->str_font = strdup(bf_get_eol_string(bf));
}
else if ( strcmp(cmd, "SIZE" ) == 0 ) /* args: lll */
{
}
else if ( strcmp(cmd, "FONTBOUNDINGBOX" ) == 0 ) /* args: llll */
{
}
else if ( strcmp(cmd, "STARTPROPERTIES" ) == 0 ) /* args: l */
{
}
else if ( strcmp(cmd, "FONTNAME_REGISTRY" ) == 0 ) /* args: s */
{
}
else if ( strcmp(cmd, "FOUNDRY" ) == 0 ) /* args: s */
{
}
else if ( strcmp(cmd, "FAMILY_NAME" ) == 0 ) /* args: s */
{
}
else if ( strcmp(cmd, "WEIGHT_NAME" ) == 0 ) /* args: s */
{
}
else if ( strcmp(cmd, "SLANT" ) == 0 ) /* args: s */
{
}
else if ( strcmp(cmd, "SETWIDTH_NAME" ) == 0 ) /* args: s */
{
}
else if ( strcmp(cmd, "ADD_STYLE_NAME" ) == 0 ) /* args: s */
{
}
else if ( strcmp(cmd, "PIXEL_SIZE" ) == 0 ) /* args: l */
{
}
else if ( strcmp(cmd, "POINT_SIZE" ) == 0 ) /* args: l */
{
}
else if ( strcmp(cmd, "RESOLUTION_X" ) == 0 ) /* args: l */
{
}
else if ( strcmp(cmd, "RESOLUTION_Y" ) == 0 ) /* args: l */
{
}
else if ( strcmp(cmd, "SPACING" ) == 0 ) /* args: s */
{
}
else if ( strcmp(cmd, "AVERAGE_WIDTH" ) == 0 ) /* args: l */
{
}
else if ( strcmp(cmd, "CHARSET_REGISTRY" ) == 0 ) /* args: s */
{
}
else if ( strcmp(cmd, "CHARSET_ENCODING" ) == 0 ) /* args: s */
{
}
else if ( strcmp(cmd, "DESTINATION" ) == 0 ) /* args: l */
{
}
else if ( strcmp(cmd, "COPYRIGHT" ) == 0 ) /* args: s */
{
if ( bf->str_copyright != NULL )
free(bf->str_copyright);
bf->str_copyright = strdup(bf_get_eol_string(bf));
}
else if ( strcmp(cmd, "_XMBDFED_INFO" ) == 0 ) /* args: s */
{
}
else if ( strcmp(cmd, "CAP_HEIGHT" ) == 0 ) /* args: l */
{
}
else if ( strcmp(cmd, "X_HEIGHT" ) == 0 ) /* args: l */
{
}
else if ( strcmp(cmd, "WEIGHT" ) == 0 ) /* args: l */
{
}
else if ( strcmp(cmd, "QUAD_WIDTH" ) == 0 ) /* args: l */
{
}
else if ( strcmp(cmd, "DEFAULT_CHAR" ) == 0 ) /* args: l */
{
}
else if ( strcmp(cmd, "FONT_DESCENT" ) == 0 ) /* args: l */
{
}
else if ( strcmp(cmd, "FONT_ASCENT" ) == 0 ) /* args: l */
{
}
else if ( strcmp(cmd, "ENDPROPERTIES" ) == 0 ) /* args: - */
{
}
else if ( strcmp(cmd, "CHARS" ) == 0 ) /* args: l */
{
}
else if ( strcmp(cmd, "STARTCHAR" ) == 0 ) /* args: s */
{
}
else if ( strcmp(cmd, "ENCODING" ) == 0 ) /* args: l */
{
bf->encoding = bf_get_long(bf);
//bf_Log(bf, "BDF File: ENCODING %d", bf->encoding);
}
else if ( strcmp(cmd, "SWIDTH" ) == 0 ) /* args: ll */
{
}
else if ( strcmp(cmd, "DWIDTH" ) == 0 ) /* args: ll */
{
bf->dwidth_x = bf_get_long(bf);
bf->dwidth_y = bf_get_long(bf);
}
else if ( strcmp(cmd, "BBX" ) == 0 ) /* args: llll */
{
bf->bbx_w = bf_get_long(bf);
bf->bbx_h = bf_get_long(bf);
bf->bbx_x = bf_get_long(bf);
bf->bbx_y = bf_get_long(bf);
}
else if ( strcmp(cmd, "BITMAP" ) == 0 ) /* args: - */
{
if ( bf_add_glyph_to_list(bf) == 0 )
return 0;
bf->is_bitmap_parsing = 1;
}
else if ( strcmp(cmd, "ENDCHAR" ) == 0 ) /* args: - */
{
bf_Error(bf, "Unexpected ENDCHAR found");
return 0;
}
}
else
{
/* a line of the glyph bitmap */
int c;
strcpy(cmd, bf_get_string(bf));
if ( strcmp(cmd, "ENDCHAR" ) == 0 ) /* args: - */
{
bf->is_bitmap_parsing = 0;
/* bg_ShowBitmap(bf->glyph_list[bf->glyph_pos]); */
}
else
{
bf->line_pos = 0;
bf_skipspace(bf);
bf->bitmap_x = 0;
for(;;)
{
c = bf_curr(bf);
if ( c < '0' )
break;
bf_set_pixel_by_hex_char(bf, c);
bf_next(bf);
}
bf->bitmap_y++;
}
}
return 1;
}
static int bf_parse_file(bf_t *bf)
{
long line_cnt = 0;
bf->is_bitmap_parsing = 0;
for(;;)
{
line_cnt++;
if ( fgets(bf->line_buf, BDF_LINE_LEN, bf->fp) == NULL )
break;
if ( bf_parse_line(bf) == 0 )
{
bf_Error(bf, "perse error in line %ld", line_cnt);
return 0;
}
}
return 1;
}
int bf_ParseFile(bf_t *bf, const char *name)
{
int r;
bf->fp = fopen(name, "r");
if ( bf->fp == NULL )
{
bf_Error(bf, "Can not open bdf file '%s'", name);
return 0;
}
r = bf_parse_file(bf);
fclose(bf->fp);
bf_Log(bf, "Parse File %s: %d glyph(s) found", name, bf->glyph_cnt);
return r;
}
+773
View File
@@ -0,0 +1,773 @@
/*
bdf_rle.c
run length glyph encoding
size comparison with old and new font format
4x6 1500 1469
4x6r 734 726
6x10 1866 2009
6x10r 889 971
7x13B 2172 2253
7x13Br 1041 1017
9x15 2959 2649
9x15r 1427 1242
10x20 3453 3053
10x20r 1667 1417 85%
courB12 3959 3312
courB12r 1857 1538
courB24 10502 6661
courB24r 4775 3015 63%
helvB24 10931 6904 63%
helvB24r 4992 3166 63%
logisoso50r 14375 5248 36%
*/
/* font information */
/*
glyph_cnt = *font++;
bits_per_0 = *font++;
bits_per_1 = *font++;
bits_per_char_width = *font++;
bits_per_char_height = *font++;
bits_per_char_x = *font++;
bits_per_char_y = *font++;
bits_per_delta_x = *font++;
*/
/* apply glyph information */
/*
~ encoding unsigned, 1 byte
~ total size unsigned, 1 byte
~ BBX width unsigned 5
~ BBX height unsigned 5
~ BBX xoffset signed 2
~ BBX yoffset signed 5
~ DWIDTH unsigned 3
*/
#define BDF_RLE_FONT_GLYPH_START 21
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "bdf_font.h"
#ifdef OLD_CODE
#define SCREEN_W 140
#define SCREEN_H 140
uint8_t screen_buf[SCREEN_H][SCREEN_W];
unsigned screen_max_y;
void screen_init(void)
{
unsigned x, y;
screen_max_y = 0;
for( y = 0; y < SCREEN_H; y++ )
{
for( x = 0; x < SCREEN_W; x++ )
{
screen_buf[y][x] = '.';
}
}
}
void screen_set_pixel(unsigned x, unsigned y, uint8_t c)
{
if ( screen_max_y < y)
screen_max_y = y;
screen_buf[y][x] = c;
}
void screen_show(void)
{
unsigned x, y;
printf("\n");
for( y = 0; y <= screen_max_y; y++ )
{
for( x = 0; x < SCREEN_W; x++ )
{
printf("%c", screen_buf[y][x]);
}
printf("\n");
}
}
/*===================================================*/
/* font decode */
struct fd_struct
{
unsigned x; /* local coordinates, (0,0) is upper left */
unsigned y;
unsigned glyph_width;
unsigned glyph_height;
const uint8_t *decode_ptr; /* pointer to the compressed data */
unsigned decode_bit_pos; /* bitpos inside a byte of the compressed data */
uint8_t bbx_x_max_bit_size;
uint8_t bbx_y_max_bit_size;
uint8_t bbx_w_max_bit_size;
uint8_t bbx_h_max_bit_size;
uint8_t dx_max_bit_size;
};
typedef struct fd_struct fd_t;
/* increment x and consider line wrap (inc y)*/
static void fd_inc(fd_t *f)
{
unsigned x = f->x;
x++;
if ( x == f->glyph_width )
{
x = 0;
f->y++;
}
f->x = x;
}
static unsigned fd_get_unsigned_bits(fd_t *f, unsigned cnt)
{
unsigned val;
unsigned bit_pos = f->decode_bit_pos;
val = *(f->decode_ptr);
val >>= bit_pos;
if ( bit_pos + cnt >= 8 )
{
f->decode_ptr++;
val |= *(f->decode_ptr) << (8-bit_pos);
bit_pos -= 8;
}
val &= (1U<<cnt)-1;
bit_pos += cnt;
f->decode_bit_pos = bit_pos;
return val;
}
/*
2 bit --> cnt = 2
-2,-1,0. 1
3 bit --> cnt = 3
-2,-1,0. 1
-4,-3,-2,-1,0,1,2,3
if ( x < 0 )
r = bits(x-1)+1;
else
r = bits(x)+1;
*/
static int fd_get_signed_bits(fd_t *t, int cnt)
{
return (int)fd_get_unsigned_bits(t, cnt) - ((1<<cnt)>>1);
}
static void fd_draw_pixel(fd_t *f)
{
screen_set_pixel(f->x, f->y, '#');
}
static void fd_decode(bg_t *bg, bbx_t *bbx, fd_t *f, unsigned rle_bits_per_0, unsigned rle_bits_per_1)
{
unsigned a, b;
unsigned i;
screen_init();
if ( bbx == NULL )
bbx = &(bg->bbx);
/* init decode algorithm */
f->decode_ptr = bg->target_data;
f->decode_bit_pos = 0;
f->glyph_width = bbx->w;
f->glyph_height = bbx->h;
/* read glyph info */
f->decode_ptr += 2;
fd_get_unsigned_bits(f, f->bbx_w_max_bit_size);
fd_get_unsigned_bits(f, f->bbx_h_max_bit_size);
fd_get_signed_bits(f, f->bbx_x_max_bit_size);
fd_get_signed_bits(f, f->bbx_y_max_bit_size);
fd_get_signed_bits(f, f->dx_max_bit_size);
/* reset local x/y position */
f->x = 0;
f->y = 0;
//puts("");
/* decode glyph */
for(;;)
{
a = fd_get_unsigned_bits(f, rle_bits_per_0);
b = fd_get_unsigned_bits(f, rle_bits_per_1);
//printf("[%u %u]", a, b);
do
{
for( i = 0; i < a; i++ )
{
fd_inc(f);
}
for( i = 0; i < b; i++ )
{
fd_draw_pixel(f);
fd_inc(f);
}
} while( fd_get_unsigned_bits(f, 1) != 0 );
if ( f->y >= f->glyph_height )
break;
}
screen_show();
}
#endif
/*===================================================*/
/*
Desc:
Output a and b to the stream.
a and b must fit to the target size in bits.
Additionally a repeat code r (one bit) is generated:
It may look like this:
r = 0: 0aaaabb
or
r = 1: 1
If r is 0, then the number of zeros (a) and ones (b) will follow and both
values must be stored as in the decoder.
If r os 1, then the number of zeros and ones is repeated once
Args:
a: number of 0 bits, log2(a) must be smaller or equal to the fieldsize
b: number of 1 bits, log2(b) must be smaller or equal to the fieldsize
*/
static void bg_err(const char *s)
{
puts(s);
}
static void bg_init_rle(bg_t *bg, unsigned rle_bits_per_0, unsigned rle_bits_per_1)
{
bg->rle_bitcnt = 0;
bg->rle_is_first = 1;
bg->rle_bits_per_0 = rle_bits_per_0;
bg->rle_bits_per_1 = rle_bits_per_1;
bg->rle_last_0 = 0;
bg->rle_last_1 = 1;
bg_ClearTargetData(bg);
}
static int bg_01_rle(bg_t *bg, unsigned a, unsigned b)
{
if ( bg->rle_is_first == 0 && bg->rle_last_0 == a && bg->rle_last_1 == b )
{
bg->rle_bitcnt++;
if ( bg_AddTargetBits(bg, 1, 1) == 0 )
return bg_err("error in bg_01_rle 1 0"), 0;
}
else
{
if ( bg->rle_is_first == 0 )
{
if ( bg_AddTargetBits(bg, 1, 0) == 0 )
return bg_err("error in bg_01_rle 1 0"), 0;
bg->rle_bitcnt++;
}
if ( bg_AddTargetBits(bg, bg->rle_bits_per_0, a) == 0 )
return bg_err("error in bg_01_rle 1 a"), 0;
if ( bg_AddTargetBits(bg, bg->rle_bits_per_1, b) == 0 )
return bg_err("error in bg_01_rle 1 b"), 0;
/*
if ( bg->encoding == ' ' )
{
printf("[%u %u]", a, b);
}
*/
bg->rle_is_first = 0;
bg->rle_bitcnt +=bg->rle_bits_per_0;
bg->rle_bitcnt +=bg->rle_bits_per_1;
bg->rle_last_0 = a;
bg->rle_last_1 = b;
}
return 1;
}
/*
Desc:
Write the number of zeros and ones to the bit stream.
There is no restriction on the size of a and b.
Args:
a: number of 0 bits
b: number of 1 bits
*/
static int bg_prepare_01_rle(bg_t *bg, unsigned a, unsigned b)
{
//printf("[%u %u]", a, b);
while( a >= (1<<bg->rle_bits_per_0) -1 )
{
if ( bg_01_rle(bg, (1<<bg->rle_bits_per_0) -1, 0) == 0 )
return 0;
a -= (1<<bg->rle_bits_per_0) -1;
}
while( b >= (1<<bg->rle_bits_per_1) -1 )
{
if ( bg_01_rle(bg, a, (1<<bg->rle_bits_per_1) -1) == 0 )
return 0;
a = 0;
b -= (1<<bg->rle_bits_per_1) -1;
}
if ( a != 0 || b != 0 )
if ( bg_01_rle(bg, a, b) == 0 )
return 0;
return 1;
}
int bg_rle_compress(bg_t *bg, bbx_t *bbx, unsigned rle_bits_per_0, unsigned rle_bits_per_1, int is_output)
{
int x;
int y;
int i;
int bd_is_one; /* bit delta */
int bd_curr_len;
int bd_max_len;
int bd_chg_cnt;
static int bd_list[1024*2];
if ( bbx == NULL )
bbx = &(bg->bbx);
bg_init_rle(bg, rle_bits_per_0, rle_bits_per_1);
/* step 0: output initial information */
//printf("%ld %ld\n", (long)bg->encoding, (long)bg->map_to);
if ( bg_AddTargetData(bg, bg->map_to) < 0 )
return bg_err("error in bg_rle_compress"), 0;
/* size, will be added later */
if ( bg_AddTargetData(bg, 0) < 0 )
return bg_err("error in bg_rle_compress"), 0;
if ( bg_AddTargetBits(bg, bg->bf->bbx_w_max_bit_size, bbx->w) == 0 )
return bg_err("error in bg_rle_compress"), 0;
if ( bg_AddTargetBits(bg, bg->bf->bbx_h_max_bit_size, bbx->h) == 0 )
return bg_err("error in bg_rle_compress"), 0;
if ( bg_AddTargetBits(bg, bg->bf->bbx_x_max_bit_size, bbx->x + (1<<(bg->bf->bbx_x_max_bit_size-1))) == 0 )
return bg_err("error in bg_rle_compress"), 0;
if ( bg_AddTargetBits(bg, bg->bf->bbx_y_max_bit_size, bbx->y + (1<<(bg->bf->bbx_y_max_bit_size-1))) == 0 )
return bg_err("error in bg_rle_compress"), 0;
if ( bg->bf->bbx_mode == BDF_BBX_MODE_MINIMAL )
{
if ( bg_AddTargetBits(bg, bg->bf->dx_max_bit_size, bg->dwidth_x + (1<<(bg->bf->dx_max_bit_size-1))) == 0 )
return bg_err("error in bg_rle_compress"), 0;
}
else if ( bg->bf->bbx_mode == BDF_BBX_MODE_MAX )
{
if ( bg_AddTargetBits(bg, bg->bf->dx_max_bit_size, bbx->w+ (1<<(bg->bf->dx_max_bit_size-1))) == 0 )
return bg_err("error in bg_rle_compress"), 0;
}
else
{
if ( bg_AddTargetBits(bg, bg->bf->dx_max_bit_size, bbx->w+ (1<<(bg->bf->dx_max_bit_size-1))) == 0 )
return bg_err("error in bg_rle_compress"), 0;
}
bd_is_one = 0;
bd_curr_len = 0;
bd_max_len = 0;
bd_chg_cnt = 0;
/* step 1: build array with pairs of a (number of zero bits) and b (number of one bits) */
for( y = bbx->y+bbx->h-1; y >= bbx->y; y--)
{
for( x = bbx->x; x < bbx->x + bbx->w; x++)
{
if ( bg_GetBBXPixel(bg, x, y) == 0 )
{
if ( bd_is_one != 0 )
{
bd_list[bd_chg_cnt] = bd_curr_len;
bd_is_one = 0;
bd_chg_cnt++;
bd_curr_len = 0;
}
bd_curr_len++;
}
else
{
if ( bd_is_one == 0 )
{
bd_list[bd_chg_cnt] = bd_curr_len;
bd_is_one = 1;
bd_chg_cnt++;
bd_curr_len = 0;
}
bd_curr_len++;
}
if ( bd_max_len < bd_curr_len )
bd_max_len = bd_curr_len;
}
}
bd_list[bd_chg_cnt] = bd_curr_len;
bd_chg_cnt++;
if ( (bd_chg_cnt & 1) == 1 )
{
assert(bd_is_one == 0);
bd_list[bd_chg_cnt] = 0;
bd_chg_cnt++;
}
//printf("01 pairs = %d\n", bd_chg_cnt/2);
/* step 2: convert the array into bit stream */
//if ( bg->encoding == ' ' )
// printf("Encoding list, pairs = %d\n", bd_chg_cnt/2);
for( i = 0; i < bd_chg_cnt; i+=2 )
{
//if ( bg->encoding == ' ' )
// printf("(%d %d)", bd_list[i], bd_list[i+1]);
if ( bg_prepare_01_rle(bg, bd_list[i], bd_list[i+1]) == 0 )
return 0;
}
//if ( bg->encoding == 'B' )
// printf("\nEncoding list end\n");
if ( bg_AddTargetBits(bg, 1, 0) == 0 ) // ensure that there is a 0 bit at the end. This will simplify decoding loop
return 0;
if ( bg_FlushTargetBits(bg) == 0 ) // finish the last byte and update bg->target_cnt
return 0;
bg->target_data[1] = bg->target_cnt;
/*
{
fd_t f;
f.bbx_x_max_bit_size = bg->bf->bbx_x_max_bit_size;
f.bbx_y_max_bit_size = bg->bf->bbx_y_max_bit_size;
f.bbx_w_max_bit_size = bg->bf->bbx_w_max_bit_size;
f.bbx_h_max_bit_size = bg->bf->bbx_h_max_bit_size;
f.dx_max_bit_size = bg->bf->dx_max_bit_size;
fd_decode(bg, bbx, &f, rle_bits_per_0, rle_bits_per_1);
}
*/
return 1;
}
unsigned long bf_RLECompressAllGlyphsWithFieldSize(bf_t *bf, int rle_0, int rle_1, int is_output)
{
int i;
bg_t *bg;
unsigned long total_bits = 0;
bbx_t local_bbx;
for( i = 0; i < bf->glyph_cnt; i++ )
{
bg = bf->glyph_list[i];
if ( bg->map_to >= 0 )
{
bf_copy_bbx_and_update_shift(bf, &local_bbx, bg);
#ifdef OLD_CLODE
/* modifing the following code requires update ind bdf_font.c also */
if ( bf->bbx_mode == BDF_BBX_MODE_MINIMAL )
{
local_bbx = bg->bbx;
}
else if ( bf->bbx_mode == BDF_BBX_MODE_MAX )
{
local_bbx = bf->max;
local_bbx.x = 0;
if ( bg->bbx.x < 0 )
bg->shift_x = bg->bbx.x;
if ( local_bbx.w < bg->dwidth_x )
local_bbx.w = bg->dwidth_x;
}
else if ( bf->bbx_mode == BDF_BBX_MODE_M8 )
{
local_bbx.w = bf->max.w;
if ( local_bbx.w < bg->dwidth_x )
local_bbx.w = bg->dwidth_x;
local_bbx.w = (local_bbx.w+7) & ~7;
local_bbx.h = (bf->max.h+7) & ~7;
local_bbx.x = bf->max.x;
local_bbx.y = bf->max.y;
local_bbx.x = 0;
if ( bg->bbx.x < 0 )
bg->shift_x = bg->bbx.x;
}
else
{
local_bbx = bf->max;
local_bbx.w = bg->bbx.w;
local_bbx.x = bg->bbx.x;
local_bbx.x = 0;
if ( bg->bbx.x < 0 )
{
/* e.g. "j" */
local_bbx.w -= bg->bbx.x;
bg->shift_x = bg->bbx.x;
}
else
{
/* e.g. "B" */
local_bbx.w += bg->bbx.x;
//bg->shift_x = bg->bbx.x;
}
if ( local_bbx.w < bg->dwidth_x )
local_bbx.w = bg->dwidth_x;
}
#endif
bg_rle_compress(bg, &local_bbx, rle_0, rle_1, is_output);
total_bits += bg->target_cnt*8+bg->target_bit_pos;
if ( is_output != 0 )
{
bf_Log(bf, "RLE Compress: Encoding %ld bits %u/%u", bg->encoding, bg->rle_bitcnt, bg->target_cnt*8+bg->target_bit_pos);
}
}
}
//bf_Log(bf, "RLE Compress: zero bits %d, one bits %d, total bit size %lu", rle_0, rle_1, total_bits);
return total_bits;
}
unsigned bf_RLE_get_glyph_data(bf_t *bf, uint8_t encoding)
{
uint8_t *font = bf->target_data;
font += BDF_RLE_FONT_GLYPH_START;
for(;;)
{
if ( font[1] == 0 )
break;
if ( font[0] == encoding )
{
return (font-bf->target_data)-BDF_RLE_FONT_GLYPH_START;
}
font += font[1];
}
return 0;
}
void bf_RLECompressAllGlyphs(bf_t *bf)
{
int i, j;
bg_t *bg;
int rle_0, rle_1;
int best_rle_0=0, best_rle_1= 0;
unsigned long total_bits = 0;
unsigned long min_total_bits = 0xffffffff;
int idx_cap_a;
int idx_cap_a_ascent;
int idx_1;
int idx_1_ascent;
int idx_g;
int idx_g_descent;
int idx_para;
int idx_para_ascent;
int idx_para_descent;
unsigned pos;
idx_cap_a_ascent = 0;
idx_cap_a = bf_GetIndexByEncoding(bf, 'A');
if ( idx_cap_a >= 0 )
{
idx_cap_a_ascent = bf->glyph_list[idx_cap_a]->bbx.h+bf->glyph_list[idx_cap_a]->bbx.y;
}
idx_1_ascent = 0;
idx_1 = bf_GetIndexByEncoding(bf, '1');
if ( idx_1 >= 0 )
{
idx_1_ascent = bf->glyph_list[idx_1]->bbx.h+bf->glyph_list[idx_1]->bbx.y;
}
idx_g_descent = 0;
idx_g = bf_GetIndexByEncoding(bf, 'g');
if ( idx_g >= 0 )
{
idx_g_descent = bf->glyph_list[idx_g]->bbx.y;
}
idx_para_ascent = 0;
idx_para = bf_GetIndexByEncoding(bf, '(');
if ( idx_para >= 0 )
{
idx_para_ascent = bf->glyph_list[idx_para]->bbx.h+bf->glyph_list[idx_para]->bbx.y;
idx_para_descent = bf->glyph_list[idx_para]->bbx.y;
}
else
{
idx_para_ascent = idx_cap_a_ascent;
if ( idx_para_ascent == 0 )
idx_para_ascent = idx_1_ascent;
idx_para_descent = idx_g_descent;
}
for( rle_0 = 2; rle_0 < 7; rle_0++ )
{
for( rle_1 = 2; rle_1 < 7; rle_1++ )
{
total_bits = bf_RLECompressAllGlyphsWithFieldSize(bf, rle_0, rle_1, 0);
if ( min_total_bits > total_bits )
{
min_total_bits = total_bits;
best_rle_0 = rle_0;
best_rle_1 = rle_1;
}
}
}
bf_Log(bf, "RLE Compress: best zero bits %d, one bits %d, total bit size %lu", best_rle_0, best_rle_1, min_total_bits);
bf_RLECompressAllGlyphsWithFieldSize(bf, best_rle_0, best_rle_1, 0);
bf_ClearTargetData(bf);
/*
glyph_cnt = *font++;
bits_per_0 = *font++;
bits_per_1 = *font++;
bits_per_char_width = *font++;
bits_per_char_height = *font++;
bits_per_char_x = *font++;
bits_per_char_y = *font++;
bits_per_delta_x = *font++;
*/
bf_Log(bf, "RLE Compress: Font code generation, selected glyphs=%d, total glyphs=%d", bf->selected_glyphs, bf->glyph_cnt);
/* 0 */
bf_AddTargetData(bf, bf->selected_glyphs);
bf_AddTargetData(bf, bf->bbx_mode);
bf_AddTargetData(bf, best_rle_0);
bf_AddTargetData(bf, best_rle_1);
/* 4 */
bf_AddTargetData(bf, bf->bbx_w_max_bit_size);
bf_AddTargetData(bf, bf->bbx_h_max_bit_size);
bf_AddTargetData(bf, bf->bbx_x_max_bit_size);
bf_AddTargetData(bf, bf->bbx_y_max_bit_size);
bf_AddTargetData(bf, bf->dx_max_bit_size);
/* 9 */
bf_AddTargetData(bf, bf->max.w);
bf_AddTargetData(bf, bf->max.h);
bf_AddTargetData(bf, bf->max.x);
bf_AddTargetData(bf, bf->max.y);
/* 13 */
if ( idx_cap_a_ascent > 0 )
bf_AddTargetData(bf, idx_cap_a_ascent);
else
bf_AddTargetData(bf, idx_1_ascent);
bf_AddTargetData(bf, idx_g_descent);
/* 15 */
bf_AddTargetData(bf, idx_para_ascent);
bf_AddTargetData(bf, idx_para_descent);
/* 17 */
bf_AddTargetData(bf, 0); /* start pos 'A', high/low */
bf_AddTargetData(bf, 0);
/* 19 */
bf_AddTargetData(bf, 0); /* start pos 'a', high/low */
bf_AddTargetData(bf, 0);
for( i = 0; i < bf->glyph_cnt; i++ )
{
bg = bf->glyph_list[i];
if ( bg->map_to >= 0 )
{
if ( bg->target_data != NULL )
{
if ( bg->target_cnt >= 255 )
{
bf_Error(bf, "RLE Compress: Error, glyph too large, encoding=", bg->encoding);
exit(1);
}
for( j = 0; j < bg->target_cnt; j++ )
{
bf_AddTargetData(bf, bg->target_data[j]);
}
}
}
}
/* add empty glyph as end of font marker */
bf_AddTargetData(bf, 0);
bf_AddTargetData(bf, 0);
pos = bf_RLE_get_glyph_data(bf, 'A');
bf->target_data[17] = pos >> 8;
bf->target_data[18] = pos & 255;
pos = bf_RLE_get_glyph_data(bf, 'a');
bf->target_data[19] = pos >> 8;
bf->target_data[20] = pos & 255;
bf_Log(bf, "RLE Compress: 'A' pos = %u, 'a' pos = %u", bf_RLE_get_glyph_data(bf, 'A'), bf_RLE_get_glyph_data(bf, 'a'));
bf_Log(bf, "RLE Compress: Font size %d", bf->target_cnt);
}
+561
View File
@@ -0,0 +1,561 @@
/*
bdf_tga.c
Modes:
BDF_BBX_MODE_MINIMAL 0
BDF_BBX_MODE_MAX 1
BDF_BBX_MODE_HEIGHT 2
For all modes, default reference should be the baseline.
This is required for mode 0, but may be optional for 1 and 2
If (x,y) is the user provided baseline point for the glyph, then
the decoding mus tbe start at
(x..., y-h-descent)
BDF_BBX_MODE_MINIMAL
- exact space as intended by the font author
- glyphs my overlap ("mj" with osb18)
BDF_BBX_MODE_MAX
- extra space may be added
- glyphs do not overlap
BDF_BBX_MODE_HEIGHT
- extra space may be added
- glyphs do not overlap
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "fd.h"
static uint16_t tga_width;
static uint16_t tga_height;
static uint8_t *tga_data = NULL;
static uint8_t *tga_font;
static int glyph_cnt;
static int bits_per_0;
static int bits_per_1;
static int bits_per_char_width;
static int bits_per_char_height;
static int bits_per_char_x;
static int bits_per_char_y;
static int bits_per_delta_x;
static int char_width;
static int char_height;
static int char_descent;
int tga_get_char_width(void)
{
return char_width;
}
int tga_get_char_height(void)
{
return char_height;
}
int tga_init(uint16_t w, uint16_t h)
{
tga_width = 0;
tga_height = 0;
if ( tga_data != NULL )
free(tga_data);
tga_data = (uint8_t *)malloc((size_t)w*(size_t)h*3);
if ( tga_data == NULL )
return 0;
tga_width = w;
tga_height = h;
memset(tga_data, 255, tga_width*tga_height*3);
return 1;
}
void tga_set_pixel(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b)
{
uint8_t *p;
if ( y>= tga_height)
return;
if ( x>= tga_width)
return;
p = tga_data + (tga_height-y-1)*(size_t)tga_width*3 + (size_t)x*3;
*p++ = b;
*p++ = g;
*p++ = r;
}
void tga_write_byte(FILE *fp, uint8_t byte)
{
fputc(byte, fp);
}
void tga_write_word(FILE *fp, uint16_t word)
{
tga_write_byte(fp, word&255);
tga_write_byte(fp, word>>8);
}
void tga_save(const char *name)
{
FILE *fp;
fp = fopen(name, "wb");
if ( fp != NULL )
{
tga_write_byte(fp, 0); /* no ID */
tga_write_byte(fp, 0); /* no color map */
tga_write_byte(fp, 2); /* uncompressed true color */
tga_write_word(fp, 0);
tga_write_word(fp, 0);
tga_write_byte(fp, 0);
tga_write_word(fp, 0); /* x origin */
tga_write_word(fp, 0); /* y origin */
tga_write_word(fp, tga_width); /* width */
tga_write_word(fp, tga_height); /* height */
tga_write_byte(fp, 24); /* color depth */
tga_write_byte(fp, 0);
fwrite(tga_data, tga_width*tga_height*3, 1, fp);
tga_write_word(fp, 0);
tga_write_word(fp, 0);
tga_write_word(fp, 0);
tga_write_word(fp, 0);
fwrite("TRUEVISION-XFILE.", 18, 1, fp);
fclose(fp);
}
}
/*
font data:
offset bytes description
0 1 glyph_cnt number of glyphs
1 1 bbx_mode 0: proportional, 1: common height, 2: monospace, 3: multiple of 8
2 1 bits_per_0 glyph rle parameter
3 1 bits_per_1 glyph rle parameter
4 1 bits_per_char_width glyph rle parameter
5 1 bits_per_char_height glyph rle parameter
6 1 bits_per_char_x glyph rle parameter
7 1 bits_per_char_y glyph rle parameter
8 1 bits_per_delta_x glyph rle parameter
9 1 max_char_width
10 1 max_char_height
11 1 x offset
12 1 y offset (descent)
13 1 ascent (capital A)
14 1 descent (lower g)
15 1 ascent '('
16 1 descent ')'
17 1 start pos 'A' high byte
18 1 start pos 'A' low byte
19 1 start pos 'a' high byte
20 1 start pos 'a' low byte
*/
void tga_set_font(uint8_t *font)
{
glyph_cnt = *font++;
font++; /* bbx mode */
bits_per_0 = *font++;
bits_per_1 = *font++;
bits_per_char_width = *font++;
bits_per_char_height = *font++;
bits_per_char_x = *font++;
bits_per_char_y = *font++;
bits_per_delta_x = *font++;
char_width = *font++;
char_height = *font++;
font++; /* x offset */
char_descent = *(int8_t *)font;
font++;
font++;
font++;
font++;
font++;
font++;
font++;
font++;
font++;
tga_font = font;
}
#ifdef OLD_CODE
uint8_t *tga_get_glyph_data(uint8_t encoding)
{
int i;
uint8_t *font = tga_font;
for( i = 0; i < glyph_cnt; i++ )
{
if ( font[0] == encoding )
{
return font;
}
font += font[1];
}
return NULL;
}
#endif
uint8_t *tga_get_glyph_data(uint8_t encoding)
{
uint8_t *font = tga_font;
for(;;)
{
if ( font[1] == 0 )
break;
if ( font[0] == encoding )
{
return font;
}
font += font[1];
}
return NULL;
}
/* font decode */
struct tga_fd_struct
{
unsigned target_x;
unsigned target_y;
unsigned is_transparent;
unsigned x; /* local coordinates, (0,0) is upper left */
unsigned y;
unsigned glyph_width;
unsigned glyph_height;
const uint8_t *decode_ptr; /* pointer to the compressed data */
unsigned decode_bit_pos; /* bitpos inside a byte of the compressed data */
uint8_t bbx_x_max_bit_size;
uint8_t bbx_y_max_bit_size;
uint8_t bbx_w_max_bit_size;
uint8_t bbx_h_max_bit_size;
uint8_t dx_max_bit_size;
};
typedef struct tga_fd_struct tga_fd_t;
/* increment x and consider line wrap (inc y)*/
/* old procedure */
void tga_fd_inc(tga_fd_t *f)
{
unsigned x = f->x;
x++;
if ( x == f->glyph_width )
{
x = 0;
f->y++;
}
f->x = x;
}
unsigned tga_fd_get_unsigned_bits(tga_fd_t *f, unsigned cnt)
{
unsigned val;
unsigned bit_pos = f->decode_bit_pos;
val = *(f->decode_ptr);
val >>= bit_pos;
if ( bit_pos + cnt >= 8 )
{
f->decode_ptr++;
val |= *(f->decode_ptr) << (8-bit_pos);
bit_pos -= 8;
}
val &= (1U<<cnt)-1;
bit_pos += cnt;
f->decode_bit_pos = bit_pos;
return val;
}
/*
2 bit --> cnt = 2
-2,-1,0. 1
3 bit --> cnt = 3
-2,-1,0. 1
-4,-3,-2,-1,0,1,2,3
if ( x < 0 )
r = bits(x-1)+1;
else
r = bits(x)+1;
*/
int tga_fd_get_signed_bits(tga_fd_t *t, int cnt)
{
return (int)tga_fd_get_unsigned_bits(t, cnt) - ((1<<cnt)>>1);
}
void tga_fd_draw_fg_pixel(tga_fd_t *f, unsigned cnt)
{
//printf("%d ", cnt);
/* cnt can be zero */
while( cnt > 0 )
{
cnt--;
tga_set_pixel(f->target_x+f->x+cnt, f->target_y+f->y, 0,0,0);
}
}
void tga_fd_draw_bg_pixel(tga_fd_t *f, unsigned cnt)
{
//printf("%d ", cnt);
/* cnt can be zero */
while( cnt > 0 )
{
cnt--;
if ( f->is_transparent == 0 )
tga_set_pixel(f->target_x+f->x+cnt, f->target_y+f->y, 0x0e8,0x0e8,0x0e8);
}
}
void tga_draw_hline(unsigned x,unsigned y, unsigned cnt, unsigned is_foreground)
{
while( cnt > 0 )
{
cnt--;
if ( is_foreground == 0 )
tga_set_pixel(x+cnt, y, 0x0e8,0x0e8,0x0e8);
else
tga_set_pixel(x+cnt, y, 255,0,0);
}
}
void tga_fd_draw_pixel(tga_fd_t *f, unsigned cnt, unsigned is_foreground)
{
if ( is_foreground )
{
tga_fd_draw_fg_pixel(f, cnt);
}
else
{
tga_fd_draw_bg_pixel(f, cnt);
}
}
void tga_fd_decode_len(tga_fd_t *f, unsigned len, unsigned is_foreground)
{
unsigned cnt, rem;
cnt = len;
for(;;)
{
rem = f->glyph_width;
rem -= f->x;
if ( cnt < rem )
break;
tga_fd_draw_pixel(f,rem, is_foreground);
cnt -= rem;
f->x = 0;
f->y++;
}
tga_fd_draw_pixel(f, cnt, is_foreground);
f->x += cnt;
}
unsigned tga_fd_decode(tga_fd_t *f, uint8_t *glyph_data)
{
unsigned a, b;
//unsigned cnt, rem;
int x, y;
unsigned d = 0;
f->decode_ptr = glyph_data;
f->decode_bit_pos = 0;
f->decode_ptr += 1;
f->decode_ptr += 1;
f->glyph_width = tga_fd_get_unsigned_bits(f, bits_per_char_width);
f->glyph_height = tga_fd_get_unsigned_bits(f, bits_per_char_height);
x = tga_fd_get_signed_bits(f, bits_per_char_x);
y = tga_fd_get_signed_bits(f, bits_per_char_y);
d = tga_fd_get_signed_bits(f, bits_per_delta_x);
if ( f->glyph_width > 0 )
{
f->target_x += x;
f->target_y -= f->glyph_height ;
f->target_y -=y ;
/* reset local x/y position */
f->x = 0;
f->y = 0;
/* decode glyph */
for(;;)
{
a = tga_fd_get_unsigned_bits(f, bits_per_0);
b = tga_fd_get_unsigned_bits(f, bits_per_1);
do
{
tga_fd_decode_len(f, a, 0);
tga_fd_decode_len(f, b, 1);
} while( tga_fd_get_unsigned_bits(f, 1) != 0 );
if ( f->y >= f->glyph_height )
break;
}
}
return d;
}
unsigned tga_fd_decode_old(tga_fd_t *f, uint8_t *glyph_data)
{
unsigned a, b;
unsigned i;
int x, y;
unsigned d = 0;
//unsigned total;
/* init decode algorithm */
f->decode_ptr = glyph_data;
f->decode_bit_pos = 0;
f->decode_ptr += 1;
/* read glyph info */
//total = *f->decode_ptr;
f->decode_ptr += 1;
f->glyph_width = tga_fd_get_unsigned_bits(f, bits_per_char_width);
f->glyph_height = tga_fd_get_unsigned_bits(f, bits_per_char_height);
x = tga_fd_get_signed_bits(f, bits_per_char_x);
y = tga_fd_get_signed_bits(f, bits_per_char_y);
d = tga_fd_get_signed_bits(f, bits_per_delta_x);
if ( f->glyph_width > 0 )
{
//printf("width: %d\n", f->glyph_width);
//printf("height: %d\n", f->glyph_height);
//printf("x: %d\n", x);
//printf("y: %d\n", y);
//printf("d: %d\n", d);
f->target_x += x;
f->target_y -= f->glyph_height ;
f->target_y -=y ;
/* reset local x/y position */
f->x = 0;
f->y = 0;
//puts("");
//printf("start decode ");
/* decode glyph */
for(;;)
{
a = tga_fd_get_unsigned_bits(f, bits_per_0);
b = tga_fd_get_unsigned_bits(f, bits_per_1);
do
{
for( i = 0; i < a; i++ )
{
tga_fd_draw_bg_pixel(f,1);
tga_fd_inc(f);
}
/*
while( a + f->x > f->glyph_width )
{
tga_fd_draw_bg_pixel(f,f->glyph_width-f->x);
f->x = 0;
f->y++;
a -= f->glyph_width-f->x;
}
tga_fd_draw_bg_pixel(f,1);
*/
for( i = 0; i < b; i++ )
{
tga_fd_draw_fg_pixel(f,1);
tga_fd_inc(f);
}
} while( tga_fd_get_unsigned_bits(f, 1) != 0 );
if ( f->y >= f->glyph_height )
break;
}
}
/*
printf("\n");
printf("[x=%u y=%u]\n", f->x, f->y);
printf("cnt=%u total=%u\n", f->decode_ptr-glyph_data-2, total);
printf("end decode\n");
*/
return d;
}
unsigned tga_draw_glyph(unsigned x, unsigned y, uint8_t encoding, int is_hints)
{
unsigned dx = 0;
tga_fd_t f;
f.target_x = x;
f.target_y = y;
f.is_transparent = !is_hints;
uint8_t *glyph_data = tga_get_glyph_data(encoding);
if ( glyph_data != NULL )
{
dx = tga_fd_decode(&f, glyph_data);
if ( is_hints )
{
tga_set_pixel(x+dx, y, 28,133,240); /* orange: reference point */
tga_set_pixel(x, y, 255,164,0); /* blue: delta x (width) for this glyph */
}
}
return dx;
}
unsigned tga_draw_string(unsigned x, unsigned y, const char *s, int is_hints, unsigned max_dx)
{
unsigned dx = 0;
while( *s != '\0' )
{
dx += tga_draw_glyph(x+dx,y,*s, is_hints);
if ( max_dx > 0 )
if ( dx > max_dx )
break;
s++;
}
return dx;
}
+49
View File
@@ -0,0 +1,49 @@
#ifndef _FD_H
#define _FD_H
#include <stdint.h>
/* font decode */
struct fd_struct
{
unsigned target_x;
unsigned target_y;
unsigned is_transparent;
unsigned x; /* local coordinates, (0,0) is upper left */
unsigned y;
unsigned glyph_width;
unsigned glyph_height;
const uint8_t *decode_ptr; /* pointer to the compressed data */
unsigned decode_bit_pos; /* bitpos inside a byte of the compressed data */
unsigned decode_byte;
uint8_t glyph_cnt;
uint8_t bits_per_0;
uint8_t bits_per_1;
uint8_t bits_per_char_width;
uint8_t bits_per_char_height;
uint8_t bits_per_char_x;
uint8_t bits_per_char_y;
uint8_t bits_per_delta_x;
uint8_t char_width;
uint8_t char_height;
uint8_t char_descent;
unsigned capital_a_pos;
unsigned small_a_pos;
uint8_t *font;
};
typedef struct fd_struct fd_t;
void fd_init(fd_t *fd);
void fd_set_font(fd_t *fd, uint8_t *font);
unsigned fd_draw_glyph(fd_t *fd, unsigned x, unsigned y, uint8_t encoding);
unsigned fd_draw_string(fd_t *fd, unsigned x, unsigned y, const char *s);
#endif /* _FD_H */
+405
View File
@@ -0,0 +1,405 @@
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "bdf_font.h"
#include "fd.h"
/*================================================*/
int get_str_arg(char ***argv, int c, char **result)
{
if ( (**argv)[0] == '-' )
{
if ( (**argv)[1] == c )
{
if ( (**argv)[2] == '\0' )
{
(*argv)++;
*result = **argv;
}
else
{
*result = (**argv)+2;
}
(*argv)++;
return 1;
}
}
return 0;
}
int get_num_arg(char ***argv, int c, unsigned long *result)
{
if ( (**argv)[0] == '-' )
{
if ( (**argv)[1] == c )
{
if ( (**argv)[2] == '\0' )
{
if ( *((*argv)+1) != NULL )
{
(*argv)++;
*result = strtoul((**argv), NULL, 10);
}
}
else
{
*result = strtoul((**argv)+2, NULL, 10);
}
(*argv)++;
return 1;
}
}
return 0;
}
int is_arg(char ***argv, int c)
{
if ( (**argv)[0] == '-' )
{
if ( (**argv)[1] == c )
{
(*argv)++;
return 1;
}
}
return 0;
}
/*================================================*/
void help(void)
{
printf("bdfconv [options] filename\n");
printf("-h Display this help\n");
printf("-v Print log messages\n");
printf("-b <n> Font build mode, 0: proportional, 1: common height, 2: monospace, 3: multiple of 8\n");
printf("-f <n> Font format, 0: ucglib font, 1: u8g2 font, 2: u8g2 uncompressed 8x8 font (enforces -b 3)\n");
printf("-m 'map' Unicode ASCII mapping\n");
printf("-o <file> C output file\n");
printf("-n <name> C indentifier (font name)\n");
printf("-d <file> Overview picture: Enable generation of bdf.tga and assign BDF font <file> for description\n");
printf("-l <margin> Overview picture: Set left margin\n");
printf("-a Overview picture: Additional font information (background, orange&blue dot)\n");
printf("-t Overview picture: Test string (Woven silk pyjamas exchanged for blue quartz.)\n");
printf("-r Runtime test\n");
printf("\n");
printf("map := <mapcmd> { \",\" <mapcmd> }\n");
printf("mapcmd := <default> | <maprange> | <exclude>\n");
printf("default := \"*\"\n");
printf("maprange := <range> [ \">\" <addexpr> ] Move specified glyph <range> to target code <num>\n");
printf("exclude := \"~\" <range> \n");
printf("range := <addexpr> [ \"-\" <addexpr> ] Select glyphs within specified range\n");
printf("addexpr := <mulexpr> [ \"+\" <mulexpr> ]\n");
printf("mulexpr := <num> [ \"*\" <num> ]\n");
printf("num := <hexnum> | <decnum>\n");
printf("hexnum := \"$\" <hexdigit> { <hexdigit> }\n");
printf("decnum := <decdigit> { <decdigit> }\n");
printf("decdigit := \"0\" | \"1\" | \"2\" | \"3\" | \"4\" | \"5\" | \"6\" | \"7\" | \"8\" | \"9\"\n");
printf("hexdigit := \"a\" | \"b\" | \"c\" | \"d\" | \"e\" | \"f\" | \"A\" | \"B\" | \"C\" | \"D\" | \"E\" | \"F\" | <decdigit>\n");
printf("{ } zero, one ore more, [ ] zero or once, | alternative\n");
printf("example:\n");
printf(" -m '32-255' select gylphs from encoding 32 to 255\n");
printf(" -m '32-255,~64' select gylphs from encoding 32 to 255, exclude '@'\n");
printf(" -m '32,48-57' select space, '1', '2', ... '9'\n");
printf("build modes:\n");
printf(" -b 0: Most compact, glyph bitmap is minimal\n");
printf(" -b 1: Like -b 0, but glyph bitmap is extended to the height of the largest glyph within the selected glyph list.\n");
printf(" Also the width of the gylphs is extended to cover the delta x advance.\n");
printf(" -b 2: Like -b 1, but glyph width is set to the width of the largest glyph within the selected gylph list.\n");
printf(" -b 3: Like -b 2, but width and height are forced to be a multiple of 8.\n");
}
/*================================================*/
unsigned long left_margin = 1;
unsigned long build_bbx_mode = 0;
unsigned long font_format = 0;
int font_picture_extra_info = 0;
int font_picture_test_string = 0;
int runtime_test = 0;
char *c_filename = NULL;
char *target_fontname = "bdf_font";
/*================================================*/
unsigned tga_get_line_height(bf_t *bf_desc_font, bf_t *bf)
{
unsigned h;
tga_set_font(bf_desc_font->target_data);
h = tga_get_char_height();
tga_set_font(bf->target_data);
if ( h < tga_get_char_height() )
return tga_get_char_height();
return h;
}
unsigned tga_draw_font_line(unsigned y, long enc_start, bf_t *bf_desc_font, bf_t *bf)
{
long i;
unsigned x;
int is_empty;
char pre[32];
is_empty = 1;
for( i = 0; i< 16 && is_empty != 0; i++ )
{
if ( tga_get_glyph_data(i+enc_start) != NULL )
is_empty = 0;
}
if ( is_empty != 0 )
return 0;
sprintf(pre, "%3ld/0x%02lx", enc_start, enc_start);
x = left_margin;
if ( bf_desc_font != NULL )
{
if ( bf_desc_font->target_data != NULL )
{
tga_set_font(bf_desc_font->target_data);
x += tga_draw_string(x, y, pre, 0, 0);
}
}
x += 4;
tga_set_font(bf->target_data);
for( i = 0; i< 16; i++ )
{
tga_draw_glyph(x + (tga_get_char_width()+2)*i,y,enc_start+i, font_picture_extra_info);
}
return left_margin + x + (tga_get_char_width()+2)*16;
}
unsigned tga_draw_font_info(unsigned y, const char *fontname, bf_t *bf_desc_font, bf_t *bf)
{
unsigned x;
int cap_a, cap_a_height;
static char s[256];
cap_a_height = 0;
cap_a = bf_GetIndexByEncoding(bf, 'A');
if ( cap_a >= 0 )
{
cap_a_height = bf->glyph_list[cap_a]->bbx.h+bf->glyph_list[cap_a]->bbx.y;
}
if ( bf_desc_font != NULL )
{
if ( bf_desc_font->target_data != NULL )
{
tga_set_font(bf_desc_font->target_data);
y += tga_get_char_height()+1;
x = left_margin;
x += tga_draw_string(x, y, fontname, 0, 0);
y += tga_get_char_height()+1;
sprintf(s, "Max width %u, max height %u", tga_get_char_width(), tga_get_char_height());
x = left_margin;
x += tga_draw_string(x, y, s, 0, 0);
y += tga_get_char_height()+1;
sprintf(s, "'A' height %d, font size %d ", cap_a_height, bf->target_cnt);
x = left_margin;
x += tga_draw_string(x, y, s, 0, 0);
return (tga_get_char_height()+1)*3;
}
}
return 0;
}
unsigned tga_draw_font(unsigned y, const char *fontname, bf_t *bf_desc_font, bf_t *bf)
{
long i;
unsigned x, xmax;
xmax = 0;
y += tga_draw_font_info( y, fontname, bf_desc_font, bf);
y += tga_get_line_height(bf_desc_font, bf)+1;
for( i = 0; i < 256; i+=16 )
{
x = tga_draw_font_line(y, i, bf_desc_font, bf);
if ( x > 0 )
{
if ( xmax < x )
xmax = x;
y += tga_get_line_height(bf_desc_font, bf)+1;
}
}
tga_set_font(bf->target_data);
//tga_draw_string(0, y, "Woven silk pyjamas exchanged for blue quartz", 1, xmax);
//y += tga_get_char_height()+1;
if ( font_picture_test_string != 0 )
{
tga_draw_string(left_margin, y, "Woven silk pyjamas exchanged for blue quartz.", 0, xmax);
y += tga_get_line_height(bf_desc_font, bf)+1;
}
return y;
}
/*================================================*/
/* main */
int main(int argc, char **argv)
{
bf_t *bf_desc_font;
bf_t *bf;
char *bdf_filename = NULL;
int is_verbose = 0;
char *map_str ="*";
char *desc_font_str = "";
unsigned y;
argv++;
/*
if ( *argv == NULL )
{
help();
exit(1);
}
*/
for(;;)
{
if ( *argv == NULL )
break;
if ( is_arg(&argv, 'h') != 0 )
{
help();
exit(1);
}
else if ( is_arg(&argv, 'v') != 0 )
{
is_verbose = 1;
}
else if ( is_arg(&argv, 'a') != 0 )
{
font_picture_extra_info = 1;
}
else if ( is_arg(&argv, 't') != 0 )
{
font_picture_test_string = 1;
}
else if ( is_arg(&argv, 'r') != 0 )
{
runtime_test = 1;
}
else if ( get_num_arg(&argv, 'b', &build_bbx_mode) != 0 )
{
}
else if ( get_num_arg(&argv, 'f', &font_format) != 0 )
{
}
else if ( get_num_arg(&argv, 'l', &left_margin) != 0 )
{
}
else if ( get_str_arg(&argv, 'd', &desc_font_str) != 0 )
{
}
else if ( get_str_arg(&argv, 'o', &c_filename) != 0 )
{
}
else if ( get_str_arg(&argv, 'n', &target_fontname) != 0 )
{
}
else if ( get_str_arg(&argv, 'm', &map_str) != 0 )
{
}
else
{
bdf_filename = *argv;
argv++;
}
}
if ( bdf_filename == NULL )
{
help();
exit(1);
}
bf_desc_font = NULL;
if ( desc_font_str[0] != '\0' )
{
bf_desc_font = bf_OpenFromFile(desc_font_str, 0, BDF_BBX_MODE_MINIMAL, "*", 0); /* assume format 0 for description */
if ( bf_desc_font == NULL )
{
exit(1);
}
}
if ( font_format == 2 )
{
build_bbx_mode = BDF_BBX_MODE_M8;
/* issue the following log message later, when there is a valid bf object */
/* bf_Log(bf, "Font mode 1: BBX mode set to 3"); */
}
bf = bf_OpenFromFile(bdf_filename, is_verbose, build_bbx_mode, map_str, font_format);
if ( bf == NULL )
{
exit(1);
}
if ( font_format == 2 )
{
/* now generate the log message */
bf_Log(bf, "Note: For font format 1 BBX mode has been set to 3");
}
if ( bf_desc_font != NULL )
{
tga_init(1024, 600);
y = tga_draw_font(0, bdf_filename, bf_desc_font, bf);
if ( runtime_test != 0 )
{
long i;
clock_t c = clock();
fd_t fd;
fd_init(&fd);
fd_set_font(&fd, bf->target_data);
for( i = 0; i < 10000; i++ )
fd_draw_string(&fd, left_margin, y, "Woven silk pyjamas exchanged for blue quartz.");
bf_Log(bf, "Runtime test: %.2lf sec", (double)(clock()-c)/(double)CLOCKS_PER_SEC);
}
tga_save("bdf.tga");
}
if ( c_filename != NULL )
{
/* write the encoded data in bf->target_data */
if ( font_format == 0 )
{
bf_WriteUCGCByFilename(bf, c_filename, target_fontname, " ");
}
else
{
/* font format >= 1 are for u8g2 */
bf_WriteU8G2CByFilename(bf, c_filename, target_fontname, " ");
}
}
bf_Close(bf);
return 0;
}