Changeset 373


Ignore:
Timestamp:
Nov 4, 2004, 10:18:52 PM (18 years ago)
Author:
Sam Hocevar
Message:
  • src/bitmap.c: + 7-3-5-1 Floyd-Steinberg dithering. Breaks all other ditherers.
File:
1 edited

Legend:

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

    r351 r373  
    4242#endif
    4343
     44#include <stdio.h>
    4445#include <stdlib.h>
     46#include <limits.h>
     47#include <string.h>
    4548
    4649#include "caca.h"
     
    7881    3,    0x0,    0xfff,  0x5ff, /* dark red */
    7982    2,    0x0,    0xfff,  0xfff  /* light red */
     83};
     84
     85/* RGB palette for the new colour picker */
     86static int rgb_palette[] =
     87{
     88    0x0,   0x0,   0x0,
     89    0x0,   0x0,   0x7ff,
     90    0x0,   0x7ff, 0x0,
     91    0x0,   0x7ff, 0x7ff,
     92    0x7ff, 0x0,   0x0,
     93    0x7ff, 0x0,   0x7ff,
     94    0x7ff, 0x7ff, 0x0,
     95    0x7ff, 0x7ff, 0x7ff,
     96    0x3ff, 0x3ff, 0x3ff,
     97    0x000, 0x000, 0xfff,
     98    0x000, 0xfff, 0x000,
     99    0x000, 0xfff, 0xfff,
     100    0xfff, 0x000, 0x000,
     101    0xfff, 0x000, 0xfff,
     102    0xfff, 0xfff, 0x000,
     103    0xfff, 0xfff, 0xfff,
    80104};
    81105
     
    108132                             unsigned int *);
    109133static inline void rgb2hsv_default(int, int, int, int *, int *, int *);
     134static inline int sq(int);
    110135
    111136/* Dithering methods */
     
    385410}
    386411
     412static inline int sq(int x)
     413{
     414    return x * x;
     415}
     416
    387417/**
    388418 * \brief Draw a bitmap on the screen.
     
    405435    unsigned int (*_get_dither) (void);
    406436    void (*_increment_dither) (void);
     437
     438    int *floyd_steinberg, *fs_r, *fs_g, *fs_b;
     439    int fs_length;
    407440
    408441    /* Only used when background is black */
     
    439472    /* FIXME: choose better characters! */
    440473#if !defined(_DOXYGEN_SKIP_ME)
    441 #   define DENSITY_CHARS ((sizeof(density_chars)/sizeof(char const)/4)-1)
     474#   define DCHMAX ((sizeof(density_chars)/sizeof(char const)/4)-1)
    442475#endif
    443476    static char const density_chars[] =
    444477        "    "
    445         ".   "
    446         "..  "
    447478        "...."
    448479        "::::"
     
    450481        "tftf"
    451482        "%$%$"
    452         "&KSZ"
    453         "WXGM"
     483        "SK&Z"
     484        "XWGM"
    454485        "@@@@"
    455486        "8888"
     
    516547    }
    517548
     549    fs_length = ((int)_caca_width <= x2 ? (int)_caca_width : x2) + 1;
     550    floyd_steinberg = malloc(3 * (fs_length + 2) * sizeof(int));
     551    memset(floyd_steinberg, 0, 3 * (fs_length + 2) * sizeof(int));
     552    fs_r = floyd_steinberg + 1;
     553    fs_g = fs_r + fs_length + 2;
     554    fs_b = fs_g + fs_length + 2;
     555
    518556    for(y = y1 > 0 ? y1 : 0; y <= y2 && y <= (int)_caca_height; y++)
     557    {
     558        int remain_r = 0, remain_g = 0, remain_b = 0;
     559        int remain_r_next = 0, remain_g_next = 0, remain_b_next = 0;
     560
    519561        for(x = x1 > 0 ? x1 : 0, _init_dither(y);
    520562            x <= x2 && x <= (int)_caca_width;
    521563            x++)
    522564    {
    523         int ch;
    524         unsigned int r, g, b, a;
    525         int hue, sat, val;
    526         int fromx, fromy, tox, toy, myx, myy, dots;
    527         enum caca_color outfg, outbg;
     565        unsigned int i;
     566        int ch = 0, distmin;
     567        int r, g, b, a, fg_r, fg_g, fg_b, bg_r, bg_g, bg_b;
     568        int fromx, fromy, tox, toy, myx, myy, dots, dist;
     569
     570        enum caca_color outfg = 0, outbg = 0;
    528571        char outch;
    529572
     
    574617
    575618        if(bitmap->has_alpha && a < 0x800)
     619        {
     620            remain_r = remain_g = remain_b = 0;
     621            fs_r[x] = 0;
     622            fs_g[x] = 0;
     623            fs_b[x] = 0;
    576624            continue;
    577 
    578         /* Now get HSV from RGB */
    579         rgb2hsv_default(r, g, b, &hue, &sat, &val);
    580 
    581         /* The hard work: calculate foreground and background colours,
    582          * as well as the most appropriate character to output. */
    583         if(_caca_background == CACA_BACKGROUND_SOLID)
     625        }
     626
     627        r += remain_r;
     628        g += remain_g;
     629        b += remain_b;
     630        r += remain_r_next;
     631        g += remain_g_next;
     632        b += remain_b_next;
     633        remain_r_next = fs_r[x+1];
     634        remain_g_next = fs_g[x+1];
     635        remain_b_next = fs_b[x+1];
     636
     637        distmin = INT_MAX;
     638        for(i = 0; i < 16; i++)
    584639        {
    585             unsigned char point;
    586             int distfg, distbg;
    587 
    588             lookup_colors[4] = dark_colors[1 + hue / 0x1000];
    589             lookup_colors[5] = light_colors[1 + hue / 0x1000];
    590             lookup_colors[6] = dark_colors[hue / 0x1000];
    591             lookup_colors[7] = light_colors[hue / 0x1000];
    592 
    593             point = hsv_distances[(val + _get_dither() * (0x1000 / LOOKUP_VAL)
    594                                     / 0x100) * (LOOKUP_VAL - 1) / 0x1000]
    595                                  [(sat + _get_dither() * (0x1000 / LOOKUP_SAT)
    596                                     / 0x100) * (LOOKUP_SAT - 1) / 0x1000]
    597                                  [((hue & 0xfff) + _get_dither()
    598                                             * (0x1000 / LOOKUP_HUE) / 0x100)
    599                                             * (LOOKUP_HUE - 1) / 0x1000];
    600 
    601             distfg = HSV_DISTANCE(hue % 0xfff, sat, val, (point >> 4));
    602             distbg = HSV_DISTANCE(hue % 0xfff, sat, val, (point & 0xf));
    603 
    604             /* Sanity check due to the lack of precision in hsv_distances,
    605              * and distbg can be > distfg because of dithering fuzziness. */
    606             if(distbg > distfg)
    607                 distbg = distfg;
    608 
    609             outfg = lookup_colors[(point >> 4)];
    610             outbg = lookup_colors[(point & 0xf)];
    611 
    612             ch = distbg * 2 * (DENSITY_CHARS - 1) / (distbg + distfg);
    613             ch = 4 * ch + _get_dither() / 0x40;
    614             outch = density_chars[ch];
     640            dist = sq(r - rgb_palette[i * 3])
     641                 + sq(g - rgb_palette[i * 3 + 1])
     642                 + sq(b - rgb_palette[i * 3 + 2]);
     643            if(dist < distmin)
     644            {
     645                outbg = i;
     646                distmin = dist;
     647            }
    615648        }
    616         else
     649        bg_r = rgb_palette[outbg * 3];
     650        bg_g = rgb_palette[outbg * 3 + 1];
     651        bg_b = rgb_palette[outbg * 3 + 2];
     652
     653        distmin = INT_MAX;
     654        for(i = 0; i < 16; i++)
    617655        {
    618             outbg = CACA_COLOR_BLACK;
    619             if((unsigned int)sat < 0x200 + _get_dither() * 0x8)
    620                 outfg = white_colors[1 + (val * 2 + _get_dither() * 0x10)
    621                                        / 0x1000];
    622             else if((unsigned int)val > 0x800 + _get_dither() * 0x4)
    623                 outfg = light_colors[(hue + _get_dither() * 0x10) / 0x1000];
    624             else
    625                 outfg = dark_colors[(hue + _get_dither() * 0x10) / 0x1000];
    626 
    627             ch = (val + 0x2 * _get_dither()) * 10 / 0x1000;
    628             ch = 4 * ch + _get_dither() / 0x40;
    629             outch = density_chars[ch];
     656            if(i == outbg)
     657                continue;
     658            dist = sq(r - rgb_palette[i * 3])
     659                 + sq(g - rgb_palette[i * 3 + 1])
     660                 + sq(b - rgb_palette[i * 3 + 2]);
     661            if(dist < distmin)
     662            {
     663                outfg = i;
     664                distmin = dist;
     665            }
    630666        }
     667        fg_r = rgb_palette[outfg * 3];
     668        fg_g = rgb_palette[outfg * 3 + 1];
     669        fg_b = rgb_palette[outfg * 3 + 2];
     670
     671        distmin = INT_MAX;
     672        for(i = 0; i < DCHMAX - 1; i++)
     673        {
     674            int newr = i * fg_r + ((2*DCHMAX-1) - i) * bg_r;
     675            int newg = i * fg_g + ((2*DCHMAX-1) - i) * bg_g;
     676            int newb = i * fg_b + ((2*DCHMAX-1) - i) * bg_b;
     677            dist = abs(r * (2*DCHMAX-1) - newr)
     678                 * abs(g * (2*DCHMAX-1) - newg)
     679                 * abs(b * (2*DCHMAX-1) - newb);
     680
     681            if(dist < distmin)
     682            {
     683                ch = i;
     684                distmin = dist;
     685            }
     686        }
     687        outch = density_chars[4 * ch];
     688
     689        remain_r = r - (fg_r * ch + bg_r * ((2*DCHMAX-1) - ch)) / (2*DCHMAX-1);
     690        remain_g = g - (fg_g * ch + bg_g * ((2*DCHMAX-1) - ch)) / (2*DCHMAX-1);
     691        remain_b = b - (fg_b * ch + bg_b * ((2*DCHMAX-1) - ch)) / (2*DCHMAX-1);
     692        remain_r_next = fs_r[x+1];
     693        remain_g_next = fs_g[x+1];
     694        remain_b_next = fs_b[x+1];
     695        fs_r[x-1] += 3 * remain_r / 16;
     696        fs_g[x-1] += 3 * remain_g / 16;
     697        fs_b[x-1] += 3 * remain_b / 16;
     698        fs_r[x] = 5 * remain_r / 16;
     699        fs_g[x] = 5 * remain_g / 16;
     700        fs_b[x] = 5 * remain_b / 16;
     701        fs_r[x+1] = 1 * remain_r / 16;
     702        fs_g[x+1] = 1 * remain_g / 16;
     703        fs_b[x+1] = 1 * remain_b / 16;
     704        remain_r = 7 * remain_r / 16;
     705        remain_g = 7 * remain_g / 16;
     706        remain_b = 7 * remain_b / 16;
    631707
    632708        /* Now output the character */
     
    636712        _increment_dither();
    637713    }
     714        /* end loop */
     715    }
     716
     717    free(floyd_steinberg);
    638718}
    639719
Note: See TracChangeset for help on using the changeset viewer.