25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

attr.c 16 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. /*
  2. * libcaca Colour ASCII-Art library
  3. * Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net>
  4. * All Rights Reserved
  5. *
  6. * This library is free software. It comes without any warranty, to
  7. * the extent permitted by applicable law. You can redistribute it
  8. * and/or modify it under the terms of the Do What the Fuck You Want
  9. * to Public License, Version 2, as published by Sam Hocevar. See
  10. * http://www.wtfpl.net/ for more details.
  11. */
  12. /*
  13. * This file contains functions for attribute management and colourspace
  14. * conversions.
  15. */
  16. #include "config.h"
  17. #include "caca.h"
  18. #include "caca_internals.h"
  19. static uint8_t nearest_ansi(uint16_t);
  20. /* RGB colours for the ANSI palette. There is no real standard, so we
  21. * use the same values as gnome-terminal. The 7th colour (brown) is a bit
  22. * special: 0xfa50 instead of 0xfaa0. */
  23. static const uint16_t ansitab16[16] =
  24. {
  25. 0xf000, 0xf00a, 0xf0a0, 0xf0aa, 0xfa00, 0xfa0a, 0xfa50, 0xfaaa,
  26. 0xf555, 0xf55f, 0xf5f5, 0xf5ff, 0xff55, 0xff5f, 0xfff5, 0xffff,
  27. };
  28. /* Same table, except on 14 bits (3-4-4-3) */
  29. static const uint16_t ansitab14[16] =
  30. {
  31. 0x3800, 0x3805, 0x3850, 0x3855, 0x3d00, 0x3d05, 0x3d28, 0x3d55,
  32. 0x3aaa, 0x3aaf, 0x3afa, 0x3aff, 0x3faa, 0x3faf, 0x3ffa, 0x3fff,
  33. };
  34. /** \brief Get the text attribute at the given coordinates.
  35. *
  36. * Get the internal \e libcaca attribute value of the character at the
  37. * given coordinates. The attribute value has 32 significant bits,
  38. * organised as follows from MSB to LSB:
  39. * - 3 bits for the background alpha
  40. * - 4 bits for the background red component
  41. * - 4 bits for the background green component
  42. * - 3 bits for the background blue component
  43. * - 3 bits for the foreground alpha
  44. * - 4 bits for the foreground red component
  45. * - 4 bits for the foreground green component
  46. * - 3 bits for the foreground blue component
  47. * - 4 bits for the bold, italics, underline and blink flags
  48. *
  49. * If the coordinates are outside the canvas boundaries, the current
  50. * attribute is returned.
  51. *
  52. * This function never fails.
  53. *
  54. * \param cv A handle to the libcaca canvas.
  55. * \param x X coordinate.
  56. * \param y Y coordinate.
  57. * \return The requested attribute.
  58. */
  59. uint32_t caca_get_attr(caca_canvas_t const *cv, int x, int y)
  60. {
  61. if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
  62. return cv->curattr;
  63. return cv->attrs[x + y * cv->width];
  64. }
  65. /** \brief Set the default character attribute.
  66. *
  67. * Set the default character attribute for drawing. Attributes define
  68. * foreground and background colour, transparency, bold, italics and
  69. * underline styles, as well as blink. String functions such as
  70. * caca_printf() and graphical primitive functions such as caca_draw_line()
  71. * will use this attribute.
  72. *
  73. * The value of \e attr is either:
  74. * - a 32-bit integer as returned by caca_get_attr(), in which case it
  75. * also contains colour information,
  76. * - a combination (bitwise OR) of style values (\e CACA_UNDERLINE,
  77. * \e CACA_BLINK, \e CACA_BOLD and \e CACA_ITALICS), in which case
  78. * setting the attribute does not modify the current colour information.
  79. *
  80. * To retrieve the current attribute value, use caca_get_attr(-1,-1).
  81. *
  82. * This function never fails.
  83. *
  84. * \param cv A handle to the libcaca canvas.
  85. * \param attr The requested attribute value.
  86. * \return This function always returns 0.
  87. */
  88. int caca_set_attr(caca_canvas_t *cv, uint32_t attr)
  89. {
  90. if(attr < 0x00000010)
  91. attr = (cv->curattr & 0xfffffff0) | attr;
  92. cv->curattr = attr;
  93. return 0;
  94. }
  95. /** \brief Unset flags in the default character attribute.
  96. *
  97. * Unset flags in the default character attribute for drawing. Attributes
  98. * define foreground and background colour, transparency, bold, italics and
  99. * underline styles, as well as blink. String functions such as
  100. * caca_printf() and graphical primitive functions such as caca_draw_line()
  101. * will use this attribute.
  102. *
  103. * The value of \e attr is a combination (bitwise OR) of style values
  104. * (\e CACA_UNDERLINE, \e CACA_BLINK, \e CACA_BOLD and \e CACA_ITALICS).
  105. * Unsetting these attributes does not modify the current colour information.
  106. *
  107. * To retrieve the current attribute value, use caca_get_attr(-1,-1).
  108. *
  109. * This function never fails.
  110. *
  111. * \param cv A handle to the libcaca canvas.
  112. * \param attr The requested attribute values to unset.
  113. * \return This function always returns 0.
  114. */
  115. int caca_unset_attr(caca_canvas_t *cv, uint32_t attr)
  116. {
  117. cv->curattr &= ~(attr & 0x0000000f);
  118. return 0;
  119. }
  120. /** \brief Toggle flags in the default character attribute.
  121. *
  122. * Toggle flags in the default character attribute for drawing. Attributes
  123. * define foreground and background colour, transparency, bold, italics and
  124. * underline styles, as well as blink. String functions such as
  125. * caca_printf() and graphical primitive functions such as caca_draw_line()
  126. * will use this attribute.
  127. *
  128. * The value of \e attr is a combination (bitwise OR) of style values
  129. * (\e CACA_UNDERLINE, \e CACA_BLINK, \e CACA_BOLD and \e CACA_ITALICS).
  130. * Toggling these attributes does not modify the current colour information.
  131. *
  132. * To retrieve the current attribute value, use caca_get_attr(-1,-1).
  133. *
  134. * This function never fails.
  135. *
  136. * \param cv A handle to the libcaca canvas.
  137. * \param attr The requested attribute values to toggle.
  138. * \return This function always returns 0.
  139. */
  140. int caca_toggle_attr(caca_canvas_t *cv, uint32_t attr)
  141. {
  142. cv->curattr ^= attr & 0x0000000f;
  143. return 0;
  144. }
  145. /** \brief Set the character attribute at the given coordinates.
  146. *
  147. * Set the character attribute, without changing the character's value. If
  148. * the character at the given coordinates is a fullwidth character, both
  149. * cells' attributes are replaced.
  150. *
  151. * The value of \e attr is either:
  152. * - a 32-bit integer as returned by caca_get_attr(), in which case it
  153. * also contains colour information,
  154. * - a combination (bitwise OR) of style values (\e CACA_UNDERLINE,
  155. * \e CACA_BLINK, \e CACA_BOLD and \e CACA_ITALICS), in which case
  156. * setting the attribute does not modify the current colour information.
  157. *
  158. * This function never fails.
  159. *
  160. * \param cv A handle to the libcaca canvas.
  161. * \param x X coordinate.
  162. * \param y Y coordinate.
  163. * \param attr The requested attribute value.
  164. * \return This function always returns 0.
  165. */
  166. int caca_put_attr(caca_canvas_t *cv, int x, int y, uint32_t attr)
  167. {
  168. uint32_t *curattr, *curchar;
  169. int xmin, xmax;
  170. if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
  171. return 0;
  172. xmin = xmax = x;
  173. curchar = cv->chars + x + y * cv->width;
  174. curattr = cv->attrs + x + y * cv->width;
  175. if(attr < 0x00000010)
  176. curattr[0] = (curattr[0] & 0xfffffff0) | attr;
  177. else
  178. curattr[0] = attr;
  179. if(x && curchar[0] == CACA_MAGIC_FULLWIDTH)
  180. {
  181. curattr[-1] = curattr[0];
  182. xmin--;
  183. }
  184. else if(x + 1 < (int)cv->width && curchar[1] == CACA_MAGIC_FULLWIDTH)
  185. {
  186. curattr[1] = curattr[0];
  187. xmax++;
  188. }
  189. if(!cv->dirty_disabled)
  190. caca_add_dirty_rect(cv, xmin, y, xmax - xmin + 1, 1);
  191. return 0;
  192. }
  193. /** \brief Set the default colour pair for text (ANSI version).
  194. *
  195. * Set the default ANSI colour pair for text drawing. String functions such
  196. * as caca_printf() and graphical primitive functions such as caca_draw_line()
  197. * will use these attributes.
  198. *
  199. * Color values are those defined in caca.h, such as CACA_RED
  200. * or CACA_TRANSPARENT.
  201. *
  202. * If an error occurs, -1 is returned and \b errno is set accordingly:
  203. * - \c EINVAL At least one of the colour values is invalid.
  204. *
  205. * \param cv A handle to the libcaca canvas.
  206. * \param fg The requested ANSI foreground colour.
  207. * \param bg The requested ANSI background colour.
  208. * \return 0 in case of success, -1 if an error occurred.
  209. */
  210. int caca_set_color_ansi(caca_canvas_t *cv, uint8_t fg, uint8_t bg)
  211. {
  212. uint32_t attr;
  213. if(fg > 0x20 || bg > 0x20)
  214. {
  215. seterrno(EINVAL);
  216. return -1;
  217. }
  218. attr = ((uint32_t)(bg | 0x40) << 18) | ((uint32_t)(fg | 0x40) << 4);
  219. cv->curattr = (cv->curattr & 0x0000000f) | attr;
  220. return 0;
  221. }
  222. /** \brief Set the default colour pair for text (truecolor version).
  223. *
  224. * Set the default ARGB colour pair for text drawing. String functions such
  225. * as caca_printf() and graphical primitive functions such as caca_draw_line()
  226. * will use these attributes.
  227. *
  228. * Colors are 16-bit ARGB values, each component being coded on 4 bits. For
  229. * instance, 0xf088 is solid dark cyan (A=15 R=0 G=8 B=8), and 0x8fff is
  230. * white with 50% alpha (A=8 R=15 G=15 B=15).
  231. *
  232. * This function never fails.
  233. *
  234. * \param cv A handle to the libcaca canvas.
  235. * \param fg The requested ARGB foreground colour.
  236. * \param bg The requested ARGB background colour.
  237. * \return This function always returns 0.
  238. */
  239. int caca_set_color_argb(caca_canvas_t *cv, uint16_t fg, uint16_t bg)
  240. {
  241. uint32_t attr;
  242. if(fg < 0x100)
  243. fg += 0x100;
  244. if(bg < 0x100)
  245. bg += 0x100;
  246. fg = ((fg >> 1) & 0x7ff) | ((fg >> 13) << 11);
  247. bg = ((bg >> 1) & 0x7ff) | ((bg >> 13) << 11);
  248. attr = ((uint32_t)bg << 18) | ((uint32_t)fg << 4);
  249. cv->curattr = (cv->curattr & 0x0000000f) | attr;
  250. return 0;
  251. }
  252. /** \brief Get DOS ANSI information from attribute.
  253. *
  254. * Get the ANSI colour pair for a given attribute. The returned value is
  255. * an 8-bit value whose higher 4 bits are the background colour and lower
  256. * 4 bits are the foreground colour.
  257. *
  258. * If the attribute has ARGB colours, the nearest colour is used. Special
  259. * attributes such as \e CACA_DEFAULT and \e CACA_TRANSPARENT are not
  260. * handled and are both replaced with \e CACA_LIGHTGRAY for the foreground
  261. * colour and \e CACA_BLACK for the background colour.
  262. *
  263. * This function never fails. If the attribute value is outside the expected
  264. * 32-bit range, higher order bits are simply ignored.
  265. *
  266. * \param attr The requested attribute value.
  267. * \return The corresponding DOS ANSI value.
  268. */
  269. uint8_t caca_attr_to_ansi(uint32_t attr)
  270. {
  271. uint8_t fg = nearest_ansi((attr >> 4) & 0x3fff);
  272. uint8_t bg = nearest_ansi(attr >> 18);
  273. return (fg < 0x10 ? fg : CACA_LIGHTGRAY)
  274. | ((bg < 0x10 ? bg : CACA_BLACK) << 4);
  275. }
  276. /** \brief Get ANSI foreground information from attribute.
  277. *
  278. * Get the ANSI foreground colour value for a given attribute. The returned
  279. * value is either one of the \e CACA_RED, \e CACA_BLACK etc. predefined
  280. * colours, or the special value \e CACA_DEFAULT meaning the media's
  281. * default foreground value, or the special value \e CACA_TRANSPARENT.
  282. *
  283. * If the attribute has ARGB colours, the nearest colour is returned.
  284. *
  285. * This function never fails. If the attribute value is outside the expected
  286. * 32-bit range, higher order bits are simply ignored.
  287. *
  288. * \param attr The requested attribute value.
  289. * \return The corresponding ANSI foreground value.
  290. */
  291. uint8_t caca_attr_to_ansi_fg(uint32_t attr)
  292. {
  293. return nearest_ansi((attr >> 4) & 0x3fff);
  294. }
  295. /** \brief Get ANSI background information from attribute.
  296. *
  297. * Get the ANSI background colour value for a given attribute. The returned
  298. * value is either one of the \e CACA_RED, \e CACA_BLACK etc. predefined
  299. * colours, or the special value \e CACA_DEFAULT meaning the media's
  300. * default background value, or the special value \e CACA_TRANSPARENT.
  301. *
  302. * If the attribute has ARGB colours, the nearest colour is returned.
  303. *
  304. * This function never fails. If the attribute value is outside the expected
  305. * 32-bit range, higher order bits are simply ignored.
  306. *
  307. * \param attr The requested attribute value.
  308. * \return The corresponding ANSI background value.
  309. */
  310. uint8_t caca_attr_to_ansi_bg(uint32_t attr)
  311. {
  312. return nearest_ansi(attr >> 18);
  313. }
  314. /** \brief Get 12-bit RGB foreground information from attribute.
  315. *
  316. * Get the 12-bit foreground colour value for a given attribute. The returned
  317. * value is a native-endian encoded integer with each red, green and blue
  318. * values encoded on 8 bits in the following order:
  319. * - 8-11 most significant bits: red
  320. * - 4-7 most significant bits: green
  321. * - least significant bits: blue
  322. *
  323. * This function never fails. If the attribute value is outside the expected
  324. * 32-bit range, higher order bits are simply ignored.
  325. *
  326. * \param attr The requested attribute value.
  327. * \return The corresponding 12-bit RGB foreground value.
  328. */
  329. uint16_t caca_attr_to_rgb12_fg(uint32_t attr)
  330. {
  331. uint16_t fg = (attr >> 4) & 0x3fff;
  332. if(fg < (0x10 | 0x40))
  333. return ansitab16[fg ^ 0x40] & 0x0fff;
  334. if(fg == (CACA_DEFAULT | 0x40))
  335. return ansitab16[CACA_LIGHTGRAY] & 0x0fff;
  336. if(fg == (CACA_TRANSPARENT | 0x40))
  337. return ansitab16[CACA_LIGHTGRAY] & 0x0fff;
  338. return (fg << 1) & 0x0fff;
  339. }
  340. /** \brief Get 12-bit RGB background information from attribute.
  341. *
  342. * Get the 12-bit background colour value for a given attribute. The returned
  343. * value is a native-endian encoded integer with each red, green and blue
  344. * values encoded on 8 bits in the following order:
  345. * - 8-11 most significant bits: red
  346. * - 4-7 most significant bits: green
  347. * - least significant bits: blue
  348. *
  349. * This function never fails. If the attribute value is outside the expected
  350. * 32-bit range, higher order bits are simply ignored.
  351. *
  352. * \param attr The requested attribute value.
  353. * \return The corresponding 12-bit RGB background value.
  354. */
  355. uint16_t caca_attr_to_rgb12_bg(uint32_t attr)
  356. {
  357. uint16_t bg = attr >> 18;
  358. if(bg < (0x10 | 0x40))
  359. return ansitab16[bg ^ 0x40] & 0x0fff;
  360. if(bg == (CACA_DEFAULT | 0x40))
  361. return ansitab16[CACA_BLACK] & 0x0fff;
  362. if(bg == (CACA_TRANSPARENT | 0x40))
  363. return ansitab16[CACA_BLACK] & 0x0fff;
  364. return (bg << 1) & 0x0fff;
  365. }
  366. /** \brief Get 64-bit ARGB information from attribute.
  367. *
  368. * Get the 64-bit colour and alpha values for a given attribute. The values
  369. * are written as 8-bit integers in the \e argb array in the following order:
  370. * - \e argb[0]: background alpha value
  371. * - \e argb[1]: background red value
  372. * - \e argb[2]: background green value
  373. * - \e argb[3]: background blue value
  374. * - \e argb[4]: foreground alpha value
  375. * - \e argb[5]: foreground red value
  376. * - \e argb[6]: foreground green value
  377. * - \e argb[7]: foreground blue value
  378. *
  379. * This function never fails. If the attribute value is outside the expected
  380. * 32-bit range, higher order bits are simply ignored.
  381. *
  382. * \param attr The requested attribute value.
  383. * \param argb An array of 8-bit integers.
  384. */
  385. void caca_attr_to_argb64(uint32_t attr, uint8_t argb[8])
  386. {
  387. uint16_t fg = (attr >> 4) & 0x3fff;
  388. uint16_t bg = attr >> 18;
  389. if(bg < (0x10 | 0x40))
  390. bg = ansitab16[bg ^ 0x40];
  391. else if(bg == (CACA_DEFAULT | 0x40))
  392. bg = ansitab16[CACA_BLACK];
  393. else if(bg == (CACA_TRANSPARENT | 0x40))
  394. bg = 0x0fff;
  395. else
  396. bg = ((bg << 2) & 0xf000) | ((bg << 1) & 0x0fff);
  397. argb[0] = bg >> 12;
  398. argb[1] = (bg >> 8) & 0xf;
  399. argb[2] = (bg >> 4) & 0xf;
  400. argb[3] = bg & 0xf;
  401. if(fg < (0x10 | 0x40))
  402. fg = ansitab16[fg ^ 0x40];
  403. else if(fg == (CACA_DEFAULT | 0x40))
  404. fg = ansitab16[CACA_LIGHTGRAY];
  405. else if(fg == (CACA_TRANSPARENT | 0x40))
  406. fg = 0x0fff;
  407. else
  408. fg = ((fg << 2) & 0xf000) | ((fg << 1) & 0x0fff);
  409. argb[4] = fg >> 12;
  410. argb[5] = (fg >> 8) & 0xf;
  411. argb[6] = (fg >> 4) & 0xf;
  412. argb[7] = fg & 0xf;
  413. }
  414. /*
  415. * XXX: the following functions are local
  416. */
  417. static uint8_t nearest_ansi(uint16_t argb14)
  418. {
  419. unsigned int i, best, dist;
  420. if(argb14 < (0x10 | 0x40))
  421. return argb14 ^ 0x40;
  422. if(argb14 == (CACA_DEFAULT | 0x40) || argb14 == (CACA_TRANSPARENT | 0x40))
  423. return argb14 ^ 0x40;
  424. if(argb14 < 0x0fff) /* too transparent */
  425. return CACA_TRANSPARENT;
  426. best = CACA_DEFAULT;
  427. dist = 0x3fff;
  428. for(i = 0; i < 16; i++)
  429. {
  430. unsigned int d = 0;
  431. int a, b;
  432. a = (ansitab14[i] >> 7) & 0xf;
  433. b = (argb14 >> 7) & 0xf;
  434. d += (a - b) * (a - b);
  435. a = (ansitab14[i] >> 3) & 0xf;
  436. b = (argb14 >> 3) & 0xf;
  437. d += (a - b) * (a - b);
  438. a = (ansitab14[i] << 1) & 0xf;
  439. b = (argb14 << 1) & 0xf;
  440. d += (a - b) * (a - b);
  441. if(d < dist)
  442. {
  443. dist = d;
  444. best = i;
  445. }
  446. }
  447. return best;
  448. }
  449. #define RGB12TO24(i) \
  450. (((uint32_t)((i & 0xf00) >> 8) * 0x110000) \
  451. | ((uint32_t)((i & 0x0f0) >> 4) * 0x001100) \
  452. | ((uint32_t)(i & 0x00f) * 0x000011))
  453. uint32_t _caca_attr_to_rgb24fg(uint32_t attr)
  454. {
  455. return RGB12TO24(caca_attr_to_rgb12_fg(attr));
  456. }
  457. uint32_t _caca_attr_to_rgb24bg(uint32_t attr)
  458. {
  459. return RGB12TO24(caca_attr_to_rgb12_bg(attr));
  460. }