// Jason Rohrer // Dither.cpp /** * * Dithering functions for decreasing number of bits per image sample * * Created 11-28-99 * Mods: */ #include #include #include "Dither.h" // Dither a 32-bit image down to 16-bit, channel by channel // drop alpha // store 16 bit as R:G:B = 5:5:5 void Dither16( unsigned long *image32, int imageHigh, int imageWide, unsigned long *image16, int ditherBlockSize ) { // make sure dither block size is even // if( ditherBlockSize % 2 != 0 ) { // ditherBlockSize++; // } float invBlockSize = 1.0 / ditherBlockSize; // image size in dither blocks int dW = (int)(imageWide * invBlockSize); int dH = (int)(imageHigh * invBlockSize); int pixInBlock = ditherBlockSize * ditherBlockSize; float invPixInBlock = 1.0 / pixInBlock; float inv8 = 1.0 / 8.0; int *yOffset32 = new int[imageHigh]; for( int y=0; y> 8) & 0xFF; colorSum[2] += (composite >> 16) & 0xFF; } } float aveColor[3]; // average color over block for each component int lowColor[3]; // low neighboring 16-bit color for this average int highColor[3]; float fractColor[3]; // fraction of low neighboring color mixed to hit this average int lowColorToSkip[3]; // number of pixels to skip between each dithered pixel set to the low neighboring color for( int i=0; i<3; i++ ) { // find average aveColor[i] = colorSum[i] * invPixInBlock; // now find closest low neighboring 16-bit components (5 bits per component) aveColor[i] = aveColor[i] * inv8; lowColor[i] = (int)( floor( aveColor[i] ) ); highColor[i] = lowColor[i] +1; fractColor[i] = aveColor[i] - lowColor[i]; /* if( fractColor[i] < .05 ) { // watch for cases of a solid low color lowColorToSkip[i] = 0; } else { // how many pixels to skip between each low-neighbor color pixel lowColorToSkip[i] = (int)(1/(1-fractColor[i])) - 1; } */ // 32 bit versions of these neighboring colors lowColor[i] = lowColor[i] * 8; highColor[i] = highColor[i] * 8; if( highColor[i] > 255 ) { highColor[i] = 255; } } // walk through this block in 16-bit image and set pixels to low color after skipping low__ToSkip pixels // set skipped pixels to high neighboring color // walk linearly int numPixelsSet = 0; int numSkipped[3]; for( int i=0; i<3; i++ ) { numSkipped[i] = 0; } for( int y=startY; y fractColor[i] ) { composite = composite | (lowColor[i] << (8*i)); } else { composite = composite | (highColor[i] << (8*i)); } /* if( numSkipped[i] >= lowColorToSkip[i] ) { // set low neighbor color composite = composite | (lowColor[i] << (8*i)); //composite = composite | (255 << (8*i)); numSkipped[i] = 0; } else { // set high neighbor color composite = composite | (highColor[i] << (8*i)); //composite = composite | (255 << (8*i)); numSkipped[i] ++; } */ } // end for each component // keep alpha the same as 32-bit alpha composite = composite | (image32[ yContrib + x ] & 0xFF000000); //image16[ yContrib + x ] = composite; image32[ yContrib + x ] = composite; } } /* int longsInImage16 = pixInBlock >> 1; for( int p=0; p= lowColorToSkip[i] ) { // set low neighbor color composite = composite | ((lowColor[i] << (5*i)) << (part * 16)); numSkipped[i] = 0; } else { // set high neighbor color composite = composite | (((lowColor[i] + 1) << (5*i)) << (part * 16)); numSkipped[i] ++; } } // end for each component // set alpha bits to 1 composite = composite | 1<< ( 15 + part * 16 ); } // end for each 16-bit part of long image16[p] = composite; } // end for each long */ } // end for each block column } // end for each block row delete [] yOffset32; } // end of Dither16