对24位bmp图像实现等比例缩放

并保存缩放后的文件,如何修改下列代码


#include 
#include 
#include 
using namespace std;
#pragma pack(1)//结构体中各成员按1字节对齐

struct BITMAPFILEHEADER//定义一个存储头文件数据结构体
{
    unsigned short bfType;        // 保存文件类型。'BM'
    unsigned long bfSize;        //位图文件总字节数
    unsigned short bfReserved1; //位图文件保留字段,必须为0
    unsigned short bfReserved2; //位图文件保留字段,必须为0
    unsigned long bfOffBits;    //RGB数据偏移地址,位图数据起始位置
    };

struct BITMAPINFOHEADER//定义一个存储位图信息的结构体
{
    unsigned long biSize;           //本结构占用字节数
    unsigned long biWidth;           //位图像素宽度
    unsigned long biHeight;           //位图像素高度
    unsigned short biPlanes;       // bmp图片的平面数量,为1
    unsigned short biBitCount;       //每个像素所占的位数
    unsigned long biCompression;   //位图压缩类型,不压缩(为0)
    unsigned long biSizeImage;       //位图图像数据所占字节数
    unsigned long biXPelsPerMeter; //位图水平分辨率,每米像素数
    unsigned long biYPelsPerMeter; //位图垂直分辨率,每米像素数
    unsigned long biClrUsed;       //位图实际使用的颜色表中的颜色数
    unsigned long biClrImportant;  //位图显示过程中重要的颜色数
};

//zoom函数用于缩放,BITMAPFILEHEADER head, BITMAPINFOHEADER info为原图像头信息,缩放倍数为2,char字符串类型指针变量
void zoom(BITMAPFILEHEADER head, BITMAPINFOHEADER info, char *input, char *output, double rate)
{//r:打开文件仅供读取,w:打开文件仅供写入,b:二进制
    FILE *fr = fopen(input, "rb");
    FILE *fw = fopen(output, "wb");

    //若读取不成功
    if (fr == NULL || fw == NULL)
    {
        printf("图片错误\n");
        return;
    }

    //读取原图像的头信息
    fread(&head, sizeof(BITMAPFILEHEADER), 1, fr);
    fread(&info, sizeof(BITMAPINFOHEADER), 1, fr);

    unsigned int old_Width = info.biWidth;//获取原图像的宽信息
    unsigned int old_height = info.biHeight;//获取原图像的高信息
    unsigned char *old_data = (unsigned char *)malloc(old_Width * old_height * 3);//获取原图像的位图数据

    ////定位到图像数据位置
    fseek(fr, 54, SEEK_SET);
    fread(old_data, old_Width * old_height * 3, 1, fr);

    //修改原图像的宽高
    unsigned int new_Width, new_Height;

    new_Width = (int)(rate * old_Width);//新宽等于倍数乘原宽
    new_Height = (int)(rate * old_height);//新高等于倍数乘原高
//修改头信息
    head.bfSize = new_Width * new_Height * 3 + 54;

    info.biWidth = new_Width;
    info.biHeight = new_Height;

    //将修改后的头信息写进新图像
    fwrite(&head, sizeof(BITMAPFILEHEADER), 1, fw);
    fwrite(&info, sizeof(BITMAPINFOHEADER), 1, fw);

    //缩放数据
    int i = 0, j = 0;
    unsigned long X, Y;
    unsigned char *pd;
    unsigned char *ps;
    unsigned char *new_data = (unsigned char *)malloc(new_Width * new_Height * 3);

    for (i = 0; i < new_Height; i++)
    {
        Y = i / rate;
        pd = new_data + i * new_Width * 3;
        ps = old_data + Y * old_Width * 3;

        for (j = 0; j < new_Width; j++)
        {
            X = j / rate;
            memcpy(pd + j * 3, ps + X * 3, 3);//拷贝数据
        }
    }

    //新文件数据定位
    fseek(fw, 54, SEEK_SET);
    fwrite(new_data, new_Width * new_Height * 3, 1, fw);
    printf("已成功缩放图像\n");

    //释放空间
    free(new_data);
    free(old_data);

    //关闭fr,fw
    fclose(fr);
    fclose(fw);
}

int main(int argc, char *argv[])
{
    //申明存储图像数据的结构体
    BITMAPFILEHEADER old_head;
    BITMAPINFOHEADER old_info;

    //初始化结构体变量
    memset(&old_head, 0, sizeof(BITMAPFILEHEADER));
    memset(&old_info, 0, sizeof(BITMAPINFOHEADER));

    //将缩放比例转化为double类型
    double rate = atof(argv[2]) / 100.0;
    zoom(old_head, old_info, argv[1], argv[3], rate);

    return 0;
}

这是一个命令行程序,需要打开cmd,输入命令运行。如cmd进入程序所在的文件夹后,输入命令:图片缩放.exe "新建位图图像.bmp" 50 "缩放后的图像.bmp"
你的代码没有考虑bmp每行按4字节对齐的情况。
修改后的代码:

 
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#pragma pack(1)//结构体中各成员按1字节对齐
 
struct BITMAPFILEHEADER//定义一个存储头文件数据结构体
{
    unsigned short bfType;        // 保存文件类型。'BM'
    unsigned long bfSize;        //位图文件总字节数
    unsigned short bfReserved1; //位图文件保留字段,必须为0
    unsigned short bfReserved2; //位图文件保留字段,必须为0
    unsigned long bfOffBits;    //RGB数据偏移地址,位图数据起始位置
    };
 
struct BITMAPINFOHEADER//定义一个存储位图信息的结构体
{
    unsigned long biSize;           //本结构占用字节数
    unsigned long biWidth;           //位图像素宽度
    unsigned long biHeight;           //位图像素高度
    unsigned short biPlanes;       // bmp图片的平面数量,为1
    unsigned short biBitCount;       //每个像素所占的位数
    unsigned long biCompression;   //位图压缩类型,不压缩(为0)
    unsigned long biSizeImage;       //位图图像数据所占字节数
    unsigned long biXPelsPerMeter; //位图水平分辨率,每米像素数
    unsigned long biYPelsPerMeter; //位图垂直分辨率,每米像素数
    unsigned long biClrUsed;       //位图实际使用的颜色表中的颜色数
    unsigned long biClrImportant;  //位图显示过程中重要的颜色数
};
 
//zoom函数用于缩放,BITMAPFILEHEADER head, BITMAPINFOHEADER info为原图像头信息,缩放倍数为2,char字符串类型指针变量
void zoom(BITMAPFILEHEADER head, BITMAPINFOHEADER info, char *input, char *output, double rate)
{//r:打开文件仅供读取,w:打开文件仅供写入,b:二进制
    FILE *fr = fopen(input, "rb");
    FILE *fw = fopen(output, "wb");
 
    //若读取不成功
    if (fr == NULL || fw == NULL)
    {
        printf("图片错误\n");
        return;
    }
 
    //读取原图像的头信息
    fread(&head, sizeof(BITMAPFILEHEADER), 1, fr);
    fread(&info, sizeof(BITMAPINFOHEADER), 1, fr);
 
    unsigned int old_Width = info.biWidth;//获取原图像的宽信息
    unsigned int old_height = info.biHeight;//获取原图像的高信息
    unsigned char *old_data = (unsigned char *)malloc((old_Width * 3+3>>2<<2)*old_height);//获取原图像的位图数据
 
    ////定位到图像数据位置
    fseek(fr, 54, SEEK_SET);
    fread(old_data, (old_Width * 3+3>>2<<2)*old_height, 1, fr);
 
    //修改原图像的宽高
    unsigned int new_Width, new_Height;
 
    new_Width = (int)(rate * old_Width);//新宽等于倍数乘原宽
    new_Height = (int)(rate * old_height);//新高等于倍数乘原高
//修改头信息
    head.bfSize = (new_Width * 3+3>>2<<2) * new_Height + 54;
 
    info.biWidth = new_Width;
    info.biHeight = new_Height;
 
    //将修改后的头信息写进新图像
    fwrite(&head, sizeof(BITMAPFILEHEADER), 1, fw);
    fwrite(&info, sizeof(BITMAPINFOHEADER), 1, fw);
 
    //缩放数据
    int i = 0, j = 0;
    unsigned long X, Y;
    unsigned char *pd;
    unsigned char *ps;
    unsigned char *new_data = (unsigned char *)malloc((new_Width *3+3>>2<<2)* new_Height);
 
    for (i = 0; i < new_Height; i++)
    {
        Y = i / rate;
        pd = new_data + i * (new_Width * 3+3>>2<<2);
        ps = old_data + Y * (old_Width * 3+3>>2<<2);
 
        for (j = 0; j < new_Width; j++)
        {
            X = j / rate;
            memcpy(pd + j * 3, ps + X * 3, 3);//拷贝数据
        }
    }
 
    //新文件数据定位
    fseek(fw, 54, SEEK_SET);
    fwrite(new_data, (new_Width *3+3>>2<<2), new_Height, fw);
    printf("已成功缩放图像\n");
 
    //关闭fr,fw
    fclose(fr);
    fclose(fw); 
    
    //释放空间
    free(new_data);
    free(old_data);
}
 
int main(int argc, char *argv[])
{
    //申明存储图像数据的结构体
    BITMAPFILEHEADER old_head;
    BITMAPINFOHEADER old_info;
 
    //初始化结构体变量
    memset(&old_head, 0, sizeof(BITMAPFILEHEADER));
    memset(&old_info, 0, sizeof(BITMAPINFOHEADER));
 
    //将缩放比例转化为double类型
    double rate = atof(argv[2]) / 100.0;
    zoom(old_head, old_info, argv[1], argv[3], rate);
 
    return 0;
}

执行结果:

img

你已经实现了rate比例缩放功能,你只是要加一个保存操作是吗?你得到的new_data数据就是图像的数据,然后使用opencv创建以new_data的图像Mat,然后imwrite这个Mat即可保存到对应路径。