
默认分类 2009-09-19 14:23 阅读106 评论0
字号: 大大 中中 小小
C语言读取和显示BMP文件
Posted on 2008-01-21 01:12 hoodlum1980 阅读(2624) 评论(0) 编辑 收藏 网摘
在TC2.0下,隶属于16位子系统,所以int是2字节,long是4字节,char是1字节。绘图系统模式是VGA,颜色当然也很有限,所以读取bmp像素后需要把像素颜色转换为“最近”的已有VGA颜色。用int GetColor(int r,int g,int b)实现返回一个颜色值(color code)。用putpixel(int x,int y,int color)绘制一个像素。
下图是几种在.NET Framework中的已知颜色和其RGB值(下图当然也是使用代码绘制的,代码略)。
16种颜色是位于RGB立方体中的16个点,相当于寻找一个最接近指定颜色的点。为了简化计算,计算出两点距离的平方即可。
为了加快搜索,我们可以用下面的类似绘制“金刚石”的代码提前求出最短距离的平方,这个数据将应用到GetColor函数中。原因是我们已知最近的两个颜色点的距离,如果某点与某颜色的距离小于最短距离的一半,则此颜色就是我们要找的结果。
Compute Minimum Dist^2 Code
int COLORS[16][3]={.};
/* i,j - color index */
/* ret - distance^2 */
long GetDist(int i,int j)
{
long dist=0;
dist+=(COLORS[i][0]-COLORS[j][0])*(COLORS[i][0]-COLORS[j][0]);
dist+=(COLORS[i][1]-COLORS[j][1])*(COLORS[i][1]-COLORS[j][1]);
dist+=(COLORS[i][2]-COLORS[j][2])*(COLORS[i][2]-COLORS[j][2]);
return dist;
}
void main(void)
{
int i, j;
long dist,mindist=195075;
for(i=0;i<15;i++)
{
for(j=i+1;j<16;j++)
{
dist=GetDist(i,j);
if(dist } } printf("mindis^2=%d",mindist); }_ 在下面的代码里为了简化处理,我们仅考虑了一种比较常见的BMP文件,即bpp=24,未经压缩的文件。 Code #include #include #include #include int MAX_Y=480; int MAX_X=0; int COLORS[16][3]= { /* R G B Index ColorName */ { 0, 0, 0}, /* 00 Black */ { 0, 0,255}, /* 01 Blue */ { 0,128, 0}, /* 02 Green */ { 0,255,255}, /* 03 Cyan */ {255, 0, 0}, /* 04 Red */ {255, 0,255}, /* 05 Magenta */ {165, 42, 42}, /* 06 Brown */ {211,211,211}, /* 07 LightGray */ {169,169,169}, /* 08 DarkGray */ {173,216,230}, /* 09 LightBlue */ {144,238,144}, /* 10 LightGreen */ {144,238,238}, /* 11 LightCyan */ {238,144,144}, /* 12 LightRed */ {238,144,238}, /* 13 LightMegenta */ {255,255, 0}, /* 14 Yellow */ {255,255,255}, /* 15 White */ }; /* pixel : keep channel order with readfile order */ typedef struct _PIXEL { unsigned char b; unsigned char g; unsigned char r; } PIXEL; /* color item in palette */ typedef struct _RGBQUAD { unsigned char rgbBlue; unsigned char rgbGreen; unsigned char rgbRed; unsigned char rgbReserved; } RGBQUAD; /* bitmap file header */ typedef struct _BITMAPFILEHEADER { unsigned int type; long fileSize; long reserved; long offbits; } BITMAPFILEHEADER,*PBITMAPFILEHEADER; /* bitmap info header */ typedef struct _BITMAPINFOHEADER { long dwSize; long width; long height; int planes; int bpp; long compression; long sizeImage; long hResolution; long vResolution; long colors; long importantColors; } BITMAPINFOHEADER,*PBITMAPINFOHEADER; /* Functions Declare List */ int GetColor(); void ReadImage(); void DrawAxes(); void CopyScreen(); /* Entry Point Function */ void main() { int driver,mode; char filename[255]; printf("input the filename of bitmap file:\\n"); scanf("%s",filename); driver=DETECT; initgraph(&driver,&mode,"c:\\\c\\\\"); /* draw a bitmap */ ReadImage(filename); getch(); closegraph(); } /* read pixels from imagefile and display */ void ReadImage(char* filename) { FILE* stream; char string[255]; int i,j,width,height,color; size_t bytesRead,stride,itemSize=1; long offset; BITMAPFILEHEADER fileHeader; BITMAPINFOHEADER infoHeader; unsigned char *pPixels,red,green,blue; stream=fopen(filename,"rb"); if(stream==NULL) { printf("open file error!\\n"); exit(0); } fseek(stream,0,0); fread(&fileHeader,1,sizeof(fileHeader),stream); fread(&infoHeader,1,sizeof(infoHeader),stream); width=infoHeader.width; height=infoHeader.height; /* stride: scan line bytes count. padding for 4 bytes */ stride=(infoHeader.bpp*width+31)/32*4; pPixels=malloc(stride); for(j=height-1;j>=0;j--) { /* !!! stride (2 bytes) must be convert to long (4 bytes) */ offset=fileHeader.offbits+j*((long)stride); fseek(stream,offset,0); bytesRead=fread(pPixels,itemSize,stride,stream); for(i=0;i red = pPixels[i*3+2]; green = pPixels[i*3+1]; blue = pPixels[i*3]; color=GetColor(red,green,blue); putpixel(100+i,height+100-j,color); } } fclose(stream); /* close the bitmap file */ free(pPixels); setcolor(63); /* draw the bitmap border rect */ rectangle(100,100,100+width,100+height); /* Draw X and Y axes */ DrawAxes(width,height); setcolor(3); sprintf(string,"FileName:\\"%s\\" bpp=%d",filename,infoHeader.bpp); outtextxy(100,30,string); outtextxy(200,460,"press any key to save screen to a bitmap."); getch(); /* copy the screen and save to bmp file */ CopyScreen("c:\\\c\\\\SCREEN.BMP",0,0,199+width,199+height); } /* compute a color by RGB */ int GetColor(unsigned int red,unsigned int green,unsigned int blue) { int i,index=0; unsigned long dist,temp; temp=195075; for(i=0;i<16;i++) { dist=0; dist+=(COLORS[i][0]-red)*(COLORS[i][0]-red); dist+=(COLORS[i][1]-green)*(COLORS[i][1]-green); dist+=(COLORS[i][2]-blue)*(COLORS[i][2]-blue); /* minimum dist^2=2492, 623=[minimum dist^2]/4 */ if(dist<=623) return i; if(dist index=i; temp=dist; } } return index; } /* draw X and Y axes */ void DrawAxes(int width,int height) { int i,j; char text[50]; setcolor(15); line(100,100,150+width,100); /* X axis */ line(150+width,100,145+width,97); line(150+width,100,145+width,103); outtextxy(154+width,95,"X"); line(100,100,100,150+height); /* Y axis */ line(100,150+height,97,145+height); line(100,150+height,103,145+height); outtextxy(95,154+height,"Y"); for(i=0;i<=width+20;i+=10) { sprintf(text,"%d",i); line(100+i,97,100+i,100); if(i%50==0) { line(100+i,94,100+i,97); /* make longer */ sprintf(text,"%d",i); outtextxy(95+i,85,text); } } for(j=0;j<=height+20;j+=10) { line(97,j+100,100,j+100); if(j%50==0) { line(94,j+100,97,j+100); /* make longer */ sprintf(text,"%d",j); outtextxy(70,j+98,text); } } sprintf(text,"ImageSize: %d * %d pixels",width,height); setcolor(2); outtextxy(100,50,text); } /* copy the screen and save to a bmp file */ void CopyScreen(char* filename,int left,int top,int right,int bottom) { int i,j,width,height,bpp=4,colorUsed=16,stride,index0,index1; BITMAPFILEHEADER fileHeader; BITMAPINFOHEADER infoHeader; RGBQUAD *palette; unsigned char *pPixels; FILE *stream; width=right-left+1; height=bottom-top+1; stride=(width*bpp+31)/32*4; /* fill file header */ fileHeader.type=0x4D42; /* filetype:"BM" ascii code */ fileHeader.fileSize=sizeof(infoHeader); fileHeader.fileSize+=sizeof(RGBQUAD)*colorUsed; fileHeader.fileSize+=((long)stride)*height; fileHeader.reserved=0; fileHeader.offbits=sizeof(fileHeader)+sizeof(infoHeader)+4*16; /* fill info header */ infoHeader.dwSize=sizeof(BITMAPINFOHEADER); infoHeader.width=width; infoHeader.height=height; infoHeader.planes=1; /* must set to 1 */ infoHeader.bpp=bpp; infoHeader.compression=0; infoHeader.sizeImage=((long)stride)*height; infoHeader.hResolution=0x27; infoHeader.vResolution=0x27; infoHeader.colors=16; infoHeader.importantColors=0; /* fill RGBQUAD items */ palette=malloc(sizeof(RGBQUAD)*16); if(palette==NULL) { printf("malloc for palette fail!"); return; } for(i=0;i<16;i++) { palette[i].rgbRed = COLORS[i][0]; palette[i].rgbGreen = COLORS[i][1]; palette[i].rgbBlue = COLORS[i][2]; palette[i].rgbReserved = 0; } /* open the file in wb mode */ stream=fopen(filename,"wb"); if(stream==NULL) { printf("open file fail!"); return; } fwrite(&fileHeader,sizeof(fileHeader),1,stream); fwrite(&infoHeader,sizeof(infoHeader),1,stream); fwrite(palette,sizeof(RGBQUAD),16,stream); free(palette); /* write the bitmap data: color indexes ,bpp=4 */ pPixels=malloc(stride); if(pPixels==NULL) { printf("malloc for pPixels fail!"); return; } for(j=bottom;j>=top;j--) { memset(pPixels,0,stride); for(i=left;i<=right;i+=2) { /* 2 pixels to 1 byte */ index0=getpixel(i,j); index1=(i==right)? 0: getpixel(i+1,j); pPixels[i/2]=(index0<<4)+index1; } fwrite(pPixels,1,stride,stream); } fclose(stream); } /* ---------END------------ */_ 首先我们要知道的几个概念: bpp:位深度,单位是位/像素(bits per pixel),bpp决定了所能表示的颜色数量。例如bpp=1,则说明图像只有黑白两色(二值图像)。bpp=8,为普通的灰度图像。bpp=24,是最常见的RGB三通道彩色图片。 stride:扫描行宽度,单位是字节。这是一个在图像数据块(文件或内存中的)中进行定位非常重要的概念,指一行像素占据的内存大小。它必须是4bytes整数倍。因此stride从下面表达式的计算: stride=(bm.Width*bpp+31)/32*4; 在这里我们必须注意,读取BMP文件时,文件地址是long型(4bytes),即32位的地址,当计算偏移地址时,我们必须把16位的size_t或者int类型首先转化为long型,以免高位地址丢失,导致不能正确定位文件。例如下面这句代码中的类型显示转换是不可缺少的。 offset=fileHeader.offbits+j*((long)stride); 由于在TC VGA绘图模式下无法截屏(没有DC),所以通过另存为一个4bpp的bmp图片来做示范。 (24 bpp Win32 bmp)->(TC VGA Graph Mode“截屏”) 0 0 0 (请您对文章做出评价)
