You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

550 line
17 KiB

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