/tools/fontextract/fontdata.c

http://ftk.googlecode.com/ · C · 498 lines · 385 code · 84 blank · 29 comment · 82 complexity · bb2c1bffcff67b548f4356ac12379263 MD5 · raw file

  1. /*
  2. * File: fontdata.c
  3. * Author: Li XianJing <xianjimli@hotmail.com>
  4. * Brief: functions to operate font data.
  5. *
  6. * Copyright (c) 2009 - 2010 Li XianJing <xianjimli@hotmail.com>
  7. *
  8. * Licensed under the Academic Free License version 2.1
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23. */
  24. /*
  25. * History:
  26. * ================================================================
  27. * 2009-09-11 Li XianJing <xianjimli@hotmail.com> created
  28. *
  29. */
  30. #include "fontdata.h"
  31. #ifdef WITHOUT_FTK
  32. #define FTK_ALLOC malloc
  33. #define FTK_FREE free
  34. #define FTK_ZALLOC(s) calloc(1, s)
  35. #define FTK_REALLOC realloc
  36. #else
  37. #include "ftk_allocator.h"
  38. #endif
  39. #define FONT_VERSION 0x00000101 /*1.01*/
  40. typedef struct _FontDataHeader
  41. {
  42. unsigned int version;
  43. unsigned int char_nr;
  44. unsigned char width;
  45. unsigned char height;
  46. unsigned short encoding;
  47. unsigned int unused;
  48. char author[64];
  49. char family[32];
  50. char style[32];
  51. }FontDataHeader;
  52. struct _FontData
  53. {
  54. FontDataHeader header;
  55. Glyph* glyphs;
  56. size_t data_size;
  57. size_t data_buffer_size;
  58. unsigned char* data;
  59. void* org_data;
  60. int new_created;
  61. char file_name[260];
  62. void* current_glyph_data;
  63. size_t current_glyph_data_size;
  64. };
  65. static Ret font_data_read_glyph(FontData* thiz, size_t offset, size_t size, Glyph* glyph);
  66. FontData* font_data_create(int char_nr, Encoding encoding)
  67. {
  68. FontData* thiz = (FontData*)FTK_ZALLOC(sizeof(FontData));
  69. if(thiz != NULL)
  70. {
  71. thiz->header.version = FONT_VERSION;
  72. thiz->header.char_nr = char_nr;
  73. thiz->header.encoding = encoding;
  74. if(char_nr > 0)
  75. {
  76. thiz->new_created = 1;
  77. thiz->glyphs = FTK_ZALLOC(char_nr * sizeof(Glyph));
  78. }
  79. }
  80. return thiz;
  81. }
  82. FontData* font_data_load(char* data, size_t length)
  83. {
  84. FontData* thiz = font_data_create(0, 0);
  85. return_val_if_fail(data != NULL && length > sizeof(FontDataHeader), NULL);
  86. if(thiz != NULL)
  87. {
  88. int glyph_size = 0;
  89. thiz->header = *(FontDataHeader*)data;
  90. glyph_size = thiz->header.char_nr * sizeof(Glyph);
  91. thiz->glyphs = (Glyph*)(data + sizeof(FontDataHeader));
  92. thiz->data = (unsigned char*)(data + sizeof(FontDataHeader) + glyph_size);
  93. thiz->data_size = length - ((char*)thiz->data - data);
  94. thiz->data_buffer_size = thiz->data_size;
  95. thiz->new_created = 0;
  96. thiz->org_data = data;
  97. }
  98. return thiz;
  99. }
  100. #ifdef WITHOUT_FTK
  101. #include <unistd.h>
  102. #include <sys/types.h>
  103. #include <sys/stat.h>
  104. char* read_file(const char* file_name, int* length)
  105. {
  106. struct stat st = {0};
  107. if(stat(file_name, &st))
  108. {
  109. return NULL;
  110. }
  111. else
  112. {
  113. char* buffer = malloc(st.st_size + 1);
  114. FILE* fp = fopen(file_name, "rb");
  115. fread(buffer, 1, st.st_size, fp);
  116. fclose(fp);
  117. buffer[st.st_size] = '\0';
  118. *length = st.st_size;
  119. return buffer;
  120. }
  121. }
  122. FontData* font_data_load_file(const char* file_name)
  123. {
  124. int length = 0;
  125. char* buffer = read_file(file_name, &length);
  126. return font_data_load(buffer, length);
  127. }
  128. static Ret font_data_read_glyph(FontData* thiz, size_t offset, size_t size, Glyph* glyph)
  129. {
  130. return RET_FAIL;
  131. }
  132. #else
  133. #include "ftk_file_system.h"
  134. FontData* font_data_load_file(const char* file_name)
  135. {
  136. FontData* thiz = NULL;
  137. return_val_if_fail(file_name != NULL, NULL);
  138. if((thiz = font_data_create(0, 0)) != NULL)
  139. {
  140. FtkFsHandle fp = ftk_file_open(file_name, "rb");
  141. if(fp != NULL)
  142. {
  143. int ret = 0;
  144. size_t glyphs_size = 0;
  145. ret = ftk_file_read(fp, &thiz->header, sizeof(thiz->header));
  146. assert(ret == sizeof(thiz->header));
  147. glyphs_size = thiz->header.char_nr * sizeof(Glyph);
  148. thiz->glyphs = FTK_ZALLOC(glyphs_size);
  149. assert(thiz->glyphs != NULL);
  150. ftk_file_read(fp, thiz->glyphs, glyphs_size);
  151. thiz->data = NULL;
  152. thiz->data_size = 0;
  153. thiz->new_created = 0;
  154. thiz->org_data = NULL;
  155. ftk_file_close(fp);
  156. ftk_strncpy(thiz->file_name, file_name, sizeof(thiz->file_name)-1);
  157. }
  158. else
  159. {
  160. FTK_FREE(thiz);
  161. }
  162. }
  163. return thiz;
  164. }
  165. static Ret font_data_read_glyph(FontData* thiz, size_t offset, size_t size, Glyph* glyph)
  166. {
  167. int ret = 0;
  168. FtkFsHandle fp = ftk_file_open(thiz->file_name, "rb");
  169. size_t skip = sizeof(thiz->header) + thiz->header.char_nr * sizeof(Glyph) + offset;
  170. return_val_if_fail(fp != NULL && glyph != NULL, RET_FAIL);
  171. ret = ftk_file_seek(fp, skip);
  172. assert(ret == 0);
  173. if(thiz->current_glyph_data_size < size)
  174. {
  175. FTK_FREE(thiz->current_glyph_data);
  176. thiz->current_glyph_data = FTK_ALLOC(size * 2);
  177. thiz->current_glyph_data_size = size * 2;
  178. }
  179. ret = ftk_file_read(fp, thiz->current_glyph_data, size);
  180. ftk_logd("%s: offset=%d size=%d ret=%d\n", __func__, offset, size, ret);
  181. ftk_file_close(fp);
  182. assert(ret == size);
  183. glyph->data = thiz->current_glyph_data;
  184. return RET_OK;
  185. }
  186. #endif
  187. Ret font_data_add_glyph(FontData* thiz, Glyph* glyph)
  188. {
  189. size_t i = 0;
  190. return_val_if_fail(thiz != NULL && glyph != NULL && thiz->new_created, RET_FAIL);
  191. for(i = 0; i < thiz->header.char_nr; i++)
  192. {
  193. if(thiz->glyphs[i].code == glyph->code)
  194. {
  195. return RET_FOUND;
  196. }
  197. if(thiz->glyphs[i].code > glyph->code || thiz->glyphs[i].code == 0)
  198. {
  199. size_t size = glyph->w * glyph->h;
  200. if(thiz->glyphs[i].code > glyph->code)
  201. {
  202. size_t k = 0;
  203. for(k = thiz->header.char_nr - 1; k > i; k--)
  204. {
  205. thiz->glyphs[k] = thiz->glyphs[k-1];
  206. }
  207. }
  208. if((thiz->data_size + size) >= thiz->data_buffer_size)
  209. {
  210. size_t data_buffer_size = thiz->data_buffer_size + (thiz->data_buffer_size >> 1) + (size << 4);
  211. unsigned char* data = (unsigned char*)FTK_REALLOC(thiz->data, data_buffer_size);
  212. if(data != NULL)
  213. {
  214. thiz->data = data;
  215. thiz->data_buffer_size = data_buffer_size;
  216. }
  217. }
  218. thiz->glyphs[i] = *glyph;
  219. if((thiz->data_size + size) < thiz->data_buffer_size)
  220. {
  221. memcpy(thiz->data + thiz->data_size, glyph->data, size);
  222. thiz->glyphs[i].data = (unsigned char*)thiz->data_size;
  223. thiz->data_size += size;
  224. }
  225. return RET_OK;
  226. }
  227. }
  228. return RET_FAIL;
  229. }
  230. Ret font_data_get_glyph(FontData* thiz, unsigned short code, Glyph* glyph)
  231. {
  232. int low = 0;
  233. int mid = 0;
  234. int high = 0;
  235. int result = 0;
  236. return_val_if_fail(thiz != NULL && glyph != NULL, RET_FAIL);
  237. high = thiz->header.char_nr;
  238. while(low <= high)
  239. {
  240. mid = low + ((high - low) >> 1);
  241. result = thiz->glyphs[mid].code - code;
  242. if(result == 0)
  243. {
  244. *glyph = thiz->glyphs[mid];
  245. if(thiz->data != NULL)
  246. {
  247. glyph->data = (unsigned char*)(thiz->data + (int)(thiz->glyphs[mid].data));
  248. }
  249. else
  250. {
  251. font_data_read_glyph(thiz, (size_t)glyph->data, glyph->w * glyph->h, glyph);
  252. }
  253. return RET_OK;
  254. }
  255. else if(result < 0)
  256. {
  257. low = mid + 1;
  258. }
  259. else
  260. {
  261. high = mid - 1;
  262. }
  263. }
  264. return RET_FAIL;
  265. }
  266. int font_data_get_version(FontData* thiz)
  267. {
  268. return_val_if_fail(thiz != NULL, 0);
  269. return thiz->header.version;
  270. }
  271. int font_data_get_width(FontData* thiz)
  272. {
  273. return_val_if_fail(thiz != NULL, 0);
  274. return thiz->header.width;
  275. }
  276. int font_data_get_height(FontData* thiz)
  277. {
  278. return_val_if_fail(thiz != NULL, 0);
  279. return thiz->header.height;
  280. }
  281. const char* font_data_get_author(FontData* thiz)
  282. {
  283. return_val_if_fail(thiz != NULL, NULL);
  284. return thiz->header.author;
  285. }
  286. const char* font_data_get_family(FontData* thiz)
  287. {
  288. return_val_if_fail(thiz != NULL, NULL);
  289. return thiz->header.family;
  290. }
  291. const char* font_data_get_style(FontData* thiz)
  292. {
  293. return_val_if_fail(thiz != NULL, NULL);
  294. return thiz->header.style;
  295. }
  296. void font_data_set_size(FontData* thiz, int width, int height)
  297. {
  298. return_if_fail(thiz != NULL);
  299. thiz->header.width = width;
  300. thiz->header.height = height;
  301. return;
  302. }
  303. void font_data_set_author(FontData* thiz, const char* author)
  304. {
  305. return_if_fail(thiz != NULL);
  306. ftk_strncpy(thiz->header.author, author, sizeof(thiz->header.author));
  307. return;
  308. }
  309. void font_data_set_family(FontData* thiz, const char* family)
  310. {
  311. return_if_fail(thiz != NULL);
  312. ftk_strncpy(thiz->header.family, family, sizeof(thiz->header.family));
  313. return;
  314. }
  315. void font_data_set_style(FontData* thiz, const char* style)
  316. {
  317. return_if_fail(thiz != NULL);
  318. ftk_strncpy(thiz->header.style, style, sizeof(thiz->header.style));
  319. return;
  320. }
  321. void font_data_destroy(FontData* thiz)
  322. {
  323. return_if_fail(thiz != NULL);
  324. if(thiz != NULL)
  325. {
  326. if(thiz->new_created)
  327. {
  328. FTK_FREE(thiz->glyphs);
  329. FTK_FREE(thiz->data);
  330. FTK_FREE(thiz->current_glyph_data);
  331. }
  332. FTK_FREE(thiz);
  333. }
  334. return;
  335. }
  336. #ifdef HAS_FONT_DATA_SAVE
  337. #include <stdio.h>
  338. Ret font_data_save(FontData* thiz, const char* file_name)
  339. {
  340. FILE* fp = fopen(file_name, "wb+");
  341. {
  342. fwrite(&thiz->header, 1, sizeof(FontDataHeader), fp);
  343. fwrite(thiz->glyphs, 1, sizeof(Glyph) * thiz->header.char_nr, fp);
  344. fwrite(thiz->data, 1, thiz->data_size, fp);
  345. fclose(fp);
  346. }
  347. return RET_OK;
  348. }
  349. #endif
  350. #ifdef FONT_DATA_TEST
  351. #include <sys/types.h>
  352. #include <sys/stat.h>
  353. #include <unistd.h>
  354. int main(int argc, char* argv[])
  355. {
  356. int ch = 'a';
  357. int length = 0;
  358. char* buffer = NULL;
  359. Glyph ret_glyph = {0};
  360. FontData* data = font_data_create(36, 0);
  361. Glyph* glyph = (Glyph*)FTK_ZALLOC(sizeof(Glyph));
  362. glyph->w = 7;
  363. glyph->h = 9;
  364. glyph->x = 5;
  365. glyph->y = 5;
  366. glyph->data = FTK_ZALLOC(glyph->w * glyph->h);
  367. for(; ch <= 'z'; ch++)
  368. {
  369. glyph->code = ch;
  370. assert(font_data_add_glyph(data, glyph) == RET_OK);
  371. }
  372. for(ch='0'; ch <= '9'; ch++)
  373. {
  374. glyph->code = ch;
  375. assert(font_data_add_glyph(data, glyph) == RET_OK);
  376. }
  377. for(ch='a'; ch <= 'z'; ch++)
  378. {
  379. glyph->code = ch;
  380. assert(font_data_get_glyph(data, ch, &ret_glyph) == RET_OK);
  381. assert(memcmp(glyph, &ret_glyph, sizeof(ret_glyph)-sizeof(void*)) == 0);
  382. assert(memcmp(glyph->data, ret_glyph.data, ret_glyph.w * ret_glyph.h) == 0);
  383. }
  384. for(ch='0'; ch <= '9'; ch++)
  385. {
  386. glyph->code = ch;
  387. assert(font_data_get_glyph(data, ch, &ret_glyph) == RET_OK);
  388. assert(memcmp(glyph, &ret_glyph, sizeof(ret_glyph)-sizeof(void*)) == 0);
  389. assert(memcmp(glyph->data, ret_glyph.data, ret_glyph.w * ret_glyph.h) == 0);
  390. }
  391. font_data_set_size(data, 16, 16);
  392. assert(font_data_get_width(data) == 16);
  393. assert(font_data_get_height(data) == 16);
  394. font_data_set_author(data, "Li XianJing <xianjimli@hotmail.com>");
  395. font_data_save(data, "test.fnt");
  396. font_data_destroy(data);
  397. buffer = read_file("test.fnt", &length);
  398. data = font_data_load(buffer, length);
  399. assert(data != NULL);
  400. for(ch='a'; ch <= 'z'; ch++)
  401. {
  402. glyph->code = ch;
  403. assert(font_data_get_glyph(data, ch, &ret_glyph) == RET_OK);
  404. assert(memcmp(glyph, &ret_glyph, sizeof(ret_glyph)-sizeof(void*)) == 0);
  405. assert(memcmp(glyph->data, ret_glyph.data, ret_glyph.w * ret_glyph.h) == 0);
  406. }
  407. assert(font_data_get_version(data) == FONT_VERSION);
  408. assert(strcmp(font_data_get_author(data), "Li XianJing <xianjimli@hotmail.com>") == 0);
  409. font_data_destroy(data);
  410. FTK_FREE(glyph->data);
  411. FTK_FREE(glyph);
  412. return 0;
  413. }
  414. #endif/*FONT_DATA_TEST*/