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