位图图像文件缩放-西安电子科技大学大一程序基础设计课程设计作业

  • 问题描述:

编写一个程序,可以在命令行输入参数,完成指定文件的缩放,并存储到新文件,命令行参数如下

zoom file1.bmp 200 file2.bmp

第一个参数为可执行程序名称,第二个参数为原始图像文件名,第三个参数为缩放比例(百分比),第四个参数为新文件名

  • 问题分析:
  1. 综述:

要实现对bmp图像操作,首先要知道bmp图像的存储机理(图像信息如何以二进制信息存储)及文件包含的内容;其次知晓基本的图像缩放算法即可;最后要知晓如何读取和存储文件信息。

  1. 实现时的困难:
    1. 定义何种类型变量?
    2. 文件大小如何读取、计算?
    3. 像素信息如何读取、写入?
  2. 对应解决方案
    1. 首先创建全局变量,如src_:原图宽高;dst_:缩放后宽高;各函数都可对其进行访问;其次用一个字符数组typedef unsigned char pixel[3];存储一个像素的RGB信息;对于缩放比例用double height_zoom_rate,width_zoom_rate;操作更精准,计算缩放后像素用类型转换即可,如:dst_width=(int)(width_zoom_rate*src_width); 而在访问文件文件头和信息头时,定义unsigned char *buf=NULL,*bui=NULL;方便逐个字节访问,也可以处理小端对齐。
    2. 即如何根据字节小端对齐计算文件大小;前面已经用buf、bui逐个访问文件头,信息头的每个字节数据,故如:b_size=bui[23]*16*16*16*16*16*16+bui[22]*16*16*16*16+bui[21]*16*16+bui[20];

可以读取图像大小;而:

f_size=dst_width*dst_height+54;则可计算操作后的文件大小

    1. 每个像素的RGB信息各占一个字节,用fgetc即可读取每个字节。读取完一行的像素后,通过计算填充字节个数(pad_num=(4-(src_width*3)%4)%4;),再用fgetc读掉填充字节,即可读取下一行。写入时采用三个字节为一组(即一个像素的RGB信息),结合最近邻插入法用fwrite写入fwrite(&info[si*src_width+sj],sizeof(pixel),1,fp_n);

再用fputc(0,fp_n)写入填充字节数。

#define _CRT_SECURE_NO_WARNINGS
#include"bmp.h"

extern double height_zoom_rate,width_zoom_rate;

int main(int argc, char* argv[]) {
	
	//打开文件 
	FILE*fp=fopen(argv[1],"rb"),*fp_n = fopen(argv[3], "wb");
	
	//读取文件头、信息头 
	read_bmp_head(fp);
	//读取像素信息 
	read_bmp_data(fp);
	
	//计算长宽缩放比例 
	width_zoom_rate=height_zoom_rate=(atoi(argv[2]) /100.0);
	
	//结合最近邻插入法写入缩放后的图像信息 
	write_data(fp_n);
	//展示操作好的图像信息 
	read_bmp_head(fp_n);
	
	//关闭两个图像文件 
	fclose(fp);
	fclose(fp_n);

	return 0;
}
/*头文件使用说明:
在主程序中:extern double height_zoom_rate,width_zoom_rate;并赋值方可正常运行
包含三个函数:
void read_bmp_head(FILE*fp); 
void read_bmp_data(FILE*fp);
void write_data(FILE* fp_n); 
*/ 
#include<stdio.h>
#include<stdlib.h>
//改对取模数为1个字节(默认为8,只可是2^n)
#pragma pack(1)
//存储一个像素信息的三元素字符数组 
typedef unsigned char pixel[3];
//文件头信息
typedef struct tagBITMAPFILEHEADER
{
	unsigned short bfType;		 //保存图片类型。 'BM'(1-2字节) 
	unsigned long bfSize; 	 //位图文件的大小,以字节为单位(3-6字节,低位在前)
	unsigned short bfReserved1;//位图文件保留字,必须为0(7-8字节)
	unsigned short bfReserved2;//位图文件保留字,必须为0(9-10字节)
	unsigned long bfOffBits;  //RGB数据偏移地址,位图数据的起始位置,以相对于位图(11-14字节,低位在前)
}BITMAP_FILE_HEADER;
//信息头信息
typedef struct tagBITMAPINFOHEADER
{
	unsigned long 	biSize; 		 //本结构所占用字节数(15-18字节)
	unsigned long  biWidth; 	 //位图的宽度,以像素为单位(19-22字节)
	unsigned long  biHeight; 	 //位图的高度,以像素为单位(23-26字节)
	unsigned short biPlanes; 	 //目标设备的级别,必须为1(27-28字节)
	unsigned short biBitCount;  //每个像素所需的位数,必须是1(双色)(29-30字节),4(16色),8(256色)16(高彩色)或24(真彩色)之一

	unsigned long  biCompression;//位图压缩类型,必须是0(不压缩),(31-34字节)
	//1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一

	unsigned long  biSizeImage;  //位图的大小(其中包含了为了补齐每行字节数是4的倍数而添加的空字节),以字节为单位(35-38字节)

	unsigned long  biXPelsPerMeter;//位图水平分辨率,每米像素数(39-42字节)
	unsigned long  biYPelsPerMeter;//位图垂直分辨率,每米像素数(43-46字节)
	unsigned long  biClrUsed; 		 //位图实际使用的颜色表中的颜色数(47-50字节)
	unsigned long  biClrImportant; //位图显示过程中重要的颜色数(51-54字节)
}BITMAP_INFO_HEADER;

//全局变量说明:src_:原图宽高;dst_:缩放后宽高;pad_num:每行补齐空字节数;
//f_size: bfSize; b_size: biSizeImage; _zoom_rate: 宽高缩放倍数;sign:是否没计算过宽高标志 
int sign1=1;
int src_width,src_height,dst_width,dst_height;
int pad_num,f_size,b_size;
double height_zoom_rate,width_zoom_rate;
unsigned char *buf=NULL,*bui=NULL;
//创建两个结构体存储文件头和信息头信息 
BITMAP_FILE_HEADER file_head;
BITMAP_INFO_HEADER info_head;
//info指向像素信息的头地址,以info[i](=*(info+i))访问第i个像素 
pixel *info=NULL;

//读取文件头和信息头的信息 
void read_bmp_head(FILE*fp){
	
	if ( fp == NULL ) {
		printf("file doesn't exist!\n");
		exit(0);
	}
	rewind(fp); 

	//读取信息 
	fread(&file_head, sizeof(BITMAP_FILE_HEADER), 1, fp);
	fread(&info_head, sizeof(BITMAP_INFO_HEADER), 1, fp);
	
	//因为信息是小端对齐,以字节为单位方便读取 
	buf=(unsigned char*)&file_head;
	printf("\nbfType:\t\t%c %c",buf[1],buf[0]);
	f_size=buf[5]*16*16*16*16*16*16+buf[4]*16*16*16*16+buf[3]*16*16+buf[2];
	printf("\nbfSize:\t\t%02x %02x %02x %02x   ----   %d",buf[5],buf[4],buf[3],buf[2],f_size);
	printf("\nbfReserved1:\t%02x %02x\nbfReserved2:\t%02x %02x",buf[7],buf[6],buf[9],buf[8]);
	printf("\nbf0ffbits:\t%02x %02x %02x %02x",buf[13],buf[12],buf[11],buf[10]); 
	printf("\n\n"); 
	
	bui=(unsigned char*)&info_head;
	printf("\nbiSize:\t\t%02x %02x %02x %02x",bui[3],bui[2],bui[1],bui[0]);
	src_width=bui[7]*16*16*16*16*16*16+bui[6]*16*16*16*16+bui[5]*16*16+bui[4];
	src_height=bui[11]*16*16*16*16*16*16+bui[10]*16*16*16*16+bui[9]*16*16+bui[8];
	printf("\nbiWidth:\t%02x %02x %02x %02x   ----   %d",bui[7],bui[6],bui[5],bui[4],src_width);
	printf("\nbiHeight:\t%02x %02x %02x %02x   ----   %d",bui[11],bui[10],bui[9],bui[8],src_height);
	printf("\nbiPlans:\t%02x %02x",bui[13],bui[12]);
	printf("\nbiBitCount:\t%02x %02x",bui[15],bui[14]);
	printf("\nbiCompression:\t%02x %02x %02x %02x",bui[19],bui[18],bui[17],bui[16]);
	b_size=bui[23]*16*16*16*16*16*16+bui[22]*16*16*16*16+bui[21]*16*16+bui[20];
	printf("\nbiSizeImage:\t%02x %02x %02x %02x   ----   %d",bui[23],bui[22],bui[21],bui[20],b_size);
	printf("\nbiXPelsPerMeter:%02x %02x %02x %02x",bui[27],bui[26],bui[25],bui[24]);
	printf("\nbiYPelsPerMeter:%02x %02x %02x %02x",bui[31],bui[30],bui[29],bui[28]);
	printf("\nbiClrUsed:\t%02x %02x %02x %02x",bui[35],bui[34],bui[33],bui[32]);
	printf("\nbiClrImportant:\t%02x %02x %02x %02x\n",bui[39],bui[38],bui[37],bui[36]);
	
	sign1=0; 
}
	
//将照片像素信息读取,通过全局变量info访问 
void read_bmp_data(FILE*fp){
	
	void read_bmp_head(FILE*fp);
	if ( fp == NULL ) {
		printf("file doesn't exist!\n");
		exit(0);
	}
	//判断是否计算好了图像的长宽,没有则执行 
	if(sign1){
		rewind(fp);
		read_bmp_head(fp);
	}
	
	int i,j,k;

	//填充字节数 
	pad_num=(4-(src_width*3)%4)%4;
	//开辟空间 
	info=(pixel*)malloc(src_width*src_height*sizeof(pixel));
	
	//读取像素信息RGB 
	for(i=0;i<src_height;i++){
		for(j=0;j<src_width;j++){
			info[i*src_width+j][0]=fgetc(fp);
			info[i*src_width+j][1]=fgetc(fp);
			info[i*src_width+j][2]=fgetc(fp);
		}
		//读掉填充字节 
		for(k=0;k<pad_num;k++)fgetc(fp);
	}
	
}

//将信息写入新文件 
void write_data(FILE* fp_n) {
	
	rewind(fp_n);
	dst_width=(int)(width_zoom_rate*src_width);
	dst_height=(int)(height_zoom_rate*src_height);
	
	//文件头信息修改、拷贝(小对齐,故用&、>>位操作) 
	int f_size=dst_width*dst_height+54,i,j,k;
	buf[2]=0x000000FF&f_size;
	buf[3]=(0x0000FF00&f_size)>>8;
	buf[4]=(0x00FF0000&f_size)>>16;
	buf[5]=(0xFF000000&f_size)>>24;
	
	for(i=0;i<14;i++)fputc(buf[i],fp_n);
	
	//信息头信息修改、拷贝 
	bui[4]=0x000000FF&dst_width;
	bui[5]=(0x0000FF00&dst_width)>>8;
	bui[6]=(0x00FF0000&dst_width)>>16;
	bui[7]=(0xFF000000&dst_width)>>24;
	bui[8]=0x000000FF&dst_height;
	bui[9]=(0x0000FF00&dst_height)>>8;
	bui[10]=(0x00FF0000&dst_height)>>16;
	bui[11]=(0xFF000000&dst_height)>>24;
	
	pad_num= (4-(dst_width*3)%4)%4;
	b_size=dst_height*(dst_width+pad_num)*3;
	bui[20]=0x000000FF&b_size;
	bui[21]=(0x0000FF00&b_size)>>8;
	bui[22]=(0x00FF0000&b_size)>>16;
	bui[23]=(0xFF000000&b_size)>>24; 
	
	for(i=0;i<40;i++)fputc(bui[i],fp_n);
	
	int si,sj;
	
	//像素信息写入 
	for(i=0;i<dst_height;i++){
		si=i/height_zoom_rate;
		for(j=0;j<dst_width;j++){
			//最近邻插入法 
			sj=j/width_zoom_rate;
			fwrite(&info[si*src_width+sj],sizeof(pixel),1,fp_n);
		}
		for(k=0;k<pad_num;k++)fputc(0,fp_n);
	}
	/*
	//不行的写法!低效且数值越界 
	for(i=0;i<dst_height;i++){
		for(j=0;j<dst_width;j++){
			//最近邻插入法 
			fwrite(&info[(int)(i*src_width/height_zoom_rate+j/width_zoom_rate)],sizeof(pixel),1,fp_n);
		}
		for(k=0;k<pad_num;k++)fputc(0,fp_n);
	}
	*/
}

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

switch_swq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值