libcaca  0.99.beta19
About: libcaca is a graphics library that outputs text instead of pixels, so that it can work on older video cards or text terminals (something like an advanced AAlib library).
  Fossies Dox: libcaca-0.99.beta19.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

dither.c
Go to the documentation of this file.
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 /*
14  * This file contains bitmap dithering functions.
15  */
16 
17 #include "config.h"
18 
19 #if !defined(__KERNEL__)
20 # if defined(HAVE_ENDIAN_H)
21 # include <endian.h>
22 # endif
23 # include <stdio.h>
24 # include <stdlib.h>
25 # include <limits.h>
26 # include <string.h>
27 #endif
28 
29 #include "caca.h"
30 #include "caca_internals.h"
31 
32 #define CP437 0
33 
34 /*
35  * Local variables
36  */
37 #if !defined(_DOXYGEN_SKIP_ME)
38 # define LOOKUP_VAL 32
39 # define LOOKUP_SAT 32
40 # define LOOKUP_HUE 16
41 #endif
43 static uint16_t lookup_colors[8];
44 static int lookup_initialised = 0;
45 
46 static int const hsv_palette[] =
47 {
48  /* weight, hue, saturation, value */
49  4, 0x0, 0x0, 0x0, /* black */
50  5, 0x0, 0x0, 0x5ff, /* 30% */
51  5, 0x0, 0x0, 0x9ff, /* 70% */
52  4, 0x0, 0x0, 0xfff, /* white */
53  3, 0x1000, 0xfff, 0x5ff, /* dark yellow */
54  2, 0x1000, 0xfff, 0xfff, /* light yellow */
55  3, 0x0, 0xfff, 0x5ff, /* dark red */
56  2, 0x0, 0xfff, 0xfff /* light red */
57 };
58 
59 /* RGB palette for the new colour picker */
60 static int const rgb_palette[] =
61 {
62  0x0, 0x0, 0x0,
63  0x0, 0x0, 0x7ff,
64  0x0, 0x7ff, 0x0,
65  0x0, 0x7ff, 0x7ff,
66  0x7ff, 0x0, 0x0,
67  0x7ff, 0x0, 0x7ff,
68  0x7ff, 0x7ff, 0x0,
69  0xaaa, 0xaaa, 0xaaa,
70  0x555, 0x555, 0x555,
71  0x000, 0x000, 0xfff,
72  0x000, 0xfff, 0x000,
73  0x000, 0xfff, 0xfff,
74  0xfff, 0x000, 0x000,
75  0xfff, 0x000, 0xfff,
76  0xfff, 0xfff, 0x000,
77  0xfff, 0xfff, 0xfff,
78 };
79 
80 static int const rgb_weight[] =
81 {
82  /* 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2 */
83  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
84 };
85 
86 /* List of glyphs */
87 static uint32_t ascii_glyphs[] =
88 {
89  ' ', '.', ':', ';', 't', '%', 'S', 'X', '@', '8', '?'
90 };
91 
92 static uint32_t shades_glyphs[] =
93 {
94  /* ' '. '·', '░', '▒', '?' */
95  ' ', 0xb7, 0x2591, 0x2592, '?'
96 };
97 
98 static uint32_t blocks_glyphs[] =
99 {
100  /* ' ', '▘', '▚', '?' */
101  ' ', 0x2598, 0x259a, '?'
102 };
103 
104 #if !defined(_DOXYGEN_SKIP_ME)
106 {
114 };
115 
117 {
119  int w, h, pitch;
123  void (*get_hsv)(caca_dither_t *, char *, int, int);
124  int red[256], green[256], blue[256], alpha[256];
125 
126  /* Colour features */
128  int gammatab[4097];
129 
130  /* Dithering features */
131  char const *antialias_name;
133 
134  char const *color_name;
136 
137  char const *algo_name;
138  void (*init_dither) (int);
139  int (*get_dither) (void);
140  void (*increment_dither) (void);
141 
142  char const *glyph_name;
143  uint32_t const * glyphs;
145 
146  int invert;
147 };
148 
149 #define HSV_XRATIO 6
150 #define HSV_YRATIO 3
151 #define HSV_HRATIO 3
152 
153 #define HSV_DISTANCE(h, s, v, index) \
154  (hsv_palette[index * 4] \
155  * ((HSV_XRATIO * ((v) - hsv_palette[index * 4 + 3]) \
156  * ((v) - hsv_palette[index * 4 + 3])) \
157  + (hsv_palette[index * 4 + 3] \
158  ? (HSV_YRATIO * ((s) - hsv_palette[index * 4 + 2]) \
159  * ((s) - hsv_palette[index * 4 + 2])) \
160  : 0) \
161  + (hsv_palette[index * 4 + 2] \
162  ? (HSV_HRATIO * ((h) - hsv_palette[index * 4 + 1]) \
163  * ((h) - hsv_palette[index * 4 + 1])) \
164  : 0)))
165 #endif
166 
167 /*
168  * Local prototypes
169  */
170 static void mask2shift(uint32_t, int *, int *);
171 static float gammapow(float x, float y);
172 
173 static void get_rgba_default(caca_dither_t const *, uint8_t const *, int, int,
174  unsigned int *);
175 static int init_lookup(void);
176 
177 /* Dithering algorithms */
178 static void init_no_dither(int);
179 static int get_no_dither(void);
180 static void increment_no_dither(void);
181 
182 static void init_fstein_dither(int);
183 static int get_fstein_dither(void);
184 static void increment_fstein_dither(void);
185 
186 static void init_ordered2_dither(int);
187 static int get_ordered2_dither(void);
188 static void increment_ordered2_dither(void);
189 
190 static void init_ordered4_dither(int);
191 static int get_ordered4_dither(void);
192 static void increment_ordered4_dither(void);
193 
194 static void init_ordered8_dither(int);
195 static int get_ordered8_dither(void);
196 static void increment_ordered8_dither(void);
197 
198 static void init_random_dither(int);
199 static int get_random_dither(void);
200 static void increment_random_dither(void);
201 
202 static inline int sq(int x)
203 {
204  return x * x;
205 }
206 
207 static inline void rgb2hsv_default(int r, int g, int b,
208  int *hue, int *sat, int *val)
209 {
210  int min, max, delta;
211 
212  min = r; max = r;
213  if(min > g) min = g; if(max < g) max = g;
214  if(min > b) min = b; if(max < b) max = b;
215 
216  delta = max - min; /* 0 - 0xfff */
217  *val = max; /* 0 - 0xfff */
218 
219  if(delta)
220  {
221  *sat = 0xfff * delta / max; /* 0 - 0xfff */
222 
223  /* Generate *hue between 0 and 0x5fff */
224  if( r == max )
225  *hue = 0x1000 + 0x1000 * (g - b) / delta;
226  else if( g == max )
227  *hue = 0x3000 + 0x1000 * (b - r) / delta;
228  else
229  *hue = 0x5000 + 0x1000 * (r - g) / delta;
230  }
231  else
232  {
233  *sat = 0;
234  *hue = 0;
235  }
236 }
237 
261 caca_dither_t *caca_create_dither(int bpp, int w, int h, int pitch,
262  uint32_t rmask, uint32_t gmask,
263  uint32_t bmask, uint32_t amask)
264 {
265  caca_dither_t *d;
266  int i;
267 
268  /* Minor sanity test */
269  if(w < 0 || h < 0 || pitch < 0 || bpp > 32 || bpp < 8)
270  {
271  seterrno(EINVAL);
272  return NULL;
273  }
274 
275  d = malloc(sizeof(caca_dither_t));
276  if(!d)
277  {
278  seterrno(ENOMEM);
279  return NULL;
280  }
281 
282  if(!lookup_initialised)
283  {
284  /* XXX: because we do not wish to be thread-safe, there is a slight
285  * chance that the following code will be executed twice. It is
286  * totally harmless. */
287  init_lookup();
288  lookup_initialised = 1;
289  }
290 
291  d->bpp = bpp;
292  d->has_palette = 0;
293  d->has_alpha = amask ? 1 : 0;
294 
295  d->w = w;
296  d->h = h;
297  d->pitch = pitch;
298 
299  d->rmask = rmask;
300  d->gmask = gmask;
301  d->bmask = bmask;
302  d->amask = amask;
303 
304  /* Load bitmasks */
305  if(rmask || gmask || bmask || amask)
306  {
307  mask2shift(rmask, &d->rright, &d->rleft);
308  mask2shift(gmask, &d->gright, &d->gleft);
309  mask2shift(bmask, &d->bright, &d->bleft);
310  mask2shift(amask, &d->aright, &d->aleft);
311  }
312 
313  /* In 8 bpp mode, default to a grayscale palette */
314  if(bpp == 8)
315  {
316  d->has_palette = 1;
317  d->has_alpha = 0;
318  for(i = 0; i < 256; i++)
319  {
320  d->red[i] = i * 0xfff / 256;
321  d->green[i] = i * 0xfff / 256;
322  d->blue[i] = i * 0xfff / 256;
323  }
324  }
325 
326  /* Default gamma value */
327  d->gamma = 1.0;
328  for(i = 0; i < 4096; i++)
329  d->gammatab[i] = i;
330 
331  /* Default colour properties */
332  d->brightness = 1.0;
333  d->contrast = 1.0;
334 
335  /* Default features */
336  d->antialias_name = "prefilter";
337  d->antialias = 1;
338 
339  d->color_name = "full16";
341 
342  d->glyph_name = "ascii";
343  d->glyphs = ascii_glyphs;
344  d->glyph_count = sizeof(ascii_glyphs) / sizeof(*ascii_glyphs);
345 
346  d->algo_name = "fstein";
350 
351  d->invert = 0;
352 
353  return d;
354 }
355 
373  uint32_t red[], uint32_t green[],
374  uint32_t blue[], uint32_t alpha[])
375 {
376  int i, has_alpha = 0;
377 
378  if(d->bpp != 8)
379  {
380  seterrno(EINVAL);
381  return -1;
382  }
383 
384  for(i = 0; i < 256; i++)
385  {
386  if((red[i] | green[i] | blue[i] | alpha[i]) >= 0x1000)
387  {
388  seterrno(EINVAL);
389  return -1;
390  }
391  }
392 
393  for(i = 0; i < 256; i++)
394  {
395  d->red[i] = red[i];
396  d->green[i] = green[i];
397  d->blue[i] = blue[i];
398  if(alpha[i])
399  {
400  d->alpha[i] = alpha[i];
401  has_alpha = 1;
402  }
403  }
404 
405  d->has_alpha = has_alpha;
406 
407  return 0;
408 }
409 
421 int caca_set_dither_brightness(caca_dither_t *d, float brightness)
422 {
423  /* FIXME */
424  d->brightness = brightness;
425 
426  return 0;
427 }
428 
439 {
440  return d->brightness;
441 }
442 
456 {
457  /* FIXME: we don't need 4096 calls to gammapow(), we could just compute
458  * a few of them and do linear interpolation for the rest. This will
459  * probably speed up things a lot. */
460  int i;
461 
462  if(gamma < 0.0)
463  {
464  d->invert = 1;
465  gamma = -gamma;
466  }
467  else if(gamma == 0.0)
468  {
469  seterrno(EINVAL);
470  return -1;
471  }
472 
473  d->gamma = gamma;
474 
475  for(i = 0; i < 4096; i++)
476  d->gammatab[i] = 4096.0 * gammapow((float)i / 4096.0, 1.0 / gamma);
477 
478  return 0;
479 }
480 
491 {
492  return d->gamma;
493 }
494 
507 {
508  /* FIXME */
509  d->contrast = contrast;
510 
511  return 0;
512 }
513 
524 {
525  return d->contrast;
526 }
527 
544 int caca_set_dither_antialias(caca_dither_t *d, char const *str)
545 {
546  if(!strcasecmp(str, "none"))
547  {
548  d->antialias_name = "none";
549  d->antialias = 0;
550  }
551  else if(!strcasecmp(str, "prefilter") || !strcasecmp(str, "default"))
552  {
553  d->antialias_name = "prefilter";
554  d->antialias = 1;
555  }
556  else
557  {
558  seterrno(EINVAL);
559  return -1;
560  }
561 
562  return 0;
563 }
564 
578 char const * const *
580 {
581  static char const * const list[] =
582  {
583  "none", "No antialiasing",
584  "prefilter", "Prefilter antialiasing",
585  NULL, NULL
586  };
587 
588  return list;
589 }
590 
601 {
602  return d->antialias_name;
603 }
604 
628 int caca_set_dither_color(caca_dither_t *d, char const *str)
629 {
630  if(!strcasecmp(str, "mono"))
631  {
632  d->color_name = "mono";
633  d->color = COLOR_MODE_MONO;
634  }
635  else if(!strcasecmp(str, "gray"))
636  {
637  d->color_name = "gray";
638  d->color = COLOR_MODE_GRAY;
639  }
640  else if(!strcasecmp(str, "8"))
641  {
642  d->color_name = "8";
643  d->color = COLOR_MODE_8;
644  }
645  else if(!strcasecmp(str, "16"))
646  {
647  d->color_name = "16";
648  d->color = COLOR_MODE_16;
649  }
650  else if(!strcasecmp(str, "fullgray"))
651  {
652  d->color_name = "fullgray";
654  }
655  else if(!strcasecmp(str, "full8"))
656  {
657  d->color_name = "full8";
658  d->color = COLOR_MODE_FULL8;
659  }
660  else if(!strcasecmp(str, "full16") || !strcasecmp(str, "default"))
661  {
662  d->color_name = "full16";
664  }
665  else
666  {
667  seterrno(EINVAL);
668  return -1;
669  }
670 
671  return 0;
672 }
673 
687 char const * const *
689 {
690  static char const * const list[] =
691  {
692  "mono", "white on black",
693  "gray", "grayscale on black",
694  "8", "8 colours on black",
695  "16", "16 colours on black",
696  "fullgray", "full grayscale",
697  "full8", "full 8 colours",
698  "full16", "full 16 colours",
699  NULL, NULL
700  };
701 
702  return list;
703 }
704 
714 char const * caca_get_dither_color(caca_dither_t const *d)
715 {
716  return d->color_name;
717 }
718 
739 int caca_set_dither_charset(caca_dither_t *d, char const *str)
740 {
741  if(!strcasecmp(str, "shades"))
742  {
743  d->glyph_name = "shades";
744  d->glyphs = shades_glyphs;
745  d->glyph_count = sizeof(shades_glyphs) / sizeof(*shades_glyphs);
746  }
747  else if(!strcasecmp(str, "blocks"))
748  {
749  d->glyph_name = "blocks";
750  d->glyphs = blocks_glyphs;
751  d->glyph_count = sizeof(blocks_glyphs) / sizeof(*blocks_glyphs);
752  }
753  else if(!strcasecmp(str, "ascii") || !strcasecmp(str, "default"))
754  {
755  d->glyph_name = "ascii";
756  d->glyphs = ascii_glyphs;
757  d->glyph_count = sizeof(ascii_glyphs) / sizeof(*ascii_glyphs);
758  }
759  else
760  {
761  seterrno(EINVAL);
762  return -1;
763  }
764 
765  return 0;
766 }
767 
781 char const * const * caca_get_dither_charset_list(caca_dither_t const *d)
782 {
783  static char const * const list[] =
784  {
785  "ascii", "plain ASCII",
786  "shades", "CP437 shades",
787  "blocks", "Unicode blocks",
788  NULL, NULL
789  };
790 
791  return list;
792 }
793 
804 {
805  return d->glyph_name;
806 }
807 
828 int caca_set_dither_algorithm(caca_dither_t *d, char const *str)
829 {
830  if(!strcasecmp(str, "none"))
831  {
832  d->algo_name = "none";
836  }
837  else if(!strcasecmp(str, "ordered2"))
838  {
839  d->algo_name = "ordered2";
843  }
844  else if(!strcasecmp(str, "ordered4"))
845  {
846  d->algo_name = "ordered4";
850  }
851  else if(!strcasecmp(str, "ordered8"))
852  {
853  d->algo_name = "ordered8";
857  }
858  else if(!strcasecmp(str, "random"))
859  {
860  d->algo_name = "random";
864  }
865  else if(!strcasecmp(str, "fstein") || !strcasecmp(str, "default"))
866  {
867  d->algo_name = "fstein";
871  }
872  else
873  {
874  seterrno(EINVAL);
875  return -1;
876  }
877 
878  return 0;
879 }
880 
894 char const * const * caca_get_dither_algorithm_list(caca_dither_t const *d)
895 {
896  static char const * const list[] =
897  {
898  "none", "no dithering",
899  "ordered2", "2x2 ordered dithering",
900  "ordered4", "4x4 ordered dithering",
901  "ordered8", "8x8 ordered dithering",
902  "random", "random dithering",
903  "fstein", "Floyd-Steinberg dithering",
904  NULL, NULL
905  };
906 
907  return list;
908 }
909 
920 {
921  return d->algo_name;
922 }
923 
940 int caca_dither_bitmap(caca_canvas_t *cv, int x, int y, int w, int h,
941  caca_dither_t const *d, void const *pixels)
942 {
943  int *floyd_steinberg, *fs_r, *fs_g, *fs_b;
944  uint32_t savedattr;
945  int fs_length;
946  int x1, y1, x2, y2, pitch, deltax, deltay, dchmax;
947 
948  if(!d || !pixels)
949  return 0;
950 
951  savedattr = caca_get_attr(cv, -1, -1);
952 
953  x1 = x; x2 = x + w - 1;
954  y1 = y; y2 = y + h - 1;
955 
956  /* FIXME: do not overwrite arguments */
957  w = d->w;
958  h = d->h;
959  pitch = d->pitch;
960 
961  deltax = x2 - x1 + 1;
962  deltay = y2 - y1 + 1;
963  dchmax = d->glyph_count;
964 
965  fs_length = ((int)cv->width <= x2 ? (int)cv->width : x2) + 1;
966  floyd_steinberg = malloc(3 * (fs_length + 2) * sizeof(int));
967  memset(floyd_steinberg, 0, 3 * (fs_length + 2) * sizeof(int));
968  fs_r = floyd_steinberg + 1;
969  fs_g = fs_r + fs_length + 2;
970  fs_b = fs_g + fs_length + 2;
971 
972  for(y = y1 > 0 ? y1 : 0; y <= y2 && y <= (int)cv->height; y++)
973  {
974  int remain_r = 0, remain_g = 0, remain_b = 0;
975 
976  for(x = x1 > 0 ? x1 : 0, d->init_dither(y);
977  x <= x2 && x <= (int)cv->width;
978  x++)
979  {
980  unsigned int rgba[4];
981  int error[3];
982  int i, ch = 0, distmin;
983  int fg_r = 0, fg_g = 0, fg_b = 0, bg_r, bg_g, bg_b;
984  int fromx, fromy, tox, toy, myx, myy, dots, dist;
985 
986  int outfg = 0, outbg = 0;
987  uint32_t outch;
988 
989  rgba[0] = rgba[1] = rgba[2] = rgba[3] = 0;
990 
991  /* First get RGB */
992  if(d->antialias)
993  {
994  fromx = (x - x1) * w / deltax;
995  fromy = (y - y1) * h / deltay;
996  tox = (x - x1 + 1) * w / deltax;
997  toy = (y - y1 + 1) * h / deltay;
998 
999  /* We want at least one pixel */
1000  if(tox == fromx) tox++;
1001  if(toy == fromy) toy++;
1002 
1003  dots = 0;
1004 
1005  for(myx = fromx; myx < tox; myx++)
1006  for(myy = fromy; myy < toy; myy++)
1007  {
1008  dots++;
1009  get_rgba_default(d, pixels, myx, myy, rgba);
1010  }
1011 
1012  /* Normalize */
1013  rgba[0] /= dots;
1014  rgba[1] /= dots;
1015  rgba[2] /= dots;
1016  rgba[3] /= dots;
1017  }
1018  else
1019  {
1020  fromx = (x - x1) * w / deltax;
1021  fromy = (y - y1) * h / deltay;
1022  tox = (x - x1 + 1) * w / deltax;
1023  toy = (y - y1 + 1) * h / deltay;
1024 
1025  /* tox and toy can overflow the canvas, but they cannot overflow
1026  * when averaged with fromx and fromy because these are guaranteed
1027  * to be within the pixel boundaries. */
1028  myx = (fromx + tox) / 2;
1029  myy = (fromy + toy) / 2;
1030 
1031  get_rgba_default(d, pixels, myx, myy, rgba);
1032  }
1033 
1034  /* FIXME: hack to force greyscale */
1035  if(d->color == COLOR_MODE_FULLGRAY)
1036  {
1037  unsigned int gray = (3 * rgba[0] + 4 * rgba[1] + rgba[2] + 4) / 8;
1038  rgba[0] = rgba[1] = rgba[2] = gray;
1039  }
1040 
1041  if(d->has_alpha && rgba[3] < 0x800)
1042  {
1043  remain_r = remain_g = remain_b = 0;
1044  fs_r[x] = 0;
1045  fs_g[x] = 0;
1046  fs_b[x] = 0;
1047  continue;
1048  }
1049 
1050  /* XXX: OMG HAX */
1052  {
1053  rgba[0] += remain_r;
1054  rgba[1] += remain_g;
1055  rgba[2] += remain_b;
1056  }
1057  else
1058  {
1059  rgba[0] += (d->get_dither() - 0x80) * 4;
1060  rgba[1] += (d->get_dither() - 0x80) * 4;
1061  rgba[2] += (d->get_dither() - 0x80) * 4;
1062  }
1063 
1064  distmin = INT_MAX;
1065  for(i = 0; i < 16; i++)
1066  {
1067  if(d->color == COLOR_MODE_FULLGRAY
1068  && (rgb_palette[i * 3] != rgb_palette[i * 3 + 1]
1069  || rgb_palette[i * 3] != rgb_palette[i * 3 + 2]))
1070  continue;
1071  dist = sq(rgba[0] - rgb_palette[i * 3])
1072  + sq(rgba[1] - rgb_palette[i * 3 + 1])
1073  + sq(rgba[2] - rgb_palette[i * 3 + 2]);
1074  dist *= rgb_weight[i];
1075  if(dist < distmin)
1076  {
1077  outbg = i;
1078  distmin = dist;
1079  }
1080  }
1081  bg_r = rgb_palette[outbg * 3];
1082  bg_g = rgb_palette[outbg * 3 + 1];
1083  bg_b = rgb_palette[outbg * 3 + 2];
1084 
1085  /* FIXME: we currently only honour "full16" */
1087  {
1088  distmin = INT_MAX;
1089  for(i = 0; i < 16; i++)
1090  {
1091  if(i == outbg)
1092  continue;
1093  if(d->color == COLOR_MODE_FULLGRAY
1094  && (rgb_palette[i * 3] != rgb_palette[i * 3 + 1]
1095  || rgb_palette[i * 3] != rgb_palette[i * 3 + 2]))
1096  continue;
1097  dist = sq(rgba[0] - rgb_palette[i * 3])
1098  + sq(rgba[1] - rgb_palette[i * 3 + 1])
1099  + sq(rgba[2] - rgb_palette[i * 3 + 2]);
1100  dist *= rgb_weight[i];
1101  if(dist < distmin)
1102  {
1103  outfg = i;
1104  distmin = dist;
1105  }
1106  }
1107  fg_r = rgb_palette[outfg * 3];
1108  fg_g = rgb_palette[outfg * 3 + 1];
1109  fg_b = rgb_palette[outfg * 3 + 2];
1110 
1111  distmin = INT_MAX;
1112  for(i = 0; i < dchmax - 1; i++)
1113  {
1114  int newr = i * fg_r + ((2*dchmax-1) - i) * bg_r;
1115  int newg = i * fg_g + ((2*dchmax-1) - i) * bg_g;
1116  int newb = i * fg_b + ((2*dchmax-1) - i) * bg_b;
1117  dist = abs(rgba[0] * (2*dchmax-1) - newr)
1118  + abs(rgba[1] * (2*dchmax-1) - newg)
1119  + abs(rgba[2] * (2*dchmax-1) - newb);
1120 
1121  if(dist < distmin)
1122  {
1123  ch = i;
1124  distmin = dist;
1125  }
1126  }
1127  outch = d->glyphs[ch];
1128 
1129  /* XXX: OMG HAX */
1131  {
1132  error[0] = rgba[0] - (fg_r * ch + bg_r * ((2*dchmax-1) - ch)) / (2*dchmax-1);
1133  error[1] = rgba[1] - (fg_g * ch + bg_g * ((2*dchmax-1) - ch)) / (2*dchmax-1);
1134  error[2] = rgba[2] - (fg_b * ch + bg_b * ((2*dchmax-1) - ch)) / (2*dchmax-1);
1135  }
1136  }
1137  else
1138  {
1139  unsigned int lum = rgba[0];
1140  if(rgba[1] > lum) lum = rgba[1];
1141  if(rgba[2] > lum) lum = rgba[2];
1142  outfg = outbg;
1143  outbg = CACA_BLACK;
1144 
1145  ch = lum * dchmax / 0x1000;
1146  if(ch < 0)
1147  ch = 0;
1148  else if(ch > (int)(dchmax - 1))
1149  ch = dchmax - 1;
1150  outch = d->glyphs[ch];
1151 
1152  /* XXX: OMG HAX */
1154  {
1155  error[0] = rgba[0] - bg_r * ch / (dchmax-1);
1156  error[1] = rgba[1] - bg_g * ch / (dchmax-1);
1157  error[2] = rgba[2] - bg_b * ch / (dchmax-1);
1158  }
1159  }
1160 
1161  /* XXX: OMG HAX */
1163  {
1164  remain_r = fs_r[x+1] + 7 * error[0] / 16;
1165  remain_g = fs_g[x+1] + 7 * error[1] / 16;
1166  remain_b = fs_b[x+1] + 7 * error[2] / 16;
1167  fs_r[x-1] += 3 * error[0] / 16;
1168  fs_g[x-1] += 3 * error[1] / 16;
1169  fs_b[x-1] += 3 * error[2] / 16;
1170  fs_r[x] = 5 * error[0] / 16;
1171  fs_g[x] = 5 * error[1] / 16;
1172  fs_b[x] = 5 * error[2] / 16;
1173  fs_r[x+1] = 1 * error[0] / 16;
1174  fs_g[x+1] = 1 * error[1] / 16;
1175  fs_b[x+1] = 1 * error[2] / 16;
1176  }
1177 
1178  if(d->invert)
1179  {
1180  outfg = 15 - outfg;
1181  outbg = 15 - outbg;
1182  }
1183 
1184  /* Now output the character */
1185  caca_set_color_ansi(cv, outfg, outbg);
1186  caca_put_char(cv, x, y, outch);
1187 
1188  d->increment_dither();
1189  }
1190  /* end loop */
1191  }
1192 
1193  free(floyd_steinberg);
1194 
1195  caca_set_attr(cv, savedattr);
1196 
1197  return 0;
1198 }
1199 
1210 {
1211  if(!d)
1212  return 0;
1213 
1214  free(d);
1215 
1216  return 0;
1217 }
1218 
1219 /*
1220  * XXX: The following functions are local.
1221  */
1222 
1223 /* Convert a mask, eg. 0x0000ff00, to shift values, eg. 8 and -4. */
1224 static void mask2shift(uint32_t mask, int *right, int *left)
1225 {
1226  int rshift = 0, lshift = 0;
1227 
1228  if(!mask)
1229  {
1230  *right = *left = 0;
1231  return;
1232  }
1233 
1234  while(!(mask & 1))
1235  {
1236  mask >>= 1;
1237  rshift++;
1238  }
1239  *right = rshift;
1240 
1241  while(mask & 1)
1242  {
1243  mask >>= 1;
1244  lshift++;
1245  }
1246  *left = 12 - lshift;
1247 }
1248 
1249 /* Compute x^y without relying on the math library */
1250 static float gammapow(float x, float y)
1251 {
1252 #ifdef HAVE_FLDLN2
1253  register double logx;
1254  register long double v, e;
1255 #else
1256  register float tmp, t, t2, r;
1257  int i;
1258 #endif
1259 
1260  if(x == 0.0)
1261  return y == 0.0 ? 1.0 : 0.0;
1262 
1263 #ifdef HAVE_FLDLN2
1264  /* FIXME: this can be optimised by directly calling fyl2x for x and y */
1265  asm volatile("fldln2; fxch; fyl2x"
1266  : "=t" (logx) : "0" (x) : "st(1)");
1267 
1268  asm volatile("fldl2e\n\t"
1269  "fmul %%st(1)\n\t"
1270  "fst %%st(1)\n\t"
1271  "frndint\n\t"
1272  "fxch\n\t"
1273  "fsub %%st(1)\n\t"
1274  "f2xm1\n\t"
1275  : "=t" (v), "=u" (e) : "0" (y * logx));
1276  v += 1.0;
1277  asm volatile("fscale"
1278  : "=t" (v) : "0" (v), "u" (e));
1279  return v;
1280 #else
1281  /* Compute ln(x) for x ∈ ]0,1]
1282  * ln(x) = 2 * (t + t^3/3 + t^5/5 + ...) with t = (x-1)/(x+1)
1283  * The convergence is a bit slow, especially when x is near 0. */
1284  t = (x - 1.0) / (x + 1.0);
1285  t2 = t * t;
1286  tmp = r = t;
1287  for(i = 3; i < 20; i += 2)
1288  {
1289  r *= t2;
1290  tmp += r / i;
1291  }
1292 
1293  /* Compute -y*ln(x) */
1294  tmp = - y * 2.0 * tmp;
1295 
1296  /* Compute x^-y as e^t where t = -y*ln(x):
1297  * e^t = 1 + t/1! + t^2/2! + t^3/3! + t^4/4! + t^5/5! ...
1298  * The convergence is quite faster here, thanks to the factorial. */
1299  r = t = tmp;
1300  tmp = 1.0 + t;
1301  for(i = 2; i < 16; i++)
1302  {
1303  r = r * t / i;
1304  tmp += r;
1305  }
1306 
1307  /* Return x^y as 1/(x^-y) */
1308  return 1.0 / tmp;
1309 #endif
1310 }
1311 
1312 static void get_rgba_default(caca_dither_t const *d, uint8_t const *pixels,
1313  int x, int y, unsigned int *rgba)
1314 {
1315  uint32_t bits;
1316 
1317  pixels += (d->bpp / 8) * x + d->pitch * y;
1318 
1319  switch(d->bpp / 8)
1320  {
1321  case 4:
1322  bits = *(uint32_t const *)pixels;
1323  break;
1324  case 3:
1325  {
1326 #if defined(HAVE_ENDIAN_H)
1327  if(__BYTE_ORDER == __BIG_ENDIAN)
1328 #else
1329  /* This is compile-time optimised with at least -O1 or -Os */
1330  uint32_t const tmp = 0x12345678;
1331  if(*(uint8_t const *)&tmp == 0x12)
1332 #endif
1333  bits = ((uint32_t)pixels[0] << 16) |
1334  ((uint32_t)pixels[1] << 8) |
1335  ((uint32_t)pixels[2]);
1336  else
1337  bits = ((uint32_t)pixels[2] << 16) |
1338  ((uint32_t)pixels[1] << 8) |
1339  ((uint32_t)pixels[0]);
1340  break;
1341  }
1342  case 2:
1343  bits = *(uint16_t const *)pixels;
1344  break;
1345  case 1:
1346  default:
1347  bits = pixels[0];
1348  break;
1349  }
1350 
1351  if(d->has_palette)
1352  {
1353  rgba[0] += d->gammatab[d->red[bits]];
1354  rgba[1] += d->gammatab[d->green[bits]];
1355  rgba[2] += d->gammatab[d->blue[bits]];
1356  rgba[3] += d->alpha[bits];
1357  }
1358  else
1359  {
1360  rgba[0] += d->gammatab[((bits & d->rmask) >> d->rright) << d->rleft];
1361  rgba[1] += d->gammatab[((bits & d->gmask) >> d->gright) << d->gleft];
1362  rgba[2] += d->gammatab[((bits & d->bmask) >> d->bright) << d->bleft];
1363  rgba[3] += ((bits & d->amask) >> d->aright) << d->aleft;
1364  }
1365 }
1366 
1367 /*
1368  * No dithering
1369  */
1370 static void init_no_dither(int line)
1371 {
1372  ;
1373 }
1374 
1375 static int get_no_dither(void)
1376 {
1377  return 0x80;
1378 }
1379 
1380 static void increment_no_dither(void)
1381 {
1382  return;
1383 }
1384 
1385 /*
1386  * Floyd-Steinberg dithering
1387  */
1388 static void init_fstein_dither(int line)
1389 {
1390  ;
1391 }
1392 
1393 static int get_fstein_dither(void)
1394 {
1395  return 0x80;
1396 }
1397 
1398 static void increment_fstein_dither(void)
1399 {
1400  return;
1401 }
1402 
1403 /*
1404  * Ordered 2 dithering
1405  */
1406 static int const *ordered2_table;
1407 static int ordered2_index;
1408 
1409 static void init_ordered2_dither(int line)
1410 {
1411  static int const dither2x2[] =
1412  {
1413  0x00, 0x80,
1414  0xc0, 0x40,
1415  };
1416 
1417  ordered2_table = dither2x2 + (line % 2) * 2;
1418  ordered2_index = 0;
1419 }
1420 
1421 static int get_ordered2_dither(void)
1422 {
1424 }
1425 
1426 static void increment_ordered2_dither(void)
1427 {
1428  ordered2_index = (ordered2_index + 1) % 2;
1429 }
1430 
1431 /*
1432  * Ordered 4 dithering
1433  */
1434 /*static int dither4x4[] = { 5, 0, 1, 6,
1435  -1, -6, -5, 2,
1436  -2, -7, -8, 3,
1437  4, -3, -4, -7};*/
1438 static int const *ordered4_table;
1439 static int ordered4_index;
1440 
1441 static void init_ordered4_dither(int line)
1442 {
1443  static int const dither4x4[] =
1444  {
1445  0x00, 0x80, 0x20, 0xa0,
1446  0xc0, 0x40, 0xe0, 0x60,
1447  0x30, 0xb0, 0x10, 0x90,
1448  0xf0, 0x70, 0xd0, 0x50
1449  };
1450 
1451  ordered4_table = dither4x4 + (line % 4) * 4;
1452  ordered4_index = 0;
1453 }
1454 
1455 static int get_ordered4_dither(void)
1456 {
1458 }
1459 
1460 static void increment_ordered4_dither(void)
1461 {
1462  ordered4_index = (ordered4_index + 1) % 4;
1463 }
1464 
1465 /*
1466  * Ordered 8 dithering
1467  */
1468 static int const *ordered8_table;
1469 static int ordered8_index;
1470 
1471 static void init_ordered8_dither(int line)
1472 {
1473  static int const dither8x8[] =
1474  {
1475  0x00, 0x80, 0x20, 0xa0, 0x08, 0x88, 0x28, 0xa8,
1476  0xc0, 0x40, 0xe0, 0x60, 0xc8, 0x48, 0xe8, 0x68,
1477  0x30, 0xb0, 0x10, 0x90, 0x38, 0xb8, 0x18, 0x98,
1478  0xf0, 0x70, 0xd0, 0x50, 0xf8, 0x78, 0xd8, 0x58,
1479  0x0c, 0x8c, 0x2c, 0xac, 0x04, 0x84, 0x24, 0xa4,
1480  0xcc, 0x4c, 0xec, 0x6c, 0xc4, 0x44, 0xe4, 0x64,
1481  0x3c, 0xbc, 0x1c, 0x9c, 0x34, 0xb4, 0x14, 0x94,
1482  0xfc, 0x7c, 0xdc, 0x5c, 0xf4, 0x74, 0xd4, 0x54,
1483  };
1484 
1485  ordered8_table = dither8x8 + (line % 8) * 8;
1486  ordered8_index = 0;
1487 }
1488 
1489 static int get_ordered8_dither(void)
1490 {
1492 }
1493 
1494 static void increment_ordered8_dither(void)
1495 {
1496  ordered8_index = (ordered8_index + 1) % 8;
1497 }
1498 
1499 /*
1500  * Random dithering
1501  */
1502 static void init_random_dither(int line)
1503 {
1504  ;
1505 }
1506 
1507 static int get_random_dither(void)
1508 {
1509  return caca_rand(0x00, 0x100);
1510 }
1511 
1512 static void increment_random_dither(void)
1513 {
1514  return;
1515 }
1516 
1517 /*
1518  * Lookup tables
1519  */
1520 static int init_lookup(void)
1521 {
1522  int v, s, h;
1523 
1524  /* These ones are constant */
1529 
1530  /* These ones will be overwritten */
1533  lookup_colors[6] = CACA_RED;
1535 
1536  for(v = 0; v < LOOKUP_VAL; v++)
1537  for(s = 0; s < LOOKUP_SAT; s++)
1538  for(h = 0; h < LOOKUP_HUE; h++)
1539  {
1540  int i, distbg, distfg, dist;
1541  int val, sat, hue;
1542  uint8_t outbg, outfg;
1543 
1544  val = 0xfff * v / (LOOKUP_VAL - 1);
1545  sat = 0xfff * s / (LOOKUP_SAT - 1);
1546  hue = 0xfff * h / (LOOKUP_HUE - 1);
1547 
1548  /* Initialise distances to the distance between pure black HSV
1549  * coordinates and our white colour (3) */
1550  outbg = outfg = 3;
1551  distbg = distfg = HSV_DISTANCE(0, 0, 0, 3);
1552 
1553  /* Calculate distances to eight major colour values and store the
1554  * two nearest points in our lookup table. */
1555  for(i = 0; i < 8; i++)
1556  {
1557  dist = HSV_DISTANCE(hue, sat, val, i);
1558  if(dist <= distbg)
1559  {
1560  outfg = outbg;
1561  distfg = distbg;
1562  outbg = i;
1563  distbg = dist;
1564  }
1565  else if(dist <= distfg)
1566  {
1567  outfg = i;
1568  distfg = dist;
1569  }
1570  }
1571 
1572  hsv_distances[v][s][h] = (outfg << 4) | outbg;
1573  }
1574 
1575  return 0;
1576 }
1577 
1578 /*
1579  * XXX: The following functions are aliases.
1580  */
1581 
1582 cucul_dither_t *cucul_create_dither(int, int, int, int, uint32_t, uint32_t,
1583  uint32_t, uint32_t)
1585 int cucul_set_dither_palette(cucul_dither_t *, uint32_t r[], uint32_t g[],
1586  uint32_t b[], uint32_t a[])
1600 int cucul_set_dither_antialias(cucul_dither_t *, char const *)
1602 char const * const * cucul_get_dither_antialias_list(cucul_dither_t const *)
1604 char const * cucul_get_dither_antialias(cucul_dither_t const *)
1606 int cucul_set_dither_color(cucul_dither_t *, char const *)
1608 char const * const * cucul_get_dither_color_list(cucul_dither_t const *)
1610 char const * cucul_get_dither_color(cucul_dither_t const *)
1612 int cucul_set_dither_charset(cucul_dither_t *, char const *)
1614 char const * const * cucul_get_dither_charset_list(cucul_dither_t const *)
1616 char const * cucul_get_dither_charset(cucul_dither_t const *)
1618 int cucul_set_dither_algorithm(cucul_dither_t *, char const *)
1620 char const * const * cucul_get_dither_algorithm_list(cucul_dither_t const *)
1622 char const * cucul_get_dither_algorithm(cucul_dither_t const *)
1624 int cucul_dither_bitmap(cucul_canvas_t *, int, int, int, int,
1625  cucul_dither_t const *, void *)
1628 
ordered8_index
static int ordered8_index
Definition: dither.c:1469
caca_dither::bmask
int bmask
Definition: dither.c:120
hsv_distances
static uint8_t hsv_distances[32][32][16]
Definition: dither.c:42
caca_create_dither
caca_dither_t * caca_create_dither(int bpp, int w, int h, int pitch, uint32_t rmask, uint32_t gmask, uint32_t bmask, uint32_t amask)
Create an internal dither object.
Definition: dither.c:261
caca_dither
Definition: dither.c:116
caca_set_dither_antialias
int caca_set_dither_antialias(caca_dither_t *d, char const *str)
Set dither antialiasing.
Definition: dither.c:544
caca_dither::bpp
int bpp
Definition: dither.c:118
rgb_palette
static const int rgb_palette[]
Definition: dither.c:60
COLOR_MODE_FULL8
Definition: dither.c:112
caca_get_dither_color
const char * caca_get_dither_color(caca_dither_t const *d)
Get current colour mode.
Definition: dither.c:714
caca_dither::green
int green[256]
Definition: dither.c:124
init_ordered8_dither
static void init_ordered8_dither(int)
Definition: dither.c:1471
caca_set_dither_brightness
int caca_set_dither_brightness(caca_dither_t *d, float brightness)
Set the brightness of a dither object.
Definition: dither.c:421
CACA_ALIAS
#define CACA_ALIAS(x)
Definition: caca.h:689
increment_random_dither
static void increment_random_dither(void)
Definition: dither.c:1512
caca_set_dither_palette
int caca_set_dither_palette(caca_dither_t *d, uint32_t red[], uint32_t green[], uint32_t blue[], uint32_t alpha[])
Set the palette of an 8bpp dither object.
Definition: dither.c:372
caca_get_dither_gamma
float caca_get_dither_gamma(caca_dither_t const *d)
Get the gamma of a dither object.
Definition: dither.c:490
shades_glyphs
static uint32_t shades_glyphs[]
Definition: dither.c:92
cucul_set_dither_antialias
#define cucul_set_dither_antialias
Definition: caca.h:885
caca_get_dither_color_list
const char *const * caca_get_dither_color_list(caca_dither_t const *d)
Get available colour modes.
Definition: dither.c:688
caca_dither::bright
int bright
Definition: dither.c:121
caca_dither::rleft
int rleft
Definition: dither.c:122
get_ordered8_dither
static int get_ordered8_dither(void)
Definition: dither.c:1489
y
static int y
Definition: cacadraw.c:27
caca_dither::get_dither
int(* get_dither)(void)
Definition: dither.c:139
mask2shift
static void mask2shift(uint32_t, int *, int *)
Definition: dither.c:1224
caca_dither::contrast
float contrast
Definition: dither.c:127
caca_set_dither_algorithm
int caca_set_dither_algorithm(caca_dither_t *d, char const *str)
Set dithering algorithm.
Definition: dither.c:828
cucul_dither_bitmap
#define cucul_dither_bitmap
Definition: caca.h:897
caca_dither::increment_dither
void(* increment_dither)(void)
Definition: dither.c:140
cucul_get_dither_algorithm_list
#define cucul_get_dither_algorithm_list
Definition: caca.h:895
cucul_set_dither_algorithm
#define cucul_set_dither_algorithm
Definition: caca.h:894
COLOR_MODE_16
Definition: dither.c:110
sq
static int sq(int x)
Definition: dither.c:202
caca_get_dither_charset
const char * caca_get_dither_charset(caca_dither_t const *d)
Get current character set.
Definition: dither.c:803
g
int g
Definition: cacaview.c:60
caca_set_attr
int caca_set_attr(caca_canvas_t *cv, uint32_t attr)
Set the default character attribute.
Definition: attr.c:97
cucul_get_dither_algorithm
#define cucul_get_dither_algorithm
Definition: caca.h:896
init_lookup
static int init_lookup(void)
Definition: dither.c:1520
cucul_get_dither_color_list
#define cucul_get_dither_color_list
Definition: caca.h:889
get_random_dither
static int get_random_dither(void)
Definition: dither.c:1507
ordered4_index
static int ordered4_index
Definition: dither.c:1439
caca_get_dither_contrast
float caca_get_dither_contrast(caca_dither_t const *d)
Get the contrast of a dither object.
Definition: dither.c:523
caca_dither::red
int red[256]
Definition: dither.c:124
cucul_get_dither_brightness
#define cucul_get_dither_brightness
Definition: caca.h:880
caca_dither::invert
int invert
Definition: dither.c:146
caca_dither::glyph_name
const char * glyph_name
Definition: dither.c:142
cucul_get_dither_charset_list
#define cucul_get_dither_charset_list
Definition: caca.h:892
increment_no_dither
static void increment_no_dither(void)
Definition: dither.c:1380
caca_dither::glyph_count
int glyph_count
Definition: dither.c:144
ordered2_index
static int ordered2_index
Definition: dither.c:1407
caca_dither::w
int w
Definition: dither.c:119
caca_dither::alpha
int alpha[256]
Definition: dither.c:124
gammapow
static float gammapow(float x, float y)
Definition: dither.c:1250
get_no_dither
static int get_no_dither(void)
Definition: dither.c:1375
caca_get_dither_antialias_list
const char *const * caca_get_dither_antialias_list(caca_dither_t const *d)
Get available antialiasing methods.
Definition: dither.c:579
caca_dither::aright
int aright
Definition: dither.c:121
cucul_set_dither_color
#define cucul_set_dither_color
Definition: caca.h:888
init_ordered4_dither
static void init_ordered4_dither(int)
Definition: dither.c:1441
caca_dither::gleft
int gleft
Definition: dither.c:122
get_fstein_dither
static int get_fstein_dither(void)
Definition: dither.c:1393
caca_get_dither_algorithm
const char * caca_get_dither_algorithm(caca_dither_t const *d)
Get current dithering algorithm.
Definition: dither.c:919
caca_get_dither_antialias
const char * caca_get_dither_antialias(caca_dither_t const *d)
Get current antialiasing method.
Definition: dither.c:600
caca_rand
#define caca_rand(a, b)
Definition: caca0.h:180
increment_fstein_dither
static void increment_fstein_dither(void)
Definition: dither.c:1398
cucul_set_dither_charset
#define cucul_set_dither_charset
Definition: caca.h:891
CACA_LIGHTGRAY
Definition: caca.h:78
COLOR_MODE_FULL16
Definition: dither.c:113
LOOKUP_VAL
#define LOOKUP_VAL
Definition: dither.c:38
strcasecmp
#define strcasecmp
Definition: config.h:95
caca_dither::get_hsv
void(* get_hsv)(caca_dither_t *, char *, int, int)
Definition: dither.c:123
caca_dither::rmask
int rmask
Definition: dither.c:120
caca_set_dither_gamma
int caca_set_dither_gamma(caca_dither_t *d, float gamma)
Set the gamma of a dither object.
Definition: dither.c:455
CACA_WHITE
Definition: caca.h:86
rgb2hsv_default
static void rgb2hsv_default(int r, int g, int b, int *hue, int *sat, int *val)
Definition: dither.c:207
caca_set_dither_charset
int caca_set_dither_charset(caca_dither_t *d, char const *str)
Choose characters used for dithering.
Definition: dither.c:739
lookup_initialised
static int lookup_initialised
Definition: dither.c:44
caca_dither::bleft
int bleft
Definition: dither.c:122
seterrno
#define seterrno(x)
Definition: caca_stubs.h:27
cucul_get_dither_gamma
#define cucul_get_dither_gamma
Definition: caca.h:882
ascii_glyphs
static uint32_t ascii_glyphs[]
Definition: dither.c:87
init_no_dither
static void init_no_dither(int)
Definition: dither.c:1370
init_ordered2_dither
static void init_ordered2_dither(int)
Definition: dither.c:1409
caca_dither::antialias_name
const char * antialias_name
Definition: dither.c:131
caca_dither::color_name
const char * color_name
Definition: dither.c:134
caca_get_attr
uint32_t caca_get_attr(caca_canvas_t const *cv, int x, int y)
Get the text attribute at the given coordinates.
Definition: attr.c:66
cucul_canvas_t
#define cucul_canvas_t
Definition: caca.h:763
caca_dither::has_alpha
int has_alpha
Definition: dither.c:118
cv
caca_canvas_t * cv
Definition: cacaview.c:45
CACA_RED
Definition: caca.h:75
caca_dither::algo_name
const char * algo_name
Definition: dither.c:137
cucul_set_dither_contrast
#define cucul_set_dither_contrast
Definition: caca.h:883
caca_dither::has_palette
int has_palette
Definition: dither.c:118
caca_dither::init_dither
void(* init_dither)(int)
Definition: dither.c:138
init_fstein_dither
static void init_fstein_dither(int)
Definition: dither.c:1388
caca_put_char
int caca_put_char(caca_canvas_t *, int, int, uint32_t)
Print an ASCII or Unicode character.
Definition: string.c:120
caca_dither::amask
int amask
Definition: dither.c:120
caca_internals.h
line
Definition: line.c:28
caca_get_dither_algorithm_list
const char *const * caca_get_dither_algorithm_list(caca_dither_t const *d)
Get dithering algorithms.
Definition: dither.c:894
min
#define min(x, y)
Definition: aafire.c:201
get_ordered2_dither
static int get_ordered2_dither(void)
Definition: dither.c:1421
caca_set_dither_contrast
int caca_set_dither_contrast(caca_dither_t *d, float contrast)
Set the contrast of a dither object.
Definition: dither.c:506
caca_dither::gright
int gright
Definition: dither.c:121
caca_dither::color
enum color_mode color
Definition: dither.c:135
ordered4_table
static const int * ordered4_table
Definition: dither.c:1438
caca_dither::antialias
int antialias
Definition: dither.c:132
COLOR_MODE_FULLGRAY
Definition: dither.c:111
COLOR_MODE_MONO
Definition: dither.c:107
CACA_BLACK
Definition: caca.h:71
CACA_DARKGRAY
Definition: caca.h:79
ordered2_table
static const int * ordered2_table
Definition: dither.c:1406
cucul_get_dither_antialias_list
#define cucul_get_dither_antialias_list
Definition: caca.h:886
increment_ordered2_dither
static void increment_ordered2_dither(void)
Definition: dither.c:1426
HSV_DISTANCE
#define HSV_DISTANCE(h, s, v, index)
Definition: dither.c:153
cucul_get_dither_antialias
#define cucul_get_dither_antialias
Definition: caca.h:887
get_rgba_default
static void get_rgba_default(caca_dither_t const *, uint8_t const *, int, int, unsigned int *)
Definition: dither.c:1312
caca_canvas::width
int width
Definition: caca_internals.h:71
caca_dither::gamma
float gamma
Definition: dither.c:127
cucul_get_dither_charset
#define cucul_get_dither_charset
Definition: caca.h:893
LOOKUP_HUE
#define LOOKUP_HUE
Definition: dither.c:40
cucul_get_dither_color
#define cucul_get_dither_color
Definition: caca.h:890
CACA_LIGHTMAGENTA
Definition: caca.h:84
rgb_weight
static const int rgb_weight[]
Definition: dither.c:80
caca_dither_bitmap
int caca_dither_bitmap(caca_canvas_t *cv, int x, int y, int w, int h, caca_dither_t const *d, void const *pixels)
Dither a bitmap on the canvas.
Definition: dither.c:940
init_random_dither
static void init_random_dither(int)
Definition: dither.c:1502
caca_set_color_ansi
int caca_set_color_ansi(caca_canvas_t *cv, uint8_t fg, uint8_t bg)
Set the default colour pair for text (ANSI version).
Definition: attr.c:234
COLOR_MODE_GRAY
Definition: dither.c:108
cucul_free_dither
#define cucul_free_dither
Definition: caca.h:898
get_ordered4_dither
static int get_ordered4_dither(void)
Definition: dither.c:1455
increment_ordered4_dither
static void increment_ordered4_dither(void)
Definition: dither.c:1460
caca.h
The libcaca public header.
caca_dither::gammatab
int gammatab[4097]
Definition: dither.c:128
LOOKUP_SAT
#define LOOKUP_SAT
Definition: dither.c:39
hsv_palette
static const int hsv_palette[]
Definition: dither.c:46
color_mode
color_mode
Definition: dither.c:105
caca_dither::aleft
int aleft
Definition: dither.c:122
cucul_dither_t
#define cucul_dither_t
Definition: caca.h:764
cucul_create_dither
#define cucul_create_dither
Definition: caca.h:877
config.h
caca_get_dither_brightness
float caca_get_dither_brightness(caca_dither_t const *d)
Get the brightness of a dither object.
Definition: dither.c:438
caca_dither::gmask
int gmask
Definition: dither.c:120
caca_dither::pitch
int pitch
Definition: dither.c:119
lookup_colors
static uint16_t lookup_colors[8]
Definition: dither.c:43
caca_dither::blue
int blue[256]
Definition: dither.c:124
caca_get_dither_charset_list
const char *const * caca_get_dither_charset_list(caca_dither_t const *d)
Get available dither character sets.
Definition: dither.c:781
caca_canvas::height
int height
Definition: caca_internals.h:71
caca_free_dither
int caca_free_dither(caca_dither_t *d)
Free the memory associated with a dither.
Definition: dither.c:1209
caca_dither::glyphs
const uint32_t * glyphs
Definition: dither.c:143
caca_dither::h
int h
Definition: dither.c:119
caca_set_dither_color
int caca_set_dither_color(caca_dither_t *d, char const *str)
Choose colours used for dithering.
Definition: dither.c:628
cucul_set_dither_palette
#define cucul_set_dither_palette
Definition: caca.h:878
CACA_LIGHTRED
Definition: caca.h:83
cucul_set_dither_gamma
#define cucul_set_dither_gamma
Definition: caca.h:881
COLOR_MODE_8
Definition: dither.c:109
CACA_MAGENTA
Definition: caca.h:76
cucul_set_dither_brightness
#define cucul_set_dither_brightness
Definition: caca.h:879
caca_canvas
Definition: caca_internals.h:47
x
static int x
Definition: cacadraw.c:27
increment_ordered8_dither
static void increment_ordered8_dither(void)
Definition: dither.c:1494
ordered8_table
static const int * ordered8_table
Definition: dither.c:1468
caca_dither::brightness
float brightness
Definition: dither.c:127
caca_dither::rright
int rright
Definition: dither.c:121
blocks_glyphs
static uint32_t blocks_glyphs[]
Definition: dither.c:98
cucul_get_dither_contrast
#define cucul_get_dither_contrast
Definition: caca.h:884