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.
 
 
 
 
 
 

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