设计算法,要求把一张任意尺寸的 BMP 图片等比例且不失真的缩小为原来的 1/2,并生成一张新的 BMP 图片,要求 BMP 图片的路径都需要通过命令行进行传递
设计思路:
1.定义一个空间 buf存放从原图片读取的颜色分量(注意考虑BMP文件的字节补齐数量);
2.定义一个空间 half_buf存放缩小到1/2的颜色分量。我采用的是每行间隔一个颜色分量取数据;
3.将half_buf空间中的颜色分量写入颜色分量数据,同样要考虑字节补齐。
实现代码
/*** file name:BMP_reduction.c* author : liaojx2016@126.com* date : 2024-05-12* function : Reduce the BMP image by half to generate a new image file* note : None* CopyRight (c) 2024 liaojx2016@126.com Right Reseverd*
**/
#include<stdio.h>
#include <string.h>
#include<stdlib.h>
//取消字节对齐,因为需要的结构体是 14字节和 40字节大小
#pragma pack(1)
//定义图像文件头结构体
typedef struct BMP_FileHeader
{char bfType[2]; //位图文件的类型,必须为BM int bfSize; //文件大小,以字节为单位unsigned short int bfReserverd1; //位图文件保留字,必须为0 unsigned short int bfReserverd2; //位图文件保留字,必须为0 unsigned int bfbfOffBits; //位图文件头到数据的偏移量,以字节为单位
}BMP_FileHeader_t;
//定义图像信息头结构体
typedef struct BMP_InfoHeader
{ unsigned int biSize; //该结构大小,字节为单位int biWidth; //图形宽度以象素为单位int biHeight; //图形高度以象素为单位unsigned short int biPlanes; //目标设备的级别,必须为1 unsigned short int biBitcount; //颜色深度,每个象素所需要的位数unsigned short int biCompression; //位图的压缩类型unsigned int biSizeImage; //位图的大小,以字节为单位unsigned int biXPelsPermeter; //位图水平分辨率,每米像素数unsigned int biYPelsPermeter; //位图垂直分辨率,每米像素数unsigned int biClrUsed; //位图实际使用的颜色表中的颜色数unsigned int biClrImportant; //位图显示过程中重要的颜色数
}BMP_InfoHeader_t;#pragma pack() //开启字节对齐int main(int argc, char const *argv[])
{//判断通过命令行传入图片文件是否有效if (2 != argc){printf("import argument is invalid\n");return -1;}//打开图片文件FILE *bmp_fp = fopen(argv[1],"rb");if (NULL == bmp_fp){printf("fopen picture file error\n");return -1;}//判断是否打开成功//定义图像文件头和信息头的结构体变量BMP_FileHeader_t Fhead1,Fhead2;BMP_InfoHeader_t info_head1,info_head2;//读取图像文件头信息头的数据到结构体变量里fread(&Fhead1,1,14,bmp_fp);fread(&info_head1,1,40,bmp_fp);//输出原图像信息printf("the BMP picture size = %d;width is %d;height is %d\n",Fhead1.bfSize,info_head1.biWidth,info_head1.biHeight);//定义变量记录原图中的宽,高,字节补齐数量int prev_wight = info_head1.biWidth;int prev_height = info_head1.biHeight;int prev_add_byte = (4-(prev_wight*3)%4)%4;printf("pre_bmp add bytes = %d\n",prev_add_byte);//申请堆空间,存放原图颜色分量char *bmpbuf=(char*)malloc(prev_wight*prev_height*3);//读取原图文件的颜色分量到空间bmpbuf中for (int i = 0; i < prev_height; i++){fread(bmpbuf+3*prev_wight*i,1,prev_wight*3,bmp_fp); //读取一行的颜色分量fseek(bmp_fp,prev_add_byte,SEEK_CUR); //图片文件的光标偏移字节补齐的数量}//关闭源图像文件fclose(bmp_fp);//将原图片文件头和信息头复制到缩小图片的结构体中memcpy(&Fhead2,&Fhead1,14);memcpy(&info_head2,&info_head1,40); //设置缩小图片的宽,高,字节补齐数量int wight = info_head2.biWidth/2;int height = info_head2.biHeight/2;int add_byte = (4-(wight*3)%4)%4;printf("bmp add bytes = %d\n",add_byte);//修改缩小图片的文件头和信息头数据Fhead2.bfSize = (wight*3+add_byte)*height + 54;info_head2.biWidth = wight;info_head2.biHeight = height;//输出缩小图片的大小,宽和高printf("the BMP picture size = %d;width is %d;height is %d\n",Fhead2.bfSize,info_head2.biWidth,info_head2.biHeight);//申请堆空间,存放缩小图片的颜色分量char *half_bmpbuf=(char*)malloc(wight*height*3);//从 bmpbuf空间中读取原图文件的颜色分量到空间half_bmpbuffor (int i = 0; i < height; i++){for (int j = 0,k=0; j < wight*3; j++,k++){half_bmpbuf[i*wight*3+j] = bmpbuf[2*i*prev_wight*3+k]; //读取一个字节数据if (k%3 ==2 ){//此时已经读取完一个颜色分量,bmpbuf的地址加3, 间隔掉一个颜色分量,做缩小的动作k+=3;}}}//打开存放缩小图片的文件,若没有,则创建FILE *half_bmp_fp = fopen("0half.bmp","wb");//将所有图片信息复制到缩小的图片文件fwrite(&Fhead2,1,14,half_bmp_fp); //写入文件头数据fwrite(&info_head2,1,40,half_bmp_fp); //写入信息头数据//写入颜色分量数据for (int i = 0; i < height; i++){//从halfbuf空间总读取一行颜色分量数据到缩小图片文件fwrite(half_bmpbuf+wight*3*i,1,wight*3,half_bmp_fp); //考虑BMP图像文件字节补齐,做光标偏移,由于我用malloc申请的是堆空间,存储单元初值为0, 所以不需要额外复制fseek(half_bmp_fp,add_byte,SEEK_CUR); }//释放堆内存free(bmpbuf);free(half_bmpbuf);//关闭缩小图像文件fclose(half_bmp_fp);return 0;
}
测试结果
缩小后