135 lines
5.1 KiB
C++
135 lines
5.1 KiB
C++
#include<stdio.h>
|
||
#include<stdlib.h>
|
||
#include<string.h>
|
||
#include <stdlib.h>
|
||
#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;
|
||
}
|