In this article, you will learn how to randomly read embedded_mono_kanji_matrix from a TTF file, how to export some matrices to some BitMap files, how to export all of them into 1 package file, how to make a TTF file from 1 package file and finally how to make a package file by 7z.
Introduction
This source code shows:
- How to random read embedded_mono_kanji_matrix from a TTF (TrueType Font) file
- How to export some matrices to some BitMap files (If you just see them in GUI, and nobody can check them in another platform, then it is teasing me.)
- How to export them all into 1 package file (Thousands of tiny files = large footprint)
- After (0.1)~(0.3), they are checked ok, how to show them
- How to make a TTF file (just mono EBDT, no vector data) from 1 package file
- How to make a package file by 7z
In medium and low-end embedded software, we maybe use several kanji fonts. But there are thousands of small matrices(16*16? 20*20?) in a font, too many file fragments. If we pack them into 1 package file, then our art designer will waste a lot of time to find a kanji matrix (which he wants) in the package file.
Our solution is pack them into 1 TTF file. So in the embedded software: no file fragment, and we random read embedded_mono_matrix
as usual. In the PC: our art designer uses the TTF to textout any matrix (which he wants) freely.
If anybody wants to modify (rare, but NOT never) some matrices in his TTF file, he can export all matrices, modify some of them, pack them into 1 package and make a new TTF file from it. If these situations occur regularly, don't delete the matrices BitMap, it can be used next time.
Background
Using the Code
1.1. ebdt2bm.c\get_matrix_fail(TTF_STRUCT* p_ttf, unsigned int scale_index, unsigned short glyph_index,..., unsigned char* dst_bmp, ...)
The ttf file stores matrices in regular sequence of scale_index
and glyph_index
. For example:
| glyph_1 | glyph_2 | glyph_3 | glyph_4 | glyph_5 | glyph_6 | glyph_7 | glyph_8 | glyph_9 | ... |
scale_0
(8*8) | matrix_01 | matrix_02 | matrix_03 | matrix_04 | | | matrix_07 | matrix_08 | matrix_09 | ... |
scale_1
(16*16) | | | matrix_13 | matrix_14 | matrix_15 | matrix_16 | matrix_17 | matrix_18 | | ... |
scale_2
(20*20) | | matrix_22 | matrix_23 | | matrix_25 | matrix_26 | | matrix_28 | | ... |
... | ... |
So, "get_matrix_fail(&ttf,0,2,..,&bmp...)
" will get matrix_02
in bmp;
"get_matrix_fail(&ttf,1,5,..,&bmp...)
" will get matrix_15
in bmp;
"get_matrix_fail(&ttf,2,7,..,&bmp...)
" will fail.
The remain parameters of function "get_matrix_fail()
", include "unsigned short *p_out_w"
and "unsigned short *p_out_h"
. That may be helpful for export BitMaps.
After getting the matrix, we can:
1.2.1. Add BitMap (#define
"USE_BMP
" or "USE_PBM
" in ebdt2bm.c) header to it.
1.2.2. Give it a file name.
1.2.3. And save the BitMap file.
ebdt2bm.c\int ebdt2bm_fail(TTF_STRUCT* p_ttf, unsigned int scale_index, unsigned short glyph_index,...)
is an example:
unsigned short w,h;
unsigned int file_size;
if((ret=get_matrix_fail(p_ttf,scale_index,glyph_index,..,
&(bmp_buf[0x3e])..,&w,&h)!=0)return(ret);
else if(make_bm_header_fail(-1,&(bmp_buf[0x3e]),w,h, &bmp_head,&file_size,NULL))return(11);
...
else if(get_fileName_from_glyIdx_fail(p_ttf,wtr_bmp_name, glyph_index,w,h))return(12);
else if((ret=save_bmp_fail(wtr_bmp_name, bmp_head,file_size...))!=0)return(20+ret);
else return(0);
gui calls this function in 1.5.3.
After #define
"USE_ZIP
" or "USE_7Z
" in writeZip.c, we can use function zip_fcreat_fail()
and zip_fclose()
. Between them, we trans all gly_index
's EBDT matrices to BitMaps.
ebdt2bm.c\export_zip(WCHAR* wtr_zip_name, TTF_STRUCT* p_ttf, unsigned int scale_index ...)
is a example:
int res=0;
if(zip_fcreat_fail(wtr_zip_name,"wb",...))return(1);
else {for(show_seq=0; show_seq<max_show; show_seq++)
{glyph_index=g_ttf.get_glyIdx_from_seq[show_seq];
if(0xffff==glyph_index);
else if(ebdt2bm_fail(p_ttf, scale_index,
glyph_index,...,&g_zip))
{res=2; break;}
}
}
zip_fclose(&g_zip);
return(res);
gui calls this function in 1.5.3.
From 1.1.~1.3. are function descriptions of ebdt2bm.c. It is a single c file (ebdt2bm.c). At the front of the file, there are notes for how to compile it from c to console EXE. The size of EXE is 18K bytes.
User can open vc6 project (ebdt2bm.dsw) to compile it too.
In cmd console, input "ebdt2bm.exe /?
" we would get str_default[] ={"ebdt2bm.exe <file.ttf> [font height]\r\n\t(default: font height=24)"}
Example 1: We input "ebdt2bm.exe demo.ttf 25
", and we would get demo.7z [which includes 0020_12x25.pbm, 0021_12x25.pbm, ..., ff0c_12x25(,).pbm].
Example 2: We input "ebdt2bm.exe demo.ttf
", and we would get demo.7z [which includes 0020_12x24.pbm, 0021_12x24.pbm, ..., ff0c_12x24(,).pbm].
Example 3: We input "ebdt2bm.exe demo.ttf 20
", and we get report "24x24,25x25, no scale match your font height".
And it exports 2 functions: fopen_ttf_fail()
and fclose_ttf()
as constructor and destructor.
int main(int argc,char** argv)
{
unsigned int font_height;
WCHAR wtr_zip_name[256];
WCHAR wtr_ttf_name[256];
TTF_STRUCT g_ttf;
unsigned int scale_index;
mem_set(&g_ttf,0,sizeof(TTF_STRUCT));
if((res=get_fontName_and_fontHeight(argc,argv,wtr_ttf_name,&font_height))!=0)
put_s(...);
else if(fopen_ttf_fail(wtr_ttf_name, font_height, &g_ttf,&scale_index ...))
put_s(...);
...
else if(get_zipName_from_ttfName_fail(wtr_zip_name, wtr_ttf_name));
else {res=export_zip(wtr_zip_name,&g_ttf,scale_index, ...);
if(0==res)
put_s(str_ok);
else
put_s(...);
}
fclose_ttf(&g_ttf);
}
gui calls these constructor and destructor in 1.5.3.
1.5. charMap2.c
ebdt2bm.exe is just a console EXE.
What a pity!
We can give it a GUI shell,
whose outlook is like
Microsoft's charmap.exe,
so we call it charMap2.exe.
| |
charMap2.c is a single c file too. At the front of the file, there are notes for how to compile it from c to gui EXE. The size of EXE is 26K bytes.
User can open vc6 project (charMap2.dsw) to compile it too.
1.5.1. Its Outlook
It shows all embedded_mono_matrices
in the TTF file, which are stored in regular sequence of scale_index
and glyph_index
. All font scales are shown at the top-right combobox. All glyph_index
are shown in status bar as "g=%04xh
". Every matrix has its matrix_offset
(in TTF file), matrix_length_byte_cnt
, matrix_width(pixels)
, and matrix_height(pixels)
, so they are shown in status bar as "ofs=%xh,len=%xh
", and "w=%d,h=%d
".
But the glyph_index
is used inside the TTF file. In the human world, we use unicode, so we show printf("U+%04xh(%c)",ucs16,ucs16)
in status bar. In the capture image above, we can see the focus = unicode 'A', and its hex_unicode_value=41h
, and its glyph_index=21h
.
If we want to change the focus by unicode, by hex_unicode_value
, or by glyph_index
, we can set one of them in the bottom edit_box
of dialog, press enter_key
or click the arrow_button
above the edit_box
, to update the old value in the status bar.
If we just travel the matrices, we can use arrow_key
, pgUp
, pgDn
, or click the scroll bar. Nice for travel!
init_instance()
call prepare_bmp_content()
, and the later's code are: str_bmp=malloc(...)
, and:
p_wh=p_ttf->str_whls;
for(show_seq=0; show_seq<max_show; show_seq++,p_wh++)
{...
x=...; y=...;
glyph_index=g_ttf.get_glyIdx_from_seq[show_seq];
if(0xffff==glyph_index);
else {get_matrix_fail(p_ttf, d1.cur_combox_index, (unsigned short)glyph_index,0,
str_bmp,bmp_byte_per_line,
x+1,y+1, x+(mtx_w+1), y+(mtx_h+1),
&ofs,&byteCnt,&fmt,&w,&h);
p_wh->w=w; p_wh->h=h; p_wh->fmt=fmt; p_wh->leng=byteCnt; p_wh->ofs=ofs;
}
}
This code gets every matrix in the str_bmp
area which is designated by us, and marks down any information of the matrix (such as Width
, Height
, Length_byte_cnt
, offSet
) in our array. So we can show any matrix in window, and show its information in status bar.
1.5.3. Its Menu
In charMap2.c\WinMain():
if(WM_COMMAND==g_msg.message){
if(ID_MENU_OPEN_FNT==g_msg.wParam)
get_open_name();
else if(ID_MENU_SAVE_1_BM==g_msg.wParam)
get_save_name();
else if(ID_MENU_SAVE_ALL_BM==g_msg.wParam)
get_export_name();
else{;}
}
Even if we don't use menu, we can use accelerate key(ctrl+O, ctrl+S) to call get_open_name()
or get_save_name()
.
Use bm2ebdt.exe, whose source C file is a single C file (bm2ebdt.c). At the front of the C file, there are notes for how to compile it from c to console EXE. The size of EXE is 16K bytes.
User can open vc6 project (bm2ebdt.dsw) to compile it too.
We can #define
"USE_ZIP
" or "USE_7Z
" in readZip.c (a sub file of bm2ebdt.c), default = "USE_7Z
".
In cmd console, input "bm2ebdt.exe /?
" we would get str_default[] ={"bm2ebdt.exe <file.7z>"}
Example 4: We input "bm2ebdt.exe demo.7z
", and we would get demo.ttf.
1.6.1. Mark Down All Width, Height, Matrices of BitMaps
In bm2ebdt.c\int find_every_file_from_folder_fail(char* folder_name,...):
if(find_1st_file_fail(folder_name, &hSeek,...);
else
do {...
hFile_tmp=f_open(psp.cFileName,...,"rb",...);
check_bm_head_fail(hFile_tmp,...,&w,&h...);
read_mtx_fail(hFile_tmp...);
...
f_close(hFile_tmp);
}while(find_nx_file_ok(&hSeek,&psp...)
1.6.2. Add TTF Header for Those Matrices
In bm2ebdt.c\int write_ttf_fail(char* ttf_name...):
hFile=_lcreat(ttf_name,0);
_lwrite(hFile,(char*)str_ttf_file_head,SIZEOFFILEHEAD);
_lwrite(hFile,(char*)str_dir,MAX_DIR<<4));
for(i=0;i<MAX_DIR;i++)
{switch(i)
{
case HCMAP: j=write_cmap(hFile); break;
case HHEAD: j=write_head(hFile); break;
case HNAME: j=write_name(hFile); break;
case HPOST: j=write_post(hFile); break;
case HOS2: j=write_os2 (hFile); break;
case HMAXP: j=write_maxp(hFile); break;
case HHHEA: j=write_hhea(hFile); break;
case HHMTX: j=write_hmtx(hFile); break;
case HLOCA: j=write_loca(hFile); break;
case HGLYF: j=write_glyf(hFile); break;
case HEBLC: j=write_eblc(hFile); break;
case HEBDT: j=write_ebdt(hFile); break;
}
if(j)
{...}
else{;}
}
_lclose(hFile);
The last line in the above switch is bm2ebdt.c\int write_ebdt(HFILE hFile)
, it writes the body of matrices:
unsigned char strbuf[864];
for(j=0;j<(unsigned short)c_map.gly_cnt;j++)
{...
size=get_mtx(...,strbuf);
_lwrite(hFile,(char*)strbuf,size)
}
If we use 7z format
(#define "USE_7Z" in writeZip.c and readZip.c), we can choose
compression_level="Store" , and parameters="hc=off tm=off" (disables Header_Compressing , disables TiMestamps for files), to make a package for (1.6).
| |
If we use zip format
(#define "USE_ZIP" in
writeZip.c and readZip.c),
we can choose compression_level="Store" too, and parameters="cu"
(uses UTF-8 for file_names)
to make a package for (1.6).
| |
1.8. Sundries
1.8.1. Smooth Edges of Screen Fonts
Of course, before use this font (just mono EBDT, no vector data), we must disable the "Smooth Edges of Screen Fonts" of window os, compel the os to use EBDT of this font.
1.8.2. Recalculate the Font Size
For example, we make a font by 24_dot matrix, so windows assume the font can be used as LOGPIXELS==72_dpi
and font_height=24_dot
in Windows 3.0.
If our LCD's LOGPIXELS=96_dpi
, then we can see the EBDT by font_size=18(in ChooseFont()
),it means font_size="18/72"
inch on our LCD, so tagLOGFONT.lfHeight=18/72 inch * 96_DotPerInch =24_dot
.
If our LCD's LOGPIXELS=120_dpi
, then we can see the EBDT by font_size=15
(in ChooseFont()
), it means font_size="15/72"
inch on our LCD, so tagLOGFONT.lfHeight=15/72 inch * 120_DotPerInch=25_dot
.
These 24_dot
and 25_dot
are "unsigned int h_96dpi,h_120dpi
" in bm2ebdt.c, and they are scale_0
and scale_1
in demo.ttf.
1.8.3. Use in DOS
ebdt2bm.com and charMap2.com and bm2ebdt.com are compiled by tc2.0 (At the front of the corresponding c_file, there are notes for how to compile them from c to xxx.com), they can be used in [dosbox] or [vdos] or [dos with xms driver].
In dosbox, we use "memsize=63
" to get 63 mega bytes xms, and use "cycles=max
" and "core=full
" to get full speed.
In vdos, we use "XMEM = 63 XMS
" to get 63 mega bytes xms, use "SCALE = 1
" to forbid vdos zoom out, and use "MOUSE = ON
" to show mouse in charMap2.com.
But they can NOT be used in window's cmd console, because they direct access extended memory.
Points of Interest
There is a black humor in P.R.China:
If [our embedded production's matrices] are NOT point to point match [the matrices of National Standard(abbreviation of it is "GB")], our production MAYBE (not sure, just maybe) be claimed to be "rejected product" by NITS (China National Information Technology Standardization Technical Committee).
But if the matrices point to point match them, then we MAYBE will be involved in patent infringement about them.
That is a catch 22. The NITS do {ignore small companies deliberately;} while (the companies!=rich);
After the companies come to rich, they must buy the copyright of fonts in every 4_years. According to oemfont.com, in January 2005, the font's price are GB2312_font=$15'000/4_years, GB13000_font=$40'000/4_years, GB18030_font=$40'000/4_years.
History
- 3rd March, 2020: Submitted, can be compiled with bc 5.2 and tc 2.0
- August 2016: Can be compiled with vc6.0 and armCC