1 /********************************************************************************
2 *                                                                               *
3 *                     F S   C o l o r   Q u a n t i z a t i o n                 *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1999,2006 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or                 *
9 * modify it under the terms of the GNU Lesser General Public                    *
10 * License as published by the Free Software Foundation; either                  *
11 * version 2.1 of the License, or (at your option) any later version.            *
12 *                                                                               *
13 * This library is distributed in the hope that it will be useful,               *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU             *
16 * Lesser General Public License for more details.                               *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public              *
19 * License along with this library; if not, write to the Free Software           *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.    *
21 *********************************************************************************
22 * $Id: fxfsquantize.cpp,v 1.5 2006/01/22 17:58:52 fox Exp $                     *
23 ********************************************************************************/
24 #include "xincs.h"
25 #include "fxver.h"
26 #include "fxdefs.h"
27 #include "fxpriv.h"
28 
29 
30 /*
31   Notes:
32 
33   - The fxfsquantize is a floyd-steinberg dither.  It is quite fast
34     but not as good as Heckbert's or Wu's.
35 */
36 
37 
38 using namespace FX;
39 
40 
41 // Up to 256 colors: 3 bits R, 3 bits G, 2 bits B  (RRRGGGBB)
42 #define REDMASK          0xe0
43 #define REDSHIFT         0
44 #define GREENMASK        0xe0
45 #define GREENSHIFT       3
46 #define BLUEMASK         0xc0
47 #define BLUESHIFT        6
48 
49 /*******************************************************************************/
50 
51 namespace FX {
52 
53 
54 // Floyd-Steinberg quantization full 32 bpp to less than or equal to maxcolors
fxfsquantize(FXuchar * dst,const FXColor * src,FXColor * colormap,FXint & actualcolors,FXint w,FXint h,FXint)55 FXbool fxfsquantize(FXuchar* dst,const FXColor* src,FXColor* colormap,FXint& actualcolors,FXint w,FXint h,FXint){
56   register FXint i,j,val,r1,g1,b1,*cr,*cg,*cb,*nr,*ng,*nb,*p;
57   FXint *begin;
58 
59   // Fill colormap
60   for(r1=i=0; r1<8; r1++){
61     for(g1=0; g1<8; g1++){
62       for(b1=0; b1<4; b1++){
63         ((FXuchar*)(colormap+i))[0]=(r1*255+3)/7;
64         ((FXuchar*)(colormap+i))[1]=(g1*255+3)/7;
65         ((FXuchar*)(colormap+i))[2]=(b1*255+1)/3;
66         ((FXuchar*)(colormap+i))[3]=255;
67         i++;
68         }
69       }
70     }
71 
72   // Temporary storage
73   if(!FXMALLOC(&begin,FXint,w*2*3)) return FALSE;
74   cr=begin;
75   cg=cr+w;
76   cb=cg+w;
77   nr=cb+w;
78   ng=nr+w;
79   nb=ng+w;
80 
81   // Get first line of picture
82   for(j=0; j<w; j++){
83     nr[j]=((const FXuchar*)(src+j))[0];
84     ng[j]=((const FXuchar*)(src+j))[1];
85     nb[j]=((const FXuchar*)(src+j))[2];
86     }
87   src+=w;
88 
89   // Dither loop
90   for(i=0; i<h; i++){
91 
92     // Swap lines
93     FXSWAP(cr,nr,p);
94     FXSWAP(cg,ng,p);
95     FXSWAP(cb,nb,p);
96 
97     // Get next line
98     if(i!=h-1){
99       for(j=0; j<w; j++){
100         nr[j]=((const FXuchar*)(src+j))[0];
101         ng[j]=((const FXuchar*)(src+j))[1];
102         nb[j]=((const FXuchar*)(src+j))[2];
103         }
104       src+=w;
105       }
106 
107     // Dither
108     for(j=0; j<w; j++){
109       r1=cr[j]; r1=FXCLAMP(0,r1,255);
110       g1=cg[j]; g1=FXCLAMP(0,g1,255);
111       b1=cb[j]; b1=FXCLAMP(0,b1,255);
112 
113       // choose actual pixel value
114       val=(((r1&REDMASK)>>REDSHIFT)|((g1&GREENMASK)>>GREENSHIFT)|((b1&BLUEMASK)>>BLUESHIFT));
115       *dst++=val;
116 
117       // compute color errors
118       r1-=((FXuchar*)(colormap+val))[0];
119       g1-=((FXuchar*)(colormap+val))[1];
120       b1-=((FXuchar*)(colormap+val))[2];
121 
122       // Add fractions of errors to adjacent pixels
123       if(j!=w-1){                       // Adjust RIGHT pixel
124         cr[j+1]+=(r1*7)/16;
125         cg[j+1]+=(g1*7)/16;
126         cb[j+1]+=(b1*7)/16;
127         }
128       if(i!=h-1){                       // do BOTTOM pixel
129         nr[j]+=(r1*5)/16;
130         ng[j]+=(g1*5)/16;
131         nb[j]+=(b1*5)/16;
132         if(j>0){                        // do BOTTOM LEFT pixel
133           nr[j-1]+=(r1*3)/16;
134           ng[j-1]+=(g1*3)/16;
135           nb[j-1]+=(b1*3)/16;
136           }
137         if(j!=w-1){                     // do BOTTOM RIGHT pixel
138           nr[j+1]+=(r1)/16;
139           ng[j+1]+=(g1)/16;
140           nb[j+1]+=(b1)/16;
141           }
142         }
143       }
144     }
145   FXFREE(&begin);
146   actualcolors=256;
147   return TRUE;
148   }
149 
150 
151 }
152