ttf2subf.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. #include <ft2build.h>
  2. #include FT_FREETYPE_H
  3. #include <freetype/ftglyph.h>
  4. #include <draw.h>
  5. #include <memdraw.h>
  6. FT_Library lib;
  7. #define FLOOR(x) ((x) & -64)
  8. #define CEIL(x) (((x) + 63) & -64)
  9. #define TRUNC(x) ((x) >> 6)
  10. #define ROUND(x) (((x) + 32) & -64)
  11. enum {
  12. Rmono = 1,
  13. Rantialias,
  14. Rsubpixel,
  15. };
  16. enum {
  17. Srgb = 1,
  18. Sbgr,
  19. Svrgb,
  20. Svbgr
  21. };
  22. typedef struct {
  23. int left;
  24. int right;
  25. int top;
  26. int bottom;
  27. int advance;
  28. int width;
  29. } FTmetrics;
  30. typedef struct _FTsubfont {
  31. int nchars;
  32. int startc;
  33. int ascent;
  34. int descent;
  35. int image_height;
  36. int image_width;
  37. FTmetrics* metrics;
  38. Fontchar* fchars;
  39. Subfont sf;
  40. Memimage* image;
  41. struct _FTsubfont* next;
  42. struct _FTsubfont* prev;
  43. } FTsubfont;
  44. typedef struct {
  45. char* name;
  46. int size;
  47. FT_Face face;
  48. FT_GlyphSlot slot;
  49. int rmode;
  50. int rgb;
  51. int image_channels;
  52. int ascent;
  53. int descent;
  54. int height;
  55. FTsubfont* sfont;
  56. } FTfont;
  57. int f[3] = { 1, 2, 3 };
  58. int fsum = 9;
  59. FT_Vector getScale(FTfont* font) {
  60. FT_Vector ret;
  61. ret.x = ret.y = 1;
  62. if (font->rmode == Rsubpixel) {
  63. switch (font->rgb) {
  64. case Srgb:
  65. case Sbgr:
  66. ret.x = 3;
  67. break;
  68. case Svrgb:
  69. case Svbgr:
  70. ret.y = 3;
  71. break;
  72. }
  73. }
  74. return ret;
  75. }
  76. FT_Glyph getGlyph(FTfont* font, int c) {
  77. int status;
  78. FT_Glyph glyph;
  79. FT_UInt gidx;
  80. FT_Int32 lflags;
  81. FT_Vector scale;
  82. FT_Vector pos;
  83. FT_Matrix tm;
  84. gidx = FT_Get_Char_Index(font->face, c);
  85. switch (font->rmode) {
  86. case Rmono:
  87. case Rsubpixel:
  88. default:
  89. lflags = FT_LOAD_TARGET_MONO;
  90. break;
  91. case Rantialias:
  92. lflags = FT_LOAD_DEFAULT;
  93. break;
  94. }
  95. status = FT_Load_Glyph(font->face, gidx, lflags);
  96. if (status) {
  97. print("FT_Load_Glyph: status=%d\n", status);
  98. exits("error: load glyph");
  99. }
  100. status = FT_Get_Glyph(font->face->glyph, &glyph);
  101. if (status) {
  102. print("FT_Get_Glyph: status=%d\n", status);
  103. exits("error: get glyph");
  104. }
  105. glyph->advance.x = font->slot->advance.x;
  106. glyph->advance.y = font->slot->advance.y;
  107. scale = getScale(font);
  108. tm.xx = 0x10000 * scale.x;
  109. tm.yy = 0x10000 * scale.y;
  110. tm.xy = tm.yx = 0;
  111. pos.x = pos.y = 0;
  112. status = FT_Glyph_Transform(glyph, &tm, &pos);
  113. if (status) {
  114. print("FT_Glyph_Transform: status=%d\n", status);
  115. exits("error: glyph transform");
  116. }
  117. return glyph;
  118. }
  119. FT_BitmapGlyph getBitmapGlyph(FTfont* font, FT_Glyph glyph) {
  120. int rmode = 0;
  121. int status;
  122. switch (font->rmode) {
  123. case Rmono:
  124. rmode = ft_render_mode_mono;
  125. break;
  126. case Rantialias:
  127. case Rsubpixel:
  128. rmode = ft_render_mode_normal;
  129. break;
  130. default:
  131. exits("error: rmode != antialias|mono|subpixel");
  132. }
  133. status = FT_Glyph_To_Bitmap(&glyph, rmode, 0, 1);
  134. if (status) {
  135. print("FT_Glyph_To_Bitmap: status=%d\n", status);
  136. exits("error: glyph to bitmap");
  137. }
  138. return (FT_BitmapGlyph) glyph;
  139. }
  140. FTmetrics getMetrics(FTfont* font, int c) {
  141. FT_Glyph glyph;
  142. FT_BitmapGlyph bglyph;
  143. FT_Bitmap bitmap;
  144. FT_Vector scale;
  145. FTmetrics ret;
  146. glyph = getGlyph(font, c);
  147. bglyph = getBitmapGlyph(font, glyph);
  148. scale = getScale(font);
  149. bitmap = bglyph->bitmap;
  150. ret.left = bglyph->left / scale.x;
  151. ret.right = (bglyph->left + bitmap.width) / scale.x;
  152. ret.top = bglyph->top / scale.y;
  153. ret.bottom = (bglyph->top - bitmap.rows) / scale.y;
  154. ret.width = bitmap.width / scale.x;
  155. ret.advance = TRUNC(font->slot->advance.x); /* usage of slot ??? */
  156. if (font->rmode == Rsubpixel) {
  157. switch (font->rgb) {
  158. case Srgb:
  159. case Sbgr:
  160. ret.left -= 1;
  161. ret.right += 1;
  162. ret.width += 2;
  163. break;
  164. case Svrgb:
  165. case Svbgr:
  166. ret.top -= 1;
  167. ret.bottom -= 1;
  168. break;
  169. }
  170. }
  171. /* FT_Done_Glyph(glyph); */
  172. return ret;
  173. }
  174. unsigned long getPixelMono(FTfont* ftf, FT_Bitmap* bitmap, int x, int y) {
  175. int g = ((bitmap->buffer[bitmap->pitch*y + x/8]) >> (7 - x%8) & 1) * 255;
  176. return (g << 24) | (g << 16) | (g << 8) | 0xFF;
  177. }
  178. unsigned long getPixelAntialias(FTfont* ftf, FT_Bitmap* bitmap, int x, int y) {
  179. int g = bitmap->buffer[bitmap->pitch*y + x];
  180. return (g << 24) | (g << 16) | (g << 8) | 0xFF;
  181. }
  182. unsigned long getPixelSubpixel(FTfont* font, FT_Bitmap* bitmap, int x, int y) {
  183. int xs = 0, ys = 0;
  184. int af = 0, bf = 0, cf = 0;
  185. int xx, yy;
  186. int h[7];
  187. int a, b, c;
  188. FT_Vector scale;
  189. int i;
  190. scale = getScale(font);
  191. switch (font->rgb) {
  192. case Srgb:
  193. case Sbgr:
  194. xs = 1;
  195. ys = 0;
  196. break;
  197. case Svrgb:
  198. case Svbgr:
  199. xs = 0;
  200. ys = 1;
  201. break;
  202. }
  203. switch (font->rgb) {
  204. case Srgb:
  205. case Svrgb:
  206. af = 24;
  207. bf = 16;
  208. cf = 8;
  209. break;
  210. case Sbgr:
  211. case Svbgr:
  212. af = 8;
  213. bf = 16;
  214. cf = 24;
  215. break;
  216. }
  217. xx = x * scale.x;
  218. yy = y * scale.y;
  219. for(i = -2; i < 5; i++) {
  220. int xc, yc;
  221. xc = xx + (i - scale.x) * xs;
  222. yc = yy + (i - scale.y) * ys;
  223. if (xc<0 || xc >= bitmap->width || yc<0 || yc>=bitmap->rows) {
  224. h[i + 2] = 0;
  225. } else {
  226. h[i + 2] = bitmap->buffer[yc * bitmap->pitch + xc] * 65536;
  227. }
  228. }
  229. a = (h[0]*f[0] + h[1]*f[1] + h[2]*f[2] + h[3]*f[1] + h[4]*f[0]) / fsum;
  230. b = (h[1]*f[0] + h[2]*f[1] + h[3]*f[2] + h[4]*f[1] + h[5]*f[0]) / fsum;
  231. c = (h[2]*f[0] + h[3]*f[1] + h[4]*f[2] + h[5]*f[1] + h[6]*f[0]) / fsum;
  232. return ((a / 65536) << af) | ((b / 65536) << bf) | ((c / 65536) << cf) | 0xFF;
  233. }
  234. typedef unsigned long (*getpixelfunc)(FTfont*, FT_Bitmap*, int, int);
  235. getpixelfunc getPixelFunc(FTfont* font) {
  236. getpixelfunc ret = 0;
  237. switch (font->rmode) {
  238. case Rmono:
  239. ret = getPixelMono;
  240. break;
  241. case Rantialias:
  242. ret = getPixelAntialias;
  243. break;
  244. case Rsubpixel:
  245. ret = getPixelSubpixel;
  246. break;
  247. }
  248. return ret;
  249. }
  250. void drawChar(FTfont* font, Memimage* img, int x0, int y0, int c) {
  251. Rectangle r;
  252. Memimage* color;
  253. FT_Glyph glyph;
  254. FT_BitmapGlyph bglyph;
  255. FT_Bitmap bitmap;
  256. int x, y;
  257. getpixelfunc getPixel;
  258. FT_Vector scale;
  259. int height, width;
  260. glyph = getGlyph(font, c);
  261. scale = getScale(font);
  262. bglyph = getBitmapGlyph(font, glyph);
  263. bitmap = bglyph->bitmap;
  264. getPixel = getPixelFunc(font);
  265. r.min.x = 0;
  266. r.min.y = 0;
  267. r.max.x = 1;
  268. r.max.y = 1;
  269. color = allocmemimage(r, font->image_channels);
  270. r.min.x = r.min.y = 0;
  271. r.max.x = bitmap.width;
  272. r.max.y = bitmap.rows;
  273. width = bitmap.width / scale.x;
  274. height = bitmap.rows / scale.y;
  275. if (font->rmode == Rsubpixel) {
  276. switch (font->rgb) {
  277. case Srgb:
  278. case Sbgr:
  279. width += 2;
  280. break;
  281. case Svrgb:
  282. case Svbgr:
  283. height += 2;
  284. break;
  285. }
  286. }
  287. for(y = 0; y < height; y++) {
  288. for(x = 0; x < width; x++) {
  289. Point pt;
  290. unsigned long cl = getPixel(font, &bitmap, x, y);
  291. pt.x = x + x0;
  292. pt.y = y + y0;
  293. memfillcolor(color, cl);
  294. memimagedraw(img, rectaddpt(Rect(0, 0, 1, 1), pt),
  295. color, ZP, nil, ZP, SatopD);
  296. }
  297. }
  298. freememimage(color);
  299. }
  300. void initSubfont(FTfont* font, FTsubfont* sf, int startc) {
  301. int i;
  302. int width;
  303. int ascent, descent;
  304. FTmetrics rc[257];
  305. // get first defined character
  306. while (startc < 65536) {
  307. if (startc == 0 || FT_Get_Char_Index(font->face, startc) != 0) {
  308. break;
  309. }
  310. startc++;
  311. }
  312. ascent = 0; descent = 100000;
  313. width = 0;
  314. for(i = 0; i < sizeof(rc)/sizeof(rc[0]); i++) {
  315. if (startc+i >= 65536) {
  316. break;
  317. }
  318. if (width > 2000) {
  319. break;
  320. }
  321. if (i > 0 && FT_Get_Char_Index(font->face, startc + i) == 0) {
  322. rc[i] = getMetrics(font, 0);
  323. rc[i].width = 0;
  324. rc[i].advance = 0;
  325. } else
  326. rc[i] = getMetrics(font, startc + i);
  327. if (ascent < rc[i].top) {
  328. ascent = rc[i].top;
  329. }
  330. if (descent > rc[i].bottom) {
  331. descent = rc[i].bottom;
  332. }
  333. width += rc[i].width; // +1?
  334. }
  335. sf->startc = startc;
  336. sf->nchars = i;
  337. sf->ascent = ascent;
  338. sf->descent = descent;
  339. sf->image_width = width;
  340. sf->metrics = malloc(i * sizeof(FTmetrics));
  341. sf->fchars = malloc((i + 1) * sizeof(Fontchar));
  342. for(i = 0; i < sf->nchars; i++) {
  343. sf->metrics[i] = rc[i];
  344. }
  345. }
  346. int createSubfont(FTfont* font, FTsubfont* sf, char* fname) {
  347. int i;
  348. Rectangle r;
  349. int x;
  350. int fd;
  351. sf->image_height = sf->ascent - sf->descent;
  352. /* print("creating %d: (%d, %d)\n", sf->startc, sf->image_height, sf->image_width); */
  353. r = Rect(0, 0, sf->image_width, font->height /*sf->image_height*/);
  354. if (sf->image_width <= 0 || sf->image_height <= 0) {
  355. return 1;
  356. }
  357. sf->image = allocmemimage(r, font->image_channels);
  358. memfillcolor(sf->image, 0x000000FF);
  359. x = 0;
  360. for(i = 0; i < sf->nchars; i++) {
  361. sf->fchars[i].x = x;
  362. sf->fchars[i].width = sf->metrics[i].advance;
  363. sf->fchars[i].left = sf->metrics[i].left;
  364. sf->fchars[i].bottom = /*sf->ascent*/ font->ascent - sf->metrics[i].bottom;
  365. sf->fchars[i].top = (font->ascent - sf->metrics[i].top) > 0 ? font->ascent - sf->metrics[i].top : 0;
  366. x += sf->metrics[i].width; // +1?
  367. drawChar(font, sf->image, sf->fchars[i].x, sf->fchars[i].top, i + sf->startc);
  368. }
  369. sf->fchars[i].x = x;
  370. sf->sf.name = font->name;
  371. sf->sf.n = sf->nchars;
  372. sf->sf.height = font->height; /*sf->image_height; */
  373. sf->sf.ascent = font->ascent /*sf->ascent */;
  374. sf->sf.info = sf->fchars;
  375. sf->sf.ref = 1;
  376. fd = create(fname, OWRITE, 0666);
  377. if(fd < 0)
  378. sysfatal("can not create font file: %r");
  379. writememimage(fd, sf->image);
  380. writesubfont(fd, &sf->sf);
  381. close(fd);
  382. freememimage(sf->image);
  383. sf->image = nil;
  384. return 0;
  385. }
  386. void
  387. usage(char *s)
  388. {
  389. fprint(2, "\nusage: %s <options>\n", s);
  390. fprint(2, "\nwhere:\n", s);
  391. fprint(2,
  392. " -s size - point size\n"
  393. " -h - this message\n"
  394. " -f fname - ttf file name\n"
  395. " -n name - font name\n"
  396. " -m mono|antialias|subpixel - rendering mode\n"
  397. " -r rgb|bgr|vrgb|vbgr - LCD display type\n\n");
  398. exits("usage");
  399. }
  400. void main(int argc, char* argv[]) {
  401. FTfont font;
  402. int status;
  403. int i;
  404. FTsubfont* sf;
  405. int fd;
  406. char buf[256];
  407. char* fname = nil;
  408. char* mode = nil;
  409. char* srgb = nil;
  410. char *progname = argv[0];
  411. font.name = nil;
  412. font.size = 0;
  413. if(argc == 1)
  414. usage(progname);
  415. ARGBEGIN {
  416. case 's':
  417. font.size = atoi(ARGF());
  418. break;
  419. case 'h':
  420. usage(progname);
  421. break; /* never reached */
  422. case 'f':
  423. fname = ARGF();
  424. break;
  425. case 'n':
  426. font.name = ARGF();
  427. break;
  428. case 'm':
  429. mode = ARGF();
  430. break;
  431. case 'r':
  432. srgb = ARGF();
  433. break;
  434. default:
  435. print("bad flag: %c", ARGC());
  436. } ARGEND
  437. if (fname == nil) {
  438. print("no font name specified\n");
  439. exits("fname");
  440. }
  441. if (font.size == 0) {
  442. print("no font size specified\n");
  443. exits("size");
  444. }
  445. if (mode != nil) {
  446. if (strcmp(mode, "mono") == 0) {
  447. font.rmode = Rmono;
  448. } else if (strcmp(mode, "antialias") == 0) {
  449. font.rmode = Rantialias;
  450. } else if (strcmp(mode, "subpixel") == 0) {
  451. font.rmode = Rsubpixel;
  452. }
  453. } else {
  454. font.rmode = Rmono;
  455. }
  456. switch (font.rmode) {
  457. case Rmono:
  458. font.image_channels = GREY1;
  459. break;
  460. case Rantialias:
  461. font.image_channels = GREY8;
  462. break;
  463. case Rsubpixel:
  464. font.image_channels = RGB24;
  465. if (strcmp(srgb, "rgb") == 0) {
  466. font.rgb = Srgb;
  467. } else if (strcmp(srgb, "bgr") == 0) {
  468. font.rgb = Sbgr;
  469. } else if (strcmp(srgb, "vrgb") == 0) {
  470. font.rgb = Svrgb;
  471. } else if (strcmp(srgb, "vbgr") == 0) {
  472. font.rgb = Svbgr;
  473. } else {
  474. print("unknown subpixel mode: %s\n", srgb);
  475. exits("rgb");
  476. }
  477. break;
  478. }
  479. if (font.name == nil) {
  480. font.name = fname;
  481. }
  482. print("font file: %s, font name: %s, size: %d\n", fname, font.name, font.size);
  483. memimageinit();
  484. status = FT_Init_FreeType(&lib);
  485. if (status) {
  486. print("FT_Init_FreeType: status=%d\n", status);
  487. return;
  488. }
  489. FT_New_Face(lib, fname, 0, &font.face);
  490. if (status) {
  491. print("FT_New_Face: status=%d\n", status);
  492. exits("FT_New_Face");
  493. }
  494. FT_Set_Char_Size(font.face, 0, font.size * 64, 72, 72);
  495. if (status) {
  496. print("FT_Set_Char_Size: status=%d\n", status);
  497. exits("FR_Set_Char_Size");
  498. }
  499. FT_Select_Charmap(font.face, ft_encoding_unicode);
  500. font.slot = font.face->glyph;
  501. font.sfont = nil;
  502. font.ascent = 0;
  503. font.descent = 10000;
  504. i = 0;
  505. while (i < 65536) {
  506. struct _FTsubfont* sf = malloc(sizeof(FTsubfont));
  507. initSubfont(&font, sf, i);
  508. if (sf->nchars == 0) {
  509. break;
  510. }
  511. print("last: %d, start: %d, nchars: %d, width: %d\n", i, sf->startc, sf->nchars, sf->image_width);
  512. i = sf->startc + sf->nchars;
  513. sf->next = font.sfont;
  514. font.sfont = sf;
  515. if (font.ascent < sf->ascent) {
  516. font.ascent = sf->ascent;
  517. }
  518. if (font.descent > sf->descent) {
  519. font.descent = sf->descent;
  520. }
  521. }
  522. /* font.height = font.ascent - font.descent; */
  523. font.height = font.size;
  524. font.ascent = font.height-3;
  525. /* do we have a directory created for this font? */
  526. snprint(buf, sizeof(buf), "%s", font.name);
  527. if(access(buf, AEXIST) == -1) {
  528. fd = create(buf, OREAD, DMDIR|0777);
  529. if(fd < 0)
  530. sysfatal("cannot create font directory: %r");
  531. }
  532. snprint(buf, sizeof(buf), "%s/%s.%d.font", font.name, font.name, font.size);
  533. fd = create(buf, OWRITE, 0666);
  534. if(fd < 0)
  535. sysfatal("cannot create .font file: %r");
  536. fprint(fd, "%d\t%d\n", font.height, font.ascent);
  537. for(sf = font.sfont; sf != nil; sf = sf->next) {
  538. snprint(buf, sizeof(buf), "%s/%s.%d.%04x", font.name, font.name, font.size, sf->startc);
  539. // printf("generating 0x%04x - 0x%04x\n", sf->startc, sf->startc + sf->nchars);
  540. if (0 ==createSubfont(&font, sf, buf)) {
  541. snprint(buf, sizeof(buf), "%s.%d.%04x", font.name, font.size, sf->startc);
  542. fprint(fd, "0x%04x\t0x%04x\t%s\n", sf->startc, sf->startc+sf->nchars - 1, buf);
  543. }
  544. }
  545. close(fd);
  546. }