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.
 
 
 
 
 
 

496 lines
16 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 Set the character attribute at the given coordinates.
  98. *
  99. * Set the character attribute, without changing the character's value. If
  100. * the character at the given coordinates is a fullwidth character, both
  101. * cells' attributes are replaced.
  102. *
  103. * The value of \e attr is either:
  104. * - a 32-bit integer as returned by caca_get_attr(), in which case it
  105. * also contains colour information,
  106. * - a combination (bitwise OR) of style values (\e CACA_UNDERLINE,
  107. * \e CACA_BLINK, \e CACA_BOLD and \e CACA_ITALICS), in which case
  108. * setting the attribute does not modify the current colour information.
  109. *
  110. * This function never fails.
  111. *
  112. * \param cv A handle to the libcaca canvas.
  113. * \param x X coordinate.
  114. * \param y Y coordinate.
  115. * \param attr The requested attribute value.
  116. * \return This function always returns 0.
  117. */
  118. int caca_put_attr(caca_canvas_t *cv, int x, int y, uint32_t attr)
  119. {
  120. uint32_t *curattr, *curchar;
  121. int xmin, xmax;
  122. if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
  123. return 0;
  124. xmin = xmax = x;
  125. curchar = cv->chars + x + y * cv->width;
  126. curattr = cv->attrs + x + y * cv->width;
  127. if(attr < 0x00000010)
  128. curattr[0] = (curattr[0] & 0xfffffff0) | attr;
  129. else
  130. curattr[0] = attr;
  131. if(x && curchar[0] == CACA_MAGIC_FULLWIDTH)
  132. {
  133. curattr[-1] = curattr[0];
  134. xmin--;
  135. }
  136. else if(x + 1 < (int)cv->width && curchar[1] == CACA_MAGIC_FULLWIDTH)
  137. {
  138. curattr[1] = curattr[0];
  139. xmax++;
  140. }
  141. if(!cv->dirty_disabled)
  142. caca_add_dirty_rect(cv, xmin, y, xmax - xmin + 1, 1);
  143. return 0;
  144. }
  145. /** \brief Set the default colour pair for text (ANSI version).
  146. *
  147. * Set the default ANSI colour pair for text drawing. String functions such
  148. * as caca_printf() and graphical primitive functions such as caca_draw_line()
  149. * will use these attributes.
  150. *
  151. * Color values are those defined in caca.h, such as CACA_RED
  152. * or CACA_TRANSPARENT.
  153. *
  154. * If an error occurs, 0 is returned and \b errno is set accordingly:
  155. * - \c EINVAL At least one of the colour values is invalid.
  156. *
  157. * \param cv A handle to the libcaca canvas.
  158. * \param fg The requested ANSI foreground colour.
  159. * \param bg The requested ANSI background colour.
  160. * \return 0 in case of success, -1 if an error occurred.
  161. */
  162. int caca_set_color_ansi(caca_canvas_t *cv, uint8_t fg, uint8_t bg)
  163. {
  164. uint32_t attr;
  165. if(fg > 0x20 || bg > 0x20)
  166. {
  167. seterrno(EINVAL);
  168. return -1;
  169. }
  170. attr = ((uint32_t)(bg | 0x40) << 18) | ((uint32_t)(fg | 0x40) << 4);
  171. cv->curattr = (cv->curattr & 0x0000000f) | attr;
  172. return 0;
  173. }
  174. /** \brief Set the default colour pair for text (truecolor version).
  175. *
  176. * Set the default ARGB colour pair for text drawing. String functions such
  177. * as caca_printf() and graphical primitive functions such as caca_draw_line()
  178. * will use these attributes.
  179. *
  180. * Colors are 16-bit ARGB values, each component being coded on 4 bits. For
  181. * instance, 0xf088 is solid dark cyan (A=15 R=0 G=8 B=8), and 0x8fff is
  182. * white with 50% alpha (A=8 R=15 G=15 B=15).
  183. *
  184. * This function never fails.
  185. *
  186. * \param cv A handle to the libcaca canvas.
  187. * \param fg The requested ARGB foreground colour.
  188. * \param bg The requested ARGB background colour.
  189. * \return This function always returns 0.
  190. */
  191. int caca_set_color_argb(caca_canvas_t *cv, uint16_t fg, uint16_t bg)
  192. {
  193. uint32_t attr;
  194. if(fg < 0x100)
  195. fg += 0x100;
  196. if(bg < 0x100)
  197. bg += 0x100;
  198. fg = ((fg >> 1) & 0x7ff) | ((fg >> 13) << 11);
  199. bg = ((bg >> 1) & 0x7ff) | ((bg >> 13) << 11);
  200. attr = ((uint32_t)bg << 18) | ((uint32_t)fg << 4);
  201. cv->curattr = (cv->curattr & 0x0000000f) | attr;
  202. return 0;
  203. }
  204. /** \brief Get DOS ANSI information from attribute.
  205. *
  206. * Get the ANSI colour pair for a given attribute. The returned value is
  207. * an 8-bit value whose higher 4 bits are the background colour and lower
  208. * 4 bits are the foreground colour.
  209. *
  210. * If the attribute has ARGB colours, the nearest colour is used. Special
  211. * attributes such as \e CACA_DEFAULT and \e CACA_TRANSPARENT are not
  212. * handled and are both replaced with \e CACA_LIGHTGRAY for the foreground
  213. * colour and \e CACA_BLACK for the background colour.
  214. *
  215. * This function never fails. If the attribute value is outside the expected
  216. * 32-bit range, higher order bits are simply ignored.
  217. *
  218. * \param attr The requested attribute value.
  219. * \return The corresponding DOS ANSI value.
  220. */
  221. uint8_t caca_attr_to_ansi(uint32_t attr)
  222. {
  223. uint8_t fg = nearest_ansi((attr >> 4) & 0x3fff);
  224. uint8_t bg = nearest_ansi(attr >> 18);
  225. return (fg < 0x10 ? fg : CACA_LIGHTGRAY)
  226. | ((bg < 0x10 ? bg : CACA_BLACK) << 4);
  227. }
  228. /** \brief Get ANSI foreground information from attribute.
  229. *
  230. * Get the ANSI foreground colour value for a given attribute. The returned
  231. * value is either one of the \e CACA_RED, \e CACA_BLACK etc. predefined
  232. * colours, or the special value \e CACA_DEFAULT meaning the media's
  233. * default foreground value, or the special value \e CACA_TRANSPARENT.
  234. *
  235. * If the attribute has ARGB colours, the nearest colour is returned.
  236. *
  237. * This function never fails. If the attribute value is outside the expected
  238. * 32-bit range, higher order bits are simply ignored.
  239. *
  240. * \param attr The requested attribute value.
  241. * \return The corresponding ANSI foreground value.
  242. */
  243. uint8_t caca_attr_to_ansi_fg(uint32_t attr)
  244. {
  245. return nearest_ansi(((uint16_t)attr >> 4) & 0x3fff);
  246. }
  247. /** \brief Get ANSI background information from attribute.
  248. *
  249. * Get the ANSI background colour value for a given attribute. The returned
  250. * value is either one of the \e CACA_RED, \e CACA_BLACK etc. predefined
  251. * colours, or the special value \e CACA_DEFAULT meaning the media's
  252. * default background value, or the special value \e CACA_TRANSPARENT.
  253. *
  254. * If the attribute has ARGB colours, the nearest colour is returned.
  255. *
  256. * This function never fails. If the attribute value is outside the expected
  257. * 32-bit range, higher order bits are simply ignored.
  258. *
  259. * \param attr The requested attribute value.
  260. * \return The corresponding ANSI background value.
  261. */
  262. uint8_t caca_attr_to_ansi_bg(uint32_t attr)
  263. {
  264. return nearest_ansi(attr >> 18);
  265. }
  266. /** \brief Get 12-bit RGB foreground information from attribute.
  267. *
  268. * Get the 12-bit foreground colour value for a given attribute. The returned
  269. * value is a native-endian encoded integer with each red, green and blue
  270. * values encoded on 8 bits in the following order:
  271. * - 8-11 most significant bits: red
  272. * - 4-7 most significant bits: green
  273. * - least significant bits: blue
  274. *
  275. * This function never fails. If the attribute value is outside the expected
  276. * 32-bit range, higher order bits are simply ignored.
  277. *
  278. * \param attr The requested attribute value.
  279. * \return The corresponding 12-bit RGB foreground value.
  280. */
  281. uint16_t caca_attr_to_rgb12_fg(uint32_t attr)
  282. {
  283. uint16_t fg = (attr >> 4) & 0x3fff;
  284. if(fg < (0x10 | 0x40))
  285. return ansitab16[fg ^ 0x40] & 0x0fff;
  286. if(fg == (CACA_DEFAULT | 0x40))
  287. return ansitab16[CACA_LIGHTGRAY] & 0x0fff;
  288. if(fg == (CACA_TRANSPARENT | 0x40))
  289. return ansitab16[CACA_LIGHTGRAY] & 0x0fff;
  290. return (fg << 1) & 0x0fff;
  291. }
  292. /** \brief Get 12-bit RGB background information from attribute.
  293. *
  294. * Get the 12-bit background colour value for a given attribute. The returned
  295. * value is a native-endian encoded integer with each red, green and blue
  296. * values encoded on 8 bits in the following order:
  297. * - 8-11 most significant bits: red
  298. * - 4-7 most significant bits: green
  299. * - least significant bits: blue
  300. *
  301. * This function never fails. If the attribute value is outside the expected
  302. * 32-bit range, higher order bits are simply ignored.
  303. *
  304. * \param attr The requested attribute value.
  305. * \return The corresponding 12-bit RGB background value.
  306. */
  307. uint16_t caca_attr_to_rgb12_bg(uint32_t attr)
  308. {
  309. uint16_t bg = attr >> 18;
  310. if(bg < (0x10 | 0x40))
  311. return ansitab16[bg ^ 0x40] & 0x0fff;
  312. if(bg == (CACA_DEFAULT | 0x40))
  313. return ansitab16[CACA_BLACK] & 0x0fff;
  314. if(bg == (CACA_TRANSPARENT | 0x40))
  315. return ansitab16[CACA_BLACK] & 0x0fff;
  316. return (bg << 1) & 0x0fff;
  317. }
  318. /** \brief Get 64-bit ARGB information from attribute.
  319. *
  320. * Get the 64-bit colour and alpha values for a given attribute. The values
  321. * are written as 8-bit integers in the \e argb array in the following order:
  322. * - \e argb[0]: background alpha value
  323. * - \e argb[1]: background red value
  324. * - \e argb[2]: background green value
  325. * - \e argb[3]: background blue value
  326. * - \e argb[4]: foreground alpha value
  327. * - \e argb[5]: foreground red value
  328. * - \e argb[6]: foreground green value
  329. * - \e argb[7]: foreground blue value
  330. *
  331. * This function never fails. If the attribute value is outside the expected
  332. * 32-bit range, higher order bits are simply ignored.
  333. *
  334. * \param attr The requested attribute value.
  335. * \param argb An array of 8-bit integers.
  336. */
  337. void caca_attr_to_argb64(uint32_t attr, uint8_t argb[8])
  338. {
  339. uint16_t fg = (attr >> 4) & 0x3fff;
  340. uint16_t bg = attr >> 18;
  341. if(bg < (0x10 | 0x40))
  342. bg = ansitab16[bg ^ 0x40];
  343. else if(bg == (CACA_DEFAULT | 0x40))
  344. bg = ansitab16[CACA_BLACK];
  345. else if(bg == (CACA_TRANSPARENT | 0x40))
  346. bg = 0x0fff;
  347. else
  348. bg = ((bg << 2) & 0xf000) | ((bg << 1) & 0x0fff);
  349. argb[0] = bg >> 12;
  350. argb[1] = (bg >> 8) & 0xf;
  351. argb[2] = (bg >> 4) & 0xf;
  352. argb[3] = bg & 0xf;
  353. if(fg < (0x10 | 0x40))
  354. fg = ansitab16[fg ^ 0x40];
  355. else if(fg == (CACA_DEFAULT | 0x40))
  356. fg = ansitab16[CACA_LIGHTGRAY];
  357. else if(fg == (CACA_TRANSPARENT | 0x40))
  358. fg = 0x0fff;
  359. else
  360. fg = ((fg << 2) & 0xf000) | ((fg << 1) & 0x0fff);
  361. argb[4] = fg >> 12;
  362. argb[5] = (fg >> 8) & 0xf;
  363. argb[6] = (fg >> 4) & 0xf;
  364. argb[7] = fg & 0xf;
  365. }
  366. /*
  367. * XXX: the following functions are local
  368. */
  369. static uint8_t nearest_ansi(uint16_t argb14)
  370. {
  371. unsigned int i, best, dist;
  372. if(argb14 < (0x10 | 0x40))
  373. return argb14 ^ 0x40;
  374. if(argb14 == (CACA_DEFAULT | 0x40) || argb14 == (CACA_TRANSPARENT | 0x40))
  375. return argb14 ^ 0x40;
  376. if(argb14 < 0x0fff) /* too transparent */
  377. return CACA_TRANSPARENT;
  378. best = CACA_DEFAULT;
  379. dist = 0x3fff;
  380. for(i = 0; i < 16; i++)
  381. {
  382. unsigned int d = 0;
  383. int a, b;
  384. a = (ansitab14[i] >> 7) & 0xf;
  385. b = (argb14 >> 7) & 0xf;
  386. d += (a - b) * (a - b);
  387. a = (ansitab14[i] >> 3) & 0xf;
  388. b = (argb14 >> 3) & 0xf;
  389. d += (a - b) * (a - b);
  390. a = (ansitab14[i] << 1) & 0xf;
  391. b = (argb14 << 1) & 0xf;
  392. d += (a - b) * (a - b);
  393. if(d < dist)
  394. {
  395. dist = d;
  396. best = i;
  397. }
  398. }
  399. return best;
  400. }
  401. #define RGB12TO24(i) \
  402. (((uint32_t)((i & 0xf00) >> 8) * 0x110000) \
  403. | ((uint32_t)((i & 0x0f0) >> 4) * 0x001100) \
  404. | ((uint32_t)(i & 0x00f) * 0x000011))
  405. uint32_t _caca_attr_to_rgb24fg(uint32_t attr)
  406. {
  407. return RGB12TO24(caca_attr_to_rgb12_fg(attr));
  408. }
  409. uint32_t _caca_attr_to_rgb24bg(uint32_t attr)
  410. {
  411. return RGB12TO24(caca_attr_to_rgb12_bg(attr));
  412. }
  413. /*
  414. * XXX: The following functions are aliases.
  415. */
  416. uint32_t cucul_get_attr(cucul_canvas_t const *, int, int)
  417. CACA_ALIAS(caca_get_attr);
  418. int cucul_set_attr(cucul_canvas_t *, uint32_t) CACA_ALIAS(caca_set_attr);
  419. int cucul_put_attr(cucul_canvas_t *, int, int, uint32_t)
  420. CACA_ALIAS(caca_put_attr);
  421. int cucul_set_color_ansi(cucul_canvas_t *, uint8_t, uint8_t)
  422. CACA_ALIAS(caca_set_color_ansi);
  423. int cucul_set_color_argb(cucul_canvas_t *, uint16_t, uint16_t)
  424. CACA_ALIAS(caca_set_color_argb);
  425. uint8_t cucul_attr_to_ansi(uint32_t) CACA_ALIAS(caca_attr_to_ansi);
  426. uint8_t cucul_attr_to_ansi_fg(uint32_t) CACA_ALIAS(caca_attr_to_ansi_fg);
  427. uint8_t cucul_attr_to_ansi_bg(uint32_t) CACA_ALIAS(caca_attr_to_ansi_bg);
  428. uint16_t cucul_attr_to_rgb12_fg(uint32_t) CACA_ALIAS(caca_attr_to_rgb12_fg);
  429. uint16_t cucul_attr_to_rgb12_bg(uint32_t) CACA_ALIAS(caca_attr_to_rgb12_bg);
  430. void cucul_attr_to_argb64(uint32_t, uint8_t[8]) CACA_ALIAS(caca_attr_to_argb64);