用标准c读取bmp文件的长宽?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用标准c读取bmp文件的长宽?相关的知识,希望对你有一定的参考价值。

要求头文件只包括 "stdlib.h"和"stdio.h"
http://zhidao.baidu.com/question/80147331.html同一个问题如果答案准确的话,此分也奉上。最好自己写要求头文件只有stdio.h和stdlib.h。不要贴那么多无关的东西。

既然这么多分,我就帮你回答一下吧。

读取bmp文件的长宽,要自己写函数的,首先需要对bmp的格式有所了解。

下面是bmp的格式,可以看出“位图信息头”的结构中有宽度和高度的信息
只需要把“位图信息头”读取出来,就能获取到bmp文件的宽度和高度了

而下面的“显示bmp”的源代码中,就有获取”位图信息头的功能。

http://blog.gisforum.net/u/69679/archives/2007/1596.html
1. BMP文件组成
BMP文件由文件头、位图信息头、颜色信息和图形数据四部分组成。
2. BMP文件头
BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。

其结构定义如下:
typedef struct tagBITMAPFILEHEADER

WORDbfType; // 位图文件的类型,必须为BM
DWORD bfSize; // 位图文件的大小,以字节为单位
WORDbfReserved1; // 位图文件保留字,必须为0
WORDbfReserved2; // 位图文件保留字,必须为0
DWORD bfOffBits; // 位图数据的起始位置,以相对于位图
// 文件头的偏移量表示,以字节为单位
BITMAPFILEHEADER;

3. 位图信息头

BMP位图信息头数据用于说明位图的尺寸等信息。
typedef struct tagBITMAPINFOHEADER
DWORD biSize; // 本结构所占用字节数
LONGbiWidth; // 位图的宽度,以像素为单位
LONGbiHeight; // 位图的高度,以像素为单位
WORD biPlanes; // 目标设备的级别,必须为1
WORD biBitCount// 每个像素所需的位数,必须是1(双色),
// 4(16色),8(256色)或24(真彩色)之一
DWORD biCompression; // 位图压缩类型,必须是 0(不压缩),
// 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
DWORD biSizeImage; // 位图的大小,以字节为单位
LONGbiXPelsPerMeter; // 位图水平分辨率,每米像素数
LONGbiYPelsPerMeter; // 位图垂直分辨率,每米像素数
DWORD biClrUsed;// 位图实际使用的颜色表中的颜色数
DWORD biClrImportant;// 位图显示过程中重要的颜色数
BITMAPINFOHEADER;

4. 颜色表
颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。RGBQUAD结构的定义如下:

typedef struct tagRGBQUAD
BYTErgbBlue;// 蓝色的亮度(值范围为0-255)
BYTErgbGreen; // 绿色的亮度(值范围为0-255)
BYTErgbRed; // 红色的亮度(值范围为0-255)
BYTErgbReserved;// 保留,必须为0
RGBQUAD;
颜色表中RGBQUAD结构数据的个数有biBitCount来确定:
当biBitCount=1,4,8时,分别有2,16,256个表项;
当biBitCount=24时,没有颜色表项。
位图信息头和颜色表组成位图信息,BITMAPINFO结构定义如下:
typedef struct tagBITMAPINFO
BITMAPINFOHEADER bmiHeader; // 位图信息头
RGBQUAD bmiColors[1]; // 颜色表
BITMAPINFO;

5. 位图数据
位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:

当biBitCount=1时,8个像素占1个字节;
当biBitCount=4时,2个像素占1个字节;
当biBitCount=8时,1个像素占1个字节;
当biBitCount=24时,1个像素占3个字节;
Windows规定一个扫描行所占的字节数必须是
4的倍数(即以long为单位),不足的以0填充,
一个扫描行所占的字节数计算方法:
DataSizePerLine= (biWidth* biBitCount+31)/8;
// 一个扫描行所占的字节数
DataSizePerLine= DataSizePerLine/4*4; // 字节数必须是4的倍数
位图数据的大小(不压缩情况下):
DataSize= DataSizePerLine* biHeight;

/*显示一个bmp文件的C程序
下面的函数LoadBmpFile,其功能是从一个.bmp文件中读取数据(包括BITMAPINFOHEADER,调色板和实际图象数据)
将其存储在一个全局内存句柄hImgData中,这个hImgData将在以后的图象处理程序中用到。
同时填写一个类型为HBITMAP的全局变量hBitmap和一个类型为HPALETTE的全局变量hPalette。
这两个变量将在处理WM_PAINT消息时用到,用来显示出位图。
该函数的两个参数分别是用来显示位图的窗口句柄,和.bmp文件名(全路径),
当函数成功时,返回TRUE,否则返回FALSE.
*/
BITMAPFILEHEADER bf;
BITMAPINFOHEADER bi;
BOOL LoadBmpFile(HWND hWnd,char* BmpFileName)

HFILE hf; //文件句柄
LPBITMAPINFOHEADER lpImgData; //指向BITMAPINFOHEADER结构的指针
LOGPALETTE *pPal; //指向逻辑调色板结构的指针
LPRGBQUAD lpRGB; //指向RGBQUAD结构的指针
HPALETTE hPrevPalette;//用来保存设备中原来的调色板
HDC hDc; //设备句柄
HLOCAL hPal; //存储调色板的局部内存句柄
DWORD LineBytes; //每一行的字节数
DWORD ImgSize; //实际的图象数据占用的字节数
DWORD NumColors; //实际用到的颜色数,即调色板数组中的颜色个数
DWORD i;

if((hf=_lopen(BmpFileName,OF_READ))==HFILE_ERROR)
MessageBox (hWnd,"Filec:\test.bmpnotfound!","ErrorMessage",
MB_OK|MB_ICONEXCLAMATION);
return FALSE;//打开文件错误,返回

//将BITMAPFILEHEADER结构从文件中读出,填写到bf中
_lread(hf,(LPSTR)&bf,sizeof(BITMAPFILEHEADER));
//将BITMAPINFOHEADER结构从文件中读出,填写到bi中
_lread(hf,(LPSTR)&bi,sizeof(BITMAPINFOHEADER));

/**//*我们定义了一个宏#define WIDTHBYTES(i) ((i+31)/32*4),上面曾经提到过,每一行的字节数必须是4的整倍数,只要调用WIDTHBYTES(bi.biWidth*bi.biBitCount)就能完成这一换算.举一个例子,对于2色图,如果图象宽是31,则每一行需要31位存储,合3个字节加7位,因为字节数必须是4的整倍数,所以应该是4,而此时的biWidth=31,biBitCount=1,WIDTHBYTES(31*1)=4,和我们设想的一样。再举一个256色的例子,如果图象宽是31,则每一行需要31个字节存储,因为字节数必须是4的整倍数,所以应该是32,而此时的biWidth=31,biBitCount=8,WIDTHBYTES(31*8)=32,和我们设想的一样。你可以多举几个例子来验证一下*/
//LineBytes为每一行的字节数
LineBytes=(DWORD)WIDTHBYTES(bi.biWidth*bi.biBitCount);
//ImgSize为实际的图象数据占用的字节数
ImgSize=(DWORD)LineBytes*bi.biHeight;
//NumColors为实际用到的颜色数,即调色板数组中的颜色个数
if(bi.biClrUsed!=0)
NumColors=(DWORD)bi.biClrUsed;//如果bi.biClrUsed不为零,就是本图象实际
//用到的颜色数
else//否则,用到的颜色数为2的biBitCount次方。
switch(bi.biBitCount)
case1:
NumColors=2;
break;
case4:
NumColors=16;
break;
case8:
NumColors=256;
break;
case24:
NumColors=0;//对于真彩色图,没用到调色板
break;
default:
//不处理其它的颜色数,认为出错。
MessageBox(hWnd,"Invalidcolornumbers!","ErrorMessage",
MB_OK|MB_ICONEXCLAMATION);
_lclose(hf);
return FALSE;//关闭文件,返回FALSE

if(bf.bfOffBits!=(DWORD)(NumColors*sizeof(RGBQUAD)+sizeof(BITMAPFILEHEADER)
+sizeof(BITMAPINFOHEADER)))

//计算出的偏移量与实际偏移量不符,一定是颜色数出错
MessageBox(hWnd,"Invalidcolornumbers!","ErrorMessage",
MB_OK|MB_ICONEXCLAMATION);
_lclose(hf);
return FALSE;//关闭文件,返回FALSE

bf.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+NumColors
*sizeof(RGBQUAD)+ImgSize;
//分配内存,大小为BITMAPINFOHEADER结构长度加调色板+实际位图数据
if((hImgData=GlobalAlloc(GHND,(DWORD)(sizeof(BITMAPINFOHEADER)+
NumColors*sizeof(RGBQUAD)+ImgSize)))==NULL)

//分配内存错误
MessageBox(hWnd,"Errorallocmemory!","ErrorMessage",
MB_OK|MB_ICONEXCLAMATION);
_lclose(hf);
return FALSE;//关闭文件,返回FALSE

//指针lpImgData指向该内存区
lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData);

//文件指针重新定位到BITMAPINFOHEADER开始处
_llseek(hf,sizeof(BITMAPFILEHEADER),SEEK_SET);
//将文件内容读入lpImgData
_hread(hf,(char*)lpImgData,(long)sizeof(BITMAPINFOHEADER)
+(long)NumColors*sizeof(RGBQUAD)+ImgSize);
_lclose(hf);//关闭文件

if(NumColors!=0) //NumColors不为零,说明用到了调色板

//为逻辑调色板分配局部内存,大小为逻辑调色板结构长度加NumColors个
//PALETTENTRY大小
hPal=LocalAlloc(LHND,sizeof(LOGPALETTE)+NumColors*sizeof(PALETTEENTRY));

//指针pPal指向该内存区
pPal=(LOGPALETTE*)LocalLock(hPal);

//填写逻辑调色板结构的头
pPal->palNumEntries=NumColors;
pPal->palVersion=0x300;

//lpRGB指向的是调色板开始的位置
lpRGB=(LPRGBQUAD)((LPSTR)lpImgData+(DWORD)sizeof(BITMAPINFOHEADER));

//填写每一项
for(i=0;i<NumColors;i++)

pPal->palPalEntry[i].peRed=lpRGB->rgbRed;
pPal->palPalEntry[i].peGreen=lpRGB->rgbGreen;
pPal->palPalEntry[i].peBlue=lpRGB->rgbBlue;
pPal->palPalEntry[i].peFlags=(BYTE)0;
lpRGB++;//指针移到下一项


//产生逻辑调色板,hPalette是一个全局变量
hPalette=CreatePalette(pPal);

//释放局部内存
LocalUnlock(hPal);
LocalFree(hPal);


//获得设备上下文句柄
hDc=GetDC(hWnd);

if(hPalette)//如果刚才产生了逻辑调色板

//将新的逻辑调色板选入DC,将旧的逻辑调色板句柄保存在hPrevPalette
hPrevPalette=SelectPalette(hDc,hPalette,FALSE);
RealizePalette(hDc);


//产生位图句柄
hBitmap=CreateDIBitmap(hDc, (LPBITMAPINFOHEADER)lpImgData,(LONG)CBM_INIT,
(LPSTR)lpImgData+sizeof(BITMAPINFOHEADER)+NumColors*sizeof(RGBQUAD),
(LPBITMAPINFO)lpImgData,DIB_RGB_COLORS);

//将原来的调色板(如果有的话)选入设备上下文句柄
if(hPalette&&hPrevPalette)

SelectPalette(hDc,hPrevPalette,FALSE);
RealizePalette(hDc);


ReleaseDC(hWnd,hDc); //释放设备上下文
GlobalUnlock(hImgData); //解锁内存区
Return TRUE; //成功返回
参考技术A #include<stdio.h>
#include<stdlib.h>
typedef struct tagBITMAPINFOHEADER

int bisize;//本结构大小字节为单位
int width;//图形宽度以象素为单位
int height;//图形高度以象素为单位
int planes;//目标设备的级别,必须为1
int bitcount;//每个象素所需要的位数
int SizeImage; // 位图的大小,以字节为单位
int compression;//是否为压缩
int xpermeter;//位图水平分辨率,每米像素数
int ypermeter;// 位图垂直分辨率,每米像素数
int ClrUsed;// 位图实际使用的颜色表中的颜色数
int ClrImportant;// 位图显示过程中重要的颜色数
BITMAPINFOHEADER;

typedef struct
unsigned short int Signature;
unsigned int Size;
unsigned int Reserved;
unsigned int BitsOffset;
BITMAP_FILEHEADER;

void main()

BITMAP_FILEHEADER head;
BITMAPINFOHEADER bmih;
FILE *fp;

if((fp=fopen("test.bmp","rb"))==NULL)

printf("不能打开该文件\n");
exit(0);

else

fread(&head,14,1,fp);
fread(&bmih,sizeof(bmih),1,fp);
printf("图形高度为%d\n",bmih.height);
printf("图形宽度为%d\n",bmih.width);

fclose(fp);
参考技术B 我只要一个头文件吧。
bmp文件存贮形式为前14个字节为文件信息区,保存的是BMP文件类型标识2,文件长度4,保留字节4,文件描述区长度4,
之后40个字节是图像信息区,为图形尺寸4,图形宽度4,图形高度4,其他就不多说了,你可看下关于BMP文件的说明。
因此读取长宽只要从文件头偏移18字节就行。
#include <stdio.h>
main()
long bmpwidth,bmpheight;
FILE *fp;
fp=fopen("FIVEANGL.bmp","rb");
fseek(fp,18L,SEEK_SET);
fread(&bmpwidth,4,1,fp);
fread(&bmpheight,4,1,fp);
fclose(fp);
printf("\n%s width is %ld,height is %ld","FIVEANGL.bmp",bmpwidth,bmpheight);
getchar();
参考技术C //给你写一个吧
#include<stdio.h>

int main()

int width,height;
FILE* bmpfp = fopen("E:\\风景\\风景1.bmp","rb");
fseek(bmpfp,18,SEEK_SET);
fread(&width,sizeof(int),1,bmpfp);
fread(&height,sizeof(int),1,bmpfp);
printf("width : %d , height : %d\n",width,height);


//运行结果
width : 700 , height : 382本回答被提问者采纳

用c语言读取24位位图bmp文件

源代码:
#include <windows.h>
#include <stdio.h>

#define BMP_SIZE_OFFSET 18
#define BMP_DATA_OFFSET 54

int main(void)


//定义操作位图的变量
int w; //图像宽度
int h; //图像高度
char *buf, *p; //图像数据
int r,g,b,pix; //像素颜色
int x,y,x0,y0; //平面坐标
FILE *fp; //文件指针
int i,j;

//定义窗口和绘图设备的变量
HWND wnd; //窗口句柄
HDC dc; //绘图设备环境句柄

if((fp=fopen("b_0.bmp","rb"))==NULL)
printf("文件未找到\n");
return-1;

fseek(fp,18L,SEEK_SET);
fread(&w,4,1,fp); //取图像宽度
fread(&h,4,1,fp); //取图像高度
buf=(char *)malloc(w*h*3);
fseek(fp,54L,SEEK_SET); //定位到数据处
fread(buf,1,w*h*3,fp); //读取像素数据
fclose(fp);

wnd=GetForegroundWindow(); //获取窗口句柄
dc=GetDC(wnd); //获取绘图设备

x0=40; y0=40;
p=buf;
for(j=0;j<h;j++)
for(i=0;i<w;i++)
b=*p++; g=*p++; r=*p++;
pix=RGB(r,g,b); //合成像素颜色值
//pix=(r&0xFF)<<16|(g&0xFF)<<8|b&0xFF; //与上一句邓加
SetPixel(dc,x0+i, y0+h-j, pix); //画像素点


free(buf);
getchar();
return 0;

经过测试此程序可以在vc6下正常运行;
不过出现了一个很诡异的事:
图片正常显示:

================================================================
图片非正常显示:
原图

经过程序读取后显示的(非正常):

以上图片已经过反复确定为24位bmp位图!
求解出现问题的原因!
谢谢!

可以使用C语言标准函数库中的fopen、fseek、fclose等系列函数来打开bmp位图文件,以及进行相应的处理,下面是一个demo,仅供参考。以下代码在vc6.0中编译通过。


#include <stdio.h>
#include <stdlib.h>
#define BITMAPFILEHEADERLENGTH 14   // The bmp FileHeader length is 14
#define BM 19778                    // The ASCII code for BM
/* Test the file is bmp file or not */
void bmpFileTest(FILE* fpbmp);
/* To get the OffSet of header to data part */
void bmpHeaderPartLength(FILE* fpbmp);
/* To get the width and height of the bmp file */
void BmpWidthHeight(FILE* fpbmp);
//get r,g,b data
void bmpDataPart(FILE* fpbmp);
// output data to corresponding txt file
void bmpoutput(FILE *fpout);
unsigned int OffSet = 0;    // OffSet from Header part to Data Part
long width ;          // The Width of the Data Part
long height ;         // The Height of the Data Part
unsigned char r[2000][2000],output_r[2000][2000];
unsigned char g[2000][2000],output_g[2000][2000];
unsigned char b[2000][2000],output_b[2000][2000];
int main(int argc, char* argv[])

     /* Open bmp file */
unsigned char *fp_temp;
     FILE *fpbmp;
     FILE *fpout;
     fpbmp= fopen("1.bmp", "rb");
     if (fpbmp == NULL)
     
 printf("Open bmp failed!!!\\n");
 return 1;
     
     fpout= fopen("out.bmp", "wb+");
     if (fpout == NULL)
     
 printf("Open out.bmp failed!!!\\n");
 return 1;
     
     
     bmpFileTest(fpbmp);                //Test the file is bmp file or not
     bmpHeaderPartLength(fpbmp);        //Get the length of Header Part
     BmpWidthHeight(fpbmp);             //Get the width and width of the Data Part
     
     
//
fseek(fpbmp, 0L, SEEK_SET);
fseek(fpout, 0L, SEEK_SET);
 
fp_temp=(unsigned char *)malloc(OffSet);
         fread(fp_temp, 1, OffSet, fpbmp);
fwrite(fp_temp,1,OffSet,fpout);
     
bmpDataPart(fpbmp);                //Reserve the data to file 
     
/*
 
 
 如果您想对图片进行处理,请您再这里插入处理函数!!!!!!!!!!!!!!!!!!
 
*/
bmpoutput(fpout);
fclose(fpbmp);
fclose(fpout);
         return 0;

void bmpoutput(FILE* fpout)

         int i, j=0;
         int stride;
unsigned char* pixout=NULL;
   
stride=(24*width+31)/8;
stride=stride/4*4;
pixout=(unsigned char *)malloc(stride);
 
fseek(fpout, OffSet, SEEK_SET);
for(j=0;j<height;j++)

   for(i=0;i<width;i++)
        
            pixout[i*3+2]=output_r[height-1-j][i];
            pixout[i*3+1]=output_g[height-1-j][i];
            pixout[i*3]  =output_b[height-1-j][i];
        
fwrite(pixout, 1, stride, fpout);


void bmpDataPart(FILE* fpbmp)

         int i, j=0;
int stride;
unsigned char* pix=NULL;
FILE* fpr;
         FILE* fpg;
FILE* fpb;
     
     if((fpr=fopen("bmpr.txt","w+")) == NULL)
     
    printf("Failed to construct file bmpr.txt.!!!");
exit(1);
     
     if((fpg=fopen("bmpg.txt","w+")) == NULL)
     
 printf("Failed to construct file bmpg.txt.!!!");
 exit(1);
     
if((fpb=fopen("bmpb.txt","w+")) == NULL)
     
printf("Failed to construct file bmpb.txt.!!!");
exit(1);
     
 
     fseek(fpbmp, OffSet, SEEK_SET);
stride=(24*width+31)/8;
stride=stride/4*4;
pix=(unsigned char *)malloc(stride);
 
for(j=0;j<height;j++)

fread(pix, 1, stride, fpbmp);
   for(i=0;i<width;i++)
        
            r[height-1-j][i]   =pix[i*3+2];
            g[height-1-j][i]   =pix[i*3+1];
            b[height-1-j][i]   =pix[i*3];
output_r[height-1-j][i]   =pix[i*3+2];
            output_g[height-1-j][i]   =pix[i*3+1];
            output_b[height-1-j][i]   =pix[i*3];
        

 for(i =0; i < height; i++)
     
for(j = 0; j < width-1; j++)
   
fprintf(fpb,"%4d",b[i][j]);
fprintf(fpg,"%4d",g[i][j]);
fprintf(fpr,"%4d",r[i][j]);

fprintf(fpb,"%4d\\n",b[i][j]);
fprintf(fpg,"%4d\\n",g[i][j]);
fprintf(fpr,"%4d\\n",r[i][j]);
 
  
fclose(fpr);
fclose(fpg);
fclose(fpb);
 

void bmpFileTest(FILE* fpbmp)
     
     unsigned short bfType = 0;
 
     fseek(fpbmp, 0L, SEEK_SET);//seek_set 起始位置
     fread(&bfType, sizeof(char), 2, fpbmp);
     if (BM != bfType)
     
 printf("This file is not bmp file.!!!\\n");
 exit(1);
     

/* To get the OffSet of header to data part */
void bmpHeaderPartLength(FILE* fpbmp)

     fseek(fpbmp, 10L, SEEK_SET);
     fread(&OffSet, sizeof(char), 4, fpbmp);  
     printf("The Header Part is of length %d.\\n", OffSet);

/* To get the width and height of the bmp file */
void BmpWidthHeight(FILE* fpbmp)

     fseek(fpbmp, 18L, SEEK_SET);
     fread(&width, sizeof(char), 4, fpbmp);
     fseek(fpbmp, 22L, SEEK_SET);
     fread(&height, sizeof(char), 4, fpbmp);
     printf("The Width of the bmp file is %ld.\\n", width);
     printf("The Height of the bmp file is %ld.\\n", height);
参考技术A 如果横向的一行叫做一个“扫描线”的话
那么每条扫描线的第一个字节一定是对齐到4字节边界的
就比如,假设一条扫描线21个像素,那么一条扫描线就是21*3=63字节
实际上每条扫描线会占用64字节,因为下一条扫描线的第一个字节要对齐到4字节边界
(所谓对齐到边界,就是 除4余0)

注意:以上是凭印象说的。文件里保存和内存里保存是不是一样的不太确定……

最简单的解决方案,你要加载的BMP都确定宽是4的倍数就可以了本回答被提问者采纳
参考技术B 行像素错了一位,导致图像倾斜了。

以上是关于用标准c读取bmp文件的长宽?的主要内容,如果未能解决你的问题,请参考以下文章

用C语言读取16位bmp图片的每个像素的信息~

用c语言读取24位位图bmp文件

C语言读取1位的BMP图

用c ++读取BMP文件的所有字节并旋转图片

用C语言编写程序处理图片bmp文件 1.读取图片的宽度,高度,每个像素所需的位数,水平分辨率,垂直

如何在c语言 读取BMP图片的信息