精简Unicode,按unicode编码方式存储检索,又称为Simple Unicode。主要目的:极致优化检索表空间。
设置选项:Simple Unicode + Height Fixed
一 、分段图解
主要分4段:文件头,编码表,检索表,点阵信息。
补充说明:字符数决定编码表和检索表的大小。
适宜场景:编码不连续,且字符数少。
文件头结构体
/*针对 height fixed 存储格式*/typedef struct gui_font_head_height_fixed{ BYTE magic[4]; //'S'('U'or ’M’), 'F', 'L', X---Unicode(or MBCS) Font Library, X: 表示版本号. 分高低4位。如 0x12表示 Ver 1.2 DWORD Size; // 文件大小 BYTE nSection; // 共分几段数据,主要针对 UNICODE 编码有效。 BYTE YSize; // 字体高度 WORD wCpFlag; // codepageflag: bit0~bit13 每个bit分别代表一个CodePage 标志,如果是1,则表示当前CodePage 被选定,否则为非选定。 WORD nTotalChars; // 总的字符数 BYTE ScanMode; // 扫描模式 BYTE bpp; // 位深度 } GUI_FONT_HEAD_HF, *PGUI_FONT_HEAD_HF;要点:字体高度,字符数,扫描方式,位深度。
二、图例详解
1、文件头
说明:上图蓝色标记部分(16字节)为文件头。详解如下:
55 46 4C 12 - 标识头,判断是否为合法的字库文件。
53 = ‘S’,表示文件为Simple Unicode编码格式。
46 = ‘F’ , 4C = 'L'
12 表示该字库文件版本信息为 V1.2
20 6B 03 00 - 文件总长度。即文件长 = 0x00036B20
00 - 表示包含几个段。00则表示 0个段。
0C - 表示字体高度。 0C = 12,表示12像素。
02 00 - 表示当前字库包含了哪些字符集。
38 1D - 表示有效字符数。0x1D38 = 7480 个字符。
00 - 表示扫描模式(比对工具设置选项就明白了)
01 - 表示位深度 (参考值:1,2,4,8),bpp = 1
2、编码表
说明:蓝色标记部分为编码表数据。按小端字节序存放,升序排列,2个字节为1个编码。如 A4 00 A7 00 A8 00 ...,则表示第一个编码为 0x00A4,第二个编码为 0x00A7,第三个编码为 0x00A8,以此类推。
3、检索表
一条检索信息占4个字节,包含了字符宽度和点阵信息的起始偏移地址。检索信息结构体如下:
typedef struct tagUflCharInfo{ DWORD OffAddr : 26; // 当前字符点阵数据的起始地址 DWORD Width : 6; // 字符点阵的像素宽度( 目前最大支持点阵 < 64)} UFL_CHAR_INDEX;说明:高 6bit 记录字符宽度,低 26bit 记录点阵信息起始偏移地址。
4、点阵信息
当前字库中所有包含字符的点阵数据集合,数据存储方式与扫描方式有关,分横向,纵向,具体视情况而定。如:B3 1A, 即为 10110011 00011010,配合位深度,逐个处理即可。
三、参考代码
1、simple unicode.h
// unicode_simple.h //#if !defined(__FONT_UNICODE_SIMPLE_H__)#define __FONT_UNICODE_SIMPLE_H__#include "..\include\typedef.h"/***************************************Func:读取编码列表, Param: nCodeNum:编码数量 dwHeadLen:文件头长度Return:成功返回“0”, 否则返回“非0”.****************************************/int font_unicode_simple_read_codes(int nCodeNum, DWORD dwHeadLen);// 释放编码列表相关内存void font_unicode_simple_release_codes();/***************************************Func:定位字符,成功返回检索信息,否则返回0.Param: nCode:编码 dwHeadLen:文件头长度Return:返回指定字符的偏移地址,若找到有效字符,则返回大于0的检索信息,否则返回0.****************************************/DWORD font_unicode_simple_find_char(WORD wCode, DWORD dwHeadLen);#endif // (__FONT_UNICODE_SIMPLE_H__)2、simple unicode.c
/***********************************************************描述:用c语言写的一个如何从unicode编码格式的点阵字库中读取字符信息(像素宽 +点阵信息) 至于容错性和效率方面还得使用者自行改善。谢谢您的参阅!作者:wujianguo日期:20090516MSN: wujianguo19@hotmail.comqq:9599598*************************************************************/#include "..\include\font.h"#include "..\include\font_file.h"#include "..\include\unicode_simple.h" #ifdef WIN32#include <stdio.h>#include <stdlib.h>#endif#define MAX_FIND_LIMIT 31 // 是否二分查找临界值static int g_nCodeNum = 0;WORD *g_pCodes = NULL; // 读取编码列表int font_unicode_simple_read_codes(int nCodeNum, DWORD dwHeadLen){ font_unicode_simple_release_codes(); g_nCodeNum = nCodeNum; g_pCodes = (WORD *)malloc(nCodeNum*sizeof(WORD)); if(g_pCodes == NULL) { printf("Malloc is fail!\n"); return -1; } font_file_seek(dwHeadLen); font_file_read(g_pCodes, nCodeNum*sizeof(WORD)); return 0;}// 释放动态分配的内存void font_unicode_simple_release_codes(){ if(g_pCodes != NULL) { free(g_pCodes); g_pCodes = NULL; }}// 定位编码位置,若找到返回 >= 0的值,否则返回 -1.int font_unicode_simple_find_code(WORD wCode){ if(g_nCodeNum > 0) { if(g_nCodeNum > MAX_FIND_LIMIT) // 二分查找 { int low, high, mid; low = 0; high = g_nCodeNum -1; while(low <= high) { mid = (high + low)/2; if(g_pCodes[mid] == wCode) return mid; else if(wCode > g_pCodes[mid]) low = mid + 1; else high = mid - 1; } } else // 顺序查找 { int i = 0; for(i = 0; i < g_nCodeNum; i++) { if(wCode == g_pCodes[i]) return i; } } } return -1;}// 根据编码获取检索信息DWORD font_unicode_simple_find_char(WORD wCode, DWORD dwHeadLen){ DWORD offset = 0; DWORD dwCharInfo = 0; int nIdx = font_unicode_simple_find_code(wCode); if(nIdx == -1) // 未找到该编码 return 0; offset = dwHeadLen + g_nCodeNum * 2 + nIdx * 4; //dwHeadLen:文件头长度;g_nCodeNum * 2: 编码表长度;nIdx*4:检索表偏移 printf("offset = 0x%X\n", offset); font_file_seek(offset); font_file_read(&dwCharInfo, sizeof(DWORD)); return dwCharInfo;}