img2term.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. #include <assert.h>
  2. #include <stdio.h>
  3. #include <math.h>
  4. #define STB_IMAGE_IMPLEMENTATION
  5. #include "stb_image.h"
  6. #define STB_IMAGE_RESIZE_IMPLEMENTATION
  7. #include "stb_image_resize.h"
  8. #define DEFAULT_WIDTH 32
  9. int hsl256[][3] = {
  10. {0, 0, 0},
  11. {0, 100, 25},
  12. {120, 100, 25},
  13. {60, 100, 25},
  14. {240, 100, 25},
  15. {300, 100, 25},
  16. {180, 100, 25},
  17. {0, 0, 75},
  18. {0, 0, 50},
  19. {0, 100, 50},
  20. {120, 100, 50},
  21. {60, 100, 50},
  22. {240, 100, 50},
  23. {300, 100, 50},
  24. {180, 100, 50},
  25. {0, 0, 100},
  26. {0, 0, 0},
  27. {240, 99, 18},
  28. {240, 100, 26},
  29. {240, 100, 34},
  30. {240, 100, 42},
  31. {240, 100, 50},
  32. {120, 99, 18},
  33. {180, 99, 18},
  34. {197, 100, 26},
  35. {207, 100, 34},
  36. {213, 100, 42},
  37. {217, 100, 50},
  38. {120, 100, 26},
  39. {162, 100, 26},
  40. {180, 100, 26},
  41. {193, 100, 34},
  42. {202, 100, 42},
  43. {208, 100, 50},
  44. {120, 100, 34},
  45. {152, 100, 34},
  46. {166, 100, 34},
  47. {180, 100, 34},
  48. {191, 100, 42},
  49. {198, 100, 50},
  50. {120, 100, 42},
  51. {146, 100, 42},
  52. {157, 100, 42},
  53. {168, 100, 42},
  54. {180, 100, 42},
  55. {189, 100, 50},
  56. {120, 100, 50},
  57. {142, 100, 50},
  58. {151, 100, 50},
  59. {161, 100, 50},
  60. {170, 100, 50},
  61. {180, 100, 50},
  62. {0, 99, 18},
  63. {300, 99, 18},
  64. {282, 100, 26},
  65. {272, 100, 34},
  66. {266, 100, 42},
  67. {262, 100, 50},
  68. {60, 99, 18},
  69. {0, 0, 37},
  70. {240, 17, 45},
  71. {240, 33, 52},
  72. {240, 60, 60},
  73. {240, 100, 68},
  74. {77, 100, 26},
  75. {120, 17, 45},
  76. {180, 17, 45},
  77. {210, 33, 52},
  78. {220, 60, 60},
  79. {225, 100, 68},
  80. {87, 100, 34},
  81. {120, 33, 52},
  82. {150, 33, 52},
  83. {180, 33, 52},
  84. {200, 60, 60},
  85. {210, 100, 68},
  86. {93, 100, 42},
  87. {120, 60, 60},
  88. {140, 60, 60},
  89. {160, 60, 60},
  90. {180, 60, 60},
  91. {195, 100, 68},
  92. {97, 100, 50},
  93. {120, 100, 68},
  94. {135, 100, 68},
  95. {150, 100, 68},
  96. {165, 100, 68},
  97. {180, 100, 68},
  98. {0, 100, 26},
  99. {317, 100, 26},
  100. {300, 100, 26},
  101. {286, 100, 34},
  102. {277, 100, 42},
  103. {271, 100, 50},
  104. {42, 100, 26},
  105. {0, 17, 45},
  106. {300, 17, 45},
  107. {270, 33, 52},
  108. {260, 60, 60},
  109. {255, 100, 68},
  110. {60, 100, 26},
  111. {60, 17, 45},
  112. {0, 0, 52},
  113. {240, 20, 60},
  114. {240, 50, 68},
  115. {240, 100, 76},
  116. {73, 100, 34},
  117. {90, 33, 52},
  118. {120, 20, 60},
  119. {180, 20, 60},
  120. {210, 50, 68},
  121. {220, 100, 76},
  122. {82, 100, 42},
  123. {100, 60, 60},
  124. {120, 50, 68},
  125. {150, 50, 68},
  126. {180, 50, 68},
  127. {200, 100, 76},
  128. {88, 100, 50},
  129. {105, 100, 68},
  130. {120, 100, 76},
  131. {140, 100, 76},
  132. {160, 100, 76},
  133. {180, 100, 76},
  134. {0, 100, 34},
  135. {327, 100, 34},
  136. {313, 100, 34},
  137. {300, 100, 34},
  138. {288, 100, 42},
  139. {281, 100, 50},
  140. {32, 100, 34},
  141. {0, 33, 52},
  142. {330, 33, 52},
  143. {300, 33, 52},
  144. {280, 60, 60},
  145. {270, 100, 68},
  146. {46, 100, 34},
  147. {30, 33, 52},
  148. {0, 20, 60},
  149. {300, 20, 60},
  150. {270, 50, 68},
  151. {260, 100, 76},
  152. {60, 100, 34},
  153. {60, 33, 52},
  154. {60, 20, 60},
  155. {0, 0, 68},
  156. {240, 33, 76},
  157. {240, 100, 84},
  158. {71, 100, 42},
  159. {80, 60, 60},
  160. {90, 50, 68},
  161. {120, 33, 76},
  162. {180, 33, 76},
  163. {210, 100, 84},
  164. {78, 100, 50},
  165. {90, 100, 68},
  166. {100, 100, 76},
  167. {120, 100, 84},
  168. {150, 100, 84},
  169. {180, 100, 84},
  170. {0, 100, 42},
  171. {333, 100, 42},
  172. {322, 100, 42},
  173. {311, 100, 42},
  174. {300, 100, 42},
  175. {290, 100, 50},
  176. {26, 100, 42},
  177. {0, 60, 60},
  178. {340, 60, 60},
  179. {320, 60, 60},
  180. {300, 60, 60},
  181. {285, 100, 68},
  182. {37, 100, 42},
  183. {20, 60, 60},
  184. {0, 50, 68},
  185. {330, 50, 68},
  186. {300, 50, 68},
  187. {280, 100, 76},
  188. {48, 100, 42},
  189. {40, 60, 60},
  190. {30, 50, 68},
  191. {0, 33, 76},
  192. {300, 33, 76},
  193. {270, 100, 84},
  194. {60, 100, 42},
  195. {60, 60, 60},
  196. {60, 50, 68},
  197. {60, 33, 76},
  198. {0, 0, 84},
  199. {240, 100, 92},
  200. {69, 100, 50},
  201. {75, 100, 68},
  202. {80, 100, 76},
  203. {90, 100, 84},
  204. {120, 100, 92},
  205. {180, 100, 92},
  206. {0, 100, 50},
  207. {337, 100, 50},
  208. {328, 100, 50},
  209. {318, 100, 50},
  210. {309, 100, 50},
  211. {300, 100, 50},
  212. {22, 100, 50},
  213. {0, 100, 68},
  214. {345, 100, 68},
  215. {330, 100, 68},
  216. {315, 100, 68},
  217. {300, 100, 68},
  218. {31, 100, 50},
  219. {15, 100, 68},
  220. {0, 100, 76},
  221. {340, 100, 76},
  222. {320, 100, 76},
  223. {300, 100, 76},
  224. {41, 100, 50},
  225. {30, 100, 68},
  226. {20, 100, 76},
  227. {0, 100, 84},
  228. {330, 100, 84},
  229. {300, 100, 84},
  230. {50, 100, 50},
  231. {45, 100, 68},
  232. {40, 100, 76},
  233. {30, 100, 84},
  234. {0, 100, 92},
  235. {300, 100, 92},
  236. {60, 100, 50},
  237. {60, 100, 68},
  238. {60, 100, 76},
  239. {60, 100, 84},
  240. {60, 100, 92},
  241. {0, 0, 100},
  242. {0, 0, 3},
  243. {0, 0, 7},
  244. {0, 0, 10},
  245. {0, 0, 14},
  246. {0, 0, 18},
  247. {0, 0, 22},
  248. {0, 0, 26},
  249. {0, 0, 30},
  250. {0, 0, 34},
  251. {0, 0, 38},
  252. {0, 0, 42},
  253. {0, 0, 46},
  254. {0, 0, 50},
  255. {0, 0, 54},
  256. {0, 0, 58},
  257. {0, 0, 61},
  258. {0, 0, 65},
  259. {0, 0, 69},
  260. {0, 0, 73},
  261. {0, 0, 77},
  262. {0, 0, 81},
  263. {0, 0, 85},
  264. {0, 0, 89},
  265. {0, 0, 93},
  266. };
  267. int rgb256[][3] = {
  268. {0,0,0},
  269. {128,0,0},
  270. {0,128,0},
  271. {128,128,0},
  272. {0,0,128},
  273. {128,0,128},
  274. {0,128,128},
  275. {192,192,192},
  276. {128,128,128},
  277. {255,0,0},
  278. {0,255,0},
  279. {255,255,0},
  280. {0,0,255},
  281. {255,0,255},
  282. {0,255,255},
  283. {255,255,255},
  284. {0,0,0},
  285. {0,0,95},
  286. {0,0,135},
  287. {0,0,175},
  288. {0,0,215},
  289. {0,0,255},
  290. {0,95,0},
  291. {0,95,95},
  292. {0,95,135},
  293. {0,95,175},
  294. {0,95,215},
  295. {0,95,255},
  296. {0,135,0},
  297. {0,135,95},
  298. {0,135,135},
  299. {0,135,175},
  300. {0,135,215},
  301. {0,135,255},
  302. {0,175,0},
  303. {0,175,95},
  304. {0,175,135},
  305. {0,175,175},
  306. {0,175,215},
  307. {0,175,255},
  308. {0,215,0},
  309. {0,215,95},
  310. {0,215,135},
  311. {0,215,175},
  312. {0,215,215},
  313. {0,215,255},
  314. {0,255,0},
  315. {0,255,95},
  316. {0,255,135},
  317. {0,255,175},
  318. {0,255,215},
  319. {0,255,255},
  320. {95,0,0},
  321. {95,0,95},
  322. {95,0,135},
  323. {95,0,175},
  324. {95,0,215},
  325. {95,0,255},
  326. {95,95,0},
  327. {95,95,95},
  328. {95,95,135},
  329. {95,95,175},
  330. {95,95,215},
  331. {95,95,255},
  332. {95,135,0},
  333. {95,135,95},
  334. {95,135,135},
  335. {95,135,175},
  336. {95,135,215},
  337. {95,135,255},
  338. {95,175,0},
  339. {95,175,95},
  340. {95,175,135},
  341. {95,175,175},
  342. {95,175,215},
  343. {95,175,255},
  344. {95,215,0},
  345. {95,215,95},
  346. {95,215,135},
  347. {95,215,175},
  348. {95,215,215},
  349. {95,215,255},
  350. {95,255,0},
  351. {95,255,95},
  352. {95,255,135},
  353. {95,255,175},
  354. {95,255,215},
  355. {95,255,255},
  356. {135,0,0},
  357. {135,0,95},
  358. {135,0,135},
  359. {135,0,175},
  360. {135,0,215},
  361. {135,0,255},
  362. {135,95,0},
  363. {135,95,95},
  364. {135,95,135},
  365. {135,95,175},
  366. {135,95,215},
  367. {135,95,255},
  368. {135,135,0},
  369. {135,135,95},
  370. {135,135,135},
  371. {135,135,175},
  372. {135,135,215},
  373. {135,135,255},
  374. {135,175,0},
  375. {135,175,95},
  376. {135,175,135},
  377. {135,175,175},
  378. {135,175,215},
  379. {135,175,255},
  380. {135,215,0},
  381. {135,215,95},
  382. {135,215,135},
  383. {135,215,175},
  384. {135,215,215},
  385. {135,215,255},
  386. {135,255,0},
  387. {135,255,95},
  388. {135,255,135},
  389. {135,255,175},
  390. {135,255,215},
  391. {135,255,255},
  392. {175,0,0},
  393. {175,0,95},
  394. {175,0,135},
  395. {175,0,175},
  396. {175,0,215},
  397. {175,0,255},
  398. {175,95,0},
  399. {175,95,95},
  400. {175,95,135},
  401. {175,95,175},
  402. {175,95,215},
  403. {175,95,255},
  404. {175,135,0},
  405. {175,135,95},
  406. {175,135,135},
  407. {175,135,175},
  408. {175,135,215},
  409. {175,135,255},
  410. {175,175,0},
  411. {175,175,95},
  412. {175,175,135},
  413. {175,175,175},
  414. {175,175,215},
  415. {175,175,255},
  416. {175,215,0},
  417. {175,215,95},
  418. {175,215,135},
  419. {175,215,175},
  420. {175,215,215},
  421. {175,215,255},
  422. {175,255,0},
  423. {175,255,95},
  424. {175,255,135},
  425. {175,255,175},
  426. {175,255,215},
  427. {175,255,255},
  428. {215,0,0},
  429. {215,0,95},
  430. {215,0,135},
  431. {215,0,175},
  432. {215,0,215},
  433. {215,0,255},
  434. {215,95,0},
  435. {215,95,95},
  436. {215,95,135},
  437. {215,95,175},
  438. {215,95,215},
  439. {215,95,255},
  440. {215,135,0},
  441. {215,135,95},
  442. {215,135,135},
  443. {215,135,175},
  444. {215,135,215},
  445. {215,135,255},
  446. {215,175,0},
  447. {215,175,95},
  448. {215,175,135},
  449. {215,175,175},
  450. {215,175,215},
  451. {215,175,255},
  452. {215,215,0},
  453. {215,215,95},
  454. {215,215,135},
  455. {215,215,175},
  456. {215,215,215},
  457. {215,215,255},
  458. {215,255,0},
  459. {215,255,95},
  460. {215,255,135},
  461. {215,255,175},
  462. {215,255,215},
  463. {215,255,255},
  464. {255,0,0},
  465. {255,0,95},
  466. {255,0,135},
  467. {255,0,175},
  468. {255,0,215},
  469. {255,0,255},
  470. {255,95,0},
  471. {255,95,95},
  472. {255,95,135},
  473. {255,95,175},
  474. {255,95,215},
  475. {255,95,255},
  476. {255,135,0},
  477. {255,135,95},
  478. {255,135,135},
  479. {255,135,175},
  480. {255,135,215},
  481. {255,135,255},
  482. {255,175,0},
  483. {255,175,95},
  484. {255,175,135},
  485. {255,175,175},
  486. {255,175,215},
  487. {255,175,255},
  488. {255,215,0},
  489. {255,215,95},
  490. {255,215,135},
  491. {255,215,175},
  492. {255,215,215},
  493. {255,215,255},
  494. {255,255,0},
  495. {255,255,95},
  496. {255,255,135},
  497. {255,255,175},
  498. {255,255,215},
  499. {255,255,255},
  500. {8,8,8},
  501. {18,18,18},
  502. {28,28,28},
  503. {38,38,38},
  504. {48,48,48},
  505. {58,58,58},
  506. {68,68,68},
  507. {78,78,78},
  508. {88,88,88},
  509. {98,98,98},
  510. {108,108,108},
  511. {118,118,118},
  512. {128,128,128},
  513. {138,138,138},
  514. {148,148,148},
  515. {158,158,158},
  516. {168,168,168},
  517. {178,178,178},
  518. {188,188,188},
  519. {198,198,198},
  520. {208,208,208},
  521. {218,218,218},
  522. {228,228,228},
  523. {238,238,238},
  524. };
  525. static void rgb_to_hsl(int r, int g, int b, int *h, int *s, int *l)
  526. {
  527. float r01 = r/255.0f;
  528. float g01 = g/255.0f;
  529. float b01 = b/255.0f;
  530. float cmax = r01;
  531. if (g01 > cmax) cmax = g01;
  532. if (b01 > cmax) cmax = b01;
  533. float cmin = r01;
  534. if (g01 < cmin) cmin = g01;
  535. if (b01 < cmin) cmin = b01;
  536. float delta = cmax - cmin;
  537. float epsilon = 1e-6;
  538. float hf = 0;
  539. if (delta < epsilon) hf = 0;
  540. else if (cmax == r01) hf = 60.0f*fmod((g01 - b01)/delta, 6.0f);
  541. else if (cmax == g01) hf = 60.0f*((b01 - r01)/delta + 2);
  542. else if (cmax == b01) hf = 60.0f*((r01 - g01)/delta + 4);
  543. else assert(0 && "unreachable");
  544. float lf = (cmax + cmin)/2;
  545. float sf = 0;
  546. if (delta < epsilon) sf = 0;
  547. else sf = delta/(1 - fabsf(2*lf - 1));
  548. *h = fmodf(fmodf(hf, 360.0f) + 360.0f, 360.0f);
  549. *s = sf*100.0f;
  550. *l = lf*100.0f;
  551. }
  552. static int distance256(int table256[256][3], int i, int a, int b, int c)
  553. {
  554. int da = a - table256[i][0];
  555. int db = b - table256[i][1];
  556. int dc = c - table256[i][2];
  557. return da*da + db*db + dc*dc;
  558. }
  559. static int find_ansi_index(int table256[256][3], int a, int b, int c)
  560. {
  561. int index = 0;
  562. for (int i = 0; i < 256; ++i) {
  563. if (distance256(table256, i, a, b, c) < distance256(table256, index, a, b, c)) {
  564. index = i;
  565. }
  566. }
  567. return index;
  568. }
  569. static char *shift_args(int *argc, char ***argv)
  570. {
  571. assert(*argc > 0);
  572. char *result = **argv;
  573. *argc -= 1;
  574. *argv += 1;
  575. return result;
  576. }
  577. typedef enum {
  578. DIST_HSL,
  579. DIST_RGB,
  580. } Distance;
  581. void usage(const char *program)
  582. {
  583. fprintf(stderr, "Usage: %s [OPTIONS...] [FILES...]\n", program);
  584. fprintf(stderr, "Options:\n");
  585. fprintf(stderr, " -w width of the image default is %d\n", DEFAULT_WIDTH);
  586. fprintf(stderr, " -rgb search nearest color in RGB space\n");
  587. fprintf(stderr, " -hsl search nearest color in HSL space (default)\n");
  588. fprintf(stderr, " -h print this help and exit\n");
  589. fprintf(stderr, "Example:\n");
  590. fprintf(stderr, " $ %s -w 16 image1.png -rgb -w 32 image2.png\n", program);
  591. fprintf(stderr, " Print image1.png with width 16 and HSL search space then \n");
  592. fprintf(stderr, " print image2.png with widht 32 and RGB search space.\n");
  593. fprintf(stderr, " Each flags override the previous one.\n");
  594. }
  595. int main(int argc, char **argv)
  596. {
  597. // TODO: Add 16 colors support
  598. // TODO: Add TrueColor support
  599. assert(argc > 0);
  600. const char *program = shift_args(&argc, &argv);
  601. int resized_width = DEFAULT_WIDTH;
  602. Distance distance = DIST_HSL;
  603. // TODO: throw an error if not a single file was provided
  604. while (argc > 0) {
  605. const char *flag = shift_args(&argc, &argv);
  606. if (strcmp(flag, "-w") == 0) {
  607. if (argc <= 0) {
  608. fprintf(stderr, "ERROR: no value is provided for %s\n", flag);
  609. exit(1);
  610. }
  611. resized_width = atoi(shift_args(&argc, &argv));
  612. if (resized_width < 0) {
  613. fprintf(stderr, "ERROR: the value of %s can't be negative\n", flag);
  614. exit(1);
  615. }
  616. } else if (strcmp(flag, "-rgb") == 0) {
  617. distance = DIST_RGB;
  618. } else if (strcmp(flag, "-hsl") == 0) {
  619. distance = DIST_HSL;
  620. } else if (strcmp(flag, "-h") == 0) {
  621. usage(program);
  622. exit(0);
  623. } else {
  624. const char *file_path = flag;
  625. int width, height;
  626. uint32_t *pixels = (uint32_t*)stbi_load(file_path, &width, &height, NULL, 4);
  627. if (pixels == NULL) {
  628. fprintf(stderr, "ERROR: could not read file %s\n", file_path);
  629. continue;
  630. }
  631. int resized_height = height*resized_width/width;
  632. // TODO: maybe use a custom resize algorithm that does not require any memory allocation?
  633. // Similar to how olive.c resize the sprites.
  634. // (Though stb_image_resize supports a lot of fancy filters and stuff which we may try
  635. // to utilize to improve the results)
  636. uint32_t *resized_pixels = malloc(sizeof(uint32_t)*resized_width*resized_height);
  637. if (resized_pixels == NULL) {
  638. fprintf(stderr, "ERROR: could not allocate memory for resized image\n");
  639. exit(1);
  640. }
  641. // TODO: stbir_resize_uint8 returns int, which means it can fail. We should check for that.
  642. stbir_resize_uint8(
  643. (const unsigned char*)pixels, width, height, sizeof(uint32_t)*width,
  644. (unsigned char*)resized_pixels, resized_width, resized_height, sizeof(uint32_t)*resized_width,
  645. 4);
  646. for (int y = 0; y < resized_height; ++y) {
  647. for (int x = 0; x < resized_width; ++x) {
  648. uint32_t pixel = resized_pixels[y*resized_width + x];
  649. int r = (pixel>>8*0)&0xFF;
  650. int g = (pixel>>8*1)&0xFF;
  651. int b = (pixel>>8*2)&0xFF;
  652. int a = (pixel>>8*3)&0xFF;
  653. r = a*r/255;
  654. g = a*g/255;
  655. b = a*b/255;
  656. switch (distance) {
  657. case DIST_HSL: {
  658. int h, s, l;
  659. rgb_to_hsl(r, g, b, &h, &s, &l);
  660. printf("\e[48;5;%dm ", find_ansi_index(hsl256, h, s, l));
  661. } break;
  662. case DIST_RGB: {
  663. printf("\e[48;5;%dm ", find_ansi_index(rgb256, r, g, b));
  664. } break;
  665. default: assert(0 && "unreachable");
  666. }
  667. }
  668. printf("\e[0m\n");
  669. }
  670. printf("\e[0m\n");
  671. free(resized_pixels);
  672. stbi_image_free(pixels);
  673. }
  674. }
  675. return 0;
  676. }
  677. // TODO: automated testing
  678. // Since the whole behaviour of the program is represented by its stdout, it should be pretty easy to have some autotests