TTFFontEncoder.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. #include "Base.h"
  2. #include "TTFFontEncoder.h"
  3. #include "GPBFile.h"
  4. #include "StringUtil.h"
  5. namespace gameplay
  6. {
  7. static void drawBitmap(unsigned char* dstBitmap, int x, int y, int dstWidth, unsigned char* srcBitmap, int srcWidth, int srcHeight)
  8. {
  9. // offset dst bitmap by x,y.
  10. dstBitmap += (x + (y * dstWidth));
  11. for (int i = 0; i < srcHeight; ++i)
  12. {
  13. memcpy(dstBitmap, (const void*)srcBitmap, srcWidth);
  14. srcBitmap += srcWidth;
  15. dstBitmap += dstWidth;
  16. }
  17. }
  18. static void writeUint(FILE* fp, unsigned int i)
  19. {
  20. fwrite(&i, sizeof(unsigned int), 1, fp);
  21. }
  22. static void writeString(FILE* fp, const char* str)
  23. {
  24. unsigned int len = strlen(str);
  25. fwrite(&len, sizeof(unsigned int), 1, fp);
  26. if (len > 0)
  27. {
  28. fwrite(str, 1, len, fp);
  29. }
  30. }
  31. unsigned char* createDistanceFields(unsigned char* img, unsigned int width, unsigned int height)
  32. {
  33. short* xDistance = (short*)malloc(width * height * sizeof(short));
  34. short* yDistance = (short*)malloc(width * height * sizeof(short));
  35. double* gx = (double*)calloc(width * height, sizeof(double));
  36. double* gy = (double*)calloc(width * height, sizeof(double));
  37. double* data = (double*)calloc(width * height, sizeof(double));
  38. double* outside = (double*)calloc(width * height, sizeof(double));
  39. double* inside = (double*)calloc(width * height, sizeof(double));
  40. unsigned int i;
  41. // Convert img into double (data)
  42. double imgMin = 255;
  43. double imgMax = -255;
  44. for (i = 0; i < width * height; ++i)
  45. {
  46. double v = img[i];
  47. data[i] = v;
  48. if (v > imgMax)
  49. imgMax = v;
  50. if (v < imgMin)
  51. imgMin = v;
  52. }
  53. // Rescale image levels between 0 and 1
  54. for (i = 0; i < width * height; ++i)
  55. {
  56. data[i] = (img[i] - imgMin) / imgMax;
  57. }
  58. // Compute outside = edtaa3(bitmap); % Transform background (0's)
  59. computegradient(data, width, height, gx, gy);
  60. edtaa3(data, gx, gy, height, width, xDistance, yDistance, outside);
  61. for (i = 0; i < width * height; ++i)
  62. {
  63. if (outside[i] < 0 )
  64. outside[i] = 0.0;
  65. }
  66. // Compute inside = edtaa3(1-bitmap); % Transform foreground (1's)
  67. memset(gx, 0, sizeof(double) * width * height);
  68. memset(gy, 0, sizeof(double) * width * height);
  69. for (i = 0; i < width * height; ++i)
  70. {
  71. data[i] = 1 - data[i];
  72. }
  73. computegradient(data, width, height, gx, gy);
  74. edtaa3(data, gx, gy, height, width, xDistance, yDistance, inside);
  75. for (i = 0; i < width * height; ++i)
  76. {
  77. if( inside[i] < 0 )
  78. inside[i] = 0.0;
  79. }
  80. // distmap = outside - inside; % Bipolar distance field
  81. unsigned char* out = (unsigned char*)malloc(sizeof(unsigned char) * width * height);
  82. for (i = 0; i < width * height; ++i)
  83. {
  84. outside[i] -= inside[i];
  85. outside[i] = 128 + outside[i] * 16;
  86. if (outside[i] < 0)
  87. outside[i] = 0;
  88. if (outside[i] > 255)
  89. outside[i] = 255;
  90. out[i] = 255 - (unsigned char) outside[i];
  91. }
  92. free(xDistance);
  93. free(yDistance);
  94. free(gx);
  95. free(gy);
  96. free(data);
  97. free(outside);
  98. free(inside);
  99. return out;
  100. }
  101. // Stores a single genreated font size to be written into the GPB
  102. struct FontData
  103. {
  104. // Array of glyphs for a font
  105. TTFGlyph glyphArray[END_INDEX - START_INDEX];
  106. // Stores final height of a row required to render all glyphs
  107. int fontSize;
  108. // Actual size of the underlying glyphs (may be different from fontSize)
  109. int glyphSize;
  110. // Font texture
  111. unsigned char* imageBuffer;
  112. unsigned int imageWidth;
  113. unsigned int imageHeight;
  114. FontData() : fontSize(0), glyphSize(0), imageBuffer(NULL), imageWidth(0), imageHeight(0)
  115. {
  116. }
  117. ~FontData()
  118. {
  119. if (imageBuffer)
  120. free(imageBuffer);
  121. }
  122. };
  123. int writeFont(const char* inFilePath, const char* outFilePath, std::vector<unsigned int>& fontSizes, const char* id, bool fontpreview = false, Font::FontFormat fontFormat = Font::BITMAP)
  124. {
  125. // Initialize freetype library.
  126. FT_Library library;
  127. FT_Error error = FT_Init_FreeType(&library);
  128. if (error)
  129. {
  130. LOG(1, "FT_Init_FreeType error: %d \n", error);
  131. return -1;
  132. }
  133. // Initialize font face.
  134. FT_Face face;
  135. error = FT_New_Face(library, inFilePath, 0, &face);
  136. if (error)
  137. {
  138. LOG(1, "FT_New_Face error: %d \n", error);
  139. return -1;
  140. }
  141. std::vector<FontData*> fonts;
  142. for (size_t fontIndex = 0, count = fontSizes.size(); fontIndex < count; ++fontIndex)
  143. {
  144. unsigned int fontSize = fontSizes[fontIndex];
  145. FontData* font = new FontData();
  146. font->fontSize = fontSize;
  147. TTFGlyph* glyphArray = font->glyphArray;
  148. int rowSize = 0;
  149. int glyphSize = 0;
  150. int actualfontHeight = 0;
  151. FT_GlyphSlot slot = NULL;
  152. FT_Int32 loadFlags = FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT;
  153. // We want to generate fonts that fit exactly the requested pixels size.
  154. // Since free type (due to modern fonts) does not directly correlate requested
  155. // size to glyph size, we'll brute-force attempt to set the largest font size
  156. // possible that will fit within the requested pixel size.
  157. for (unsigned int requestedSize = fontSize; requestedSize > 0; --requestedSize)
  158. {
  159. // Set the pixel size.
  160. error = FT_Set_Char_Size( face, 0, requestedSize * 64, 0, 0 );
  161. if (error)
  162. {
  163. LOG(1, "FT_Set_Pixel_Sizes error: %d \n", error);
  164. return -1;
  165. }
  166. // Save glyph information (slot contains the actual glyph bitmap).
  167. slot = face->glyph;
  168. rowSize = 0;
  169. glyphSize = 0;
  170. actualfontHeight = 0;
  171. // Find the width of the image.
  172. for (unsigned char ascii = START_INDEX; ascii < END_INDEX; ++ascii)
  173. {
  174. // Load glyph image into the slot (erase previous one)
  175. error = FT_Load_Char(face, ascii, loadFlags);
  176. if (error)
  177. {
  178. LOG(1, "FT_Load_Char error : %d \n", error);
  179. }
  180. int bitmapRows = slot->bitmap.rows;
  181. actualfontHeight = (actualfontHeight < bitmapRows) ? bitmapRows : actualfontHeight;
  182. if (slot->bitmap.rows > slot->bitmap_top)
  183. {
  184. bitmapRows += (slot->bitmap.rows - slot->bitmap_top);
  185. }
  186. rowSize = (rowSize < bitmapRows) ? bitmapRows : rowSize;
  187. }
  188. // Have we found a pixel size that fits?
  189. if (rowSize <= (int)fontSize)
  190. {
  191. glyphSize = rowSize;
  192. rowSize = fontSize;
  193. break;
  194. }
  195. }
  196. if (slot == NULL || glyphSize == 0)
  197. {
  198. LOG(1, "Cannot generate a font of the requested size: %d\n", fontSize);
  199. return -1;
  200. }
  201. // Include padding in the rowSize.
  202. rowSize += GLYPH_PADDING;
  203. // Initialize with padding.
  204. int penX = 0;
  205. int penY = 0;
  206. int row = 0;
  207. double powerOf2 = 2;
  208. unsigned int imageWidth = 0;
  209. unsigned int imageHeight = 0;
  210. bool textureSizeFound = false;
  211. int advance;
  212. int i;
  213. while (textureSizeFound == false)
  214. {
  215. imageWidth = (unsigned int)pow(2.0, powerOf2);
  216. imageHeight = (unsigned int)pow(2.0, powerOf2);
  217. penX = 0;
  218. penY = 0;
  219. row = 0;
  220. // Find out the squared texture size that would fit all the require font glyphs.
  221. i = 0;
  222. for (unsigned char ascii = START_INDEX; ascii < END_INDEX; ++ascii)
  223. {
  224. // Load glyph image into the slot (erase the previous one).
  225. error = FT_Load_Char(face, ascii, loadFlags);
  226. if (error)
  227. {
  228. LOG(1, "FT_Load_Char error : %d \n", error);
  229. }
  230. // Glyph image.
  231. int glyphWidth = slot->bitmap.pitch;
  232. int glyphHeight = slot->bitmap.rows;
  233. advance = glyphWidth + GLYPH_PADDING;
  234. // If we reach the end of the image wrap aroud to the next row.
  235. if ((penX + advance) > (int)imageWidth)
  236. {
  237. penX = 0;
  238. row += 1;
  239. penY = row * rowSize;
  240. if (penY + rowSize > (int)imageHeight)
  241. {
  242. powerOf2++;
  243. break;
  244. }
  245. }
  246. // penY should include the glyph offsets.
  247. penY += (actualfontHeight - glyphHeight) + (glyphHeight - slot->bitmap_top);
  248. // Set the pen position for the next glyph
  249. penX += advance; // Move X to next glyph position
  250. // Move Y back to the top of the row.
  251. penY = row * rowSize;
  252. if (ascii == (END_INDEX - 1))
  253. {
  254. textureSizeFound = true;
  255. }
  256. i++;
  257. }
  258. }
  259. // Try further to find a tighter texture size.
  260. powerOf2 = 1;
  261. for (;;)
  262. {
  263. if ((penY + rowSize) >= pow(2.0, powerOf2))
  264. {
  265. powerOf2++;
  266. }
  267. else
  268. {
  269. imageHeight = (int)pow(2.0, powerOf2);
  270. break;
  271. }
  272. }
  273. // Allocate temporary image buffer to draw the glyphs into.
  274. unsigned char* imageBuffer = (unsigned char*)malloc(imageWidth * imageHeight);
  275. memset(imageBuffer, 0, imageWidth * imageHeight);
  276. penX = 0;
  277. penY = 0;
  278. row = 0;
  279. i = 0;
  280. for (unsigned char ascii = START_INDEX; ascii < END_INDEX; ++ascii)
  281. {
  282. // Load glyph image into the slot (erase the previous one).
  283. error = FT_Load_Char(face, ascii, loadFlags);
  284. if (error)
  285. {
  286. LOG(1, "FT_Load_Char error : %d \n", error);
  287. }
  288. // Glyph image.
  289. unsigned char* glyphBuffer = slot->bitmap.buffer;
  290. int glyphWidth = slot->bitmap.pitch;
  291. int glyphHeight = slot->bitmap.rows;
  292. advance = glyphWidth + GLYPH_PADDING;
  293. // If we reach the end of the image wrap aroud to the next row.
  294. if ((penX + advance) > (int)imageWidth)
  295. {
  296. penX = 0;
  297. row += 1;
  298. penY = row * rowSize;
  299. if (penY + rowSize > (int)imageHeight)
  300. {
  301. free(imageBuffer);
  302. LOG(1, "Image size exceeded!");
  303. return -1;
  304. }
  305. }
  306. // penY should include the glyph offsets.
  307. penY += (actualfontHeight - glyphHeight) + (glyphHeight - slot->bitmap_top);
  308. // Draw the glyph to the bitmap with a one pixel padding.
  309. drawBitmap(imageBuffer, penX, penY, imageWidth, glyphBuffer, glyphWidth, glyphHeight);
  310. // Move Y back to the top of the row.
  311. penY = row * rowSize;
  312. glyphArray[i].index = ascii;
  313. glyphArray[i].width = advance - GLYPH_PADDING;
  314. // Generate UV coords.
  315. glyphArray[i].uvCoords[0] = (float)penX / (float)imageWidth;
  316. glyphArray[i].uvCoords[1] = (float)penY / (float)imageHeight;
  317. glyphArray[i].uvCoords[2] = (float)(penX + advance - GLYPH_PADDING) / (float)imageWidth;
  318. glyphArray[i].uvCoords[3] = (float)(penY + rowSize - GLYPH_PADDING) / (float)imageHeight;
  319. // Set the pen position for the next glyph
  320. penX += advance;
  321. i++;
  322. }
  323. font->glyphSize = glyphSize;
  324. font->imageBuffer = imageBuffer;
  325. font->imageWidth = imageWidth;
  326. font->imageHeight = imageHeight;
  327. fonts.push_back(font);
  328. }
  329. // File header and version.
  330. FILE *gpbFp = fopen(outFilePath, "wb");
  331. char fileHeader[9] = {'\xAB', 'G', 'P', 'B', '\xBB', '\r', '\n', '\x1A', '\n'};
  332. fwrite(fileHeader, sizeof(char), 9, gpbFp);
  333. fwrite(gameplay::GPB_VERSION, sizeof(char), 2, gpbFp);
  334. // Write Ref table (for a single font)
  335. writeUint(gpbFp, 1); // Ref[] count
  336. writeString(gpbFp, id); // Ref id
  337. writeUint(gpbFp, 128); // Ref type
  338. writeUint(gpbFp, ftell(gpbFp) + 4); // Ref offset (current pos + 4 bytes)
  339. // Family name.
  340. writeString(gpbFp, face->family_name);
  341. // Style.
  342. // TODO: Switch based on TTF style name and write appropriate font style unsigned int for now just hardcoding to 0 = PLAIN.
  343. writeUint(gpbFp, 0);
  344. // Number of included font sizes (GPB version 1.3+)
  345. writeUint(gpbFp, (unsigned int)fonts.size());
  346. for (size_t i = 0, count = fonts.size(); i < count; ++i)
  347. {
  348. FontData* font = fonts[i];
  349. // Font size (pixels).
  350. writeUint(gpbFp, font->fontSize);
  351. // Character set. TODO: Empty for now
  352. writeString(gpbFp, "");
  353. // Glyphs.
  354. unsigned int glyphSetSize = END_INDEX - START_INDEX;
  355. writeUint(gpbFp, glyphSetSize);
  356. fwrite(&font->glyphArray, sizeof(TTFGlyph), glyphSetSize, gpbFp);
  357. // Image dimensions
  358. unsigned int imageSize = font->imageWidth * font->imageHeight;
  359. writeUint(gpbFp, font->imageWidth);
  360. writeUint(gpbFp, font->imageHeight);
  361. writeUint(gpbFp, imageSize);
  362. FILE* previewFp = NULL;
  363. std::string pgmFilePath;
  364. if (fontpreview)
  365. {
  366. // Save out a pgm monochome image file for preview
  367. std::ostringstream pgmFilePathStream;
  368. pgmFilePathStream << getFilenameNoExt(outFilePath) << "-" << font->fontSize << ".pgm";
  369. pgmFilePath = pgmFilePathStream.str();
  370. previewFp = fopen(pgmFilePath.c_str(), "wb");
  371. fprintf(previewFp, "P5 %u %u 255\n", font->imageWidth, font->imageHeight);
  372. }
  373. if (fontFormat == Font::DISTANCE_FIELD)
  374. {
  375. // Flip height and width since the distance field map generator is column-wise.
  376. unsigned char* distanceFieldBuffer = createDistanceFields(font->imageBuffer, font->imageHeight, font->imageWidth);
  377. fwrite(distanceFieldBuffer, sizeof(unsigned char), imageSize, gpbFp);
  378. writeUint(gpbFp, Font::DISTANCE_FIELD);
  379. if (previewFp)
  380. {
  381. fwrite((const char*)distanceFieldBuffer, sizeof(unsigned char), imageSize, previewFp);
  382. fclose(previewFp);
  383. }
  384. free(distanceFieldBuffer);
  385. }
  386. else
  387. {
  388. fwrite(font->imageBuffer, sizeof(unsigned char), imageSize, gpbFp);
  389. writeUint(gpbFp, Font::BITMAP);
  390. if (previewFp)
  391. {
  392. fwrite((const char*)font->imageBuffer, sizeof(unsigned char), font->imageWidth * font->imageHeight, previewFp);
  393. fclose(previewFp);
  394. }
  395. }
  396. if (previewFp)
  397. {
  398. fclose(previewFp);
  399. LOG(1, "%s.pgm preview image created successfully. \n", getBaseName(pgmFilePath).c_str());
  400. }
  401. }
  402. // Close file.
  403. fclose(gpbFp);
  404. LOG(1, "%s.gpb created successfully. \n", getBaseName(outFilePath).c_str());
  405. for (size_t i = 0, count = fonts.size(); i < count; ++i)
  406. {
  407. delete fonts[i];
  408. }
  409. FT_Done_Face(face);
  410. FT_Done_FreeType(library);
  411. return 0;
  412. }
  413. }