vector.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. /*
  2. * libsfn/vector.c
  3. *
  4. * Copyright (C) 2020 bzt (bztsrc@gitlab)
  5. *
  6. * Permission is hereby granted, free of charge, to any person
  7. * obtaining a copy of this software and associated documentation
  8. * files (the "Software"), to deal in the Software without
  9. * restriction, including without limitation the rights to use, copy,
  10. * modify, merge, publish, distribute, sublicense, and/or sell copies
  11. * of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be
  15. * included in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. * DEALINGS IN THE SOFTWARE.
  25. *
  26. * @brief File functions for vector fonts (sfd is native, otherwise using FreeType2)
  27. *
  28. */
  29. #ifndef USE_NOFOREIGN
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include "libsfn.h"
  33. #include "vector.h"
  34. #include "bitmap.h"
  35. #ifdef HAS_FT
  36. #include <ft2build.h>
  37. #include FT_FREETYPE_H
  38. #include FT_OUTLINE_H
  39. #include FT_IMAGE_H
  40. #include FT_BBOX_H
  41. #include FT_SFNT_NAMES_H
  42. #define FT_SIZE 1024
  43. FT_Library ft = NULL;
  44. FT_Face face;
  45. FT_BBox *bbox;
  46. typedef struct {
  47. int unicode;
  48. FT_BBox bbox;
  49. } ftchr_t;
  50. ftchr_t *ftchars;
  51. #endif
  52. int min_y, max_y, min_x, max_x, max_b, max_s, max_w, max_h, unicode;
  53. sfnlayer_t *currlayer;
  54. /**
  55. * Parse FontForge's SplineFontDb
  56. */
  57. void sfd(char *ptr, int size)
  58. {
  59. int i, j, w = -1, h = 0, b = 0, unicode = 0, nc = 0, numchars = 0, ps = 0, p[7], mx, xx, my, xy, f = 0;
  60. long int avg_w = 0, avg_h = 0, avg_n = 0;
  61. char *end = ptr + size, *endprop, *face, *name = NULL;
  62. #define scx(x) (((x - mx) * 255 + max_s / 2) / max_s)
  63. #define scy(y) (((max_b - y) * 255 + max_s / 2) / max_s)
  64. for(face = ptr; face + 11 < end && *face; face++) {
  65. if(!memcmp(face, "StartChar:", 10)) numchars++;
  66. if(!memcmp(face, "BitmapFont:", 11)) {
  67. /* Ooops, we have a bitmap font */
  68. bdf(face, end - face);
  69. return;
  70. }
  71. }
  72. face = NULL;
  73. while(ptr < end && *ptr) {
  74. if(!memcmp(ptr, "FullName: ", 10) && !face) { ptr += 10; face = ptr; }
  75. if(!memcmp(ptr, "Version: ", 9) && !ctx.revision) { ptr += 9; sfn_setstr(&ctx.revision, ptr, 0); }
  76. if(!memcmp(ptr, "FontName: ", 10) && !ctx.name && !ctx.subname) {
  77. ptr += 10; while(*ptr && *ptr!='-' && *ptr!='\n') { ptr++; }
  78. if(*ptr == '-') { ptr++; sfn_setstr(&ctx.subname, ptr, 0); }
  79. }
  80. if(!memcmp(ptr, "FamilyName: ", 12) && !ctx.manufacturer) { ptr += 12; sfn_setstr(&ctx.manufacturer, ptr, 0); }
  81. if(!memcmp(ptr, "FamilyName: ", 12) && !ctx.familyname) { ptr += 12; sfn_setstr(&ctx.familyname, ptr, 0); }
  82. if(!memcmp(ptr, "Copyright: ", 11) && !ctx.license) { ptr += 11; sfn_setstr(&ctx.license, ptr, 0); }
  83. if(!memcmp(ptr, "Ascent: ", 8)) {
  84. ptr += 8; while(*ptr == ' ') ptr++;
  85. b = atoi(ptr); }
  86. if(!memcmp(ptr, "Descent: ", 9)) {
  87. ptr += 9; while(*ptr == ' ') ptr++;
  88. ps = atoi(ptr); }
  89. if(!memcmp(ptr, "UnderlinePosition: ", 19)) {
  90. ptr += 19; while(*ptr == ' ') ptr++;
  91. relul = atoi(ptr); if(relul < 0) relul = -relul; }
  92. if(!memcmp(ptr, "ItalicAngle: ", 13)) {
  93. ptr += 13; while(*ptr == ' ') ptr++;
  94. if(ptr[0] != '0') ctx.style |= SSFN_STYLE_ITALIC; }
  95. if(!memcmp(ptr, "Weight: Bold", 12)) ctx.style |= SSFN_STYLE_BOLD;
  96. if(!memcmp(ptr, "BeginChars:", 11)) break;
  97. while(*ptr && *ptr!='\n') ptr++;
  98. while(*ptr=='\n') ptr++;
  99. }
  100. ps += b;
  101. if(!ctx.name) {
  102. if(!face) face = ctx.familyname;
  103. if(face && ctx.subname && ctx.subname[0]) {
  104. for(i = 0; face[i] && face[i] != '\"' && face[i] != '\r' && face[i] != '\n'; i++);
  105. j = strlen(ctx.subname);
  106. name = malloc(i + j + 2);
  107. if(!name) { fprintf(stderr,"libsfn: memory allocation error\n"); return; }
  108. memcpy(name, face, i);
  109. name[i] = ' ';
  110. memcpy(name + i + 1, ctx.subname, j);
  111. name[i + j + 1] = 0;
  112. sfn_setstr(&ctx.name, name, 0);
  113. free(name);
  114. } else
  115. sfn_setstr(&ctx.name, ctx.familyname, 0);
  116. }
  117. printf("\r Name '%s' num_glyphs: %d, ascender: %d, underline: %d, height: %d\n", ctx.name, numchars, b, b + relul, ps);
  118. if(!ps) return;
  119. min_x = min_y = 2*ps; max_x = max_y = max_b = max_w = max_h = -2*ps; numchars = 0;
  120. endprop = ptr;
  121. while(ptr < end && *ptr) {
  122. if(!memcmp(ptr, "Encoding: ", 10)) {
  123. ptr += 10; while(*ptr && *ptr != ' ') { ptr++; } while(*ptr == ' ') ptr++;
  124. unicode = atoi(ptr); while(*ptr && *ptr != ' ') { ptr++; } while(*ptr == ' ') ptr++;
  125. if(*ptr == '0' && (ptr[1] == '\r' || ptr[1] == '\n')) unicode = 0;
  126. f = 0;
  127. }
  128. if(!memcmp(ptr, "Fore", 4)) f = 1;
  129. if(!memcmp(ptr, "Back", 4)) f = 0;
  130. if(f && !memcmp(ptr, "SplineSet", 9)) {
  131. ptr += 9; while(*ptr && *ptr!='\n') { ptr++; } while(*ptr=='\n') ptr++;
  132. if(unicode >= 0 && unicode >= rs && unicode <= re && !(ctx.skip[unicode >> 3] & (1 << (unicode & 7)))) {
  133. mx = my = 2*ps; xx = xy = -2*ps; numchars++;
  134. while(ptr < end && *ptr && memcmp(ptr, "EndSplineSet", 12)) {
  135. for(j = 0; j < 7; j++) {
  136. while(*ptr == ' ') ptr++;
  137. if(!memcmp(ptr, "Spiro", 5)) while(ptr < end && *ptr && memcmp(ptr - 9, "EndSpiro", 8)) ptr++;
  138. if(j >=6 || (*ptr != ' ' && *ptr != '-' && !(*ptr >= '0' && *ptr <= '9'))) break;
  139. p[j] = atoi(ptr); while(*ptr && *ptr != ' ') ptr++;
  140. if(j & 1) {
  141. if(p[j] > max_b) max_b = p[j];
  142. if(p[j] < min_y) min_y = p[j];
  143. if(p[j] > max_y) max_y = p[j];
  144. if(p[j] < my) my = p[j];
  145. if(p[j] > xy) xy = p[j];
  146. } else {
  147. if(p[j] < min_x) min_x = p[j];
  148. if(p[j] > max_x) max_x = p[j];
  149. if(p[j] < mx) mx = p[j];
  150. if(p[j] > xx) xx = p[j];
  151. }
  152. }
  153. if(ptr[0] != 'm' && ptr[0] != 'l' && ptr[0] != 'c') {
  154. if(!quiet)
  155. fprintf(stderr, "\rlibsfn: bad font, unknown spline command '%c' for U+%06X \n", ptr[0], unicode);
  156. return;
  157. }
  158. while(*ptr && *ptr!='\n') ptr++;
  159. while(*ptr=='\n') ptr++;
  160. }
  161. if(mx < xx && my < xy) {
  162. xx -= mx - 1; xy -= my - 1;
  163. if(xx > max_w) max_w = xx;
  164. if(xy > max_h) max_h = xy;
  165. avg_w += xx;
  166. avg_h += xy;
  167. avg_n++;
  168. }
  169. }
  170. while(ptr < end && *ptr && memcmp(ptr, "EndChar", 7)) ptr++;
  171. }
  172. while(*ptr && *ptr!='\n') ptr++;
  173. while(*ptr=='\n') ptr++;
  174. }
  175. if(avg_n > 0) {
  176. avg_w /= avg_n;
  177. avg_h /= avg_n;
  178. }
  179. if(!quiet && b != max_b) {
  180. fprintf(stderr, "\rlibsfn: inconsistent font: ascender %d != max(yMax) %d \n", b, max_b);
  181. }
  182. printf("\r Numchars: %d, Bounding box: (%d, %d), (%d, %d) dx %d dy %d, w: %d, h: %d, baseline: %d\n", numchars,
  183. min_x, min_y, max_x, max_y, max_x - min_x, max_y - min_y, max_w, max_h, max_b);
  184. max_s = max_w > max_h ? max_w : max_h;
  185. if(max_s > 0) {
  186. printf(" Scaling to %d x %d, average: %ld x %ld\n", max_s, max_s, avg_w, avg_h);
  187. ptr = endprop;
  188. while(ptr < end && *ptr) {
  189. if(!memcmp(ptr, "Encoding: ", 10)) {
  190. ptr += 10; while(*ptr && *ptr != ' ') { ptr++; } while(*ptr == ' ') ptr++;
  191. unicode = atoi(ptr); while(*ptr && *ptr != ' ') { ptr++; } while(*ptr == ' ') ptr++;
  192. if(*ptr == '0' && (ptr[1] == '\r' || ptr[1] == '\n')) unicode = 0;
  193. w = -1; h = f = 0;
  194. }
  195. if(!memcmp(ptr, "Fore", 4)) f = 1;
  196. if(!memcmp(ptr, "Back", 4)) f = 0;
  197. if(!memcmp(ptr, "Width: ", 7)) { ptr += 7; w = atoi(ptr); }
  198. if(!memcmp(ptr, "VWidth: ", 8)) { ptr += 8; h = atoi(ptr); }
  199. if(!memcmp(ptr, "EndChar", 7) && iswhitespace(unicode) && (w || h))
  200. sfn_charadd(unicode, 0, 0, w, h, 0);
  201. if(f && !memcmp(ptr, "SplineSet", 9)) {
  202. ptr += 9; while(*ptr && *ptr!='\n') { ptr++; } while(*ptr=='\n') ptr++;
  203. if(unicode >= 0 && unicode >= rs && unicode <= re && !(ctx.skip[unicode >> 3] & (1 << (unicode & 7)))) {
  204. if(pbar) (*pbar)(0, 0, ++nc, numchars, PBAR_OUTLINE);
  205. mx = my = 2*ps; xx = xy = -2*ps; endprop = ptr;
  206. /* sfd does not store the glyph metrics */
  207. while(ptr < end && *ptr && memcmp(ptr, "EndSplineSet", 12)) {
  208. for(j = 0; j < 7; j++) {
  209. while(*ptr == ' ') ptr++;
  210. if(!memcmp(ptr, "Spiro", 5)) while(ptr < end && *ptr && memcmp(ptr - 9, "EndSpiro", 8)) ptr++;
  211. if(j >=6 || (*ptr != ' ' && *ptr != '-' && !(*ptr >= '0' && *ptr <= '9'))) break;
  212. p[j] = atoi(ptr); while(*ptr && *ptr != ' ') ptr++;
  213. if(j & 1) {
  214. if(p[j] < my) my = p[j];
  215. if(p[j] > xy) xy = p[j];
  216. } else {
  217. if(p[j] < mx) mx = p[j];
  218. if(p[j] > xx) xx = p[j];
  219. }
  220. }
  221. while(*ptr && *ptr!='\n') ptr++;
  222. while(*ptr=='\n') ptr++;
  223. }
  224. if(mx < xx && my < xy) {
  225. xx -= mx - 1; xy -= my - 1;
  226. if(!quiet && (xx >= 2*avg_w+avg_w/2 || xy >= 2*avg_h+avg_h/2)) {
  227. fprintf(stderr, "\rlibsfn: irregular dimensions in font: U+%06X", unicode);
  228. if(xx >= 2*avg_w+avg_w/2) {
  229. fprintf(stderr, ", width: %d ", xx);
  230. if(xx >= 3*avg_w)
  231. fprintf(stderr, "(%ld times the average, can't be right!!!)", xx / avg_w);
  232. }
  233. if(xy >= 2*avg_h+avg_h/2) {
  234. fprintf(stderr, ", height: %d ", xy);
  235. if(xy >= 3*avg_h)
  236. fprintf(stderr, "(%ld times the average, can't be right!!!)", xy / avg_h);
  237. }
  238. fprintf(stderr, "\n");
  239. }
  240. /* now that we know the actual dimensions of the glyph, go once again... */
  241. if(h > 0) w = 0;
  242. if(w < 0) w = xx > 0 ? xx : 0;
  243. if(sfn_charadd(unicode, 0, 0, w, h, !h && mx < 0 ? -mx * 255 / max_s : 0)) {
  244. ptr = endprop;
  245. while(ptr < end && *ptr && memcmp(ptr, "EndSplineSet", 12)) {
  246. for(j = 0; j < 7; j++) {
  247. while(*ptr == ' ') ptr++;
  248. if(!memcmp(ptr, "Spiro", 5)) while(ptr < end && *ptr && memcmp(ptr - 9, "EndSpiro", 8)) ptr++;
  249. if(j >=6 || (*ptr != ' ' && *ptr != '-' && !(*ptr >= '0' && *ptr <= '9'))) break;
  250. p[j] = atoi(ptr); while(*ptr && *ptr != ' ') ptr++;
  251. }
  252. switch(ptr[0]) {
  253. case 'm':
  254. currlayer = sfn_layeradd(unicode, SSFN_FRAG_CONTOUR, 0, 0, 0, 0, 0xFE, NULL);
  255. sfn_contadd(currlayer, SSFN_CONTOUR_MOVE, scx(p[0]), scy(p[1]), 0,0, 0,0);
  256. break;
  257. case 'l': sfn_contadd(currlayer, SSFN_CONTOUR_LINE, scx(p[0]), scy(p[1]), 0,0, 0,0); break;
  258. case 'c':
  259. sfn_contadd(currlayer, SSFN_CONTOUR_CUBIC, scx(p[4]), scy(p[5]), scx(p[0]), scy(p[1]),
  260. scx(p[2]),scy(p[3]));
  261. break;
  262. }
  263. while(*ptr && *ptr!='\n') ptr++;
  264. while(*ptr=='\n') ptr++;
  265. }
  266. }
  267. }
  268. }
  269. while(ptr < end && *ptr && memcmp(ptr, "EndChar", 7)) ptr++;
  270. }
  271. while(*ptr && *ptr!='\n') ptr++;
  272. while(*ptr=='\n') ptr++;
  273. }
  274. } /* max_s != 0 */
  275. if(!ctx.baseline && max_b) ctx.baseline = max_b;
  276. }
  277. #ifdef HAS_FT
  278. /**
  279. * Transform and scale coordinates
  280. */
  281. int sx(int i)
  282. {
  283. return ((i - bbox->xMin) * 255 + max_s / 2) / max_s;
  284. }
  285. int sy(int i)
  286. {
  287. return ((max_b - i) * 255 + max_s / 2) / max_s;
  288. }
  289. /*** contour command callbacks for FT2 ***/
  290. int move(const FT_Vector *to, void *ptr)
  291. {
  292. (void)ptr;
  293. currlayer = sfn_layeradd(unicode, SSFN_FRAG_CONTOUR, 0, 0, 0, 0, 0xFE, NULL);
  294. sfn_contadd(currlayer, SSFN_CONTOUR_MOVE, sx(to->x), sy(to->y), 0,0, 0,0);
  295. return 0;
  296. }
  297. int line(const FT_Vector *to, void *ptr)
  298. {
  299. (void)ptr;
  300. sfn_contadd(currlayer, SSFN_CONTOUR_LINE, sx(to->x), sy(to->y), 0,0, 0,0);
  301. return 0;
  302. }
  303. int quad(const FT_Vector *control, const FT_Vector *to, void *ptr)
  304. {
  305. (void)ptr;
  306. sfn_contadd(currlayer, SSFN_CONTOUR_QUAD, sx(to->x), sy(to->y), sx(control->x), sy(control->y), 0,0);
  307. return 0;
  308. }
  309. int cubic(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *ptr)
  310. {
  311. (void)ptr;
  312. sfn_contadd(currlayer, SSFN_CONTOUR_CUBIC, sx(to->x), sy(to->y), sx(control1->x), sy(control1->y),
  313. sx(control2->x), sy(control2->y));
  314. return 0;
  315. }
  316. FT_Outline_Funcs funcs = { move, line, quad, cubic, 0, 0 };
  317. /**
  318. * Parse a TTF (or any other vector font that FT2 supports)
  319. */
  320. void ttf()
  321. {
  322. FT_UInt agi;
  323. FT_ULong cp;
  324. FT_Vector v;
  325. FT_Error error;
  326. int i, j, n, x, y, numchars = 0;
  327. long int avg_w = 0, avg_h = 0, avg_n = 0;
  328. ftchr_t *c;
  329. /* unbeliveable, FT2 lib does not return the number of characters in the font... */
  330. for(cp = FT_Get_First_Char(face, &agi); agi; cp = FT_Get_Next_Char(face, cp, &agi)) numchars++;
  331. c = ftchars = (ftchr_t*)malloc((numchars + 1) * sizeof(ftchr_t));
  332. if(!ftchars) { fprintf(stderr,"libsfn: memory allocation error\n"); return; }
  333. memset(ftchars, 0, (numchars + 1) * sizeof(ftchr_t));
  334. /* ...and it returns incorrect bounding box. Never trust FT2's scaling. */
  335. min_x = min_y = face->units_per_EM*2; max_x = max_y = max_b = max_w = max_h = -face->units_per_EM*2;
  336. for(cp = FT_Get_First_Char(face, &agi), i = 0; i <= numchars && agi; i++) {
  337. if(pbar) (*pbar)(1, 3, i, numchars, PBAR_MEASURE);
  338. if(!(ctx.skip[cp >> 3] & (1 << (cp & 7)))) {
  339. c->unicode = (int)cp;
  340. c->bbox.xMin = c->bbox.xMax = c->bbox.yMin = c->bbox.yMax = 0;
  341. if(FT_Load_Glyph(face, FT_Get_Char_Index(face, cp), FT_LOAD_NO_SCALE) ||
  342. (i && !face->glyph->glyph_index)) continue;
  343. if(!origwh) {
  344. FT_Outline_Get_BBox(&face->glyph->outline, &c->bbox);
  345. } else {
  346. if(!face->glyph->metrics.vertBearingX && !face->glyph->metrics.vertBearingY) {
  347. c->bbox.xMin = face->glyph->metrics.horiBearingX;
  348. c->bbox.xMax = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
  349. c->bbox.yMin = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
  350. c->bbox.yMax = face->glyph->metrics.horiBearingY;
  351. } else {
  352. c->bbox.xMin = face->glyph->metrics.vertBearingX;
  353. c->bbox.xMax = face->glyph->metrics.vertBearingX + face->glyph->metrics.width;
  354. c->bbox.yMin = face->glyph->metrics.vertBearingY - face->glyph->metrics.height;
  355. c->bbox.yMax = face->glyph->metrics.vertBearingY;
  356. }
  357. }
  358. if(face->glyph->metrics.width > max_w) max_w = face->glyph->metrics.width;
  359. if(face->glyph->metrics.height > max_h) max_h = face->glyph->metrics.height;
  360. if(c->bbox.yMax > max_b) max_b = c->bbox.yMax;
  361. if(c->bbox.xMin < min_x) min_x = c->bbox.xMin;
  362. if(c->bbox.xMax > max_x) max_x = c->bbox.xMax;
  363. if(c->bbox.yMin < min_y) min_y = c->bbox.yMin;
  364. if(c->bbox.yMax > max_y) max_y = c->bbox.yMax;
  365. avg_w += face->glyph->metrics.width;
  366. avg_h += face->glyph->metrics.height;
  367. avg_n++;
  368. /*
  369. if(cp==0x21) {
  370. printf("\n%ld UUUUU Bounding box (%ld, %ld), (%ld, %ld)\n", cp,c->bbox.xMin, c->bbox.yMin, c->bbox.xMax, c->bbox.yMax);
  371. printf("metrics w %ld h %ld horiAdv %ld vertAdv %ld hbear %ld %ld vbear %ld %ld\n", face->glyph->metrics.width, face->glyph->metrics.height,
  372. face->glyph->metrics.horiAdvance, face->glyph->metrics.vertAdvance, face->glyph->metrics.horiBearingX, face->glyph->metrics.horiBearingY,
  373. face->glyph->metrics.vertBearingX, face->glyph->metrics.vertBearingY);
  374. }
  375. */
  376. if(!quiet && (c->bbox.xMin != face->glyph->metrics.horiBearingX ||
  377. c->bbox.yMin != face->glyph->metrics.horiBearingY - face->glyph->metrics.height ||
  378. c->bbox.xMax != c->bbox.xMin + face->glyph->metrics.width ||
  379. c->bbox.yMax != c->bbox.yMin + face->glyph->metrics.height)) {
  380. fprintf(stderr, "\rlibsfn: inconsistent font: U+%06lX", cp);
  381. if(c->bbox.xMin != face->glyph->metrics.horiBearingX)
  382. fprintf(stderr, ", xMin %ld != hBX %ld", c->bbox.xMin, face->glyph->metrics.horiBearingX);
  383. if(c->bbox.yMin != face->glyph->metrics.horiBearingY - face->glyph->metrics.height)
  384. fprintf(stderr, ", yMin %ld != hBY-h %ld", c->bbox.yMin,
  385. face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
  386. if(c->bbox.xMax != c->bbox.xMin + face->glyph->metrics.width)
  387. fprintf(stderr, ", xMax %ld != xMin+w %ld", c->bbox.xMax,
  388. c->bbox.xMin + face->glyph->metrics.width);
  389. if(c->bbox.yMax != c->bbox.yMin + face->glyph->metrics.height)
  390. fprintf(stderr, ", yMax %ld != yMin+h %ld", c->bbox.yMax,
  391. c->bbox.yMin + face->glyph->metrics.height);
  392. fprintf(stderr, " \n");
  393. }
  394. c++;
  395. }
  396. cp = FT_Get_Next_Char(face, cp, &agi);
  397. }
  398. if(avg_n > 0) {
  399. avg_w /= avg_n;
  400. avg_h /= avg_n;
  401. }
  402. /* due to optionally skipped characters */
  403. numchars = (int)((unsigned long int)c - (unsigned long int)ftchars) / sizeof(ftchr_t);
  404. if(min_x >= max_x || min_y >= max_y) min_x = max_x = min_y = max_y = max_w = max_h = max_b = 0;
  405. if(!quiet && face->ascender != max_b) {
  406. fprintf(stderr, "\rlibsfn: inconsistent font: ascender %d != max(yMax) %d \n", face->ascender, max_b);
  407. }
  408. if(origwh) {
  409. if(max_x - min_x > max_w) max_w = max_x - min_x;
  410. if(max_y - min_y > max_h) max_h = max_y - min_y;
  411. }
  412. printf("\r Numchars: %d, Bounding box: (%d, %d), (%d, %d) dx %d dy %d, w: %d, h: %d, baseline: %d\n", numchars,
  413. min_x, min_y, max_x, max_y, max_x - min_x, max_y - min_y, max_w, max_h, max_b);
  414. max_s = max_w > max_h ? max_w : max_h;
  415. if(max_s > 0) {
  416. printf(" Scaling to %d x %d, average: %ld x %ld\n", max_s, max_s, avg_w, avg_h);
  417. /* get font style */
  418. if(face->style_flags & FT_STYLE_FLAG_BOLD) ctx.style |= SSFN_STYLE_BOLD;
  419. if(face->style_flags & FT_STYLE_FLAG_ITALIC) ctx.style |= SSFN_STYLE_ITALIC;
  420. /* baseline and underline */
  421. ctx.baseline = (max_b * 255 + max_s - 1) / max_s;
  422. ctx.underline = ((max_b - face->underline_position) * 255 + max_s - 1) / max_s;
  423. /* iterate on characters and contour outlines */
  424. lastuni = -1;
  425. for(i = 0; i < numchars; i++) {
  426. unicode = ftchars[i].unicode;
  427. if(pbar) (*pbar)(2, 3, i, numchars, PBAR_OUTLINE);
  428. if(FT_Load_Glyph(face, FT_Get_Char_Index(face, unicode), FT_LOAD_NO_SCALE) ||
  429. (i && !face->glyph->glyph_index)) continue;
  430. bbox = &ftchars[i].bbox;
  431. if(face->glyph->metrics.horiAdvance /* !face->glyph->metrics.vertBearingX && !face->glyph->metrics.vertBearingY*/) {
  432. x = face->glyph->metrics.horiAdvance - bbox->xMin + 1; y = 0;
  433. if(x < 0) x = 1;
  434. x = (x * 255 + max_s - 1) / max_s;
  435. } else {
  436. x = 0; y = face->glyph->metrics.vertAdvance - bbox->yMin + 1;
  437. if(y < 0) y = 1;
  438. y = (y * 255 + max_s - 1) / max_s;
  439. }
  440. if(!quiet && (face->glyph->metrics.width >= 2*avg_w+avg_w/2 || face->glyph->metrics.height >= 2*avg_h+avg_h/2)) {
  441. fprintf(stderr, "\rlibsfn: irregular dimensions in font: U+%06X", unicode);
  442. if(face->glyph->metrics.width >= 2*avg_w+avg_w/2) {
  443. fprintf(stderr, ", width: %ld ", face->glyph->metrics.width);
  444. if(face->glyph->metrics.width >= 3*avg_w)
  445. fprintf(stderr, "(%ld times the average, can't be right!!!)", face->glyph->metrics.width / avg_w);
  446. }
  447. if(face->glyph->metrics.height >= 2*avg_h+avg_h/2) {
  448. fprintf(stderr, ", height: %ld ", face->glyph->metrics.height);
  449. if(face->glyph->metrics.height >= 3*avg_h)
  450. fprintf(stderr, "(%ld times the average, can't be right!!!)", face->glyph->metrics.height / avg_h);
  451. }
  452. fprintf(stderr, "\n");
  453. }
  454. /* don't trust FT2's width and height, we'll recalculate them from the coordinates */
  455. if(sfn_charadd(unicode, 0, 0, x, y, !y && bbox->xMin < 0 ? (-bbox->xMin * 255 + max_s - 1) / max_s : 0)) {
  456. error = FT_Outline_Decompose(&face->glyph->outline, &funcs, NULL);
  457. if(error && !quiet) { fprintf(stderr, "libsfn: FreeType2 decompose error %x\n", error); }
  458. }
  459. }
  460. /* get kerning information */
  461. if(face->face_flags & FT_FACE_FLAG_KERNING) {
  462. for(i = n = 0; i < numchars; i++) {
  463. if(pbar) (*pbar)(3, 3, i, numchars, PBAR_GETKERN);
  464. for(j = 0; j < numchars; j++) {
  465. if(ftchars[i].unicode<33 || ftchars[j].unicode<33) continue;
  466. v.x = v.y = 0;
  467. FT_Get_Kerning(face, ftchars[i].unicode, ftchars[j].unicode, FT_KERNING_UNSCALED, &v);
  468. if(v.x) { v.x = (v.x * 255 + max_s - 1) / max_s; v.y = 0; }
  469. else { v.x = 0; v.y = (v.y * 255 + max_s - 1) / max_s; }
  470. if(v.x >= -1 && v.x <= 1 && v.y >= -1 && v.x <= 1) continue;
  471. sfn_kernadd(ftchars[i].unicode, ftchars[j].unicode, v.x, v.y);
  472. n++;
  473. }
  474. }
  475. printf("\r\x1b[K Kerning %d pairs\n", n);
  476. } else
  477. printf("\r\x1b[K No kerning information\n");
  478. }
  479. free(ftchars);
  480. }
  481. /**
  482. * Parse bitmap font (any format that FT2 supports)
  483. * I know, this is not vector font related, but since all the other FT2 functions are here I didn't wanted
  484. * to move this function with all the includes into bitmap.c
  485. */
  486. void ft2()
  487. {
  488. int i, j, k, l, n, a = 0, w = 8, h = 16, nc = 0, numchars = 0, ft2bug = 0;
  489. unsigned char *glyph, *bitmap;
  490. FT_UInt agi;
  491. FT_ULong cp;
  492. /* unbeliveable, FT2 lib can't iterate on characters in the font if there's no encoding... */
  493. for(cp = FT_Get_First_Char(face, &agi); agi; cp = FT_Get_Next_Char(face, cp, &agi)) numchars++;
  494. for(i = 0; i < face->num_fixed_sizes; i++)
  495. if(face->available_sizes[i].height > h) {
  496. h = face->available_sizes[i].height;
  497. w = face->available_sizes[i].width;
  498. }
  499. printf("\r Numchars: %d, num_fixed_sizes: %d, selected: %d x %d\n", numchars, face->num_fixed_sizes, w, h);
  500. if(!numchars) {
  501. printf(" FreeType2 bug, FT_Get_Next_char didn't work, trying to render ALL code points one-by-one...\n");
  502. ft2bug = 1; numchars = 0x10FFFF;
  503. }
  504. FT_Set_Pixel_Sizes(face, w, h);
  505. n = 2*h*h;
  506. bitmap = (unsigned char*)malloc(n);
  507. if(!bitmap) { fprintf(stderr,"libsfn: memory allocation error\n"); return; }
  508. if(ft2bug) { cp = 0; agi = 1; } else cp = FT_Get_First_Char(face, &agi);
  509. while(agi) {
  510. if(pbar) (*pbar)(0, 0, ++nc, numchars, PBAR_BITMAP);
  511. if(ctx.skip[cp >> 3] & (1 << (cp & 7))) goto cont;
  512. if(cp < (FT_ULong)rs || cp > (FT_ULong)re || FT_Load_Glyph(face, FT_Get_Char_Index(face, cp), FT_LOAD_NO_SCALE) ||
  513. (cp && !face->glyph->glyph_index)) goto cont;
  514. FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO);
  515. if(face->glyph->bitmap.pixel_mode != FT_PIXEL_MODE_MONO) goto cont;
  516. memset(bitmap, 0, n);
  517. glyph = face->glyph->bitmap.buffer;
  518. w = ((int)(face->glyph->bitmap.width+7) & ~7);
  519. for(i = k = 0; i < (int)face->glyph->bitmap.rows; i++) {
  520. for(j = 0; j < (int)(face->glyph->bitmap.width+7)/8; j++)
  521. for(l=0x80;l && k < n;l>>=1)
  522. bitmap[k++] = (glyph[j] & l) ? 0xFE : 0xFF;
  523. glyph += face->glyph->bitmap.pitch;
  524. }
  525. a += face->glyph->bitmap_top;
  526. if(sfn_charadd(cp, w, face->glyph->bitmap.rows, face->glyph->advance.x >> 6, face->glyph->advance.y >> 6,
  527. face->glyph->bitmap_left))
  528. sfn_layeradd(cp, SSFN_FRAG_BITMAP, 0, 0, w, face->glyph->bitmap.rows, 0xFE, bitmap);
  529. cont: if(ft2bug) { cp++; if(cp > 0x10FFFF) break; } else cp = FT_Get_Next_Char(face, cp, &agi);
  530. }
  531. ctx.baseline = numchars ? a / numchars : a;
  532. ctx.underline = ctx.baseline + (h - ctx.baseline) / 2;
  533. free(bitmap);
  534. }
  535. /**
  536. * Check if FT2 can read the font
  537. */
  538. int ft2_read(unsigned char *data, int size)
  539. {
  540. if(!ft && FT_Init_FreeType(&ft)) { fprintf(stderr, "libsfn: unable to initialize FreeType2\n"); return 0; }
  541. face = NULL;
  542. return (!FT_New_Memory_Face(ft, data, size, 0, &face) && face) ? 1 : 0;
  543. }
  544. /**
  545. * Get a string from ft2
  546. * for the sfnt string ids, see https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=IWS-Chapter08#3054f18b
  547. */
  548. int ft2_str(int id, FT_SfntName *name)
  549. {
  550. uint8_t *src, *dst, *end, *old;
  551. uint16_t chr;
  552. int i;
  553. if(!name || !face) return 0;
  554. /* NOTE: see freetype2/src/base/ftsnames.c line 73, it is a real mine-field:
  555. * 1. it does not check if the name entry for an idx is valid or not
  556. * 2. if it happens to have bad values, or otherwise unable to read from the stream, it will still return FT_Err_OK.
  557. * Also, see freetype2/src/sfnt/ttload.c line 947, it skips empty and bad records, which means FT_Get_Sfnt_Name's idx isn't
  558. * necessarily aligned with sfnt ids any more, it could be just a total arbitrary ft2 internal id.
  559. * So we have to do it the hard way...
  560. */
  561. for(i = 0; i < (int)FT_Get_Sfnt_Name_Count(face); i++)
  562. if(!FT_Get_Sfnt_Name(face, i, name) && name->string != NULL && name->string_len > 0 && name->name_id == id) {
  563. if(!name->encoding_id && name->string[0]) return 1;
  564. /* TTF isn't really documented, but ft2 seems to think this is UTF16-BE when it gets face->family_name */
  565. src = old = name->string; end = name->string + name->string_len;
  566. dst = name->string = (uint8_t*)malloc(name->string_len * 2);
  567. if(!dst) { name->string = old; return 0; }
  568. for(; src < end; src += 2) {
  569. chr = (src[0] << 8) | src[1];
  570. if(!chr) break;
  571. if(chr < 0x80) *dst++ = chr;
  572. else if(chr < 0x800) { *dst++ = ((chr>>6)&0x1F)|0xC0; *dst++ = (chr&0x3F)|0x80; }
  573. else { *dst++ = ((chr>>12)&0x0F)|0xE0; *dst++ = ((chr>>6)&0x3F)|0x80; *dst++ = (chr&0x3F)|0x80; }
  574. }
  575. name->encoding_id = 1;
  576. name->string_len = (uintptr_t)dst - (uintptr_t)name->string;
  577. /* with some fonts, this leads to double-free when FT_Done_Face is called. With other fonts, ft2 memleaks... */
  578. /*free(old);*/
  579. return 1;
  580. }
  581. return 0;
  582. }
  583. /**
  584. * Parse a FT2 font
  585. */
  586. void ft2_parse()
  587. {
  588. FT_SfntName name;
  589. if(!ft || !face) return;
  590. FT_Select_Charmap(face, FT_ENCODING_UNICODE);
  591. printf("\r Name '%s' num_glyphs: %ld, units_per_EM: %d, ascender: %d, underline: %d, %s\n",
  592. face->family_name, face->num_glyphs, face->units_per_EM, face->ascender, face->underline_position,
  593. face->face_flags & FT_FACE_FLAG_SCALABLE ? "vector" : "bitmap");
  594. if(face->face_flags & FT_FACE_FLAG_SCALABLE) ttf(); else ft2();
  595. /* unique font name */
  596. if(!ctx.name) {
  597. name.string = NULL;
  598. if(ft2_str(4, &name)) sfn_setstr(&ctx.name, (char*)name.string, name.string_len); else
  599. if(ft2_str(3, &name)) sfn_setstr(&ctx.name, (char*)name.string, name.string_len); else
  600. if(ft2_str(6, &name)) sfn_setstr(&ctx.name, (char*)name.string, name.string_len); else
  601. if(ft2_str(20, &name)) sfn_setstr(&ctx.name, (char*)name.string, name.string_len); else
  602. if(ft2_str(18, &name)) sfn_setstr(&ctx.name, (char*)name.string, name.string_len);
  603. }
  604. /* fallback */
  605. if(!ctx.name) sfn_setstr(&ctx.name, face->family_name, 0);
  606. /* family name */
  607. if(!ctx.familyname) {
  608. name.string = NULL;
  609. if(ft2_str(1, &name)) sfn_setstr(&ctx.familyname, (char*)name.string, name.string_len); else
  610. if(ft2_str(16, &name)) sfn_setstr(&ctx.familyname, (char*)name.string, name.string_len);
  611. }
  612. /* fallback */
  613. if(!ctx.familyname) sfn_setstr(&ctx.familyname, face->family_name, 0);
  614. /* subfamily name */
  615. if(!ctx.subname) {
  616. name.string = NULL;
  617. if(ft2_str(2, &name)) sfn_setstr(&ctx.subname, (char*)name.string, name.string_len); else
  618. if(ft2_str(17, &name)) sfn_setstr(&ctx.subname, (char*)name.string, name.string_len);
  619. }
  620. /* fallback */
  621. if(!ctx.subname) sfn_setstr(&ctx.subname, face->style_name, 0);
  622. /* version / revision */
  623. name.string = NULL;
  624. if(!ctx.revision && ft2_str(5, &name)) sfn_setstr(&ctx.revision, (char*)name.string, name.string_len);
  625. /* manufacturer */
  626. if(!ctx.manufacturer) {
  627. name.string = NULL;
  628. if(ft2_str(8, &name)) sfn_setstr(&ctx.manufacturer, (char*)name.string, name.string_len); else
  629. if(ft2_str(9, &name)) sfn_setstr(&ctx.manufacturer, (char*)name.string, name.string_len);
  630. }
  631. /* copyright */
  632. if(!ctx.license) {
  633. name.string = NULL;
  634. if(ft2_str(13, &name)) sfn_setstr(&ctx.license, (char*)name.string, name.string_len); else
  635. if(ft2_str(0, &name)) sfn_setstr(&ctx.license, (char*)name.string, name.string_len); else
  636. if(ft2_str(7, &name)) sfn_setstr(&ctx.license, (char*)name.string, name.string_len);
  637. }
  638. FT_Done_Face(face); face = NULL;
  639. FT_Done_FreeType(ft); ft = NULL;
  640. }
  641. #endif
  642. #endif