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.

преди 21 години
преди 15 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 15 години
преди 19 години
преди 15 години
преди 15 години
преди 15 години
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628
  1. /*
  2. * libcaca Colour ASCII-Art library
  3. * Copyright (c) 2002-2012 Sam Hocevar <sam@hocevar.net>
  4. * All Rights Reserved
  5. *
  6. * This library is free software. It comes without any warranty, to
  7. * the extent permitted by applicable law. You can redistribute it
  8. * and/or modify it under the terms of the Do What the Fuck You Want
  9. * to Public License, Version 2, as published by Sam Hocevar. See
  10. * http://www.wtfpl.net/ for more details.
  11. */
  12. /*
  13. * This file contains bitmap dithering functions.
  14. */
  15. #include "config.h"
  16. #if !defined(__KERNEL__)
  17. # if defined(HAVE_ENDIAN_H)
  18. # include <endian.h>
  19. # endif
  20. # include <stdio.h>
  21. # include <stdlib.h>
  22. # include <limits.h>
  23. # include <string.h>
  24. #endif
  25. #include "caca.h"
  26. #include "caca_internals.h"
  27. #define CP437 0
  28. /*
  29. * Local variables
  30. */
  31. #if !defined(_DOXYGEN_SKIP_ME)
  32. # define LOOKUP_VAL 32
  33. # define LOOKUP_SAT 32
  34. # define LOOKUP_HUE 16
  35. #endif
  36. static uint8_t hsv_distances[LOOKUP_VAL][LOOKUP_SAT][LOOKUP_HUE];
  37. static uint16_t lookup_colors[8];
  38. static int lookup_initialised = 0;
  39. static int const hsv_palette[] =
  40. {
  41. /* weight, hue, saturation, value */
  42. 4, 0x0, 0x0, 0x0, /* black */
  43. 5, 0x0, 0x0, 0x5ff, /* 30% */
  44. 5, 0x0, 0x0, 0x9ff, /* 70% */
  45. 4, 0x0, 0x0, 0xfff, /* white */
  46. 3, 0x1000, 0xfff, 0x5ff, /* dark yellow */
  47. 2, 0x1000, 0xfff, 0xfff, /* light yellow */
  48. 3, 0x0, 0xfff, 0x5ff, /* dark red */
  49. 2, 0x0, 0xfff, 0xfff /* light red */
  50. };
  51. /* RGB palette for the new colour picker */
  52. static int const rgb_palette[] =
  53. {
  54. 0x0, 0x0, 0x0,
  55. 0x0, 0x0, 0x7ff,
  56. 0x0, 0x7ff, 0x0,
  57. 0x0, 0x7ff, 0x7ff,
  58. 0x7ff, 0x0, 0x0,
  59. 0x7ff, 0x0, 0x7ff,
  60. 0x7ff, 0x7ff, 0x0,
  61. 0xaaa, 0xaaa, 0xaaa,
  62. 0x555, 0x555, 0x555,
  63. 0x000, 0x000, 0xfff,
  64. 0x000, 0xfff, 0x000,
  65. 0x000, 0xfff, 0xfff,
  66. 0xfff, 0x000, 0x000,
  67. 0xfff, 0x000, 0xfff,
  68. 0xfff, 0xfff, 0x000,
  69. 0xfff, 0xfff, 0xfff,
  70. };
  71. static int const rgb_weight[] =
  72. {
  73. /* 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2 */
  74. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
  75. };
  76. /* List of glyphs */
  77. static uint32_t ascii_glyphs[] =
  78. {
  79. ' ', '.', ':', ';', 't', '%', 'S', 'X', '@', '8', '?'
  80. };
  81. static uint32_t shades_glyphs[] =
  82. {
  83. /* ' '. '·', '░', '▒', '?' */
  84. ' ', 0xb7, 0x2591, 0x2592, '?'
  85. };
  86. static uint32_t blocks_glyphs[] =
  87. {
  88. /* ' ', '▘', '▚', '?' */
  89. ' ', 0x2598, 0x259a, '?'
  90. };
  91. #if !defined(_DOXYGEN_SKIP_ME)
  92. enum color_mode
  93. {
  94. COLOR_MODE_MONO,
  95. COLOR_MODE_GRAY,
  96. COLOR_MODE_8,
  97. COLOR_MODE_16,
  98. COLOR_MODE_FULLGRAY,
  99. COLOR_MODE_FULL8,
  100. COLOR_MODE_FULL16
  101. };
  102. struct caca_dither
  103. {
  104. int bpp, has_palette, has_alpha;
  105. int w, h, pitch;
  106. int rmask, gmask, bmask, amask;
  107. int rright, gright, bright, aright;
  108. int rleft, gleft, bleft, aleft;
  109. void (*get_hsv)(caca_dither_t *, char *, int, int);
  110. int red[256], green[256], blue[256], alpha[256];
  111. /* Colour features */
  112. float gamma, brightness, contrast;
  113. int gammatab[4097];
  114. /* Dithering features */
  115. char const *antialias_name;
  116. int antialias;
  117. char const *color_name;
  118. enum color_mode color;
  119. char const *algo_name;
  120. void (*init_dither) (int);
  121. int (*get_dither) (void);
  122. void (*increment_dither) (void);
  123. char const *glyph_name;
  124. uint32_t const * glyphs;
  125. int glyph_count;
  126. int invert;
  127. };
  128. #define HSV_XRATIO 6
  129. #define HSV_YRATIO 3
  130. #define HSV_HRATIO 3
  131. #define HSV_DISTANCE(h, s, v, index) \
  132. (hsv_palette[index * 4] \
  133. * ((HSV_XRATIO * ((v) - hsv_palette[index * 4 + 3]) \
  134. * ((v) - hsv_palette[index * 4 + 3])) \
  135. + (hsv_palette[index * 4 + 3] \
  136. ? (HSV_YRATIO * ((s) - hsv_palette[index * 4 + 2]) \
  137. * ((s) - hsv_palette[index * 4 + 2])) \
  138. : 0) \
  139. + (hsv_palette[index * 4 + 2] \
  140. ? (HSV_HRATIO * ((h) - hsv_palette[index * 4 + 1]) \
  141. * ((h) - hsv_palette[index * 4 + 1])) \
  142. : 0)))
  143. #endif
  144. /*
  145. * Local prototypes
  146. */
  147. static void mask2shift(uint32_t, int *, int *);
  148. static float gammapow(float x, float y);
  149. static void get_rgba_default(caca_dither_t const *, uint8_t const *, int, int,
  150. unsigned int *);
  151. static int init_lookup(void);
  152. /* Dithering algorithms */
  153. static void init_no_dither(int);
  154. static int get_no_dither(void);
  155. static void increment_no_dither(void);
  156. static void init_fstein_dither(int);
  157. static int get_fstein_dither(void);
  158. static void increment_fstein_dither(void);
  159. static void init_ordered2_dither(int);
  160. static int get_ordered2_dither(void);
  161. static void increment_ordered2_dither(void);
  162. static void init_ordered4_dither(int);
  163. static int get_ordered4_dither(void);
  164. static void increment_ordered4_dither(void);
  165. static void init_ordered8_dither(int);
  166. static int get_ordered8_dither(void);
  167. static void increment_ordered8_dither(void);
  168. static void init_random_dither(int);
  169. static int get_random_dither(void);
  170. static void increment_random_dither(void);
  171. static inline int sq(int x)
  172. {
  173. return x * x;
  174. }
  175. static inline void rgb2hsv_default(int r, int g, int b,
  176. int *hue, int *sat, int *val)
  177. {
  178. int min, max, delta;
  179. min = r; max = r;
  180. if(min > g) min = g; if(max < g) max = g;
  181. if(min > b) min = b; if(max < b) max = b;
  182. delta = max - min; /* 0 - 0xfff */
  183. *val = max; /* 0 - 0xfff */
  184. if(delta)
  185. {
  186. *sat = 0xfff * delta / max; /* 0 - 0xfff */
  187. /* Generate *hue between 0 and 0x5fff */
  188. if( r == max )
  189. *hue = 0x1000 + 0x1000 * (g - b) / delta;
  190. else if( g == max )
  191. *hue = 0x3000 + 0x1000 * (b - r) / delta;
  192. else
  193. *hue = 0x5000 + 0x1000 * (r - g) / delta;
  194. }
  195. else
  196. {
  197. *sat = 0;
  198. *hue = 0;
  199. }
  200. }
  201. /** \brief Create an internal dither object.
  202. *
  203. * Create a dither structure from its coordinates (depth, width, height and
  204. * pitch) and pixel mask values. If the depth is 8 bits per pixel, the mask
  205. * values are ignored and the colour palette should be set using the
  206. * caca_set_dither_palette() function. For depths greater than 8 bits per
  207. * pixel, a zero alpha mask causes the alpha values to be ignored.
  208. *
  209. * If an error occurs, NULL is returned and \b errno is set accordingly:
  210. * - \c EINVAL Requested width, height, pitch or bits per pixel value was
  211. * invalid.
  212. * - \c ENOMEM Not enough memory to allocate dither structure.
  213. *
  214. * \param bpp Bitmap depth in bits per pixel.
  215. * \param w Bitmap width in pixels.
  216. * \param h Bitmap height in pixels.
  217. * \param pitch Bitmap pitch in bytes.
  218. * \param rmask Bitmask for red values.
  219. * \param gmask Bitmask for green values.
  220. * \param bmask Bitmask for blue values.
  221. * \param amask Bitmask for alpha values.
  222. * \return Dither object upon success, NULL if an error occurred.
  223. */
  224. caca_dither_t *caca_create_dither(int bpp, int w, int h, int pitch,
  225. uint32_t rmask, uint32_t gmask,
  226. uint32_t bmask, uint32_t amask)
  227. {
  228. caca_dither_t *d;
  229. int i;
  230. /* Minor sanity test */
  231. if(w < 0 || h < 0 || pitch < 0 || bpp > 32 || bpp < 8)
  232. {
  233. seterrno(EINVAL);
  234. return NULL;
  235. }
  236. d = malloc(sizeof(caca_dither_t));
  237. if(!d)
  238. {
  239. seterrno(ENOMEM);
  240. return NULL;
  241. }
  242. if(!lookup_initialised)
  243. {
  244. /* XXX: because we do not wish to be thread-safe, there is a slight
  245. * chance that the following code will be executed twice. It is
  246. * totally harmless. */
  247. init_lookup();
  248. lookup_initialised = 1;
  249. }
  250. d->bpp = bpp;
  251. d->has_palette = 0;
  252. d->has_alpha = amask ? 1 : 0;
  253. d->w = w;
  254. d->h = h;
  255. d->pitch = pitch;
  256. d->rmask = rmask;
  257. d->gmask = gmask;
  258. d->bmask = bmask;
  259. d->amask = amask;
  260. /* Load bitmasks */
  261. if(rmask || gmask || bmask || amask)
  262. {
  263. mask2shift(rmask, &d->rright, &d->rleft);
  264. mask2shift(gmask, &d->gright, &d->gleft);
  265. mask2shift(bmask, &d->bright, &d->bleft);
  266. mask2shift(amask, &d->aright, &d->aleft);
  267. }
  268. /* In 8 bpp mode, default to a grayscale palette */
  269. if(bpp == 8)
  270. {
  271. d->has_palette = 1;
  272. d->has_alpha = 0;
  273. for(i = 0; i < 256; i++)
  274. {
  275. d->red[i] = i * 0xfff / 256;
  276. d->green[i] = i * 0xfff / 256;
  277. d->blue[i] = i * 0xfff / 256;
  278. }
  279. }
  280. /* Default gamma value */
  281. d->gamma = 1.0;
  282. for(i = 0; i < 4096; i++)
  283. d->gammatab[i] = i;
  284. /* Default colour properties */
  285. d->brightness = 1.0;
  286. d->contrast = 1.0;
  287. /* Default features */
  288. d->antialias_name = "prefilter";
  289. d->antialias = 1;
  290. d->color_name = "full16";
  291. d->color = COLOR_MODE_FULL16;
  292. d->glyph_name = "ascii";
  293. d->glyphs = ascii_glyphs;
  294. d->glyph_count = sizeof(ascii_glyphs) / sizeof(*ascii_glyphs);
  295. d->algo_name = "fstein";
  296. d->init_dither = init_fstein_dither;
  297. d->get_dither = get_fstein_dither;
  298. d->increment_dither = increment_fstein_dither;
  299. d->invert = 0;
  300. return d;
  301. }
  302. /** \brief Set the palette of an 8bpp dither object.
  303. *
  304. * Set the palette of an 8 bits per pixel bitmap. Values should be between
  305. * 0 and 4095 (0xfff).
  306. *
  307. * If an error occurs, -1 is returned and \b errno is set accordingly:
  308. * - \c EINVAL Dither bits per pixel value is not 8, or one of the pixel
  309. * values was outside the range 0 - 4095.
  310. *
  311. * \param d Dither object.
  312. * \param red Array of 256 red values.
  313. * \param green Array of 256 green values.
  314. * \param blue Array of 256 blue values.
  315. * \param alpha Array of 256 alpha values.
  316. * \return 0 in case of success, -1 if an error occurred.
  317. */
  318. int caca_set_dither_palette(caca_dither_t *d,
  319. uint32_t red[], uint32_t green[],
  320. uint32_t blue[], uint32_t alpha[])
  321. {
  322. int i, has_alpha = 0;
  323. if(d->bpp != 8)
  324. {
  325. seterrno(EINVAL);
  326. return -1;
  327. }
  328. for(i = 0; i < 256; i++)
  329. {
  330. if((red[i] | green[i] | blue[i] | alpha[i]) >= 0x1000)
  331. {
  332. seterrno(EINVAL);
  333. return -1;
  334. }
  335. }
  336. for(i = 0; i < 256; i++)
  337. {
  338. d->red[i] = red[i];
  339. d->green[i] = green[i];
  340. d->blue[i] = blue[i];
  341. if(alpha[i])
  342. {
  343. d->alpha[i] = alpha[i];
  344. has_alpha = 1;
  345. }
  346. }
  347. d->has_alpha = has_alpha;
  348. return 0;
  349. }
  350. /** \brief Set the brightness of a dither object.
  351. *
  352. * Set the brightness of dither.
  353. *
  354. * If an error occurs, -1 is returned and \b errno is set accordingly:
  355. * - \c EINVAL Brightness value was out of range.
  356. *
  357. * \param d Dither object.
  358. * \param brightness brightness value.
  359. * \return 0 in case of success, -1 if an error occurred.
  360. */
  361. int caca_set_dither_brightness(caca_dither_t *d, float brightness)
  362. {
  363. /* FIXME */
  364. d->brightness = brightness;
  365. return 0;
  366. }
  367. /** \brief Get the brightness of a dither object.
  368. *
  369. * Get the brightness of the given dither object.
  370. *
  371. * This function never fails.
  372. *
  373. * \param d Dither object.
  374. * \return Brightness value.
  375. */
  376. float caca_get_dither_brightness(caca_dither_t const *d)
  377. {
  378. return d->brightness;
  379. }
  380. /** \brief Set the gamma of a dither object.
  381. *
  382. * Set the gamma of the given dither object. A negative value causes
  383. * colour inversion.
  384. *
  385. * If an error occurs, -1 is returned and \b errno is set accordingly:
  386. * - \c EINVAL Gamma value was out of range.
  387. *
  388. * \param d Dither object.
  389. * \param gamma Gamma value.
  390. * \return 0 in case of success, -1 if an error occurred.
  391. */
  392. int caca_set_dither_gamma(caca_dither_t *d, float gamma)
  393. {
  394. /* FIXME: we don't need 4096 calls to gammapow(), we could just compute
  395. * a few of them and do linear interpolation for the rest. This will
  396. * probably speed up things a lot. */
  397. int i;
  398. if(gamma < 0.0)
  399. {
  400. d->invert = 1;
  401. gamma = -gamma;
  402. }
  403. else if(gamma == 0.0)
  404. {
  405. seterrno(EINVAL);
  406. return -1;
  407. }
  408. d->gamma = gamma;
  409. for(i = 0; i < 4096; i++)
  410. d->gammatab[i] = 4096.0 * gammapow((float)i / 4096.0, 1.0 / gamma);
  411. return 0;
  412. }
  413. /** \brief Get the gamma of a dither object.
  414. *
  415. * Get the gamma of the given dither object.
  416. *
  417. * This function never fails.
  418. *
  419. * \param d Dither object.
  420. * \return Gamma value.
  421. */
  422. float caca_get_dither_gamma(caca_dither_t const *d)
  423. {
  424. return d->gamma;
  425. }
  426. /** \brief Set the contrast of a dither object.
  427. *
  428. * Set the contrast of dither.
  429. *
  430. * If an error occurs, -1 is returned and \b errno is set accordingly:
  431. * - \c EINVAL Contrast value was out of range.
  432. *
  433. * \param d Dither object.
  434. * \param contrast contrast value.
  435. * \return 0 in case of success, -1 if an error occurred.
  436. */
  437. int caca_set_dither_contrast(caca_dither_t *d, float contrast)
  438. {
  439. /* FIXME */
  440. d->contrast = contrast;
  441. return 0;
  442. }
  443. /** \brief Get the contrast of a dither object.
  444. *
  445. * Get the contrast of the given dither object.
  446. *
  447. * This function never fails.
  448. *
  449. * \param d Dither object.
  450. * \return Contrast value.
  451. */
  452. float caca_get_dither_contrast(caca_dither_t const *d)
  453. {
  454. return d->contrast;
  455. }
  456. /** \brief Set dither antialiasing
  457. *
  458. * Tell the renderer whether to antialias the dither. Antialiasing smoothens
  459. * the rendered image and avoids the commonly seen staircase effect.
  460. * - \c "none": no antialiasing.
  461. * - \c "prefilter" or \c "default": simple prefilter antialiasing. This
  462. * is the default value.
  463. *
  464. * If an error occurs, -1 is returned and \b errno is set accordingly:
  465. * - \c EINVAL Invalid antialiasing mode.
  466. *
  467. * \param d Dither object.
  468. * \param str A string describing the antialiasing method that will be used
  469. * for the dithering.
  470. * \return 0 in case of success, -1 if an error occurred.
  471. */
  472. int caca_set_dither_antialias(caca_dither_t *d, char const *str)
  473. {
  474. if(!strcasecmp(str, "none"))
  475. {
  476. d->antialias_name = "none";
  477. d->antialias = 0;
  478. }
  479. else if(!strcasecmp(str, "prefilter") || !strcasecmp(str, "default"))
  480. {
  481. d->antialias_name = "prefilter";
  482. d->antialias = 1;
  483. }
  484. else
  485. {
  486. seterrno(EINVAL);
  487. return -1;
  488. }
  489. return 0;
  490. }
  491. /** \brief Get available antialiasing methods
  492. *
  493. * Return a list of available antialiasing methods for a given dither. The
  494. * list is a NULL-terminated array of strings, interleaving a string
  495. * containing the internal value for the antialiasing method to be used with
  496. * caca_set_dither_antialias(), and a string containing the natural
  497. * language description for that antialiasing method.
  498. *
  499. * This function never fails.
  500. *
  501. * \param d Dither object.
  502. * \return An array of strings.
  503. */
  504. char const * const *
  505. caca_get_dither_antialias_list(caca_dither_t const *d)
  506. {
  507. static char const * const list[] =
  508. {
  509. "none", "No antialiasing",
  510. "prefilter", "Prefilter antialiasing",
  511. NULL, NULL
  512. };
  513. return list;
  514. }
  515. /** \brief Get current antialiasing method
  516. *
  517. * Return the given dither's current antialiasing method.
  518. *
  519. * This function never fails.
  520. *
  521. * \param d Dither object.
  522. * \return A static string.
  523. */
  524. char const * caca_get_dither_antialias(caca_dither_t const *d)
  525. {
  526. return d->antialias_name;
  527. }
  528. /** \brief Choose colours used for dithering
  529. *
  530. * Tell the renderer which colours should be used to render the
  531. * bitmap. Valid values for \c str are:
  532. * - \c "mono": use light gray on a black background.
  533. * - \c "gray": use white and two shades of gray on a black background.
  534. * - \c "8": use the 8 ANSI colours on a black background.
  535. * - \c "16": use the 16 ANSI colours on a black background.
  536. * - \c "fullgray": use black, white and two shades of gray for both the
  537. * characters and the background.
  538. * - \c "full8": use the 8 ANSI colours for both the characters and the
  539. * background.
  540. * - \c "full16" or \c "default": use the 16 ANSI colours for both the
  541. * characters and the background. This is the default value.
  542. *
  543. * If an error occurs, -1 is returned and \b errno is set accordingly:
  544. * - \c EINVAL Invalid colour set.
  545. *
  546. * \param d Dither object.
  547. * \param str A string describing the colour set that will be used
  548. * for the dithering.
  549. * \return 0 in case of success, -1 if an error occurred.
  550. */
  551. int caca_set_dither_color(caca_dither_t *d, char const *str)
  552. {
  553. if(!strcasecmp(str, "mono"))
  554. {
  555. d->color_name = "mono";
  556. d->color = COLOR_MODE_MONO;
  557. }
  558. else if(!strcasecmp(str, "gray"))
  559. {
  560. d->color_name = "gray";
  561. d->color = COLOR_MODE_GRAY;
  562. }
  563. else if(!strcasecmp(str, "8"))
  564. {
  565. d->color_name = "8";
  566. d->color = COLOR_MODE_8;
  567. }
  568. else if(!strcasecmp(str, "16"))
  569. {
  570. d->color_name = "16";
  571. d->color = COLOR_MODE_16;
  572. }
  573. else if(!strcasecmp(str, "fullgray"))
  574. {
  575. d->color_name = "fullgray";
  576. d->color = COLOR_MODE_FULLGRAY;
  577. }
  578. else if(!strcasecmp(str, "full8"))
  579. {
  580. d->color_name = "full8";
  581. d->color = COLOR_MODE_FULL8;
  582. }
  583. else if(!strcasecmp(str, "full16") || !strcasecmp(str, "default"))
  584. {
  585. d->color_name = "full16";
  586. d->color = COLOR_MODE_FULL16;
  587. }
  588. else
  589. {
  590. seterrno(EINVAL);
  591. return -1;
  592. }
  593. return 0;
  594. }
  595. /** \brief Get available colour modes
  596. *
  597. * Return a list of available colour modes for a given dither. The list
  598. * is a NULL-terminated array of strings, interleaving a string containing
  599. * the internal value for the colour mode, to be used with
  600. * caca_set_dither_color(), and a string containing the natural
  601. * language description for that colour mode.
  602. *
  603. * This function never fails.
  604. *
  605. * \param d Dither object.
  606. * \return An array of strings.
  607. */
  608. char const * const *
  609. caca_get_dither_color_list(caca_dither_t const *d)
  610. {
  611. static char const * const list[] =
  612. {
  613. "mono", "white on black",
  614. "gray", "grayscale on black",
  615. "8", "8 colours on black",
  616. "16", "16 colours on black",
  617. "fullgray", "full grayscale",
  618. "full8", "full 8 colours",
  619. "full16", "full 16 colours",
  620. NULL, NULL
  621. };
  622. return list;
  623. }
  624. /** \brief Get current colour mode
  625. *
  626. * Return the given dither's current colour mode.
  627. *
  628. * This function never fails.
  629. *
  630. * \param d Dither object.
  631. * \return A static string.
  632. */
  633. char const * caca_get_dither_color(caca_dither_t const *d)
  634. {
  635. return d->color_name;
  636. }
  637. /** \brief Choose characters used for dithering
  638. *
  639. * Tell the renderer which characters should be used to render the
  640. * dither. Valid values for \c str are:
  641. * - \c "ascii" or \c "default": use only ASCII characters. This is the
  642. * default value.
  643. * - \c "shades": use Unicode characters "U+2591 LIGHT SHADE", "U+2592
  644. * MEDIUM SHADE" and "U+2593 DARK SHADE". These characters are also
  645. * present in the CP437 codepage available on DOS and VGA.
  646. * - \c "blocks": use Unicode quarter-cell block combinations. These
  647. * characters are only found in the Unicode set.
  648. *
  649. * If an error occurs, -1 is returned and \b errno is set accordingly:
  650. * - \c EINVAL Invalid character set.
  651. *
  652. * \param d Dither object.
  653. * \param str A string describing the characters that need to be used
  654. * for the dithering.
  655. * \return 0 in case of success, -1 if an error occurred.
  656. */
  657. int caca_set_dither_charset(caca_dither_t *d, char const *str)
  658. {
  659. if(!strcasecmp(str, "shades"))
  660. {
  661. d->glyph_name = "shades";
  662. d->glyphs = shades_glyphs;
  663. d->glyph_count = sizeof(shades_glyphs) / sizeof(*shades_glyphs);
  664. }
  665. else if(!strcasecmp(str, "blocks"))
  666. {
  667. d->glyph_name = "blocks";
  668. d->glyphs = blocks_glyphs;
  669. d->glyph_count = sizeof(blocks_glyphs) / sizeof(*blocks_glyphs);
  670. }
  671. else if(!strcasecmp(str, "ascii") || !strcasecmp(str, "default"))
  672. {
  673. d->glyph_name = "ascii";
  674. d->glyphs = ascii_glyphs;
  675. d->glyph_count = sizeof(ascii_glyphs) / sizeof(*ascii_glyphs);
  676. }
  677. else
  678. {
  679. seterrno(EINVAL);
  680. return -1;
  681. }
  682. return 0;
  683. }
  684. /** \brief Get available dither character sets
  685. *
  686. * Return a list of available character sets for a given dither. The list
  687. * is a NULL-terminated array of strings, interleaving a string containing
  688. * the internal value for the character set, to be used with
  689. * caca_set_dither_charset(), and a string containing the natural
  690. * language description for that character set.
  691. *
  692. * This function never fails.
  693. *
  694. * \param d Dither object.
  695. * \return An array of strings.
  696. */
  697. char const * const * caca_get_dither_charset_list(caca_dither_t const *d)
  698. {
  699. static char const * const list[] =
  700. {
  701. "ascii", "plain ASCII",
  702. "shades", "CP437 shades",
  703. "blocks", "Unicode blocks",
  704. NULL, NULL
  705. };
  706. return list;
  707. }
  708. /** \brief Get current character set
  709. *
  710. * Return the given dither's current character set.
  711. *
  712. * This function never fails.
  713. *
  714. * \param d Dither object.
  715. * \return A static string.
  716. */
  717. char const * caca_get_dither_charset(caca_dither_t const *d)
  718. {
  719. return d->glyph_name;
  720. }
  721. /** \brief Set dithering algorithm
  722. *
  723. * Tell the renderer which dithering algorithm should be used. Dithering is
  724. * necessary because the picture being rendered has usually far more colours
  725. * than the available palette. Valid values for \c str are:
  726. * - \c "none": no dithering is used, the nearest matching colour is used.
  727. * - \c "ordered2": use a 2x2 Bayer matrix for dithering.
  728. * - \c "ordered4": use a 4x4 Bayer matrix for dithering.
  729. * - \c "ordered8": use a 8x8 Bayer matrix for dithering.
  730. * - \c "random": use random dithering.
  731. * - \c "fstein": use Floyd-Steinberg dithering. This is the default value.
  732. *
  733. * If an error occurs, -1 is returned and \b errno is set accordingly:
  734. * - \c EINVAL Unknown dithering mode.
  735. *
  736. * \param d Dither object.
  737. * \param str A string describing the algorithm that needs to be used
  738. * for the dithering.
  739. * \return 0 in case of success, -1 if an error occurred.
  740. */
  741. int caca_set_dither_algorithm(caca_dither_t *d, char const *str)
  742. {
  743. if(!strcasecmp(str, "none"))
  744. {
  745. d->algo_name = "none";
  746. d->init_dither = init_no_dither;
  747. d->get_dither = get_no_dither;
  748. d->increment_dither = increment_no_dither;
  749. }
  750. else if(!strcasecmp(str, "ordered2"))
  751. {
  752. d->algo_name = "ordered2";
  753. d->init_dither = init_ordered2_dither;
  754. d->get_dither = get_ordered2_dither;
  755. d->increment_dither = increment_ordered2_dither;
  756. }
  757. else if(!strcasecmp(str, "ordered4"))
  758. {
  759. d->algo_name = "ordered4";
  760. d->init_dither = init_ordered4_dither;
  761. d->get_dither = get_ordered4_dither;
  762. d->increment_dither = increment_ordered4_dither;
  763. }
  764. else if(!strcasecmp(str, "ordered8"))
  765. {
  766. d->algo_name = "ordered8";
  767. d->init_dither = init_ordered8_dither;
  768. d->get_dither = get_ordered8_dither;
  769. d->increment_dither = increment_ordered8_dither;
  770. }
  771. else if(!strcasecmp(str, "random"))
  772. {
  773. d->algo_name = "random";
  774. d->init_dither = init_random_dither;
  775. d->get_dither = get_random_dither;
  776. d->increment_dither = increment_random_dither;
  777. }
  778. else if(!strcasecmp(str, "fstein") || !strcasecmp(str, "default"))
  779. {
  780. d->algo_name = "fstein";
  781. d->init_dither = init_fstein_dither;
  782. d->get_dither = get_fstein_dither;
  783. d->increment_dither = increment_fstein_dither;
  784. }
  785. else
  786. {
  787. seterrno(EINVAL);
  788. return -1;
  789. }
  790. return 0;
  791. }
  792. /** \brief Get dithering algorithms
  793. *
  794. * Return a list of available dithering algorithms for a given dither. The
  795. * list is a NULL-terminated array of strings, interleaving a string
  796. * containing the internal value for the dithering algorithm, to be used
  797. * with caca_set_dither_dithering(), and a string containing the natural
  798. * language description for that algorithm.
  799. *
  800. * This function never fails.
  801. *
  802. * \param d Dither object.
  803. * \return An array of strings.
  804. */
  805. char const * const * caca_get_dither_algorithm_list(caca_dither_t const *d)
  806. {
  807. static char const * const list[] =
  808. {
  809. "none", "no dithering",
  810. "ordered2", "2x2 ordered dithering",
  811. "ordered4", "4x4 ordered dithering",
  812. "ordered8", "8x8 ordered dithering",
  813. "random", "random dithering",
  814. "fstein", "Floyd-Steinberg dithering",
  815. NULL, NULL
  816. };
  817. return list;
  818. }
  819. /** \brief Get current dithering algorithm
  820. *
  821. * Return the given dither's current dithering algorithm.
  822. *
  823. * This function never fails.
  824. *
  825. * \param d Dither object.
  826. * \return A static string.
  827. */
  828. char const * caca_get_dither_algorithm(caca_dither_t const *d)
  829. {
  830. return d->algo_name;
  831. }
  832. /** \brief Dither a bitmap on the canvas.
  833. *
  834. * Dither a bitmap at the given coordinates. The dither can be of any size
  835. * and will be stretched to the text area.
  836. *
  837. * This function never fails.
  838. *
  839. * \param cv A handle to the libcaca canvas.
  840. * \param x X coordinate of the upper-left corner of the drawing area.
  841. * \param y Y coordinate of the upper-left corner of the drawing area.
  842. * \param w Width of the drawing area.
  843. * \param h Height of the drawing area.
  844. * \param d Dither object to be drawn.
  845. * \param pixels Bitmap's pixels.
  846. * \return This function always returns 0.
  847. */
  848. int caca_dither_bitmap(caca_canvas_t *cv, int x, int y, int w, int h,
  849. caca_dither_t const *d, void const *pixels)
  850. {
  851. int *floyd_steinberg, *fs_r, *fs_g, *fs_b;
  852. uint32_t savedattr;
  853. int fs_length;
  854. int x1, y1, x2, y2, pitch, deltax, deltay, dchmax;
  855. if(!d || !pixels)
  856. return 0;
  857. savedattr = caca_get_attr(cv, -1, -1);
  858. x1 = x; x2 = x + w - 1;
  859. y1 = y; y2 = y + h - 1;
  860. /* FIXME: do not overwrite arguments */
  861. w = d->w;
  862. h = d->h;
  863. pitch = d->pitch;
  864. deltax = x2 - x1 + 1;
  865. deltay = y2 - y1 + 1;
  866. dchmax = d->glyph_count;
  867. fs_length = ((int)cv->width <= x2 ? (int)cv->width : x2) + 1;
  868. floyd_steinberg = malloc(3 * (fs_length + 2) * sizeof(int));
  869. memset(floyd_steinberg, 0, 3 * (fs_length + 2) * sizeof(int));
  870. fs_r = floyd_steinberg + 1;
  871. fs_g = fs_r + fs_length + 2;
  872. fs_b = fs_g + fs_length + 2;
  873. for(y = y1 > 0 ? y1 : 0; y <= y2 && y <= (int)cv->height; y++)
  874. {
  875. int remain_r = 0, remain_g = 0, remain_b = 0;
  876. for(x = x1 > 0 ? x1 : 0, d->init_dither(y);
  877. x <= x2 && x <= (int)cv->width;
  878. x++)
  879. {
  880. unsigned int rgba[4];
  881. int error[3];
  882. int i, ch = 0, distmin;
  883. int fg_r = 0, fg_g = 0, fg_b = 0, bg_r, bg_g, bg_b;
  884. int fromx, fromy, tox, toy, myx, myy, dots, dist;
  885. int outfg = 0, outbg = 0;
  886. uint32_t outch;
  887. rgba[0] = rgba[1] = rgba[2] = rgba[3] = 0;
  888. /* First get RGB */
  889. if(d->antialias)
  890. {
  891. fromx = (x - x1) * w / deltax;
  892. fromy = (y - y1) * h / deltay;
  893. tox = (x - x1 + 1) * w / deltax;
  894. toy = (y - y1 + 1) * h / deltay;
  895. /* We want at least one pixel */
  896. if(tox == fromx) tox++;
  897. if(toy == fromy) toy++;
  898. dots = 0;
  899. for(myx = fromx; myx < tox; myx++)
  900. for(myy = fromy; myy < toy; myy++)
  901. {
  902. dots++;
  903. get_rgba_default(d, pixels, myx, myy, rgba);
  904. }
  905. /* Normalize */
  906. rgba[0] /= dots;
  907. rgba[1] /= dots;
  908. rgba[2] /= dots;
  909. rgba[3] /= dots;
  910. }
  911. else
  912. {
  913. fromx = (x - x1) * w / deltax;
  914. fromy = (y - y1) * h / deltay;
  915. tox = (x - x1 + 1) * w / deltax;
  916. toy = (y - y1 + 1) * h / deltay;
  917. /* tox and toy can overflow the canvas, but they cannot overflow
  918. * when averaged with fromx and fromy because these are guaranteed
  919. * to be within the pixel boundaries. */
  920. myx = (fromx + tox) / 2;
  921. myy = (fromy + toy) / 2;
  922. get_rgba_default(d, pixels, myx, myy, rgba);
  923. }
  924. /* FIXME: hack to force greyscale */
  925. if(d->color == COLOR_MODE_FULLGRAY)
  926. {
  927. unsigned int gray = (3 * rgba[0] + 4 * rgba[1] + rgba[2] + 4) / 8;
  928. rgba[0] = rgba[1] = rgba[2] = gray;
  929. }
  930. if(d->has_alpha && rgba[3] < 0x800)
  931. {
  932. remain_r = remain_g = remain_b = 0;
  933. fs_r[x] = 0;
  934. fs_g[x] = 0;
  935. fs_b[x] = 0;
  936. continue;
  937. }
  938. /* XXX: OMG HAX */
  939. if(d->init_dither == init_fstein_dither)
  940. {
  941. rgba[0] += remain_r;
  942. rgba[1] += remain_g;
  943. rgba[2] += remain_b;
  944. }
  945. else
  946. {
  947. rgba[0] += (d->get_dither() - 0x80) * 4;
  948. rgba[1] += (d->get_dither() - 0x80) * 4;
  949. rgba[2] += (d->get_dither() - 0x80) * 4;
  950. }
  951. distmin = INT_MAX;
  952. for(i = 0; i < 16; i++)
  953. {
  954. if(d->color == COLOR_MODE_FULLGRAY
  955. && (rgb_palette[i * 3] != rgb_palette[i * 3 + 1]
  956. || rgb_palette[i * 3] != rgb_palette[i * 3 + 2]))
  957. continue;
  958. dist = sq(rgba[0] - rgb_palette[i * 3])
  959. + sq(rgba[1] - rgb_palette[i * 3 + 1])
  960. + sq(rgba[2] - rgb_palette[i * 3 + 2]);
  961. dist *= rgb_weight[i];
  962. if(dist < distmin)
  963. {
  964. outbg = i;
  965. distmin = dist;
  966. }
  967. }
  968. bg_r = rgb_palette[outbg * 3];
  969. bg_g = rgb_palette[outbg * 3 + 1];
  970. bg_b = rgb_palette[outbg * 3 + 2];
  971. /* FIXME: we currently only honour "full16" */
  972. if(d->color == COLOR_MODE_FULL16 || d->color == COLOR_MODE_FULLGRAY)
  973. {
  974. distmin = INT_MAX;
  975. for(i = 0; i < 16; i++)
  976. {
  977. if(i == outbg)
  978. continue;
  979. if(d->color == COLOR_MODE_FULLGRAY
  980. && (rgb_palette[i * 3] != rgb_palette[i * 3 + 1]
  981. || rgb_palette[i * 3] != rgb_palette[i * 3 + 2]))
  982. continue;
  983. dist = sq(rgba[0] - rgb_palette[i * 3])
  984. + sq(rgba[1] - rgb_palette[i * 3 + 1])
  985. + sq(rgba[2] - rgb_palette[i * 3 + 2]);
  986. dist *= rgb_weight[i];
  987. if(dist < distmin)
  988. {
  989. outfg = i;
  990. distmin = dist;
  991. }
  992. }
  993. fg_r = rgb_palette[outfg * 3];
  994. fg_g = rgb_palette[outfg * 3 + 1];
  995. fg_b = rgb_palette[outfg * 3 + 2];
  996. distmin = INT_MAX;
  997. for(i = 0; i < dchmax - 1; i++)
  998. {
  999. int newr = i * fg_r + ((2*dchmax-1) - i) * bg_r;
  1000. int newg = i * fg_g + ((2*dchmax-1) - i) * bg_g;
  1001. int newb = i * fg_b + ((2*dchmax-1) - i) * bg_b;
  1002. dist = abs(rgba[0] * (2*dchmax-1) - newr)
  1003. + abs(rgba[1] * (2*dchmax-1) - newg)
  1004. + abs(rgba[2] * (2*dchmax-1) - newb);
  1005. if(dist < distmin)
  1006. {
  1007. ch = i;
  1008. distmin = dist;
  1009. }
  1010. }
  1011. outch = d->glyphs[ch];
  1012. /* XXX: OMG HAX */
  1013. if(d->init_dither == init_fstein_dither)
  1014. {
  1015. error[0] = rgba[0] - (fg_r * ch + bg_r * ((2*dchmax-1) - ch)) / (2*dchmax-1);
  1016. error[1] = rgba[1] - (fg_g * ch + bg_g * ((2*dchmax-1) - ch)) / (2*dchmax-1);
  1017. error[2] = rgba[2] - (fg_b * ch + bg_b * ((2*dchmax-1) - ch)) / (2*dchmax-1);
  1018. }
  1019. }
  1020. else
  1021. {
  1022. unsigned int lum = rgba[0];
  1023. if(rgba[1] > lum) lum = rgba[1];
  1024. if(rgba[2] > lum) lum = rgba[2];
  1025. outfg = outbg;
  1026. outbg = CACA_BLACK;
  1027. ch = lum * dchmax / 0x1000;
  1028. if(ch < 0)
  1029. ch = 0;
  1030. else if(ch > (int)(dchmax - 1))
  1031. ch = dchmax - 1;
  1032. outch = d->glyphs[ch];
  1033. /* XXX: OMG HAX */
  1034. if(d->init_dither == init_fstein_dither)
  1035. {
  1036. error[0] = rgba[0] - bg_r * ch / (dchmax-1);
  1037. error[1] = rgba[1] - bg_g * ch / (dchmax-1);
  1038. error[2] = rgba[2] - bg_b * ch / (dchmax-1);
  1039. }
  1040. }
  1041. /* XXX: OMG HAX */
  1042. if(d->init_dither == init_fstein_dither)
  1043. {
  1044. remain_r = fs_r[x+1] + 7 * error[0] / 16;
  1045. remain_g = fs_g[x+1] + 7 * error[1] / 16;
  1046. remain_b = fs_b[x+1] + 7 * error[2] / 16;
  1047. fs_r[x-1] += 3 * error[0] / 16;
  1048. fs_g[x-1] += 3 * error[1] / 16;
  1049. fs_b[x-1] += 3 * error[2] / 16;
  1050. fs_r[x] = 5 * error[0] / 16;
  1051. fs_g[x] = 5 * error[1] / 16;
  1052. fs_b[x] = 5 * error[2] / 16;
  1053. fs_r[x+1] = 1 * error[0] / 16;
  1054. fs_g[x+1] = 1 * error[1] / 16;
  1055. fs_b[x+1] = 1 * error[2] / 16;
  1056. }
  1057. if(d->invert)
  1058. {
  1059. outfg = 15 - outfg;
  1060. outbg = 15 - outbg;
  1061. }
  1062. /* Now output the character */
  1063. caca_set_color_ansi(cv, outfg, outbg);
  1064. caca_put_char(cv, x, y, outch);
  1065. d->increment_dither();
  1066. }
  1067. /* end loop */
  1068. }
  1069. free(floyd_steinberg);
  1070. caca_set_attr(cv, savedattr);
  1071. return 0;
  1072. }
  1073. /** \brief Free the memory associated with a dither.
  1074. *
  1075. * Free the memory allocated by caca_create_dither().
  1076. *
  1077. * This function never fails.
  1078. *
  1079. * \param d Dither object.
  1080. * \return This function always returns 0.
  1081. */
  1082. int caca_free_dither(caca_dither_t *d)
  1083. {
  1084. if(!d)
  1085. return 0;
  1086. free(d);
  1087. return 0;
  1088. }
  1089. /*
  1090. * XXX: The following functions are local.
  1091. */
  1092. /* Convert a mask, eg. 0x0000ff00, to shift values, eg. 8 and -4. */
  1093. static void mask2shift(uint32_t mask, int *right, int *left)
  1094. {
  1095. int rshift = 0, lshift = 0;
  1096. if(!mask)
  1097. {
  1098. *right = *left = 0;
  1099. return;
  1100. }
  1101. while(!(mask & 1))
  1102. {
  1103. mask >>= 1;
  1104. rshift++;
  1105. }
  1106. *right = rshift;
  1107. while(mask & 1)
  1108. {
  1109. mask >>= 1;
  1110. lshift++;
  1111. }
  1112. *left = 12 - lshift;
  1113. }
  1114. /* Compute x^y without relying on the math library */
  1115. static float gammapow(float x, float y)
  1116. {
  1117. #ifdef HAVE_FLDLN2
  1118. register double logx;
  1119. register long double v, e;
  1120. #else
  1121. register float tmp, t, t2, r;
  1122. int i;
  1123. #endif
  1124. if(x == 0.0)
  1125. return y == 0.0 ? 1.0 : 0.0;
  1126. #ifdef HAVE_FLDLN2
  1127. /* FIXME: this can be optimised by directly calling fyl2x for x and y */
  1128. asm volatile("fldln2; fxch; fyl2x"
  1129. : "=t" (logx) : "0" (x) : "st(1)");
  1130. asm volatile("fldl2e\n\t"
  1131. "fmul %%st(1)\n\t"
  1132. "fst %%st(1)\n\t"
  1133. "frndint\n\t"
  1134. "fxch\n\t"
  1135. "fsub %%st(1)\n\t"
  1136. "f2xm1\n\t"
  1137. : "=t" (v), "=u" (e) : "0" (y * logx));
  1138. v += 1.0;
  1139. asm volatile("fscale"
  1140. : "=t" (v) : "0" (v), "u" (e));
  1141. return v;
  1142. #else
  1143. /* Compute ln(x) for x ∈ ]0,1]
  1144. * ln(x) = 2 * (t + t^3/3 + t^5/5 + ...) with t = (x-1)/(x+1)
  1145. * The convergence is a bit slow, especially when x is near 0. */
  1146. t = (x - 1.0) / (x + 1.0);
  1147. t2 = t * t;
  1148. tmp = r = t;
  1149. for(i = 3; i < 20; i += 2)
  1150. {
  1151. r *= t2;
  1152. tmp += r / i;
  1153. }
  1154. /* Compute -y*ln(x) */
  1155. tmp = - y * 2.0 * tmp;
  1156. /* Compute x^-y as e^t where t = -y*ln(x):
  1157. * e^t = 1 + t/1! + t^2/2! + t^3/3! + t^4/4! + t^5/5! ...
  1158. * The convergence is quite faster here, thanks to the factorial. */
  1159. r = t = tmp;
  1160. tmp = 1.0 + t;
  1161. for(i = 2; i < 16; i++)
  1162. {
  1163. r = r * t / i;
  1164. tmp += r;
  1165. }
  1166. /* Return x^y as 1/(x^-y) */
  1167. return 1.0 / tmp;
  1168. #endif
  1169. }
  1170. static void get_rgba_default(caca_dither_t const *d, uint8_t const *pixels,
  1171. int x, int y, unsigned int *rgba)
  1172. {
  1173. uint32_t bits;
  1174. pixels += (d->bpp / 8) * x + d->pitch * y;
  1175. switch(d->bpp / 8)
  1176. {
  1177. case 4:
  1178. bits = *(uint32_t const *)pixels;
  1179. break;
  1180. case 3:
  1181. {
  1182. #if defined(HAVE_ENDIAN_H)
  1183. if(__BYTE_ORDER == __BIG_ENDIAN)
  1184. #else
  1185. /* This is compile-time optimised with at least -O1 or -Os */
  1186. uint32_t const tmp = 0x12345678;
  1187. if(*(uint8_t const *)&tmp == 0x12)
  1188. #endif
  1189. bits = ((uint32_t)pixels[0] << 16) |
  1190. ((uint32_t)pixels[1] << 8) |
  1191. ((uint32_t)pixels[2]);
  1192. else
  1193. bits = ((uint32_t)pixels[2] << 16) |
  1194. ((uint32_t)pixels[1] << 8) |
  1195. ((uint32_t)pixels[0]);
  1196. break;
  1197. }
  1198. case 2:
  1199. bits = *(uint16_t const *)pixels;
  1200. break;
  1201. case 1:
  1202. default:
  1203. bits = pixels[0];
  1204. break;
  1205. }
  1206. if(d->has_palette)
  1207. {
  1208. rgba[0] += d->gammatab[d->red[bits]];
  1209. rgba[1] += d->gammatab[d->green[bits]];
  1210. rgba[2] += d->gammatab[d->blue[bits]];
  1211. rgba[3] += d->alpha[bits];
  1212. }
  1213. else
  1214. {
  1215. rgba[0] += d->gammatab[((bits & d->rmask) >> d->rright) << d->rleft];
  1216. rgba[1] += d->gammatab[((bits & d->gmask) >> d->gright) << d->gleft];
  1217. rgba[2] += d->gammatab[((bits & d->bmask) >> d->bright) << d->bleft];
  1218. rgba[3] += ((bits & d->amask) >> d->aright) << d->aleft;
  1219. }
  1220. }
  1221. /*
  1222. * No dithering
  1223. */
  1224. static void init_no_dither(int line)
  1225. {
  1226. ;
  1227. }
  1228. static int get_no_dither(void)
  1229. {
  1230. return 0x80;
  1231. }
  1232. static void increment_no_dither(void)
  1233. {
  1234. return;
  1235. }
  1236. /*
  1237. * Floyd-Steinberg dithering
  1238. */
  1239. static void init_fstein_dither(int line)
  1240. {
  1241. ;
  1242. }
  1243. static int get_fstein_dither(void)
  1244. {
  1245. return 0x80;
  1246. }
  1247. static void increment_fstein_dither(void)
  1248. {
  1249. return;
  1250. }
  1251. /*
  1252. * Ordered 2 dithering
  1253. */
  1254. static int const *ordered2_table;
  1255. static int ordered2_index;
  1256. static void init_ordered2_dither(int line)
  1257. {
  1258. static int const dither2x2[] =
  1259. {
  1260. 0x00, 0x80,
  1261. 0xc0, 0x40,
  1262. };
  1263. ordered2_table = dither2x2 + (line % 2) * 2;
  1264. ordered2_index = 0;
  1265. }
  1266. static int get_ordered2_dither(void)
  1267. {
  1268. return ordered2_table[ordered2_index];
  1269. }
  1270. static void increment_ordered2_dither(void)
  1271. {
  1272. ordered2_index = (ordered2_index + 1) % 2;
  1273. }
  1274. /*
  1275. * Ordered 4 dithering
  1276. */
  1277. /*static int dither4x4[] = { 5, 0, 1, 6,
  1278. -1, -6, -5, 2,
  1279. -2, -7, -8, 3,
  1280. 4, -3, -4, -7};*/
  1281. static int const *ordered4_table;
  1282. static int ordered4_index;
  1283. static void init_ordered4_dither(int line)
  1284. {
  1285. static int const dither4x4[] =
  1286. {
  1287. 0x00, 0x80, 0x20, 0xa0,
  1288. 0xc0, 0x40, 0xe0, 0x60,
  1289. 0x30, 0xb0, 0x10, 0x90,
  1290. 0xf0, 0x70, 0xd0, 0x50
  1291. };
  1292. ordered4_table = dither4x4 + (line % 4) * 4;
  1293. ordered4_index = 0;
  1294. }
  1295. static int get_ordered4_dither(void)
  1296. {
  1297. return ordered4_table[ordered4_index];
  1298. }
  1299. static void increment_ordered4_dither(void)
  1300. {
  1301. ordered4_index = (ordered4_index + 1) % 4;
  1302. }
  1303. /*
  1304. * Ordered 8 dithering
  1305. */
  1306. static int const *ordered8_table;
  1307. static int ordered8_index;
  1308. static void init_ordered8_dither(int line)
  1309. {
  1310. static int const dither8x8[] =
  1311. {
  1312. 0x00, 0x80, 0x20, 0xa0, 0x08, 0x88, 0x28, 0xa8,
  1313. 0xc0, 0x40, 0xe0, 0x60, 0xc8, 0x48, 0xe8, 0x68,
  1314. 0x30, 0xb0, 0x10, 0x90, 0x38, 0xb8, 0x18, 0x98,
  1315. 0xf0, 0x70, 0xd0, 0x50, 0xf8, 0x78, 0xd8, 0x58,
  1316. 0x0c, 0x8c, 0x2c, 0xac, 0x04, 0x84, 0x24, 0xa4,
  1317. 0xcc, 0x4c, 0xec, 0x6c, 0xc4, 0x44, 0xe4, 0x64,
  1318. 0x3c, 0xbc, 0x1c, 0x9c, 0x34, 0xb4, 0x14, 0x94,
  1319. 0xfc, 0x7c, 0xdc, 0x5c, 0xf4, 0x74, 0xd4, 0x54,
  1320. };
  1321. ordered8_table = dither8x8 + (line % 8) * 8;
  1322. ordered8_index = 0;
  1323. }
  1324. static int get_ordered8_dither(void)
  1325. {
  1326. return ordered8_table[ordered8_index];
  1327. }
  1328. static void increment_ordered8_dither(void)
  1329. {
  1330. ordered8_index = (ordered8_index + 1) % 8;
  1331. }
  1332. /*
  1333. * Random dithering
  1334. */
  1335. static void init_random_dither(int line)
  1336. {
  1337. ;
  1338. }
  1339. static int get_random_dither(void)
  1340. {
  1341. return caca_rand(0x00, 0x100);
  1342. }
  1343. static void increment_random_dither(void)
  1344. {
  1345. return;
  1346. }
  1347. /*
  1348. * Lookup tables
  1349. */
  1350. static int init_lookup(void)
  1351. {
  1352. int v, s, h;
  1353. /* These ones are constant */
  1354. lookup_colors[0] = CACA_BLACK;
  1355. lookup_colors[1] = CACA_DARKGRAY;
  1356. lookup_colors[2] = CACA_LIGHTGRAY;
  1357. lookup_colors[3] = CACA_WHITE;
  1358. /* These ones will be overwritten */
  1359. lookup_colors[4] = CACA_MAGENTA;
  1360. lookup_colors[5] = CACA_LIGHTMAGENTA;
  1361. lookup_colors[6] = CACA_RED;
  1362. lookup_colors[7] = CACA_LIGHTRED;
  1363. for(v = 0; v < LOOKUP_VAL; v++)
  1364. for(s = 0; s < LOOKUP_SAT; s++)
  1365. for(h = 0; h < LOOKUP_HUE; h++)
  1366. {
  1367. int i, distbg, distfg, dist;
  1368. int val, sat, hue;
  1369. uint8_t outbg, outfg;
  1370. val = 0xfff * v / (LOOKUP_VAL - 1);
  1371. sat = 0xfff * s / (LOOKUP_SAT - 1);
  1372. hue = 0xfff * h / (LOOKUP_HUE - 1);
  1373. /* Initialise distances to the distance between pure black HSV
  1374. * coordinates and our white colour (3) */
  1375. outbg = outfg = 3;
  1376. distbg = distfg = HSV_DISTANCE(0, 0, 0, 3);
  1377. /* Calculate distances to eight major colour values and store the
  1378. * two nearest points in our lookup table. */
  1379. for(i = 0; i < 8; i++)
  1380. {
  1381. dist = HSV_DISTANCE(hue, sat, val, i);
  1382. if(dist <= distbg)
  1383. {
  1384. outfg = outbg;
  1385. distfg = distbg;
  1386. outbg = i;
  1387. distbg = dist;
  1388. }
  1389. else if(dist <= distfg)
  1390. {
  1391. outfg = i;
  1392. distfg = dist;
  1393. }
  1394. }
  1395. hsv_distances[v][s][h] = (outfg << 4) | outbg;
  1396. }
  1397. return 0;
  1398. }
  1399. /*
  1400. * XXX: The following functions are aliases.
  1401. */
  1402. cucul_dither_t *cucul_create_dither(int, int, int, int, uint32_t, uint32_t,
  1403. uint32_t, uint32_t)
  1404. CACA_ALIAS(caca_create_dither);
  1405. int cucul_set_dither_palette(cucul_dither_t *, uint32_t r[], uint32_t g[],
  1406. uint32_t b[], uint32_t a[])
  1407. CACA_ALIAS(caca_set_dither_palette);
  1408. int cucul_set_dither_brightness(cucul_dither_t *, float)
  1409. CACA_ALIAS(caca_set_dither_brightness);
  1410. float cucul_get_dither_brightness(cucul_dither_t const *)
  1411. CACA_ALIAS(caca_get_dither_brightness);
  1412. int cucul_set_dither_gamma(cucul_dither_t *, float)
  1413. CACA_ALIAS(caca_set_dither_gamma);
  1414. float cucul_get_dither_gamma(cucul_dither_t const *)
  1415. CACA_ALIAS(caca_get_dither_gamma);
  1416. int cucul_set_dither_contrast(cucul_dither_t *, float)
  1417. CACA_ALIAS(caca_set_dither_contrast);
  1418. float cucul_get_dither_contrast(cucul_dither_t const *)
  1419. CACA_ALIAS(caca_get_dither_contrast);
  1420. int cucul_set_dither_antialias(cucul_dither_t *, char const *)
  1421. CACA_ALIAS(caca_set_dither_antialias);
  1422. char const * const * cucul_get_dither_antialias_list(cucul_dither_t const *)
  1423. CACA_ALIAS(caca_get_dither_antialias_list);
  1424. char const * cucul_get_dither_antialias(cucul_dither_t const *)
  1425. CACA_ALIAS(caca_get_dither_antialias);
  1426. int cucul_set_dither_color(cucul_dither_t *, char const *)
  1427. CACA_ALIAS(caca_set_dither_color);
  1428. char const * const * cucul_get_dither_color_list(cucul_dither_t const *)
  1429. CACA_ALIAS(caca_get_dither_color_list);
  1430. char const * cucul_get_dither_color(cucul_dither_t const *)
  1431. CACA_ALIAS(caca_get_dither_color);
  1432. int cucul_set_dither_charset(cucul_dither_t *, char const *)
  1433. CACA_ALIAS(caca_set_dither_charset);
  1434. char const * const * cucul_get_dither_charset_list(cucul_dither_t const *)
  1435. CACA_ALIAS(caca_get_dither_charset_list);
  1436. char const * cucul_get_dither_charset(cucul_dither_t const *)
  1437. CACA_ALIAS(caca_get_dither_charset);
  1438. int cucul_set_dither_algorithm(cucul_dither_t *, char const *)
  1439. CACA_ALIAS(caca_set_dither_algorithm);
  1440. char const * const * cucul_get_dither_algorithm_list(cucul_dither_t const *)
  1441. CACA_ALIAS(caca_get_dither_algorithm_list);
  1442. char const * cucul_get_dither_algorithm(cucul_dither_t const *)
  1443. CACA_ALIAS(caca_get_dither_algorithm);
  1444. int cucul_dither_bitmap(cucul_canvas_t *, int, int, int, int,
  1445. cucul_dither_t const *, void *)
  1446. CACA_ALIAS(caca_dither_bitmap);
  1447. int cucul_free_dither(cucul_dither_t *) CACA_ALIAS(caca_free_dither);