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.
 
 
 
 
 
 

364 lines
10 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. /* Legacy stuff from old versions */
  25. int cucul_set_color(cucul_canvas_t *, unsigned char, unsigned char);
  26. int cucul_set_truecolor(cucul_canvas_t *, unsigned int, unsigned int);
  27. /* RGB colours for the ANSI palette. There is no real standard, so we
  28. * use the same values as gnome-terminal. The 7th colour (brown) is a bit
  29. * special: 0xfa50 instead of 0xfaa0. */
  30. static const uint16_t ansitab[16] =
  31. {
  32. 0xf000, 0xf00a, 0xf0a0, 0xf0aa, 0xfa00, 0xfa0a, 0xfa50, 0xfaaa,
  33. 0xf555, 0xf55f, 0xf5f5, 0xf5ff, 0xff55, 0xff5f, 0xfff5, 0xffff,
  34. };
  35. /** \brief Set the default character attribute.
  36. *
  37. * Set the default character attribute for drawing. Attributes define
  38. * foreground and background colour, transparency, bold, italics and
  39. * underline styles, as well as blink. String functions such as
  40. * caca_printf() and graphical primitive functions such as caca_draw_line()
  41. * will use this attribute.
  42. *
  43. * The attribute value is a 32-bit integer as returned by cucul_get_attr().
  44. * For more user-friendly versions of this function, see cucul_set_attr_ansi()
  45. * and cucul_set_attr_argb().
  46. *
  47. * If an error occurs, -1 is returned and \b errno is set accordingly:
  48. * - \c EINVAL The attribute value is out of the 32-bit range.
  49. *
  50. * \param cv A handle to the libcucul canvas.
  51. * \param attr The requested attribute value.
  52. * \return 0 in case of success, -1 if an error occurred.
  53. */
  54. int cucul_set_attr(cucul_canvas_t *cv, unsigned long int attr)
  55. {
  56. if(sizeof(unsigned long int) > sizeof(uint32_t) && attr > 0xffffffff)
  57. {
  58. #if defined(HAVE_ERRNO_H)
  59. errno = EINVAL;
  60. #endif
  61. return -1;
  62. }
  63. cv->curattr = attr;
  64. return 0;
  65. }
  66. /** \brief Set the default colour pair and text style (ANSI version).
  67. *
  68. * Set the default ANSI colour pair and text style for drawing. String
  69. * functions such as caca_printf() and graphical primitive functions such as
  70. * caca_draw_line() will use these attributes.
  71. *
  72. * Color values are those defined in cucul.h, such as CUCUL_COLOR_RED
  73. * or CUCUL_COLOR_TRANSPARENT.
  74. *
  75. * Style values are those defined in cucul.h, such as CUCUL_STYLE_UNDERLINE
  76. * or CUCUL_STYLE_BLINK. The values can be ORed to set several styles at
  77. * the same time.
  78. *
  79. * If an error occurs, -1 is returned and \b errno is set accordingly:
  80. * - \c EINVAL The colour values and/or the style mask are invalid.
  81. *
  82. * \param cv A handle to the libcucul canvas.
  83. * \param fg The requested foreground colour.
  84. * \param bg The requested background colour.
  85. * \param style The requested text styles.
  86. * \return 0 in case of success, -1 if an error occurred.
  87. */
  88. int cucul_set_attr_ansi(cucul_canvas_t *cv, unsigned char fg, unsigned char bg,
  89. unsigned char style)
  90. {
  91. uint32_t attr;
  92. if(fg > 0x20 || bg > 0x20 || style > 0x0f)
  93. {
  94. #if defined(HAVE_ERRNO_H)
  95. errno = EINVAL;
  96. #endif
  97. return -1;
  98. }
  99. attr = ((uint32_t)bg << 20) | ((uint32_t)fg << 4);
  100. if(style)
  101. attr |= (0x02004801 * style) & 0x10011001;
  102. cv->curattr = attr;
  103. return 0;
  104. }
  105. /* Legacy function for old programs */
  106. int cucul_set_color(cucul_canvas_t *cv, unsigned char fg, unsigned char bg)
  107. {
  108. return cucul_set_attr_ansi(cv, fg, bg, 0);
  109. }
  110. /** \brief Set the default colour pair and text style (truecolor version).
  111. *
  112. * Set the default colour pair and text style for drawing. String
  113. * functions such as caca_printf() and graphical primitive functions such as
  114. * caca_draw_line() will use these attributes.
  115. *
  116. * Colors are 16-bit ARGB values, each component being coded on 4 bits. For
  117. * instance, 0xf088 is solid dark cyan (A=15 R=0 G=8 B=8), and 0x8fff is
  118. * white with 50% alpha (A=8 R=15 G=15 B=15).
  119. *
  120. * Style values are those defined in cucul.h, such as CUCUL_STYLE_UNDERLINE
  121. * or CUCUL_STYLE_BLINK. The values can be ORed to set several styles at
  122. * the same time.
  123. *
  124. * If an error occurs, -1 is returned and \b errno is set accordingly:
  125. * - \c EINVAL At least one of the colour values is invalid.
  126. *
  127. * \param cv A handle to the libcucul canvas.
  128. * \param fg The requested foreground colour.
  129. * \param bg The requested background colour.
  130. * \param style The requested text styles.
  131. * \return 0 in case of success, -1 if an error occurred.
  132. */
  133. int cucul_set_attr_argb(cucul_canvas_t *cv, unsigned int fg, unsigned int bg,
  134. unsigned char style)
  135. {
  136. uint32_t attr;
  137. if(fg > 0xffff || bg > 0xffff || style > 0x0f)
  138. {
  139. #if defined(HAVE_ERRNO_H)
  140. errno = EINVAL;
  141. #endif
  142. return -1;
  143. }
  144. if(fg < 0x100)
  145. fg += 0x100;
  146. if(bg < 0x100)
  147. bg += 0x100;
  148. attr = (((uint32_t)bg << 16) | (uint32_t)fg) & 0xeffeeffe;
  149. if(style)
  150. attr |= (0x02004801 * style) & 0x10011001;
  151. cv->curattr = attr;
  152. return 0;
  153. }
  154. /* Legacy function for old programs */
  155. int cucul_set_truecolor(cucul_canvas_t *cv, unsigned int fg, unsigned int bg)
  156. {
  157. return cucul_set_attr_argb(cv, fg, bg, 0);
  158. }
  159. /** \brief Get the text attribute at the given coordinates.
  160. *
  161. * Get the internal \e libcucul attribute value of the character at the
  162. * given coordinates. The attribute value has 32 significant bits,
  163. * organised as follows from MSB to LSB:
  164. * - 3 bits for the background alpha
  165. * - 1 bit for the blink flag
  166. * - 4 bits for the background red component
  167. * - 4 bits for the background green component
  168. * - 3 bits for the background blue component
  169. * - 1 bit for the underline flag
  170. * - 3 bits for the foreground alpha
  171. * - 1 bit for the italics flag
  172. * - 4 bits for the foreground red component
  173. * - 4 bits for the foreground green component
  174. * - 3 bits for the foreground blue component
  175. * - 1 bit for the bold flag
  176. *
  177. * If the coordinates are outside the canvas boundaries, the current
  178. * attribute is returned.
  179. *
  180. * This function never fails.
  181. *
  182. * \param cv A handle to the libcucul canvas.
  183. * \param x X coordinate.
  184. * \param y Y coordinate.
  185. * \return The requested attribute.
  186. */
  187. unsigned long int cucul_get_attr(cucul_canvas_t *cv, int x, int y)
  188. {
  189. if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
  190. return (unsigned long int)cv->curattr;
  191. return (unsigned long int)cv->attrs[x + y * cv->width];
  192. }
  193. /*
  194. * XXX: the following functions are local
  195. */
  196. static uint8_t nearest_ansi(uint16_t argb16, uint8_t def)
  197. {
  198. unsigned int i, best, dist;
  199. if(argb16 == (argb16 & 0x00f0))
  200. return argb16 >> 4;
  201. if(argb16 == (CUCUL_COLOR_DEFAULT << 4)
  202. || argb16 == (CUCUL_COLOR_TRANSPARENT << 4))
  203. return def;
  204. if(argb16 < 0x6fff) /* too transparent, return default colour */
  205. return def;
  206. best = def;
  207. dist = 0xffff;
  208. for(i = 0; i < 16; i++)
  209. {
  210. unsigned int d = 0;
  211. int a, b;
  212. a = (ansitab[i] >> 8) & 0xf;
  213. b = (argb16 >> 8) & 0xf;
  214. d += (a - b) * (a - b);
  215. a = (ansitab[i] >> 4) & 0xf;
  216. b = (argb16 >> 4) & 0xf;
  217. d += (a - b) * (a - b);
  218. a = ansitab[i] & 0xf;
  219. b = argb16 & 0xf;
  220. d += (a - b) * (a - b);
  221. if(d < dist)
  222. {
  223. dist = d;
  224. best = i;
  225. }
  226. }
  227. return best;
  228. }
  229. uint8_t _cucul_attr_to_ansi8(uint32_t attr)
  230. {
  231. uint16_t fg = attr & 0xeffe;
  232. uint16_t bg = (attr >> 16) & 0xeffe;
  233. return nearest_ansi(fg, CUCUL_COLOR_LIGHTGRAY)
  234. | (nearest_ansi(bg, CUCUL_COLOR_BLACK) << 4);
  235. }
  236. uint8_t _cucul_attr_to_ansi4fg(uint32_t attr)
  237. {
  238. return nearest_ansi(attr & 0xeffe, CUCUL_COLOR_LIGHTGRAY);
  239. }
  240. uint8_t _cucul_attr_to_ansi4bg(uint32_t attr)
  241. {
  242. return nearest_ansi((attr >> 16) & 0xeffe, CUCUL_COLOR_BLACK);
  243. }
  244. uint16_t _cucul_attr_to_rgb12fg(uint32_t attr)
  245. {
  246. uint16_t fg = attr & 0xeffe;
  247. if(fg == (fg & 0x00f0))
  248. return ansitab[fg >> 4] & 0x0fff;
  249. if(fg == (CUCUL_COLOR_DEFAULT << 4))
  250. return ansitab[CUCUL_COLOR_LIGHTGRAY] & 0x0fff;
  251. if(fg == (CUCUL_COLOR_TRANSPARENT << 4))
  252. return ansitab[CUCUL_COLOR_LIGHTGRAY] & 0x0fff;
  253. return fg & 0x0fff;
  254. }
  255. uint16_t _cucul_attr_to_rgb12bg(uint32_t attr)
  256. {
  257. uint16_t bg = (attr >> 16) & 0xeffe;
  258. if(bg == (bg & 0x00f0))
  259. return ansitab[bg >> 4] & 0x0fff;
  260. if(bg == (CUCUL_COLOR_DEFAULT << 4))
  261. return ansitab[CUCUL_COLOR_BLACK] & 0x0fff;
  262. if(bg == (CUCUL_COLOR_TRANSPARENT << 4))
  263. return ansitab[CUCUL_COLOR_BLACK] & 0x0fff;
  264. return bg & 0x0fff;
  265. }
  266. #define RGB12TO24(i) \
  267. (((uint32_t)((i & 0xf00) >> 8) * 0x110000) \
  268. | ((uint32_t)((i & 0x0f0) >> 4) * 0x001100) \
  269. | ((uint32_t)(i & 0x00f) * 0x000011))
  270. uint32_t _cucul_attr_to_rgb24fg(uint32_t attr)
  271. {
  272. return RGB12TO24(_cucul_attr_to_rgb12fg(attr));
  273. }
  274. uint32_t _cucul_attr_to_rgb24bg(uint32_t attr)
  275. {
  276. return RGB12TO24(_cucul_attr_to_rgb12bg(attr));
  277. }
  278. void _cucul_attr_to_argb4(uint32_t attr, uint8_t argb[8])
  279. {
  280. uint16_t fg = attr & 0xeffe;
  281. uint16_t bg = (attr >> 16) & 0xeffe;
  282. if(fg == (fg & 0x00f0))
  283. fg = ansitab[fg >> 4];
  284. else if(fg == (CUCUL_COLOR_DEFAULT << 4))
  285. fg = ansitab[CUCUL_COLOR_LIGHTGRAY];
  286. else if(fg == (CUCUL_COLOR_TRANSPARENT << 4))
  287. fg = 0x0fff;
  288. if(bg == (bg & 0x00f0))
  289. bg = ansitab[bg >> 4];
  290. else if(bg == (CUCUL_COLOR_DEFAULT << 4))
  291. bg = ansitab[CUCUL_COLOR_BLACK];
  292. else if(bg == (CUCUL_COLOR_TRANSPARENT << 4))
  293. bg = 0x0fff;
  294. argb[0] = bg >> 12;
  295. argb[1] = (bg >> 8) & 0xf;
  296. argb[2] = (bg >> 4) & 0xf;
  297. argb[3] = bg & 0xf;
  298. argb[4] = fg >> 12;
  299. argb[5] = (fg >> 8) & 0xf;
  300. argb[6] = (fg >> 4) & 0xf;
  301. argb[7] = fg & 0xf;
  302. }