个人博客地址:https://travis1024.github.io/
位图图像文件缩放
1. 问题描述
编写一个程序,可以在命令行输入参数,完成指定文件的缩放,并存储到新文件,命令行参数如下: zoom file1.bmp 200 file2.bmp
第一个参数为可执行程序名称,第二个参数为原始图像文件名,第三个参数为缩放比例(百分比),第四个参数为新文件名
2. 问题分析
- 提前查阅资料,熟悉BMP位图文件结构,知道怎么通过命令行参数读取相应的BMP文件;
2) 明确解决BMP位图文件的按比例压缩问题的步骤;
3) 明确解决存储压缩后生成的BMP文件的问题的步骤;
3. 处理方法设计(算法步骤)
-
整个bmp文件的内容可以分为3到4块,第一块是bmp的文件头用于描述整个bmp文件的情况。结构如下:
第一个bfType用于表示文件类型,如果它是bmp文件,那么它这个位置的值一定是”BM” 也就是0x4D42。第二个bfSize表示整个文件的字节数。第三第四个 则保留,目前无意义,最后一个相当重要,表示,位图的数据信息离文件头的偏移量,以字节为单位。
-
第二块是位图信息头,即BITMAPINFOHEADER,用于描述整个位图文件的情况,结构如下:
-
第三块就是调色板信息或者掩码部分,如果是8位位图 则存放调色板 ;16 与32位位图则存放RGB颜色的掩码,这些掩码以DWORD大小来存放。
-
为了进行放缩操作,我们根据放缩的比例把后来对应的图片的位置的像素,映射到原先的像素位置,用原先的像素进行填充。
-
位图快速缩放公式:
4.测试数据设计
原文件为travis.bmp,通过以下两个命令生成两张新的bmp文件:
Third travis.bmp 200 Large_travis.bmp
Third travis.bmp 20 Small_travis.bmp
5.测试结果分析
6.程序结构
7.源代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#pragma pack(1)
using namespace std;
typedef struct ClBitMapFileHeader { //文件信息
unsigned short bfType; //文件信息类型
unsigned long bfSize; //文件大小
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits; //文件头到真正的数据之间的数据量
} tagBITMAPFILEHEADER;
typedef struct ClBitMapInfoHeader { //BMP信息
unsigned long biSize; //此结构默认字节数40
long biWidth;
long biHeight;
unsigned short biPlanes; //颜色平面,总是1
unsigned short biBitCount; //比特数/像素 ,一般是24,(真彩色)
unsigned long biCompression; //压缩方式,这里一般是0,真彩色图像
unsigned long biSizeImage; //图像大小
long biXPelsPerMeter; //水平分辨率
long biYPelsPerMeter; //垂直分辨率
unsigned long biClrUsed; //颜色索引
unsigned long biClrImportant; //重要颜色信息,一般是0
}tagBITMAPINFOHEADER;
void Transtition(char source[],char target[],double times) {
FILE* f1 = fopen(source,"rb");
FILE* f2 = fopen(target,"wb");
if(f1 == NULL || f2 == NULL){
cout << "File read/write error!" << endl;
}
tagBITMAPFILEHEADER filehead; //文件头
tagBITMAPINFOHEADER BMPhead; //BMP头
fread(&filehead,sizeof(filehead),1,f1);
fread(&BMPhead,sizeof(BMPhead),1,f1);
long width = BMPhead.biWidth; //获取宽度和高度
long height = BMPhead.biHeight;
unsigned char *data = (unsigned char*)malloc(sizeof(unsigned char)*width*3*height);//获取真正的数据信息
fseek(f1,54,SEEK_SET);
fread(data,width*3*height,1,f1);
long new_width = (long)1.0*times*width; //新的图片的宽度
long new_height = (long)1.0*times*height; //新的图片的高度
filehead.bfSize = new_width*new_height*3+54; //更改文件的信息头和BMP信息头
BMPhead.biHeight = new_height;
BMPhead.biWidth = new_width;
fwrite(&filehead,sizeof(filehead),1,f2);
fwrite(&BMPhead,sizeof(BMPhead),1,f2);
unsigned char *new_data = (unsigned char*)malloc(sizeof(unsigned char)*new_width*3*new_height);//分配新的数据空间
long src_x,src_y;//代表原x和y;
for(long i=0;i<new_height;i++){
src_y = (long)1.0*i/times;
unsigned char *src_row_begin = data + src_y*3*width;//换算成原先行的起始处;
for(long j=0;j<new_width;j++){
src_x = (long)1.0*j/times;
memcpy(new_data + i*new_width*3+j*3,src_row_begin + src_x * 3,3);
}
}
fseek(f2,54,SEEK_SET);
fwrite(new_data,new_width*3*new_height,1,f2);
cout << "New BMP image generated successfully!" << endl;
free(data);
free(new_data);
fclose(f1);
fclose(f2);
}
int main(int argc,char** argv){
double times= atof(argv[2])/100.0;
Transtition(argv[1],argv[3],times);
return 0;
}