Changeset 308


Ignore:
Timestamp:
Jan 3, 2004, 3:33:35 PM (19 years ago)
Author:
Sam Hocevar
Message:
  • 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.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcaca/trunk/src/bitmap.c

    r306 r308  
    6060#define LOOKUP_SAT 32
    6161#define LOOKUP_HUE 16
    62 static unsigned char lookup_table[LOOKUP_VAL][LOOKUP_SAT][LOOKUP_HUE];
     62static unsigned char hsv_distances[LOOKUP_VAL][LOOKUP_SAT][LOOKUP_HUE];
    6363static enum caca_color lookup_colors[8];
    6464
    6565static int const hsv_palette[] =
    6666{
    67     /* hue, saturation, value */
    68     0x0,    0x0,    0x0,   /* black */
    69     0x0,    0x0,    0x5ff, /* 30% */
    70     0x0,    0x0,    0x9ff, /* 70% */
    71     0x0,    0x0,    0xfff, /* white */
    72     0x1000, 0xfff,  0x5ff, /* dark yellow */
    73     0x1000, 0xfff,  0xfff, /* light yellow */
    74     0x0,    0xfff,  0x5ff, /* dark red */
    75     0x0,    0xfff,  0xfff  /* light red */
     67    /* weight, hue, saturation, value */
     68    4,    0x0,    0x0,    0x0,   /* black */
     69    5,    0x0,    0x0,    0x5ff, /* 30% */
     70    5,    0x0,    0x0,    0x9ff, /* 70% */
     71    4,    0x0,    0x0,    0xfff, /* white */
     72    3,    0x1000, 0xfff,  0x5ff, /* dark yellow */
     73    2,    0x1000, 0xfff,  0xfff, /* light yellow */
     74    3,    0x0,    0xfff,  0x5ff, /* dark red */
     75    2,    0x0,    0xfff,  0xfff  /* light red */
    7676};
    7777
    78 #define HSV_XRATIO (5*5)
    79 #define HSV_YRATIO (3*3)
    80 #define HSV_HRATIO (2*2)
     78#define HSV_XRATIO 6
     79#define HSV_YRATIO 3
     80#define HSV_HRATIO 3
    8181
    8282#define HSV_DISTANCE(h, s, v, index) \
    83     ((HSV_XRATIO * ((v) - hsv_palette[index * 3 + 2]) \
    84                  * ((v) - hsv_palette[index * 3 + 2])) \
    85     + (hsv_palette[index * 3 + 2] \
    86         ? (HSV_YRATIO * ((s) - hsv_palette[index * 3 + 1]) \
    87                       * ((s) - hsv_palette[index * 3 + 1])) \
    88         : 0) \
    89     + (hsv_palette[index * 3 + 1] \
    90         ? (HSV_HRATIO * ((h) - hsv_palette[index * 3 + 0]) \
    91                       * ((h) - hsv_palette[index * 3 + 0])) \
    92         : 0))
     83    (hsv_palette[index * 4] \
     84     * ((HSV_XRATIO * ((v) - hsv_palette[index * 4 + 3]) \
     85                    * ((v) - hsv_palette[index * 4 + 3])) \
     86       + (hsv_palette[index * 4 + 3] \
     87           ? (HSV_YRATIO * ((s) - hsv_palette[index * 4 + 2]) \
     88                         * ((s) - hsv_palette[index * 4 + 2])) \
     89           : 0) \
     90       + (hsv_palette[index * 4 + 2] \
     91           ? (HSV_HRATIO * ((h) - hsv_palette[index * 4 + 1]) \
     92                         * ((h) - hsv_palette[index * 4 + 1])) \
     93           : 0)))
    9394
    9495/*
     
    558559            lookup_colors[7] = light_colors[hue / 0x1000];
    559560
    560             point = lookup_table[val * LOOKUP_VAL / 0x1000]
    561                                 [sat * LOOKUP_SAT / 0x1000]
    562                                 [(hue & 0xfff) * LOOKUP_HUE / 0x1000];
    563 
    564 try_again:
     561            point = hsv_distances[(val + _get_dither() * (0x1000 / LOOKUP_VAL)
     562                                    / 0x100) * (LOOKUP_VAL - 1) / 0x1000]
     563                                 [(sat + _get_dither() * (0x1000 / LOOKUP_SAT)
     564                                    / 0x100) * (LOOKUP_SAT - 1) / 0x1000]
     565                                 [((hue & 0xfff) + _get_dither()
     566                                            * (0x1000 / LOOKUP_HUE) / 0x100)
     567                                            * (LOOKUP_HUE - 1) / 0x1000];
     568
    565569            distfg = HSV_DISTANCE(hue % 0xfff, sat, val, (point >> 4));
    566570            distbg = HSV_DISTANCE(hue % 0xfff, sat, val, (point & 0xf));
    567571
    568             /* Sanity check due to the lack of precision in lookup_table */
    569 #if 0
    570             if(distbg > distfg)
    571             {
    572                 point = ((point & 0xf) << 4) | (point >> 4);
    573                 goto try_again;
    574             }
    575 #endif
     572            /* Sanity check due to the lack of precision in hsv_distances,
     573             * and distbg can be > distfg because of dithering fuzziness. */
    576574            if(distbg > distfg)
    577575                distbg = distfg;
     
    580578            outbg = lookup_colors[(point & 0xf)];
    581579
    582             outch = density_chars[4 * (distbg * (DENSITY_CHARS - 1) / distfg)];
     580            ch = distbg * 2 * (DENSITY_CHARS - 1) / (distbg + distfg);
     581            ch = 4 * ch + _get_dither() / 0x40;
     582            outch = density_chars[ch];
    583583        }
    584584        else
     
    626626            for(h = 0; h < LOOKUP_HUE; h++)
    627627    {
    628         int distbg, distfg, dist;
     628        int i, distbg, distfg, dist;
    629629        int val, sat, hue;
    630630        unsigned char outbg, outfg;
    631631
    632         val = 0x1000 * v / LOOKUP_VAL;
    633         sat = 0x1000 * s / LOOKUP_SAT;
    634         hue = 0x1000 * h / LOOKUP_HUE;
    635 
    636         /* distance to black */
    637         distbg = HSV_DISTANCE(hue, sat, val, 0);
    638         distbg = distbg * 2 / 4;
    639         outbg = 0;
    640 
    641         /* distance to 30% */
    642         dist = HSV_DISTANCE(hue, sat, val, 1);
    643         dist = dist * 3 / 2;
    644         if(dist <= distbg)
     632        val = 0xfff * v / (LOOKUP_VAL - 1);
     633        sat = 0xfff * s / (LOOKUP_SAT - 1);
     634        hue = 0xfff * h / (LOOKUP_HUE - 1);
     635
     636        /* Initialise distances to the distance between pure black HSV
     637         * coordinates and our white colour (3) */
     638        outbg = outfg = 3;
     639        distbg = distfg = HSV_DISTANCE(0, 0, 0, 3);
     640
     641        /* Calculate distances to eight major colour values and store the
     642         * two nearest points in our lookup table. */
     643        for(i = 0; i < 8; i++)
    645644        {
    646             outfg = outbg;
    647             distfg = distbg;
    648             outbg = 1;
    649             distbg = dist;
     645            dist = HSV_DISTANCE(hue, sat, val, i);
     646            if(dist <= distbg)
     647            {
     648                outfg = outbg;
     649                distfg = distbg;
     650                outbg = i;
     651                distbg = dist;
     652            }
     653            else if(dist <= distfg)
     654            {
     655                outfg = i;
     656                distfg = dist;
     657            }
    650658        }
    651         else
    652         {
    653             outfg = 1;
    654             distfg = dist;
    655         }
    656 
    657         /* check dist to 70% */
    658         dist = HSV_DISTANCE(hue, sat, val, 2);
    659         dist = dist * 3 / 2;
    660         if(dist <= distbg)
    661         {
    662             outfg = outbg;
    663             distfg = distbg;
    664             outbg = 2;
    665             distbg = dist;
    666         }
    667         else if(dist <= distfg)
    668         {
    669             outfg = 2;
    670             distfg = dist;
    671         }
    672 
    673         /* check dist to white */
    674         dist = HSV_DISTANCE(hue, sat, val, 3);
    675         if(dist <= distbg)
    676         {
    677             outfg = outbg;
    678             distfg = distbg;
    679             outbg = 3;
    680             distbg = dist;
    681         }
    682         else if(dist <= distfg)
    683         {
    684             outfg = 3;
    685             distfg = dist;
    686         }
    687 
    688         /* check dist to 2nd closest dark color */
    689         dist = HSV_DISTANCE(hue, sat, val, 4);
    690         //dist = dist * 3 / 4;
    691         dist = dist * 3 / 4;
    692         if(dist <= distbg)
    693         {
    694             outfg = outbg;
    695             distfg = distbg;
    696             outbg = 4;
    697             distbg = dist;
    698         }
    699         else if(dist <= distfg)
    700         {
    701             outfg = 4;
    702             distfg = dist;
    703         }
    704 
    705         /* check dist to 2nd closest light color */
    706         dist = HSV_DISTANCE(hue, sat, val, 5);
    707         dist = dist / 2;
    708         //dist = dist * 3 / 4;
    709         //dist = dist / 2;
    710         if(dist <= distbg)
    711         {
    712             outfg = outbg;
    713             distfg = distbg;
    714             outbg = 5;
    715             distbg = dist;
    716         }
    717         else if(dist <= distfg)
    718         {
    719             outfg = 5;
    720             distfg = dist;
    721         }
    722 
    723         /* check dist to closest dark color */
    724         dist = HSV_DISTANCE(hue, sat, val, 6);
    725         dist = dist * 3 / 4;
    726         if(dist <= distbg)
    727         {
    728             outfg = outbg;
    729             distfg = distbg;
    730             outbg = 6;
    731             distbg = dist;
    732         }
    733         else if(dist <= distfg)
    734         {
    735             outfg = 6;
    736             distfg = dist;
    737         }
    738 
    739         /* check dist to closest light color */
    740         dist = HSV_DISTANCE(hue, sat, val, 7);
    741         dist = dist / 2;
    742         if(dist <= distbg)
    743         {
    744             outfg = outbg;
    745             distfg = distbg;
    746             outbg = 7;
    747             distbg = dist;
    748         }
    749         else if(dist <= distfg)
    750         {
    751             outfg = 7;
    752             distfg = dist;
    753         }
    754 
    755         lookup_table[v][s][h] = (outfg << 4) | outbg;
     659
     660        hsv_distances[v][s][h] = (outfg << 4) | outbg;
    756661    }
    757662
Note: See TracChangeset for help on using the changeset viewer.