pbm.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <stdint.h>
  5. #include <assert.h>
  6. #define STR_MAX_LEN 1024
  7. struct _pbm_struct
  8. {
  9. uint16_t w;
  10. uint16_t h;
  11. uint16_t width_in_bytes;
  12. uint8_t *bitmap;
  13. char line[STR_MAX_LEN];
  14. uint8_t is_ascii;
  15. FILE *fp;
  16. };
  17. typedef struct _pbm_struct pbm_t;
  18. void pbm_SetPixel(pbm_t *pbm, uint16_t x, uint16_t y, uint8_t value)
  19. {
  20. uint8_t *p;
  21. uint8_t mask;
  22. p = pbm->bitmap;
  23. p += pbm->width_in_bytes * y;
  24. p += x/8;
  25. mask = 1<<(x&7);
  26. if ( value == 0 )
  27. *p &= ~mask;
  28. else
  29. *p |= mask;
  30. }
  31. uint8_t pbm_GetPixel(pbm_t *pbm, uint16_t x, uint16_t y)
  32. {
  33. uint8_t *p;
  34. uint8_t mask;
  35. p = pbm->bitmap;
  36. p += pbm->width_in_bytes * y;
  37. p += x/8;
  38. mask = 1<<(x&7);
  39. if ( (*p & mask) != 0 )
  40. return 1;
  41. return 0;
  42. }
  43. /*=================================================*/
  44. void skip_space(const char **s)
  45. {
  46. for(;;)
  47. {
  48. if ( **s == '\0' )
  49. return;
  50. if ( **s > 32 )
  51. return;
  52. (*s)++;
  53. }
  54. }
  55. int get_int(const char **s)
  56. {
  57. int x = 0;
  58. for(;;)
  59. {
  60. if ( **s < '0' || **s > '9' )
  61. break;
  62. x = x*10 + (((int)**s) - '0' );
  63. (*s)++;
  64. }
  65. skip_space(s);
  66. return x;
  67. }
  68. const char *get_identifier(const char **s)
  69. {
  70. static char buf[STR_MAX_LEN];
  71. int i = 0;
  72. for(;;)
  73. {
  74. if ( **s <=' ' )
  75. break;
  76. if ( i+2 < STR_MAX_LEN )
  77. {
  78. buf[i] = **s;
  79. i++;
  80. }
  81. (*s)++;
  82. }
  83. buf[i] = '\0';
  84. skip_space(s);
  85. return buf;
  86. }
  87. /*=================================================*/
  88. int pbm_ReadLine(pbm_t *pbm)
  89. {
  90. if ( fgets(pbm->line, STR_MAX_LEN, pbm->fp) == NULL )
  91. return 0;
  92. return 1;
  93. }
  94. int pbm_ReadFP(pbm_t *pbm)
  95. {
  96. const char *s = pbm->line;
  97. if ( pbm_ReadLine(pbm) == 0 )
  98. return 0;
  99. if ( strncmp(pbm->line, "P1", 2) == 0 )
  100. pbm->is_ascii = 1;
  101. else if ( strncmp(pbm->line, "P4", 2) == 0 )
  102. pbm->is_ascii = 0;
  103. else
  104. return 0;
  105. for(;;)
  106. {
  107. if ( pbm_ReadLine(pbm) == 0 )
  108. return 0;
  109. if ( pbm->line[0] != '#' )
  110. break;
  111. }
  112. skip_space(&s);
  113. pbm->w = get_int(&s);
  114. pbm->h = get_int(&s);
  115. assert( pbm->w < 10000);
  116. assert( pbm->h < 10000);
  117. pbm->width_in_bytes = (pbm->w+7)/8;
  118. pbm->bitmap = (uint8_t *)malloc(pbm->width_in_bytes * pbm->h);
  119. assert( pbm->bitmap != NULL );
  120. if ( pbm->is_ascii != 0 )
  121. {
  122. uint16_t x,y;
  123. int c;
  124. x = 0;
  125. y = 0;
  126. for(;;)
  127. {
  128. c = fgetc(pbm->fp);
  129. if ( c == EOF )
  130. break;
  131. if ( c == '1' || c == '0' )
  132. {
  133. pbm_SetPixel(pbm, x, y, c == '1');
  134. x++;
  135. if ( x >= pbm->w )
  136. {
  137. y++;
  138. x = 0;
  139. }
  140. }
  141. }
  142. }
  143. return 1;
  144. }
  145. uint8_t pbm_GetByte(pbm_t *pbm, uint16_t x, uint16_t y, uint8_t cnt)
  146. {
  147. uint8_t b;
  148. uint8_t i;
  149. b = 0;
  150. for( i = 0; i < cnt; i++ )
  151. {
  152. if ( pbm_GetPixel(pbm, x+i, y) != 0 )
  153. {
  154. b |= 1<<(7-i);
  155. }
  156. }
  157. return b;
  158. }
  159. uint8_t *pbm_GetBytes(pbm_t *pbm, uint16_t x, uint16_t y, uint16_t cnt)
  160. {
  161. uint8_t i;
  162. static uint8_t buf[1024];
  163. i = 0;
  164. while( cnt > 8 )
  165. {
  166. buf[i] = pbm_GetByte(pbm, x, y, 8);
  167. x+=8;
  168. i++;
  169. cnt -= 8;
  170. }
  171. buf[i] = pbm_GetByte(pbm, x, y, cnt);
  172. return buf;
  173. }
  174. void pbm_WriteHexBytes(pbm_t *pbm, uint16_t x, uint16_t y, uint16_t cnt, FILE *fp)
  175. {
  176. uint8_t i;
  177. uint8_t *p;
  178. p = pbm_GetBytes(pbm, x, y, cnt);
  179. cnt = (cnt+7)/8;
  180. for( i = 0; i < cnt; i++)
  181. fprintf(fp, "%02x", p[i]);
  182. fprintf(fp, "\n");
  183. }
  184. void pbm_WriteHexBitmap(pbm_t *pbm, uint16_t x, uint16_t y, uint16_t w, uint16_t h, FILE *fp)
  185. {
  186. uint16_t i;
  187. for( i = 0; i < h; i++ )
  188. {
  189. pbm_WriteHexBytes(pbm, x, y+i, w, fp);
  190. }
  191. }
  192. void pbm_WriteGlyph(pbm_t *pbm, uint16_t e, uint16_t x, uint16_t y, uint16_t w, uint16_t h, FILE *fp)
  193. {
  194. fprintf(fp, "STARTCHAR %u\n", e);
  195. fprintf(fp, "ENCODING %u\n", e);
  196. fprintf(fp, "SWIDTH %u 0\n", w*72); // ???
  197. fprintf(fp, "DWIDTH %u 0\n", w);
  198. fprintf(fp, "BBX %u %u 0 0\n", w, h);
  199. fprintf(fp, "BITMAP\n");
  200. pbm_WriteHexBitmap(pbm, x, y, w, h, fp);
  201. fprintf(fp, "ENDCHAR\n");
  202. }
  203. void pbm_WriteFontStart(FILE *fp, const char *s)
  204. {
  205. fprintf(fp, "STARTFONT 2.1\n");
  206. fprintf(fp, "FONT %s\n", s);
  207. fprintf(fp, "SIZE 16 75 75\n");
  208. fprintf(fp, "FONTBOUNDINGBOX 16 16 0 0\n");
  209. fprintf(fp, "STARTPROPERTIES 3\n");
  210. fprintf(fp, "COPYRIGHT \"CC-BY-3.0\"\n");
  211. fprintf(fp, "FONT_ASCENT 0\n");
  212. fprintf(fp, "FONT_DESCENT 0\n");
  213. fprintf(fp, "ENDPROPERTIES\n");
  214. fprintf(fp, "CHARS 235\n"); // hard coded :-(
  215. }
  216. void pbm_WriteFontEnd(FILE *fp)
  217. {
  218. fprintf(fp, "ENDFONT\n");
  219. }
  220. void pbm_Show(pbm_t *pbm)
  221. {
  222. uint16_t x, y;
  223. for( y = 0; y < pbm->h; y++ )
  224. {
  225. for( x = 0; x < pbm->w; x++ )
  226. {
  227. printf("%c", pbm_GetPixel(pbm, x, y) == 0 ? '0' : '1');
  228. }
  229. puts("");
  230. pbm_WriteHexBytes(pbm, 0, y, pbm->w, stdout);
  231. }
  232. }
  233. int pbm_ReadFilename(pbm_t *pbm, const char *name)
  234. {
  235. pbm->fp = fopen(name, "r");
  236. pbm->is_ascii = 0;
  237. if ( pbm->fp == NULL )
  238. return 0;
  239. pbm_ReadFP(pbm);
  240. fclose(pbm->fp);
  241. return 1;
  242. }
  243. /*=================================================*/
  244. void outline(pbm_t *pbm, FILE *fp, uint16_t e, uint16_t y, uint16_t cnt)
  245. {
  246. uint16_t i;
  247. for(i = 0; i < cnt; i++ )
  248. pbm_WriteGlyph(pbm, i+e, 32+i*16, y, 16, 16, fp);
  249. }
  250. void out(pbm_t *pbm, FILE *fp, const char *s)
  251. {
  252. uint16_t e;
  253. pbm_WriteFontStart(fp, s);
  254. outline(pbm, fp, 0x01, 320, 8); /* The Unliving */
  255. outline(pbm, fp, 0x10, 496, 12); /* Traps&Devices */
  256. outline(pbm, fp, 0x1c, 272, 4); /* Trollkind */
  257. outline(pbm, fp, 0x20, 96-32, 1); /* Space */
  258. outline(pbm, fp, 0x21, 784, 15); /* Magic */
  259. e = 0x030;
  260. outline(pbm, fp, e, 96, 13); /* Characters */
  261. e+= 13;
  262. outline(pbm, fp, e, 112, 13); /* Characters */
  263. e+= 13;
  264. outline(pbm, fp, e, 128, 7); /* Characters */
  265. e+= 7;
  266. outline(pbm, fp, e, 224, 13); /* Fauna */
  267. e+= 13;
  268. outline(pbm, fp, e, 368, 8); /* Creatures */
  269. e+= 8;
  270. outline(pbm, fp, e, 416, 16); /* Building */
  271. e+= 16;
  272. outline(pbm, fp, e, 432, 7); /* Building */
  273. e+= 7;
  274. outline(pbm, fp, e, 448, 12); /* Building */
  275. e+= 12;
  276. outline(pbm, fp, e, 544, 13); /* Outerworld */
  277. e+= 13;
  278. outline(pbm, fp, e, 592, 16); /* Exploration */
  279. e+= 16;
  280. outline(pbm, fp, e, 608, 5); /* Exploration */
  281. e+= 5;
  282. outline(pbm, fp, e, 656, 16); /* Food&Drink */
  283. e+= 16;
  284. outline(pbm, fp, e, 672, 6); /* Food&Drink */
  285. e+= 6;
  286. outline(pbm, fp, e, 720, 16); /* Outfit */
  287. e+= 16;
  288. outline(pbm, fp, e, 736, 11); /* Outfit */
  289. e+= 11;
  290. //outline(pbm, fp, 400, 832, 6); /* Music */
  291. outline(pbm, fp, e, 880, 16); /* Symbols */
  292. e+= 16;
  293. outline(pbm, fp, e, 896, 7); /* Symbols */
  294. e+= 7;
  295. pbm_WriteFontEnd(fp);
  296. }
  297. int main(int argc, char **argv)
  298. {
  299. pbm_t pbm;
  300. if ( argc <= 1 )
  301. {
  302. printf("%s <pbm ascii file>\n", argv[0]);
  303. }
  304. else
  305. {
  306. pbm_ReadFilename(&pbm, argv[1]);
  307. out(&pbm, stdout, argv[1]);
  308. //printf("Size: %d x %d\n", pbm.w, pbm.h);
  309. //pbm_Show(&pbm);
  310. }
  311. return 0;
  312. }