/* dither.c -- convert 16- or 24-bit bmp to 8 or fewer bits (Floyd-Steinberg) */
/* see end-of-file for (c) */
/* This was written for Microsoft 32-bit-integer compilers--it
* should compile with
* cl gif2bmp.c
* to produce the executable gif2bmp.exe
*
* The Microsoft oddities are:
* The funny include files -- they may be omitted on compilers
* that can not find them (stdio.h better be there, however)
* #pragma pack(1) -- This forces the BITMAPFILEHEADER structure
* to be the same length in memory as in files (otherwise, the structure
* is padded out to be a multiple of 8? bytes long
* Note that Microsoft uses all-caps for typedefs. Ugh.
*/
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <math.h>
typedef unsigned char byte;
typedef unsigned short WORD;
typedef unsigned long DWORD;#define SIZE_BITMAPFILEHEADER 14
#define SIZE_BITMAPINFOHEADER 40
#define BI_BITFIELDS 3double gamma= 1.85;
int outmode= 0;
#define OUT16 1 // 16-color output
#define OUT2 2 // 2-color output
int reversing= 1;
int (*nearrtn)(int,int,int);
int bpp= 8;
int threshhold;
int startnoisy= 1;unsigned char winmap[]= {
0, 0, 0,0, 0, 0,128,0, 0,128, 0,0, 0,128,128,0,
128, 0, 0,0, 128, 0,128,0, 128,128, 0,0, 192,192,192,0,
128,128,128,0, 0, 0,255,0, 0,255, 0,0, 0,255,255,0,
255, 0, 0,0, 255, 0,255,0, 255,255, 0,0, 255,255,255,0};
unsigned char monomap[]= {0,0,0,0, 255,255,255,0};#pragma pack(1)
typedef struct tagRGBQUAD {
byte rgbBlue;
byte rgbGreen;
byte rgbRed;
byte rgbReserved;
} RGBQUAD;
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
typedef BITMAPFILEHEADER *PBITMAPFILEHEADER;typedef struct tagBITMAPINFOHEADER{
DWORD biSize;
DWORD biWidth;
DWORD biHeight;
WORD biPlanes;
WORD biBitCount; DWORD biCompression;
DWORD biSizeImage;
DWORD biXPelsPerMeter;
DWORD biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;BITMAPFILEHEADER hdr;
BITMAPINFOHEADER bi; // Source image header
BITMAPINFOHEADER bo; // Output image headerlong wib;
long dwib;RGBQUAD srccmap[256];
unsigned char cmap[256*4]; /* Bytes of blue, green, red, reserved */
unsigned char *scanline;
unsigned char used[256];FILE *fpin; /* Input file fp */static int dib_wib(int bitcount, int wi){
switch (bitcount){
case 1: wi= (wi+31) >> 3; break;
case 4: wi= (wi+7) >> 1; break;
case 8: wi= wi+3; break;
case 16:wi= (wi*2)+3; break;
case 24:wi= (wi*3)+3; break;
case 32:return wi*4;
}
return wi & ~3;
}
void err(char *msg){
fprintf(stderr, "%s\n", msg);
exit(5);
}
/* These are used for 16- and 32-bit DIBS */
static DWORD rgbmask[3]= {0x7c00,0x03e0,0x001f};
static int rgbshft[3]= {7, 2, -3};
void gulp_header(char *dibname){
int v, y; if((fpin= fopen (dibname, "rb"))==0){
perror(dibname);
exit(0);
}
fread(&hdr,1,sizeof(hdr),fpin);
if(hdr.bfType!= 0x4d42)
err("Image not a .bmp"); fread(&bi, 1, sizeof(bi), fpin);
wib= dib_wib((int)bi.biBitCount, (int)bi.biWidth);
bi.biSizeImage= bi.biHeight * wib;
if(bi.biBitCount<=8){
v= (int)((hdr.bfOffBits - bi.biSize - sizeof(BITMAPFILEHEADER))/sizeof(RGBQUAD));
bi.biClrUsed= v;
if(v>0)
fread(srccmap, sizeof(RGBQUAD), v, fpin);
}else if((bi.biBitCount==16 || bi.biBitCount==32)
&& bi.biCompression==BI_BITFIELDS){
/* Read 3 masks */
fread(rgbmask, sizeof(DWORD), 3, fpin);
for(y= 0; y<3; y++){
for(v= sizeof(DWORD); --v>=0 && 0==(rgbmask[y]&(1<<v)); v++);
rgbshft[y]= v-8;
}
}
v= (int)wib;
if(v<(int)(3*bi.biWidth))
v= (int)3*bi.biWidth;
scanline= malloc(v);
if(scanline==0)
err("Not enough room for the scanline");
}
void readnextscanline(){
int k= 0;
int x;
DWORD *dwp;
WORD *wp;
fread(scanline, 1, (int)wib, fpin);
switch((int)bi.biBitCount){
case 32:
dwp= (DWORD *)scanline;
for(x= 0; x<(int)bi.biWidth; x++){
if(bi.biCompression==BI_BITFIELDS){
scanline[k++]= (byte)((*dwp&rgbmask[2]) >> rgbshft[2]);
scanline[k++]= (byte)((*dwp&rgbmask[1]) >> rgbshft[1]);
scanline[k++]= (byte)((*dwp&rgbmask[0]) >> rgbshft[0]);
++dwp;
}else{
scanline[k++]= scanline[4*x];
scanline[k++]= scanline[4*x+1];
scanline[k++]= scanline[4*x+2];
}
} break;
case 24:
break;
case 16:
k= (int)(3*bi.biWidth);
wp= (WORD *)(&scanline[wib]);
for(x= (int)bi.biWidth; --x>=0; ){
--wp;
scanline[--k]= (byte)((*wp&rgbmask[0]) >> rgbshft[0]);
scanline[--k]= (byte)((*wp&rgbmask[1]) >> rgbshft[1]);
scanline[--k]= (byte)((*wp&rgbmask[2]) >> rgbshft[2]);
} break;
case 8: case 4: case 1:
k= (int)(3*bi.biWidth);
for(x= (int)bi.biWidth; --x>=0; ){
int pv;
if(bi.biBitCount==8)
pv= scanline[x];
else if(bi.biBitCount==4)
pv= (x&1? scanline[x>>1] : scanline[x>>1] >> 4) & 15;
else
pv= scanline[x>>3] & (1 << (x&7)) ? 255 : 0;
scanline[--k]= srccmap[pv].rgbRed;
scanline[--k]= srccmap[pv].rgbGreen;
scanline[--k]= srccmap[pv].rgbBlue;
} break;
}
}
/* Output the image */
int spew_header(FILE *fp, unsigned char *cmap){
int n= 0; dwib= dib_wib((int)bo.biBitCount, (int)bo.biWidth);
if(bo.biBitCount==1)n= 2;
if(bo.biBitCount==4)n= 16;
if(bo.biBitCount==8)n= 256;
bo.biSize= SIZE_BITMAPINFOHEADER;
bo.biPlanes= 1;
bo.biCompression= 0;
bo.biSizeImage= bo.biHeight * dwib;
bo.biClrUsed= n;
bo.biClrImportant= n;
bo.biXPelsPerMeter= 0;
bo.biYPelsPerMeter= 0; hdr.bfType= 0x4d42; /* BM */
hdr.bfReserved1= 0;
hdr.bfReserved2= 0;
hdr.bfOffBits = SIZE_BITMAPFILEHEADER + bo.biSize + n*sizeof(RGBQUAD);
hdr.bfSize= hdr.bfOffBits + bo.biSizeImage; fwrite(&hdr,1,sizeof(hdr),fp);
fwrite(&bo, 1, sizeof(bo), fp);
if(n>0)
fwrite(cmap, sizeof(RGBQUAD), n, fp);
return 1;
}
char *note[]= {
"Usage: [Options] source.bmp dest.bmp",
"Dither a 24-bit .bmp file to 8 bits (or 4 bits Windows colors)",
"Options:",
"-n### Dither to # red, # green, # blue values [default is -n666]",
"-w Dither to the 16 standard windows colors (4 bits/pixel output)",
"-m Dither to black and white (1 bit/pixel output)",
"-g # Set image gamma [default 1.85]",
"-r Send errors to the right [default alternates right/left]",
"-i Start with no noise (when background color is an output color)",
0};int tab7[1024], tab5[1024], tab3[1024], tab1[1024];
unsigned char neartable[16*16*16];
int *rtab, *gtab, *btab;
int gammatab[256];
unsigned char degamma[4*512];
int gammacmap[4*256];/* The 'get the pvalue of a color near this color' routines: */int pvnear(int r, int g, int b){ /* reds x greens x blues colormap */
return rtab[degamma[512+r]] + gtab[degamma[512+g]] + btab[degamma[512+b]];
}
int pvtab_near(int r, int g, int b){ /* disordered colormap */
r >>= 5; g >>= 5; b >>= 5;
if((r|g|b)&-16){ // Color off cube, then force to a cube corner!
r= r>7? 15:0;
g= g>7? 15:0;
b= b>7? 15:0;
}
return neartable[b+16*(g+16*r)];
}
int mono_near(int r, int g, int b){ /* one-bit output */
return b + 2*(r+2*g) < threshhold? 0 : 1;
}void neartable_make(int n){ /* Set up the disordered table from gammacmap */
int r,g,b;
int j= 0;
for(r= 0; r<512; r+= 34)
for(g= 0; g<512; g+= 34)
for(b= 0; b<512; b+= 34){
int pv= 0;
int k;
long dmin= 0x7fffffff;
for(k= 0; k<n; k++){
int k4= 4*k;
long dr= r-gammacmap[k4+2];
long dg= g-gammacmap[k4+1];
long db= b-gammacmap[k4+0];
long d= dr*dr+db*db+dg*dg;
if(d<dmin){
dmin= d;
pv= k;
}
}
neartable[j++]= pv;
}
}
void createmap(unsigned char *map, int nr, int ng, int nb){
int r,g,b,k;
if(nr*ng*nb>256)
return; for(k= 0; k<512; k++){
tab7[512+k]= (7*k+8)/16;
tab7[512-k]= -tab7[512+k];
tab5[512+k]= (5*k+8)/16;
tab5[512-k]= -tab5[512+k];
tab3[512+k]= (3*k+8)/16;
tab3[512-k]= -tab3[512+k];
tab1[512+k]= (1*k+8)/16;
tab1[512-k]= -tab1[512+k];
}
for(k= 0; k<256; k++)
gammatab[k]= (int)(511.0*pow(k/255.0, gamma) + 0.5);
for(k= 0; k<512; k++){
degamma[k]= 0;
degamma[k+512]= (int)(255.0*pow(k/511.0, 1/gamma) + 0.5);
degamma[k+1024]= 255;
degamma[k+1536]= 255;
}
if(outmode==OUT2){ // One-bit colormap
threshhold= (int)(7*511*pow(0.5, 1/gamma) + 0.5);
for(k= 0; k<sizeof(monomap); k++)
map[k]= monomap[k];
for(k= 0; k<4*2; k++)
gammacmap[k]= map[k]? 511 : 0;
}else if(outmode==OUT16){ // Windows colormap
for(k= 0; k<sizeof(winmap); k++)
map[k]= winmap[k];
for(k= 0; k<4*16; k++)
gammacmap[k]= gammatab[map[k]];
neartable_make(16);
}else{ // Ordered colormap
for(k= r= 0; r<nr; r++){
for(g= 0; g<ng; g++){
for(b= 0; b<nb; b++){
map[k++]= b*255/(nb-1);
map[k++]= g*255/(ng-1);
map[k++]= r*255/(nr-1);
k++;
}
}
}
rtab= (int *)(&neartable[0]);
gtab= rtab+256;
btab= gtab+256;
for(k= 0; k<256; k++){
rtab[k]= ng * nb * ( k * nr/256 );
gtab[k]= nb * ( k * ng/256 );
btab[k]= k * nb/256;
}
for(k= 0; k<4*256; k++)
gammacmap[k]= gammatab[map[k]];
}
}
void fsdither(FILE *fo){
int y, r, g, b, pv;
int ru, gu, bu;
unsigned char *outbuf= (char *)malloc((int)bo.biWidth);
int x= 3*bi.biWidth+6;
int *scanerr= (int *)malloc(sizeof(int)*x); // Scanline of errors if(startnoisy){
int mask;
switch(bo.biBitCount){
case 1: mask= 511; break;
case 4: mask= 255; break;
case 8: mask= 128; break;
}
srand(12345); // Always use the same noise
while(--x>=0)scanerr[x]= 2*(rand()&mask)-mask;
}else
while(--x>=0)scanerr[x]= 0;
ru= 0; gu= 0; bu= 0;
for(y= 0; y<(int)bi.biHeight; y++){
unsigned char *pc;
int *pe;
readnextscanline();
if(y&reversing){
while(--x>=0){
pc -= 3;
pe -= 3;
r= gammatab[pc[2]] + tab7[ru] + pe[2];
g= gammatab[pc[1]] + tab7[gu] + pe[1];
b= gammatab[pc[0]] + tab7[bu] + pe[0];
pv= (*nearrtn)(r,g,b);
outbuf[x]= pv;
pv *= 4;
r -= gammacmap[pv+2]-512; if(r>1023)r= 1023;
g -= gammacmap[pv+1]-512; if(g>1023)g= 1023;
b -= gammacmap[pv+0]-512; if(b>1023)b= 1023;
pe[5] += tab3[r];
pe[4] += tab3[g];
pe[3] += tab3[b];
pe[2]= tab5[r] + tab1[ru];
pe[1]= tab5[g] + tab1[gu];
pe[0]= tab5[b] + tab1[bu];
ru= r; gu= g; bu= b;
}
}else{
pc= scanline;
pe= scanerr+3;
for(x= 0; x<(int)bi.biWidth; x++){
r= gammatab[pc[2]] + tab7[ru] + pe[2];
g= gammatab[pc[1]] + tab7[gu] + pe[1];
b= gammatab[pc[0]] + tab7[bu] + pe[0];
pv= (*nearrtn)(r,g,b);
outbuf[x]= pv;
pv *= 4;
r -= gammacmap[pv+2]-512; if(r>1023)r= 1023;
g -= gammacmap[pv+1]-512; if(g>1023)g= 1023;
b -= gammacmap[pv+0]-512; if(b>1023)b= 1023;
pe[-1] += tab3[r];
pe[-2] += tab3[g];
pe[-3] += tab3[b];
pe[2]= tab5[r] + tab1[ru];
pe[1]= tab5[g] + tab1[gu];
pe[0]= tab5[b] + tab1[bu];
ru= r; gu= g; bu= b;
pc += 3;
pe += 3;
}
}
if(bpp==1){
b= 64;
r= 0;
if(outbuf[0])
outbuf[0]= 128;
for(x= 1; x<(int)bi.biWidth; x++){
if(outbuf[x])
outbuf[r] |= b;
if(0==(b >>= 1)){
b= 128;
outbuf[++r]= 0;
}
}
}else if(bpp==4){
for(r= x= 0; x<(int)bi.biWidth; x+= 2)
outbuf[r++]= (unsigned char)((outbuf[x]<<4) | outbuf[x+1]);
}
fwrite(outbuf, 1, (int)dwib, fo);
}
}
void main(int ac, char **av){
FILE *fp;
char *cp;
char *srcname= 0;
char *dstname= 0;
int nr= 6, ng= 6, nb= 6; bpp= 8;
nearrtn= pvnear; while(cp= *++av)if(*cp++=='-')switch(*cp++){
case 'i': startnoisy= 0; break;
case 'r': reversing= 0; break;
case 'w': outmode= OUT16; nearrtn= pvtab_near; bpp= 4; break;
case 'm': outmode= OUT2; nearrtn= mono_near; bpp= 1; break;
case 'g': gamma= atof(*++av); break;
case 'n': if(*cp==0)cp= *++av;
nr= *cp++ - '0'; ng= *cp++ - '0'; nb= *cp++ - '0';
break;
default:
erra: for(av= note; *av; ++av)
fprintf(stderr, "%s\n", *av);
exit(1);
}else if(srcname==0)
srcname= *av;
else if(dstname==0)
dstname= *av;
else
goto erra;
if(dstname==0)
goto erra; /* Open the source bmp */
gulp_header(srcname); /* Create the gif file */
fp= fopen(dstname, "wb");
if(fp==0){
perror(dstname);
exit(1);
}
bo= bi; // The output image resembles the source image
bo.biBitCount= bpp; // With fewer bits per pixel
createmap(cmap, nr, ng, nb);
spew_header(fp, cmap);
fsdither(fp);
}
/*(C)1996 Ephraim Cohen--
** permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notices appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation. This software is provided "as is" without express or
** implied warranty.
*
*/
这个可以学习一下
/* see end-of-file for (c) */
/* This was written for Microsoft 32-bit-integer compilers--it
* should compile with
* cl gif2bmp.c
* to produce the executable gif2bmp.exe
*
* The Microsoft oddities are:
* The funny include files -- they may be omitted on compilers
* that can not find them (stdio.h better be there, however)
* #pragma pack(1) -- This forces the BITMAPFILEHEADER structure
* to be the same length in memory as in files (otherwise, the structure
* is padded out to be a multiple of 8? bytes long
* Note that Microsoft uses all-caps for typedefs. Ugh.
*/
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <math.h>
typedef unsigned char byte;
typedef unsigned short WORD;
typedef unsigned long DWORD;#define SIZE_BITMAPFILEHEADER 14
#define SIZE_BITMAPINFOHEADER 40
#define BI_BITFIELDS 3double gamma= 1.85;
int outmode= 0;
#define OUT16 1 // 16-color output
#define OUT2 2 // 2-color output
int reversing= 1;
int (*nearrtn)(int,int,int);
int bpp= 8;
int threshhold;
int startnoisy= 1;unsigned char winmap[]= {
0, 0, 0,0, 0, 0,128,0, 0,128, 0,0, 0,128,128,0,
128, 0, 0,0, 128, 0,128,0, 128,128, 0,0, 192,192,192,0,
128,128,128,0, 0, 0,255,0, 0,255, 0,0, 0,255,255,0,
255, 0, 0,0, 255, 0,255,0, 255,255, 0,0, 255,255,255,0};
unsigned char monomap[]= {0,0,0,0, 255,255,255,0};#pragma pack(1)
typedef struct tagRGBQUAD {
byte rgbBlue;
byte rgbGreen;
byte rgbRed;
byte rgbReserved;
} RGBQUAD;
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
typedef BITMAPFILEHEADER *PBITMAPFILEHEADER;typedef struct tagBITMAPINFOHEADER{
DWORD biSize;
DWORD biWidth;
DWORD biHeight;
WORD biPlanes;
WORD biBitCount; DWORD biCompression;
DWORD biSizeImage;
DWORD biXPelsPerMeter;
DWORD biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;BITMAPFILEHEADER hdr;
BITMAPINFOHEADER bi; // Source image header
BITMAPINFOHEADER bo; // Output image headerlong wib;
long dwib;RGBQUAD srccmap[256];
unsigned char cmap[256*4]; /* Bytes of blue, green, red, reserved */
unsigned char *scanline;
unsigned char used[256];FILE *fpin; /* Input file fp */static int dib_wib(int bitcount, int wi){
switch (bitcount){
case 1: wi= (wi+31) >> 3; break;
case 4: wi= (wi+7) >> 1; break;
case 8: wi= wi+3; break;
case 16:wi= (wi*2)+3; break;
case 24:wi= (wi*3)+3; break;
case 32:return wi*4;
}
return wi & ~3;
}
void err(char *msg){
fprintf(stderr, "%s\n", msg);
exit(5);
}
/* These are used for 16- and 32-bit DIBS */
static DWORD rgbmask[3]= {0x7c00,0x03e0,0x001f};
static int rgbshft[3]= {7, 2, -3};
void gulp_header(char *dibname){
int v, y; if((fpin= fopen (dibname, "rb"))==0){
perror(dibname);
exit(0);
}
fread(&hdr,1,sizeof(hdr),fpin);
if(hdr.bfType!= 0x4d42)
err("Image not a .bmp"); fread(&bi, 1, sizeof(bi), fpin);
wib= dib_wib((int)bi.biBitCount, (int)bi.biWidth);
bi.biSizeImage= bi.biHeight * wib;
if(bi.biBitCount<=8){
v= (int)((hdr.bfOffBits - bi.biSize - sizeof(BITMAPFILEHEADER))/sizeof(RGBQUAD));
bi.biClrUsed= v;
if(v>0)
fread(srccmap, sizeof(RGBQUAD), v, fpin);
}else if((bi.biBitCount==16 || bi.biBitCount==32)
&& bi.biCompression==BI_BITFIELDS){
/* Read 3 masks */
fread(rgbmask, sizeof(DWORD), 3, fpin);
for(y= 0; y<3; y++){
for(v= sizeof(DWORD); --v>=0 && 0==(rgbmask[y]&(1<<v)); v++);
rgbshft[y]= v-8;
}
}
v= (int)wib;
if(v<(int)(3*bi.biWidth))
v= (int)3*bi.biWidth;
scanline= malloc(v);
if(scanline==0)
err("Not enough room for the scanline");
}
void readnextscanline(){
int k= 0;
int x;
DWORD *dwp;
WORD *wp;
fread(scanline, 1, (int)wib, fpin);
switch((int)bi.biBitCount){
case 32:
dwp= (DWORD *)scanline;
for(x= 0; x<(int)bi.biWidth; x++){
if(bi.biCompression==BI_BITFIELDS){
scanline[k++]= (byte)((*dwp&rgbmask[2]) >> rgbshft[2]);
scanline[k++]= (byte)((*dwp&rgbmask[1]) >> rgbshft[1]);
scanline[k++]= (byte)((*dwp&rgbmask[0]) >> rgbshft[0]);
++dwp;
}else{
scanline[k++]= scanline[4*x];
scanline[k++]= scanline[4*x+1];
scanline[k++]= scanline[4*x+2];
}
} break;
case 24:
break;
case 16:
k= (int)(3*bi.biWidth);
wp= (WORD *)(&scanline[wib]);
for(x= (int)bi.biWidth; --x>=0; ){
--wp;
scanline[--k]= (byte)((*wp&rgbmask[0]) >> rgbshft[0]);
scanline[--k]= (byte)((*wp&rgbmask[1]) >> rgbshft[1]);
scanline[--k]= (byte)((*wp&rgbmask[2]) >> rgbshft[2]);
} break;
case 8: case 4: case 1:
k= (int)(3*bi.biWidth);
for(x= (int)bi.biWidth; --x>=0; ){
int pv;
if(bi.biBitCount==8)
pv= scanline[x];
else if(bi.biBitCount==4)
pv= (x&1? scanline[x>>1] : scanline[x>>1] >> 4) & 15;
else
pv= scanline[x>>3] & (1 << (x&7)) ? 255 : 0;
scanline[--k]= srccmap[pv].rgbRed;
scanline[--k]= srccmap[pv].rgbGreen;
scanline[--k]= srccmap[pv].rgbBlue;
} break;
}
}
/* Output the image */
int spew_header(FILE *fp, unsigned char *cmap){
int n= 0; dwib= dib_wib((int)bo.biBitCount, (int)bo.biWidth);
if(bo.biBitCount==1)n= 2;
if(bo.biBitCount==4)n= 16;
if(bo.biBitCount==8)n= 256;
bo.biSize= SIZE_BITMAPINFOHEADER;
bo.biPlanes= 1;
bo.biCompression= 0;
bo.biSizeImage= bo.biHeight * dwib;
bo.biClrUsed= n;
bo.biClrImportant= n;
bo.biXPelsPerMeter= 0;
bo.biYPelsPerMeter= 0; hdr.bfType= 0x4d42; /* BM */
hdr.bfReserved1= 0;
hdr.bfReserved2= 0;
hdr.bfOffBits = SIZE_BITMAPFILEHEADER + bo.biSize + n*sizeof(RGBQUAD);
hdr.bfSize= hdr.bfOffBits + bo.biSizeImage; fwrite(&hdr,1,sizeof(hdr),fp);
fwrite(&bo, 1, sizeof(bo), fp);
if(n>0)
fwrite(cmap, sizeof(RGBQUAD), n, fp);
return 1;
}
char *note[]= {
"Usage: [Options] source.bmp dest.bmp",
"Dither a 24-bit .bmp file to 8 bits (or 4 bits Windows colors)",
"Options:",
"-n### Dither to # red, # green, # blue values [default is -n666]",
"-w Dither to the 16 standard windows colors (4 bits/pixel output)",
"-m Dither to black and white (1 bit/pixel output)",
"-g # Set image gamma [default 1.85]",
"-r Send errors to the right [default alternates right/left]",
"-i Start with no noise (when background color is an output color)",
0};int tab7[1024], tab5[1024], tab3[1024], tab1[1024];
unsigned char neartable[16*16*16];
int *rtab, *gtab, *btab;
int gammatab[256];
unsigned char degamma[4*512];
int gammacmap[4*256];/* The 'get the pvalue of a color near this color' routines: */int pvnear(int r, int g, int b){ /* reds x greens x blues colormap */
return rtab[degamma[512+r]] + gtab[degamma[512+g]] + btab[degamma[512+b]];
}
int pvtab_near(int r, int g, int b){ /* disordered colormap */
r >>= 5; g >>= 5; b >>= 5;
if((r|g|b)&-16){ // Color off cube, then force to a cube corner!
r= r>7? 15:0;
g= g>7? 15:0;
b= b>7? 15:0;
}
return neartable[b+16*(g+16*r)];
}
int mono_near(int r, int g, int b){ /* one-bit output */
return b + 2*(r+2*g) < threshhold? 0 : 1;
}void neartable_make(int n){ /* Set up the disordered table from gammacmap */
int r,g,b;
int j= 0;
for(r= 0; r<512; r+= 34)
for(g= 0; g<512; g+= 34)
for(b= 0; b<512; b+= 34){
int pv= 0;
int k;
long dmin= 0x7fffffff;
for(k= 0; k<n; k++){
int k4= 4*k;
long dr= r-gammacmap[k4+2];
long dg= g-gammacmap[k4+1];
long db= b-gammacmap[k4+0];
long d= dr*dr+db*db+dg*dg;
if(d<dmin){
dmin= d;
pv= k;
}
}
neartable[j++]= pv;
}
}
void createmap(unsigned char *map, int nr, int ng, int nb){
int r,g,b,k;
if(nr*ng*nb>256)
return; for(k= 0; k<512; k++){
tab7[512+k]= (7*k+8)/16;
tab7[512-k]= -tab7[512+k];
tab5[512+k]= (5*k+8)/16;
tab5[512-k]= -tab5[512+k];
tab3[512+k]= (3*k+8)/16;
tab3[512-k]= -tab3[512+k];
tab1[512+k]= (1*k+8)/16;
tab1[512-k]= -tab1[512+k];
}
for(k= 0; k<256; k++)
gammatab[k]= (int)(511.0*pow(k/255.0, gamma) + 0.5);
for(k= 0; k<512; k++){
degamma[k]= 0;
degamma[k+512]= (int)(255.0*pow(k/511.0, 1/gamma) + 0.5);
degamma[k+1024]= 255;
degamma[k+1536]= 255;
}
if(outmode==OUT2){ // One-bit colormap
threshhold= (int)(7*511*pow(0.5, 1/gamma) + 0.5);
for(k= 0; k<sizeof(monomap); k++)
map[k]= monomap[k];
for(k= 0; k<4*2; k++)
gammacmap[k]= map[k]? 511 : 0;
}else if(outmode==OUT16){ // Windows colormap
for(k= 0; k<sizeof(winmap); k++)
map[k]= winmap[k];
for(k= 0; k<4*16; k++)
gammacmap[k]= gammatab[map[k]];
neartable_make(16);
}else{ // Ordered colormap
for(k= r= 0; r<nr; r++){
for(g= 0; g<ng; g++){
for(b= 0; b<nb; b++){
map[k++]= b*255/(nb-1);
map[k++]= g*255/(ng-1);
map[k++]= r*255/(nr-1);
k++;
}
}
}
rtab= (int *)(&neartable[0]);
gtab= rtab+256;
btab= gtab+256;
for(k= 0; k<256; k++){
rtab[k]= ng * nb * ( k * nr/256 );
gtab[k]= nb * ( k * ng/256 );
btab[k]= k * nb/256;
}
for(k= 0; k<4*256; k++)
gammacmap[k]= gammatab[map[k]];
}
}
void fsdither(FILE *fo){
int y, r, g, b, pv;
int ru, gu, bu;
unsigned char *outbuf= (char *)malloc((int)bo.biWidth);
int x= 3*bi.biWidth+6;
int *scanerr= (int *)malloc(sizeof(int)*x); // Scanline of errors if(startnoisy){
int mask;
switch(bo.biBitCount){
case 1: mask= 511; break;
case 4: mask= 255; break;
case 8: mask= 128; break;
}
srand(12345); // Always use the same noise
while(--x>=0)scanerr[x]= 2*(rand()&mask)-mask;
}else
while(--x>=0)scanerr[x]= 0;
ru= 0; gu= 0; bu= 0;
for(y= 0; y<(int)bi.biHeight; y++){
unsigned char *pc;
int *pe;
readnextscanline();
if(y&reversing){
while(--x>=0){
pc -= 3;
pe -= 3;
r= gammatab[pc[2]] + tab7[ru] + pe[2];
g= gammatab[pc[1]] + tab7[gu] + pe[1];
b= gammatab[pc[0]] + tab7[bu] + pe[0];
pv= (*nearrtn)(r,g,b);
outbuf[x]= pv;
pv *= 4;
r -= gammacmap[pv+2]-512; if(r>1023)r= 1023;
g -= gammacmap[pv+1]-512; if(g>1023)g= 1023;
b -= gammacmap[pv+0]-512; if(b>1023)b= 1023;
pe[5] += tab3[r];
pe[4] += tab3[g];
pe[3] += tab3[b];
pe[2]= tab5[r] + tab1[ru];
pe[1]= tab5[g] + tab1[gu];
pe[0]= tab5[b] + tab1[bu];
ru= r; gu= g; bu= b;
}
}else{
pc= scanline;
pe= scanerr+3;
for(x= 0; x<(int)bi.biWidth; x++){
r= gammatab[pc[2]] + tab7[ru] + pe[2];
g= gammatab[pc[1]] + tab7[gu] + pe[1];
b= gammatab[pc[0]] + tab7[bu] + pe[0];
pv= (*nearrtn)(r,g,b);
outbuf[x]= pv;
pv *= 4;
r -= gammacmap[pv+2]-512; if(r>1023)r= 1023;
g -= gammacmap[pv+1]-512; if(g>1023)g= 1023;
b -= gammacmap[pv+0]-512; if(b>1023)b= 1023;
pe[-1] += tab3[r];
pe[-2] += tab3[g];
pe[-3] += tab3[b];
pe[2]= tab5[r] + tab1[ru];
pe[1]= tab5[g] + tab1[gu];
pe[0]= tab5[b] + tab1[bu];
ru= r; gu= g; bu= b;
pc += 3;
pe += 3;
}
}
if(bpp==1){
b= 64;
r= 0;
if(outbuf[0])
outbuf[0]= 128;
for(x= 1; x<(int)bi.biWidth; x++){
if(outbuf[x])
outbuf[r] |= b;
if(0==(b >>= 1)){
b= 128;
outbuf[++r]= 0;
}
}
}else if(bpp==4){
for(r= x= 0; x<(int)bi.biWidth; x+= 2)
outbuf[r++]= (unsigned char)((outbuf[x]<<4) | outbuf[x+1]);
}
fwrite(outbuf, 1, (int)dwib, fo);
}
}
void main(int ac, char **av){
FILE *fp;
char *cp;
char *srcname= 0;
char *dstname= 0;
int nr= 6, ng= 6, nb= 6; bpp= 8;
nearrtn= pvnear; while(cp= *++av)if(*cp++=='-')switch(*cp++){
case 'i': startnoisy= 0; break;
case 'r': reversing= 0; break;
case 'w': outmode= OUT16; nearrtn= pvtab_near; bpp= 4; break;
case 'm': outmode= OUT2; nearrtn= mono_near; bpp= 1; break;
case 'g': gamma= atof(*++av); break;
case 'n': if(*cp==0)cp= *++av;
nr= *cp++ - '0'; ng= *cp++ - '0'; nb= *cp++ - '0';
break;
default:
erra: for(av= note; *av; ++av)
fprintf(stderr, "%s\n", *av);
exit(1);
}else if(srcname==0)
srcname= *av;
else if(dstname==0)
dstname= *av;
else
goto erra;
if(dstname==0)
goto erra; /* Open the source bmp */
gulp_header(srcname); /* Create the gif file */
fp= fopen(dstname, "wb");
if(fp==0){
perror(dstname);
exit(1);
}
bo= bi; // The output image resembles the source image
bo.biBitCount= bpp; // With fewer bits per pixel
createmap(cmap, nr, ng, nb);
spew_header(fp, cmap);
fsdither(fp);
}
/*(C)1996 Ephraim Cohen--
** permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notices appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation. This software is provided "as is" without express or
** implied warranty.
*
*/
这个可以学习一下
解决方案 »
- 用datagrid 绑定数据集,为什么数据集是联合查询出来的时候,指定数据集就说 not bookmarkable? 在线等
- __declspec(dllimport)
- VC+ODBC(用DynaSet)+Oracle 9i Lite 4.0中报错:message file is not loaded,请高手解决,可加分!
- VC菜鸟
- psapi.dll-系统进程和线程
- ★看看这个,你不会后悔的。
- MFC Extension Dll中一个有挑战性的问题
- pDoc = GetDocument();问题
- 关于类的static变量
- 谁用VC读写过WAVE文件?
- 怎么才能知道,DLL文件的,COM组件是否已经注册 "
- 如何屏蔽掉A:盘(软盘驱动器)
这段代码是有彩色转为灰度图的算法。简单的变一下,就可用于16色变2色。
即判断一下lum的值即可。大于中间值即128就是白色的否则就是黑色的。
我做过图像处理的软件,不过主要是解码也做了一点色彩的转换。
我的妹儿 [email protected]