Переглянути джерело

* src/bitmap.c:

+ Dither H/S/V when looking up the two nearest colours.
    + Weigh pixels in the distance calculation.
    + Factorised the lookup table calculation.
tags/v0.99.beta14
Sam Hocevar sam 21 роки тому
джерело
коміт
1f643aedee
1 змінених файлів з 61 додано та 156 видалено
  1. +61
    -156
      src/bitmap.c

+ 61
- 156
src/bitmap.c Переглянути файл

@@ -59,37 +59,38 @@ enum caca_feature _caca_antialiasing;
#define LOOKUP_VAL 32
#define LOOKUP_SAT 32
#define LOOKUP_HUE 16
static unsigned char lookup_table[LOOKUP_VAL][LOOKUP_SAT][LOOKUP_HUE];
static unsigned char hsv_distances[LOOKUP_VAL][LOOKUP_SAT][LOOKUP_HUE];
static enum caca_color lookup_colors[8];

static int const hsv_palette[] =
{
/* hue, saturation, value */
0x0, 0x0, 0x0, /* black */
0x0, 0x0, 0x5ff, /* 30% */
0x0, 0x0, 0x9ff, /* 70% */
0x0, 0x0, 0xfff, /* white */
0x1000, 0xfff, 0x5ff, /* dark yellow */
0x1000, 0xfff, 0xfff, /* light yellow */
0x0, 0xfff, 0x5ff, /* dark red */
0x0, 0xfff, 0xfff /* light red */
/* weight, hue, saturation, value */
4, 0x0, 0x0, 0x0, /* black */
5, 0x0, 0x0, 0x5ff, /* 30% */
5, 0x0, 0x0, 0x9ff, /* 70% */
4, 0x0, 0x0, 0xfff, /* white */
3, 0x1000, 0xfff, 0x5ff, /* dark yellow */
2, 0x1000, 0xfff, 0xfff, /* light yellow */
3, 0x0, 0xfff, 0x5ff, /* dark red */
2, 0x0, 0xfff, 0xfff /* light red */
};

#define HSV_XRATIO (5*5)
#define HSV_YRATIO (3*3)
#define HSV_HRATIO (2*2)
#define HSV_XRATIO 6
#define HSV_YRATIO 3
#define HSV_HRATIO 3

#define HSV_DISTANCE(h, s, v, index) \
((HSV_XRATIO * ((v) - hsv_palette[index * 3 + 2]) \
* ((v) - hsv_palette[index * 3 + 2])) \
+ (hsv_palette[index * 3 + 2] \
? (HSV_YRATIO * ((s) - hsv_palette[index * 3 + 1]) \
* ((s) - hsv_palette[index * 3 + 1])) \
: 0) \
+ (hsv_palette[index * 3 + 1] \
? (HSV_HRATIO * ((h) - hsv_palette[index * 3 + 0]) \
* ((h) - hsv_palette[index * 3 + 0])) \
: 0))
(hsv_palette[index * 4] \
* ((HSV_XRATIO * ((v) - hsv_palette[index * 4 + 3]) \
* ((v) - hsv_palette[index * 4 + 3])) \
+ (hsv_palette[index * 4 + 3] \
? (HSV_YRATIO * ((s) - hsv_palette[index * 4 + 2]) \
* ((s) - hsv_palette[index * 4 + 2])) \
: 0) \
+ (hsv_palette[index * 4 + 2] \
? (HSV_HRATIO * ((h) - hsv_palette[index * 4 + 1]) \
* ((h) - hsv_palette[index * 4 + 1])) \
: 0)))

/*
* Local prototypes
@@ -557,29 +558,28 @@ void caca_draw_bitmap(int x1, int y1, int x2, int y2,
lookup_colors[6] = dark_colors[hue / 0x1000];
lookup_colors[7] = light_colors[hue / 0x1000];

point = lookup_table[val * LOOKUP_VAL / 0x1000]
[sat * LOOKUP_SAT / 0x1000]
[(hue & 0xfff) * LOOKUP_HUE / 0x1000];
point = hsv_distances[(val + _get_dither() * (0x1000 / LOOKUP_VAL)
/ 0x100) * (LOOKUP_VAL - 1) / 0x1000]
[(sat + _get_dither() * (0x1000 / LOOKUP_SAT)
/ 0x100) * (LOOKUP_SAT - 1) / 0x1000]
[((hue & 0xfff) + _get_dither()
* (0x1000 / LOOKUP_HUE) / 0x100)
* (LOOKUP_HUE - 1) / 0x1000];

try_again:
distfg = HSV_DISTANCE(hue % 0xfff, sat, val, (point >> 4));
distbg = HSV_DISTANCE(hue % 0xfff, sat, val, (point & 0xf));

/* Sanity check due to the lack of precision in lookup_table */
#if 0
if(distbg > distfg)
{
point = ((point & 0xf) << 4) | (point >> 4);
goto try_again;
}
#endif
/* Sanity check due to the lack of precision in hsv_distances,
* and distbg can be > distfg because of dithering fuzziness. */
if(distbg > distfg)
distbg = distfg;

outfg = lookup_colors[(point >> 4)];
outbg = lookup_colors[(point & 0xf)];

outch = density_chars[4 * (distbg * (DENSITY_CHARS - 1) / distfg)];
ch = distbg * 2 * (DENSITY_CHARS - 1) / (distbg + distfg);
ch = 4 * ch + _get_dither() / 0x40;
outch = density_chars[ch];
}
else
{
@@ -625,134 +625,39 @@ int _caca_init_bitmap(void)
for(s = 0; s < LOOKUP_SAT; s++)
for(h = 0; h < LOOKUP_HUE; h++)
{
int distbg, distfg, dist;
int i, distbg, distfg, dist;
int val, sat, hue;
unsigned char outbg, outfg;

val = 0x1000 * v / LOOKUP_VAL;
sat = 0x1000 * s / LOOKUP_SAT;
hue = 0x1000 * h / LOOKUP_HUE;

/* distance to black */
distbg = HSV_DISTANCE(hue, sat, val, 0);
distbg = distbg * 2 / 4;
outbg = 0;

/* distance to 30% */
dist = HSV_DISTANCE(hue, sat, val, 1);
dist = dist * 3 / 2;
if(dist <= distbg)
{
outfg = outbg;
distfg = distbg;
outbg = 1;
distbg = dist;
}
else
{
outfg = 1;
distfg = dist;
}

/* check dist to 70% */
dist = HSV_DISTANCE(hue, sat, val, 2);
dist = dist * 3 / 2;
if(dist <= distbg)
{
outfg = outbg;
distfg = distbg;
outbg = 2;
distbg = dist;
}
else if(dist <= distfg)
{
outfg = 2;
distfg = dist;
}
val = 0xfff * v / (LOOKUP_VAL - 1);
sat = 0xfff * s / (LOOKUP_SAT - 1);
hue = 0xfff * h / (LOOKUP_HUE - 1);

/* check dist to white */
dist = HSV_DISTANCE(hue, sat, val, 3);
if(dist <= distbg)
{
outfg = outbg;
distfg = distbg;
outbg = 3;
distbg = dist;
}
else if(dist <= distfg)
{
outfg = 3;
distfg = dist;
}
/* Initialise distances to the distance between pure black HSV
* coordinates and our white colour (3) */
outbg = outfg = 3;
distbg = distfg = HSV_DISTANCE(0, 0, 0, 3);

/* check dist to 2nd closest dark color */
dist = HSV_DISTANCE(hue, sat, val, 4);
//dist = dist * 3 / 4;
dist = dist * 3 / 4;
if(dist <= distbg)
/* Calculate distances to eight major colour values and store the
* two nearest points in our lookup table. */
for(i = 0; i < 8; i++)
{
outfg = outbg;
distfg = distbg;
outbg = 4;
distbg = dist;
}
else if(dist <= distfg)
{
outfg = 4;
distfg = dist;
}

/* check dist to 2nd closest light color */
dist = HSV_DISTANCE(hue, sat, val, 5);
dist = dist / 2;
//dist = dist * 3 / 4;
//dist = dist / 2;
if(dist <= distbg)
{
outfg = outbg;
distfg = distbg;
outbg = 5;
distbg = dist;
}
else if(dist <= distfg)
{
outfg = 5;
distfg = dist;
}

/* check dist to closest dark color */
dist = HSV_DISTANCE(hue, sat, val, 6);
dist = dist * 3 / 4;
if(dist <= distbg)
{
outfg = outbg;
distfg = distbg;
outbg = 6;
distbg = dist;
}
else if(dist <= distfg)
{
outfg = 6;
distfg = dist;
}

/* check dist to closest light color */
dist = HSV_DISTANCE(hue, sat, val, 7);
dist = dist / 2;
if(dist <= distbg)
{
outfg = outbg;
distfg = distbg;
outbg = 7;
distbg = dist;
}
else if(dist <= distfg)
{
outfg = 7;
distfg = dist;
dist = HSV_DISTANCE(hue, sat, val, i);
if(dist <= distbg)
{
outfg = outbg;
distfg = distbg;
outbg = i;
distbg = dist;
}
else if(dist <= distfg)
{
outfg = i;
distfg = dist;
}
}

lookup_table[v][s][h] = (outfg << 4) | outbg;
hsv_distances[v][s][h] = (outfg << 4) | outbg;
}

return 0;


Завантаження…
Відмінити
Зберегти