#include #include #include #include #pragma pack(1)//必须在结构体定义之前使用,这是为了让结构体中各成员按1字节对齐 // 文件头结构体 typedef struct tagBITMAPFILEHEADER { unsigned short bfType; // 保存图片类型,读取时需要注释掉,文本标识符只能单独进行读写 2 unsigned long bfSize; // 文件大小 4 unsigned short bfReserved1; // 保留,设置为0 2 unsigned short bfReserved2; // 保留,设置为0 2 unsigned long bfOffBits; // 从文件头到实际的图像数据之间的字节的偏移量(没调色板的话是54) 4 } BITMAPFILEHEADER; //图像信息头结构体 typedef struct tagBITMAPINFOHEADER { unsigned long biSize; // 此结构体的大小 unsigned long biWidth; // 图像的宽 unsigned long biHeight; // 图像的高 unsigned short biPlanes; // 颜色平面数 恒为1 unsigned short biBitCount; // 一像素所占的位数 Windows系统有8,16,24 unsigned long biCompression; // 说明图象数据压缩的类型,0为不压缩 unsigned long biSizeImage; // 图像大小, 值等于上面文件头结构中bfSize-bfOffBits unsigned long biXPelsPerMeter; // 说明水平分辨率,用像素/米表示 一般为0 unsigned long biYPelsPerMeter; // 说明垂直分辨率,用像素/米表示 一般为0 unsigned long biClrUsed; // 说明位图实际使用的彩色表中的颜色索引数(设为0的话,则说明使用所有调色板项) unsigned long biClrImportant; // 说明对图象显示有重要影响的颜色索引的数目 如果是0表示都重要 } BITMAPINFOHEADER; void changeBmpFile(const char *src, const char *dest, double proportion) { //源文件名,目标文件名,放大或缩小比例 //1.源位图文件文件头和信息头 BITMAPFILEHEADER src_fileHeader; BITMAPINFOHEADER src_infoHeader; //2.目标位图文件文件头和信息头 BITMAPFILEHEADER dest_fileHeader; BITMAPINFOHEADER dest_infoHeader; //3.源位图文件对象&目标位图文件对象 FILE *src_file; FILE *dest_file; //4.源位图文件以读取(允许读和写)模式打开&目标位图文件以写入(只允许写)模式打开 src_file = fopen(src,"rb+"); dest_file = fopen(dest,"wb+"); if(src_file == NULL || dest_file == NULL) { printf("文件打开失败,程序结束...\n"); exit(-1); } //5.读取源位图文件的标识符信息&文件头&信息头 // unsigned short fileIdentifier; // fread(&fileIdentifier, sizeof(unsigned short), 1, src_file); fread(&src_fileHeader, sizeof(BITMAPFILEHEADER), 1, src_file); fread(&src_infoHeader, sizeof(BITMAPINFOHEADER), 1, src_file); //6.一个位图文件的像素占据的内存空间 = 位数 ? 8,例如24位图一个像素占据3字节内存 int byte = src_infoHeader.biBitCount / 8;//表示每个像素由几个字节表示,对于24位位图文件来说,byte值为3 //7.获取源位图文件和目标位图文件的长宽(以像素为单位)以及尺寸(位图文件图像数据的字节大小) unsigned long oldWidth, oldHeight, oldSize, newWidth, newHeight, newSize; oldWidth = src_infoHeader.biWidth; oldHeight = src_infoHeader.biHeight; newWidth = ((int)(src_infoHeader.biWidth * proportion) + 3) / 4 * 4;//图像显示不出来原因在于图像长或宽不是4的倍数 下面这一步可以保证得到的宽高是4的倍数 newHeight = ((int)(src_infoHeader.biHeight * proportion) + 3) / 4 * 4; printf("源位图文件高为:%d\n", oldHeight); printf("源位图文件宽为:%d\n", oldWidth); printf("目标位图文件高为:%d\n", newHeight); printf("目标位图文件宽为:%d\n", newWidth); oldSize = oldWidth * oldHeight * byte; newSize = newWidth * newHeight * byte; //8.sourceData是一个指针,指向源位图文件的图像存储数据 unsigned char *sourceData = (unsigned char*)malloc(oldSize);//该指针指向源位图文件图像数据的内存空间 fseek(src_file, 54, SEEK_SET);//使文件的指针指向文件的第55个字节 fread(sourceData, oldSize, 1, src_file);//将src_file中的图像数据存储到sourceData指向的内存空间 //9.目标位图文件文件头和信息头内容的更改 dest_fileHeader = src_fileHeader; dest_infoHeader = src_infoHeader; dest_fileHeader.bfSize = 54 + newSize; dest_infoHeader.biWidth = newWidth; dest_infoHeader.biHeight = newHeight; dest_infoHeader.biSizeImage = newSize; // fwrite(&fileIdentifier, sizeof(unsigned short), 1, dest_file); fwrite(&dest_fileHeader, sizeof(BITMAPFILEHEADER), 1, dest_file); fwrite(&dest_infoHeader, sizeof(BITMAPINFOHEADER), 1, dest_file); //10.使用最邻近插值算法进行图片缩放 unsigned int x,y,X,Y;//源位图文件像素点宽高和目标位图文件像素点宽高 unsigned char *destData = (unsigned char*)malloc(newSize);//该指针指向目标位图文件图像数据的内存空间 unsigned char *sourceWhere, *destWhere;//修改像素的对应位置 for(Y = 0; Y < newHeight; Y++) { y = Y / proportion; destWhere = destData + Y * newWidth * byte; sourceWhere = sourceData + y * oldWidth * byte; for(X = 0; X < newWidth; X++) { x = X / proportion; memcpy(destWhere + X * byte, sourceWhere + x * byte, byte); } } //11.写入数据并且释放内存&关闭文件流 fwrite(destData, newSize, 1, dest_file); free(destData); free(sourceData); fclose(src_file); fclose(dest_file); } int main(int argc,char *argv[]) { printf("******位图文件压缩程序******\n"); // if(argc >= 4) { // changeBmpFile(argv[1],argv[3],atoi(argv[2]) / 100.0); // printf("缩放成功!\n"); changeBmpFile("./input/hello.bmp","./output/test(output).bmp",100.0 / 100.0); printf("缩放成功!\n"); // } else if(argc == 1){ // printf("未传入参数,需要在控制台进行位图文件的压缩!!!"); // return 0; // }else { // printf("参数不足 ,程序结束...\n"); // exit(-1); // } return 0; }