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.
 
 
 
 
 
 

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