C语言读取和显示BMP文件 (zt)
默认分类 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函数中。原因是我们已知最近的两个颜色点的距离,如果某点与某颜色的距离小于最短距离的一半,则此颜色就是我们要找的结果。
INCLUDEPICTURE "http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" \* MERGEFORMATINET Compute Minimum Dist^2 Code
int COLORS[16][3]={
INCLUDEPICTURE "http://www.cnblogs.com/Images/dot.gif" \* MERGEFORMATINET
INCLUDEPICTURE "http://www.cnblogs.com/Images/dot.gif" \* MERGEFORMATINET
INCLUDEPICTURE "http://www.cnblogs.com/Images/dot.gif" \* MERGEFORMATINET .};
/* 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
#include
#include
#include
int MAX_Y=480;
int MAX_X=640;
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:\\tc\\");
/* 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=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
(请您对文章做出评价)