前言: c语言课程设计需要实现位图图像缩放,但并没有提供很详细的位图图像的理解,所以颇费了一番功夫,这里给大家整理下以供参考,如有不当之处,还希望纠正
本篇文章只介绍biBitCount=24的位图图像,且代码也只适用于24位图像,且无压缩
由多个像素点组成的图像
共三部分
头文件
#include
typedef struct tagBITMAPFILEHEADER {
WORD bfType;//固定为0x4d42
DWORD bfSize;//文件大小
WORD bfReserved1;//保留字
WORD bfReserved2;//保留字
DWORD bfOffBits;//实际位图数据的偏移字节数,即前两个部分长度之和
} BITMAPFILEHEADER,*LPBITMAPFILEHEADER,*PBITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER {
DWORD biSize;//指定此结构体的长度,为40
LONG biWidth;//位图宽(单位:像素)
LONG biHeight;//位图高(单位:像素)
WORD biPlanes;//平面数,为1
WORD biBitCount;//采用颜色位数,可以是1 2 4 8 16 24 32
DWORD biCompression;//压缩方式,可以是0 1 2,其中0表示不压缩
DWORD biSizeImage;//实际位图数据占用的字节数
LONG biXPelsPerMeter;//X方向分辨率
LONG biYPelsPerMeter;//Y方向分辨率
DWORD biClrUsed;//使用的颜色数
DWORD biClrImportant;//重要颜色数
} BITMAPINFOHEADER,*LPBITMAPINFOHEADER,*PBITMAPINFOHEADER;
每个属性的具体意义可参考 这里
看起来属性很多,你只需要关注这些:
下面主要介绍biBitCount和像素点的存储方式
运行方法
例如源程序名为 convert.cpp 源图像名 cat.bmp 且在同一路径下
目标图像名为 cat_a.bmp 需要放大1.5倍
编译好后,在命令行输入
convert cat.bmp 150 cat_a.bmp
/*@auther:gtyinstinct*/
/*该程序只能处理biBitCount为24的bmp图片*/
#include
#include
#define WIDTHBYTES(bits) (((bits)+31)/32*4)//用于使图像宽度所占字节数为4byte的倍数
using namespace std;
int bmpwidth,bmpheight; //原图像的宽度和高度(单位:像素)
int src_width,dest_width; //实际存储每一行宽度(单位:字节)
int new_bmpwidth,new_bmpheight;//新图像的宽度和高度(单位:像素)
unsigned char *pBmpBuf; //存储原图像像素数据
unsigned char *new_pBmpBuf; //存储新图像像素数据
BITMAPFILEHEADER header;//位图文件头
BITMAPINFOHEADER info;//位图文件信息
int idx(int i,int j,int k){
return i*src_width + j*3 + k;
}
int idx_n(int i,int j,int k){
return i*dest_width + j*3 + k;
}
unsigned char process(int i1,int i2,int j1,int j2,int k,double i_t,double j_t){
unsigned int tmp[] = {pBmpBuf[idx(i1,j1,k)],
pBmpBuf[idx(i1,j2,k)],
pBmpBuf[idx(i2,j1,k)],
pBmpBuf[idx(i2,j2,k)]};
unsigned int ret = (unsigned int)(tmp[0] * (1-i_t) * (1-j_t) +
tmp[1] * (1-i_t) * j_t +
tmp[2] * i_t * (1-j_t) +
tmp[3] * i_t * j_t);
return (unsigned char) ret;
}
bool convert(char *bmpName,char *new_bmpName,double scale)
{
/*检查缩放比例是否正确*/
if(scale <=0){
cout << "scale is not correct" << endl;
return 0;
}
/*以二进制的方式打开文件*/
FILE *src,*dest;
dest = fopen(new_bmpName,"wb");
if( (src = fopen(bmpName,"rb")) == NULL)
{
cout<<"File "<< bmpName <<"failed to open"<<endl;
return 0;
}
/*读取文件头和位图信息*/
fread(&header,sizeof(BITMAPFILEHEADER),1,src);
fread(&info,sizeof(BITMAPINFOHEADER),1,src);
/*获取并打印位图大小*/
bmpwidth = info.biWidth;
bmpheight = info.biHeight;
if(info.biBitCount!=24){
cout << "biBitCount is not equal to 24" << endl;
return 0;
}
cout << "source image:" << endl;
cout << "width:" << bmpwidth << " height:" << bmpheight << endl;
/*计算缩放后的位图大小*/
new_bmpwidth = (int) (bmpwidth*scale);
new_bmpheight = (int) (bmpheight*scale);
cout << "dest image:" << endl;
cout << "width:" << new_bmpwidth << " height:" << new_bmpheight << endl;
/*修改位图信息的大小信息*/
info.biWidth = new_bmpwidth;
info.biHeight = new_bmpheight;
/*计算位图的实际宽度并确保是4byte的倍数*/
src_width = WIDTHBYTES(bmpwidth*info.biBitCount);
dest_width = WIDTHBYTES(new_bmpwidth*info.biBitCount);
/*写入新位图的位图信息和文件头*/
fwrite(&header,sizeof(BITMAPFILEHEADER),1,dest);
fwrite(&info,sizeof(BITMAPINFOHEADER),1,dest);
/*读取原位图的像素阵列*/
pBmpBuf = new unsigned char[bmpheight*src_width];
fread(pBmpBuf,sizeof(unsigned char),bmpheight*src_width,src);
/*计算新位图的像素阵列并写入*/
new_pBmpBuf = new unsigned char[dest_width*new_bmpheight];
for(int i=0;i<new_bmpheight;i++){
for(int j=0;j<new_bmpwidth;j++){
double i_,j_;
i_ = 1.0 * i * (bmpheight-1) / (new_bmpheight-1);
j_ = 1.0 * j * (bmpwidth-1) / (new_bmpwidth-1);
int i1,i2,j1,j2;
i1 = (int)i_;
j1 = (int)j_;
i2 = i1 + 1;
j2 = j1 + 1;
double i_t,j_t;
i_t = i_ - i1;
j_t = j_ - j1;
for(int k=0;k<3;k++){
new_pBmpBuf[idx_n(i,j,k)] = process(i1,i2,j1,j2,k,i_t,j_t);
}
}
}
fwrite(new_pBmpBuf,sizeof(unsigned char),dest_width*new_bmpheight,dest);
/*关闭文件*/
fclose(src);
fclose(dest);
return 1;
}
int main(int argc,char** argv)
{
if(convert(argv[1],argv[3],(double)atoi(argv[2])/100))
cout << "convert successfully";
else
cout << "fail to convert";
return 0;
}
/*@auther:gtyinstinct*/
ps:仅供参考,xder别直接拿源码交差