您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577
  1. /*
  2. * libcaca Colour ASCII-Art library
  3. * Copyright © 2002—2018 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 the WTFPL Task Force.
  10. * See 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. size_t 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 = (uint64_t)(x - x1) * w / deltax;
  892. fromy = (uint64_t)(y - y1) * h / deltay;
  893. tox = (uint64_t)(x - x1 + 1) * w / deltax;
  894. toy = (uint64_t)(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 = (uint64_t)(x - x1) * w / deltax;
  914. fromy = (uint64_t)(y - y1) * h / deltay;
  915. tox = (uint64_t)(x - x1 + 1) * w / deltax;
  916. toy = (uint64_t)(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. }