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.
 
 
 
 
 
 

354 lines
9.8 KiB

  1. /*
  2. * libcucul Canvas for ultrafast compositing of Unicode letters
  3. * Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * $Id$
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the Do What The Fuck You Want To
  10. * Public License, Version 2, as published by Sam Hocevar. See
  11. * http://sam.zoy.org/wtfpl/COPYING for more details.
  12. */
  13. /*
  14. * This file contains functions for converting colour values between
  15. * various colourspaces.
  16. */
  17. #include "config.h"
  18. #include "common.h"
  19. #if defined(HAVE_ERRNO_H)
  20. # include <errno.h>
  21. #endif
  22. #include "cucul.h"
  23. #include "cucul_internals.h"
  24. /** \brief Set the default character attribute.
  25. *
  26. * Set the default character attribute for drawing. Attributes define
  27. * foreground and background colour, transparency, bold, italics and
  28. * underline styles, as well as blink. String functions such as
  29. * caca_printf() and graphical primitive functions such as caca_draw_line()
  30. * will use this attribute.
  31. *
  32. * The attribute value is a 32-bit integer as returned by cucul_get_attr()
  33. * or created using cucul_ansi_to_attr() and cucul_argb_to_attr(), optionally
  34. * ORed with style values such as CUCUL_UNDERLINE or CUCUL_BLINK.
  35. *
  36. * Only changing the style does not affect the current colour value.
  37. *
  38. * If an error occurs, -1 is returned and \b errno is set accordingly:
  39. * - \c EINVAL The attribute value is out of the 32-bit range.
  40. *
  41. * \param cv A handle to the libcucul canvas.
  42. * \param attr The requested attribute value.
  43. * \return 0 in case of success, -1 if an error occurred.
  44. */
  45. int cucul_set_attr(cucul_canvas_t *cv, unsigned long int attr)
  46. {
  47. if(sizeof(unsigned long int) > sizeof(uint32_t) && attr > 0xffffffff)
  48. {
  49. #if defined(HAVE_ERRNO_H)
  50. errno = EINVAL;
  51. #endif
  52. return -1;
  53. }
  54. if(attr < 0x00000010)
  55. attr = (cv->curattr & 0xfffffff0) | attr;
  56. cv->curattr = attr;
  57. return 0;
  58. }
  59. /** \brief Get the text attribute at the given coordinates.
  60. *
  61. * Get the internal \e libcucul attribute value of the character at the
  62. * given coordinates. The attribute value has 32 significant bits,
  63. * organised as follows from MSB to LSB:
  64. * - 3 bits for the background alpha
  65. * - 4 bits for the background red component
  66. * - 4 bits for the background green component
  67. * - 3 bits for the background blue component
  68. * - 3 bits for the foreground alpha
  69. * - 4 bits for the foreground red component
  70. * - 4 bits for the foreground green component
  71. * - 3 bits for the foreground blue component
  72. * - 4 bits for the bold, italics, underline and blink flags
  73. *
  74. * If the coordinates are outside the canvas boundaries, the current
  75. * attribute is returned.
  76. *
  77. * This function never fails.
  78. *
  79. * \param cv A handle to the libcucul canvas.
  80. * \param x X coordinate.
  81. * \param y Y coordinate.
  82. * \return The requested attribute.
  83. */
  84. unsigned long int cucul_get_attr(cucul_canvas_t *cv, int x, int y)
  85. {
  86. if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
  87. return (unsigned long int)cv->curattr;
  88. return (unsigned long int)cv->attrs[x + y * cv->width];
  89. }
  90. /** \brief Set the default colour pair and text style (ANSI version).
  91. *
  92. * Set the default ANSI colour pair and text style for drawing. String
  93. * functions such as caca_printf() and graphical primitive functions such as
  94. * caca_draw_line() will use these attributes.
  95. *
  96. * Color values are those defined in cucul.h, such as CUCUL_RED
  97. * or CUCUL_TRANSPARENT.
  98. *
  99. * Style values are those defined in cucul.h, such as CUCUL_UNDERLINE
  100. * or CUCUL_BLINK. The values can be ORed to set several styles at
  101. * the same time.
  102. *
  103. * If an error occurs, 0 is returned and \b errno is set accordingly:
  104. * - \c EINVAL The colour values and/or the style mask are invalid.
  105. *
  106. * \param cv A handle to the libcucul canvas.
  107. * \param fg The requested foreground colour.
  108. * \param bg The requested background colour.
  109. * \param style The requested text styles.
  110. * \return 0 in case of success, -1 if an error occurred.
  111. */
  112. unsigned long int cucul_ansi_to_attr(unsigned char fg, unsigned char bg)
  113. {
  114. if(fg > 0x20 || bg > 0x20)
  115. {
  116. #if defined(HAVE_ERRNO_H)
  117. errno = EINVAL;
  118. #endif
  119. return 0;
  120. }
  121. fg |= 0x40;
  122. bg |= 0x40;
  123. return ((unsigned long int)bg << 18) | ((unsigned long int)fg << 4);
  124. }
  125. /* Legacy function for old programs */
  126. int cucul_set_color(cucul_canvas_t *cv, unsigned char fg, unsigned char bg)
  127. {
  128. return cucul_set_attr(cv, cucul_ansi_to_attr(fg, bg));
  129. }
  130. /** \brief Set the default colour pair and text style (truecolor version).
  131. *
  132. * Set the default colour pair and text style for drawing. String
  133. * functions such as caca_printf() and graphical primitive functions such as
  134. * caca_draw_line() will use these attributes.
  135. *
  136. * Colors are 16-bit ARGB values, each component being coded on 4 bits. For
  137. * instance, 0xf088 is solid dark cyan (A=15 R=0 G=8 B=8), and 0x8fff is
  138. * white with 50% alpha (A=8 R=15 G=15 B=15).
  139. *
  140. * If an error occurs, 0 is returned and \b errno is set accordingly:
  141. * - \c EINVAL At least one of the colour values is invalid.
  142. *
  143. * \param cv A handle to the libcucul canvas.
  144. * \param fg The requested foreground colour.
  145. * \param bg The requested background colour.
  146. * \param style The requested text styles.
  147. * \return 0 in case of success, -1 if an error occurred.
  148. */
  149. unsigned long int cucul_argb_to_attr(unsigned int fg, unsigned int bg)
  150. {
  151. if(fg > 0xffff || bg > 0xffff)
  152. {
  153. #if defined(HAVE_ERRNO_H)
  154. errno = EINVAL;
  155. #endif
  156. return -1;
  157. }
  158. if(fg < 0x100)
  159. fg += 0x100;
  160. if(bg < 0x100)
  161. bg += 0x100;
  162. fg = ((fg >> 1) & 0x7ff) | ((fg >> 13) << 11);
  163. bg = ((bg >> 1) & 0x7ff) | ((bg >> 13) << 11);
  164. return ((unsigned long int)bg << 18) | ((unsigned long int)fg << 4);
  165. }
  166. /* Legacy function for old programs */
  167. int cucul_set_truecolor(cucul_canvas_t *cv, unsigned int fg, unsigned int bg)
  168. {
  169. return cucul_set_attr(cv, cucul_argb_to_attr(fg, bg));
  170. }
  171. /*
  172. * XXX: the following functions are local
  173. */
  174. /* RGB colours for the ANSI palette. There is no real standard, so we
  175. * use the same values as gnome-terminal. The 7th colour (brown) is a bit
  176. * special: 0xfa50 instead of 0xfaa0. */
  177. static const uint16_t ansitab16[16] =
  178. {
  179. 0xf000, 0xf00a, 0xf0a0, 0xf0aa, 0xfa00, 0xfa0a, 0xfa50, 0xfaaa,
  180. 0xf555, 0xf55f, 0xf5f5, 0xf5ff, 0xff55, 0xff5f, 0xfff5, 0xffff,
  181. };
  182. /* Same table, except on 14 bits (3-4-4-3) */
  183. static const uint16_t ansitab14[16] =
  184. {
  185. 0x3800, 0x3805, 0x3850, 0x3855, 0x3d00, 0x3d05, 0x3d28, 0x3d55,
  186. 0x3aaa, 0x3aaf, 0x3afa, 0x3aff, 0x3faa, 0x3faf, 0x3ffa, 0x3fff,
  187. };
  188. static uint8_t nearest_ansi(uint16_t argb14, uint8_t def)
  189. {
  190. unsigned int i, best, dist;
  191. if(argb14 < 0x0050)
  192. return argb14 ^ 0x40;
  193. if(argb14 == (CUCUL_DEFAULT | 0x40) || argb14 == (CUCUL_TRANSPARENT | 0x40))
  194. return def;
  195. if(argb14 < 0x0fff) /* too transparent, return default colour */
  196. return def;
  197. best = def;
  198. dist = 0x3fff;
  199. for(i = 0; i < 16; i++)
  200. {
  201. unsigned int d = 0;
  202. int a, b;
  203. a = (ansitab14[i] >> 7) & 0xf;
  204. b = (argb14 >> 7) & 0xf;
  205. d += (a - b) * (a - b);
  206. a = (ansitab14[i] >> 3) & 0xf;
  207. b = (argb14 >> 3) & 0xf;
  208. d += (a - b) * (a - b);
  209. a = (ansitab14[i] << 1) & 0xf;
  210. b = (argb14 << 1) & 0xf;
  211. d += (a - b) * (a - b);
  212. if(d < dist)
  213. {
  214. dist = d;
  215. best = i;
  216. }
  217. }
  218. return best;
  219. }
  220. uint8_t _cucul_attr_to_ansi8(uint32_t attr)
  221. {
  222. uint16_t fg = (attr >> 4) & 0x3fff;
  223. uint16_t bg = attr >> 18;
  224. return nearest_ansi(fg, CUCUL_LIGHTGRAY)
  225. | (nearest_ansi(bg, CUCUL_BLACK) << 4);
  226. }
  227. uint8_t _cucul_attr_to_ansi4fg(uint32_t attr)
  228. {
  229. return nearest_ansi((attr >> 4) & 0x3fff, CUCUL_LIGHTGRAY);
  230. }
  231. uint8_t _cucul_attr_to_ansi4bg(uint32_t attr)
  232. {
  233. return nearest_ansi(attr >> 18, CUCUL_BLACK);
  234. }
  235. uint16_t _cucul_attr_to_rgb12fg(uint32_t attr)
  236. {
  237. uint16_t fg = (attr >> 4) & 0x3fff;
  238. if(fg < 0x0050)
  239. return ansitab16[fg ^ 0x40] & 0x0fff;
  240. if(fg == (CUCUL_DEFAULT | 0x40))
  241. return ansitab16[CUCUL_LIGHTGRAY] & 0x0fff;
  242. if(fg == (CUCUL_TRANSPARENT | 0x40))
  243. return ansitab16[CUCUL_LIGHTGRAY] & 0x0fff;
  244. return (fg << 1) & 0x0fff;
  245. }
  246. uint16_t _cucul_attr_to_rgb12bg(uint32_t attr)
  247. {
  248. uint16_t bg = attr >> 18;
  249. if(bg < 0x0050)
  250. return ansitab16[bg ^ 0x40] & 0x0fff;
  251. if(bg == (CUCUL_DEFAULT | 0x40))
  252. return ansitab16[CUCUL_BLACK] & 0x0fff;
  253. if(bg == (CUCUL_TRANSPARENT | 0x40))
  254. return ansitab16[CUCUL_BLACK] & 0x0fff;
  255. return (bg << 1) & 0x0fff;
  256. }
  257. #define RGB12TO24(i) \
  258. (((uint32_t)((i & 0xf00) >> 8) * 0x110000) \
  259. | ((uint32_t)((i & 0x0f0) >> 4) * 0x001100) \
  260. | ((uint32_t)(i & 0x00f) * 0x000011))
  261. uint32_t _cucul_attr_to_rgb24fg(uint32_t attr)
  262. {
  263. return RGB12TO24(_cucul_attr_to_rgb12fg(attr));
  264. }
  265. uint32_t _cucul_attr_to_rgb24bg(uint32_t attr)
  266. {
  267. return RGB12TO24(_cucul_attr_to_rgb12bg(attr));
  268. }
  269. void _cucul_attr_to_argb4(uint32_t attr, uint8_t argb[8])
  270. {
  271. uint16_t fg = (attr >> 4) & 0x3fff;
  272. uint16_t bg = attr >> 18;
  273. if(bg < 0x0050)
  274. bg = ansitab16[bg ^ 0x40];
  275. else if(bg == (CUCUL_DEFAULT | 0x40))
  276. bg = ansitab16[CUCUL_BLACK];
  277. else if(bg == (CUCUL_TRANSPARENT | 0x40))
  278. bg = 0x0fff;
  279. else
  280. bg = ((bg << 2) & 0xf000) | ((bg << 1) & 0x0fff);
  281. argb[0] = bg >> 12;
  282. argb[1] = (bg >> 8) & 0xf;
  283. argb[2] = (bg >> 4) & 0xf;
  284. argb[3] = bg & 0xf;
  285. if(fg < 0x0050)
  286. fg = ansitab16[fg ^ 0x40];
  287. else if(fg == (CUCUL_DEFAULT | 0x40))
  288. fg = ansitab16[CUCUL_LIGHTGRAY];
  289. else if(fg == (CUCUL_TRANSPARENT | 0x40))
  290. fg = 0x0fff;
  291. else
  292. fg = ((fg << 2) & 0xf000) | ((fg << 1) & 0x0fff);
  293. argb[4] = fg >> 12;
  294. argb[5] = (fg >> 8) & 0xf;
  295. argb[6] = (fg >> 4) & 0xf;
  296. argb[7] = fg & 0xf;
  297. }