FloydSteinbergDither.cpp
Go to the documentation of this file.00001 //*** FloydSteinbergDither.h *** 00002 00003 #include "FloydSteinbergDither.h" 00004 00005 #include "StandardLibrary.h" 00006 #include "Debug.h" 00007 #include "ColorHelper.h" 00008 00009 #pragma warning (disable:4244) 00010 00011 typedef struct { 00012 unsigned char R, G, B, A; 00013 } RGBTriple; 00014 00015 typedef struct { 00016 int size; 00017 RGBTriple* table; 00018 } RGBPalette; 00019 00020 typedef struct { 00021 int width, height; 00022 RGBTriple* pixels; 00023 } RGBImage; 00024 00025 typedef struct { 00026 int width, height; 00027 unsigned char* pixels; 00028 } PalettizedImage; 00029 00030 #define plus_truncate_uchar(a, b) \ 00031 if (((int)(a)) + (b) < 0) \ 00032 (a) = 0; \ 00033 else if (((int)(a)) + (b) > 255) \ 00034 (a) = 255; \ 00035 else \ 00036 (a) += (b); 00037 00038 00039 static 00040 unsigned char FindNearestColor(RGBTriple color, RGBPalette palette) { 00041 int i, distanceSquared, minDistanceSquared, bestIndex = 0; 00042 minDistanceSquared = 255*255 + 255*255 + 255*255 + 1; 00043 for (i=0; i<palette.size; i++) { 00044 int Rdiff = ((int)color.R) - palette.table[i].R; 00045 int Gdiff = ((int)color.G) - palette.table[i].G; 00046 int Bdiff = ((int)color.B) - palette.table[i].B; 00047 distanceSquared = Rdiff*Rdiff + Gdiff*Gdiff + Bdiff*Bdiff; 00048 if (distanceSquared < minDistanceSquared) { 00049 minDistanceSquared = distanceSquared; 00050 bestIndex = i; 00051 } 00052 } 00053 return bestIndex; 00054 } 00055 00056 00057 #define compute_disperse(channel) \ 00058 error = ((int)(currentPixel->channel)) - palette.table[index].channel; \ 00059 if (x + 1 < image.width && image.pixels[(x+1) + (y+0)*image.width].A>0) { \ 00060 plus_truncate_uchar(image.pixels[(x+1) + (y+0)*image.width].channel, (error*7) >> 4); \ 00061 } \ 00062 if (y + 1 < image.height) { \ 00063 if (x - 1 > 0 && image.pixels[(x-1) + (y+1)*image.width].A>0) { \ 00064 plus_truncate_uchar(image.pixels[(x-1) + (y+1)*image.width].channel, (error*3) >> 4); \ 00065 } \ 00066 if (image.pixels[(x+0) + (y+1)*image.width].A>0) { \ 00067 plus_truncate_uchar(image.pixels[(x+0) + (y+1)*image.width].channel, (error*5) >> 4); \ 00068 }\ 00069 if (x + 1 < image.width && image.pixels[(x+1) + (y+1)*image.width].A>0) { \ 00070 plus_truncate_uchar(image.pixels[(x+1) + (y+1)*image.width].channel, (error*1) >> 4); \ 00071 } \ 00072 } 00073 00074 00075 PalettizedImage FloydSteinbergDitherer(RGBImage image, RGBPalette palette) 00076 { 00077 PalettizedImage result; 00078 result.width = image.width; 00079 result.height = image.height; 00080 result.pixels = (unsigned char*)Malloc(sizeof(unsigned char) * result.width * result.height); 00081 00082 int x, y; 00083 for(y = 0; y < image.height; y++) 00084 { 00085 for(x = 0; x < image.width; x++) 00086 { 00087 RGBTriple* currentPixel = &(image.pixels[x + y*image.width]); 00088 unsigned char index = FindNearestColor(*currentPixel, palette); 00089 result.pixels[x + y*result.width] = index; 00090 if (currentPixel->A==0) 00091 { 00092 result.pixels[x + y*result.width]=0; 00093 continue; 00094 } 00095 00096 int error; 00097 compute_disperse(R); 00098 compute_disperse(G); 00099 compute_disperse(B); 00100 } 00101 } 00102 00103 return result; 00104 } 00105 00106 00107 //*** DitherImage *** 00108 00109 void FloydSteinbergDither::DitherImage(unsigned int* image, int imageWidth, int imageHeight, unsigned int* palette, int paletteCount, unsigned char* outputData) 00110 { 00111 RGBPalette pal; 00112 pal.size=paletteCount; 00113 pal.table=new RGBTriple[paletteCount]; 00114 for (int i=0; i<paletteCount; i++) 00115 { 00116 unsigned int color=palette[i]; 00117 unsigned char a=((unsigned char)((color&0xff000000)>>24)); 00118 unsigned char r=((unsigned char)((color&0x00ff0000)>>16)); 00119 unsigned char g=((unsigned char)((color&0x0000ff00)>>8 )); 00120 unsigned char b=((unsigned char)((color&0x000000ff) )); 00121 00122 pal.table[i].A=a; 00123 pal.table[i].R=r; 00124 pal.table[i].G=g; 00125 pal.table[i].B=b; 00126 } 00127 00128 RGBImage img; 00129 img.width=imageWidth; 00130 img.height=imageHeight; 00131 img.pixels=new RGBTriple[imageWidth*imageHeight]; 00132 for (int y=0; y<imageHeight; y++) 00133 { 00134 for (int x=0; x<imageWidth; x++) 00135 { 00136 unsigned int color=image[x+y*imageWidth]; 00137 unsigned char a=((unsigned char)((color&0xff000000)>>24)); 00138 unsigned char r=((unsigned char)((color&0x00ff0000)>>16)); 00139 unsigned char g=((unsigned char)((color&0x0000ff00)>>8 )); 00140 unsigned char b=((unsigned char)((color&0x000000ff) )); 00141 RGBTriple t; 00142 t.A=a; 00143 t.R=r; 00144 t.G=g; 00145 t.B=b; 00146 img.pixels[x+y*imageWidth]=t; 00147 } 00148 } 00149 00150 PalettizedImage palImg=FloydSteinbergDitherer(img,pal); 00151 delete[] pal.table; 00152 delete[] img.pixels; 00153 00154 Assert(palImg.width==imageWidth && palImg.height==imageHeight,"Image sizes doesn't match"); 00155 00156 for (int y=0; y<palImg.height; y++) 00157 { 00158 for (int x=0; x<palImg.width; x++) 00159 { 00160 outputData[x+palImg.width*y]=palImg.pixels[x+palImg.width*y]; 00161 } 00162 } 00163 Free(palImg.pixels); 00164 } 00165 00166 00167 //*** DitherImage *** 00168 00169 void FloydSteinbergDither::DitherImage(unsigned int* image, int imageWidth, int imageHeight, unsigned short* outputData) 00170 { 00171 for (int y=0; y<imageHeight; y++) 00172 { 00173 for (int x=0; x<imageWidth; x++) 00174 { 00175 unsigned int color=image[x+y*imageWidth]; 00176 unsigned char r=((unsigned char)((color&0x00ff0000)>>16)); 00177 unsigned char g=((unsigned char)((color&0x0000ff00)>>8 )); 00178 unsigned char b=((unsigned char)((color&0x000000ff) )); 00179 unsigned short color16 = RGB32TO16(color); 00180 unsigned char r16=((unsigned char)((RGB16TO32(color16)&0x00ff0000)>>16)); 00181 unsigned char g16=((unsigned char)((RGB16TO32(color16)&0x0000ff00)>>8 )); 00182 unsigned char b16=((unsigned char)((RGB16TO32(color16)&0x000000ff) )); 00183 outputData[x+y*imageWidth]=color16; 00184 00185 int error = ((int)r) - r16; 00186 if (x + 1 < imageWidth) 00187 { 00188 unsigned char& r=*(((unsigned char*)(&image[x+1+y*imageWidth]))+2); 00189 plus_truncate_uchar(r, (error*7) >> 4); 00190 } 00191 if (y + 1 < imageHeight) 00192 { 00193 if (x - 1 > 0) 00194 { 00195 unsigned char& r=*(((unsigned char*)(&image[x-1+(y+1)*imageWidth]))+2); 00196 plus_truncate_uchar(r, (error*3) >> 4); 00197 } 00198 unsigned char& r=*(((unsigned char*)(&image[x+0+(y+1)*imageWidth]))+2); 00199 plus_truncate_uchar(r, (error*5) >> 4); 00200 if (x + 1 < imageWidth) 00201 { 00202 unsigned char& r=*(((unsigned char*)(&image[x+1+(y+1)*imageWidth]))+2); 00203 plus_truncate_uchar(r, (error*1) >> 4); 00204 } 00205 } 00206 00207 00208 error = ((int)g) - g16; 00209 if (x + 1 < imageWidth) 00210 { 00211 unsigned char& g=*(((unsigned char*)(&image[x+1+y*imageWidth]))+1); 00212 plus_truncate_uchar(g, (error*7) >> 4); 00213 } 00214 if (y + 1 < imageHeight) 00215 { 00216 if (x - 1 > 0) 00217 { 00218 unsigned char& g=*(((unsigned char*)(&image[x-1+(y+1)*imageWidth]))+1); 00219 plus_truncate_uchar(g, (error*3) >> 4); 00220 } 00221 unsigned char& g=*(((unsigned char*)(&image[x+0+(y+1)*imageWidth]))+1); 00222 plus_truncate_uchar(g, (error*5) >> 4); 00223 if (x + 1 < imageWidth) 00224 { 00225 unsigned char& g=*(((unsigned char*)(&image[x+1+(y+1)*imageWidth]))+1); 00226 plus_truncate_uchar(g, (error*1) >> 4); 00227 } 00228 } 00229 00230 error = ((int)b) - b16; 00231 if (x + 1 < imageWidth) 00232 { 00233 unsigned char& b=*(((unsigned char*)(&image[x+1+y*imageWidth]))+0); 00234 plus_truncate_uchar(b, (error*7) >> 4); 00235 } 00236 if (y + 1 < imageHeight) 00237 { 00238 if (x - 1 > 0) 00239 { 00240 unsigned char& b=*(((unsigned char*)(&image[x-1+(y+1)*imageWidth]))+0); 00241 plus_truncate_uchar(b, (error*3) >> 4); 00242 } 00243 unsigned char& b=*(((unsigned char*)(&image[x+0+(y+1)*imageWidth]))+0); 00244 plus_truncate_uchar(b, (error*5) >> 4); 00245 if (x + 1 < imageWidth) 00246 { 00247 unsigned char& b=*(((unsigned char*)(&image[x+1+(y+1)*imageWidth]))+0); 00248 plus_truncate_uchar(b, (error*1) >> 4); 00249 } 00250 } 00251 00252 } 00253 00254 } 00255 00256 }
Reproduction/republishing of any material on this site without permission is strictly prohibited.
