RGB24/RGBA生成BMP图片代码

本文详细介绍了BMP文件的结构,包括文件头、位图信息头、颜色表和位图数据四个部分,并提供了将PNG文件通过ffmpeg转换为BGR或BGRA格式的数据,然后利用C语言实现将这些数据保存为BMP文件的函数。代码示例展示了如何将128x128的PNG文件转换为BMP文件,涉及位图数据的字节顺序处理和颜色格式的转换。
摘要由CSDN通过智能技术生成

一、BMP文件由文件头、位图信息头、颜色信息和图形数据四部分组成

1、BMP文件头(14字节)

typedef struct                       /**** BMP file header structure ****/  
{  
    unsigned int   bfSize;           /* Size of file */  
    unsigned short bfReserved1;      /* Reserved */  
    unsigned short bfReserved2;      /* ... */  
    unsigned int   bfOffBits;        /* Offset to bitmap data */  
} BITMAPFILEHEADER; 

2、位图信息头(40字节)

typedef struct                       /**** BMP file info structure ****/  
{  
    unsigned int   biSize;           /* Size of info header */  
    int            biWidth;          /* Width of image */  
    int            biHeight;         /* Height of image */  
    unsigned short biPlanes;         /* Number of color planes */  
    unsigned short biBitCount;       /* Number of bits per pixel */  
    unsigned int   biCompression;    /* Type of compression to use */  
    unsigned int   biSizeImage;      /* Size of image data */  
    int            biXPelsPerMeter;  /* X pixels per meter */  
    int            biYPelsPerMeter;  /* Y pixels per meter */  
    unsigned int   biClrUsed;        /* Number of colors used */  
    unsigned int   biClrImportant;   /* Number of important colors */  
} BITMAPINFOHEADER;  

3、颜色表

颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。RGBQUAD结构的定义如下:

typedef struct tagRGBQUAD{  
    BYTErgbBlue;//蓝色的亮度(值范围为0-255)  
    BYTErgbGreen;//绿色的亮度(值范围为0-255)  
    BYTErgbRed;//红色的亮度(值范围为0-255)  
    BYTErgbReserved;//保留,必须为0  
} RGBQUAD;  

颜色表中的RGBQUAD结构数据的个数由biBitCount来确定:当biBitCount=1,4,8时,分别为2,16,256个表项;当biBitCount=24时,没有颜色表项。

???RGBQUAD还不知道怎么用。

4、位图数据
位图 数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:
当biBitCount=1时,8个像素占1个字节;
当biBitCount=4时,2个像素占1个字节;
当biBitCount=8时,1个像素占1个字节;
当biBitCount=24时,1个像素占3个字节,按顺序分别为B,G,R;

当biBitCount=32时,1个像素占3个字节,按顺序分别为B,G,R;

对应的,在通过ffmpeg获取位图数据的时候需要指定数据格式,这里以biBitCount=24和biBitCount=32为例子分别加以说明:

a. biBitCount=24

ffmpeg -i origin.png -s 128x128 -pix_fmt bgr24 origin.rgb

b. biBitCount=32

ffmpeg -i origin.png -s 128x128 -pix_fmt bgra origin.rgb

二、将rgb数据保存为bmp图片的方法

1.bgr24数据与bmp图片像素的对应关系(bgra据此类推)

bmp图片每个像素点按bgr24的格式存放颜色数据。

2.将bgr24数据保存成bmp图片的函数实现

void MySaveBmp(const char *filename,unsigned char *rgbbuf,int width,int height)  
{  
    BITMAPFILEHEADER bfh;  
    BITMAPINFOHEADER bih;  
    /* 
     * Magic number for file. It does not fit in the header structure due to 
     * alignment requirements, so put it outside 
     * 文件的魔术字,由于对齐的需要,没办法将魔术字作为BITMAPFILEHEADER的成员,所以
     * 这里将魔术字放在BITMAPFILEHEADER开头外面的位置。
     */  
    unsigned short bfType=0x4d42;    //'BM'             
    bfh.bfReserved1 = 0;  
    bfh.bfReserved2 = 0;  
    bfh.bfSize = 2/* 2B魔术字 */+sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+width*height*3;  
    bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);  
  
    bih.biSize = sizeof(BITMAPINFOHEADER);  
    bih.biWidth = width;  
    bih.biHeight = height;  
    bih.biPlanes = 1;  
    bih.biBitCount = 24;  
    bih.biCompression = 0;  
    bih.biSizeImage = 0;  
    bih.biXPelsPerMeter = 5000;  
    bih.biYPelsPerMeter = 5000;  
    bih.biClrUsed = 0;  
    bih.biClrImportant = 0;  
  
    FILE *file = fopen(filename, "wb");  
    if (!file)  
    {  
        printf("Could not write file\n");  
        return;  
    }  
  
    /*Write headers*/  
    fwrite(&bfType,sizeof(bfType),1,file);  
    fwrite(&bfh,sizeof(bfh),1, file);  
    fwrite(&bih,sizeof(bih),1, file);  
  
    fwrite(rgbbuf,width*height*3,1,file);  
    fclose(file);  
}  

三.完整代码(将一个128 * 128的png文件转换成bmp文件,bgr24格式)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct                       /**** BMP file header structure ****/  
{  
    unsigned int   bfSize;           /* Size of file */  
    unsigned short bfReserved1;      /* Reserved */  
    unsigned short bfReserved2;      /* ... */  
    unsigned int   bfOffBits;        /* Offset to bitmap data */  
} BITMAPFILEHEADER;

typedef struct                       /**** BMP file info structure ****/  
{  
    unsigned int   biSize;           /* Size of info header */  
    int            biWidth;          /* Width of image */  
    int            biHeight;         /* Height of image */  
    unsigned short biPlanes;         /* Number of color planes */  
    unsigned short biBitCount;       /* Number of bits per pixel */  
    unsigned int   biCompression;    /* Type of compression to use */  
    unsigned int   biSizeImage;      /* Size of image data */  
    int            biXPelsPerMeter;  /* X pixels per meter */  
    int            biYPelsPerMeter;  /* Y pixels per meter */  
    unsigned int   biClrUsed;        /* Number of colors used */  
    unsigned int   biClrImportant;   /* Number of important colors */  
} BITMAPINFOHEADER;  


void MySaveBmp(const char *filename,unsigned char *rgbbuf,int width,int height)  
{  
    BITMAPFILEHEADER bfh;  
    BITMAPINFOHEADER bih;  
    /* 
     * Magic number for file. It does not fit in the header structure due to 
     * alignment requirements, so put it outside 
     * 文件的魔术字,由于对齐的需要,没办法将魔术字作为BITMAPFILEHEADER的成员,所以
     * 这里将魔术字放在BITMAPFILEHEADER开头外面的位置。
     */  
    unsigned short bfType=0x4d42;    //'BM'             
    bfh.bfReserved1 = 0;  
    bfh.bfReserved2 = 0;  
    bfh.bfSize = 2/* 2B魔术字 */+sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+width*height*3;  
    bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);  
  
    bih.biSize = sizeof(BITMAPINFOHEADER); 

    printf("filesize = %u header size = %u \n", bfh.bfSize, bfh.bfOffBits);

    bih.biWidth = width;  
    bih.biHeight = height;  
    bih.biPlanes = 1;  
    bih.biBitCount = 24;  
    bih.biCompression = 0;  
    bih.biSizeImage = 0;  
    bih.biXPelsPerMeter = 5000;  
    bih.biYPelsPerMeter = 5000;  
    bih.biClrUsed = 0;  
    bih.biClrImportant = 0;  
  
    FILE *file = fopen(filename, "w+");  
    if (!file)  
    {  
        printf("Could not write file\n");  
        return;  
    }  
  
    /*Write headers*/  
    fwrite(&bfType,sizeof(bfType),1,file);  
    fwrite(&bfh,sizeof(bfh),1, file);  
    fwrite(&bih,sizeof(bih),1, file);  
  
    fwrite(rgbbuf,width*height*3,1,file);  
    fclose(file);  
}

int main(void)
{
    unsigned int len = 0, i = 0;
    unsigned char *dest = NULL;
    unsigned char *dest2 = NULL;
    int ret = 0;

    dest = (char *)malloc(sizeof(unsigned char) * 3 * 128 * 128);
    if(!dest) {
        ret = -1;
        goto fail;
    }

    dest2 = (char *)malloc(sizeof(unsigned char) * 3 * 128 * 128);
    if(!dest2) {
        ret = -1;
        goto fail;
    }

    ret = system("ffmpeg -i origin.png -s 128x128 -pix_fmt bgr24 origin.rgb");
    if(ret)
        goto fail;

    FILE *fp = fopen("origin.rgb", "r");
    if(!fp) {
        ret = 1;
        goto fail;
    }
    
    ret = fseek(fp, 0, SEEK_END);       //读写位置指针移动到文件尾
    if(ret) {
        ret = -1;
        goto fail;
    }

    len = ftell(fp);
    if(!len) {
        ret = -1;
        goto fail;
    }

    ret = fseek(fp, 0, SEEK_SET);         //读写位置指针移动到文件头
    if(ret) {
        ret = -1;
        goto fail;
    }

    len = fread(dest, sizeof(unsigned char), len, fp);
    if(!len) {
        ret = -1;
        goto fail;
    }

    fclose(fp);

    for(i = 0; i < 128; i++)
        memcpy(&dest2[i * sizeof(unsigned char) * 3 * 128], &dest[(127-i) * sizeof(unsigned char) * 3 * 128], sizeof(unsigned char) * 3 * 128);

    MySaveBmp("origin.bmp", dest2, 128, 128);

    ret = system("rm -rf origin.rgb");

fail:
    free(dest);
    free(dest2);
    return ret;
}

四.完整代码(将一个128 * 128的png文件转换成bmp文件,bgra格式)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct                       /**** BMP file header structure ****/  
{  
    unsigned int   bfSize;           /* Size of file */  
    unsigned short bfReserved1;      /* Reserved */  
    unsigned short bfReserved2;      /* ... */  
    unsigned int   bfOffBits;        /* Offset to bitmap data */  
} BITMAPFILEHEADER;

typedef struct                       /**** BMP file info structure ****/  
{  
    unsigned int   biSize;           /* Size of info header */  
    int            biWidth;          /* Width of image */  
    int            biHeight;         /* Height of image */  
    unsigned short biPlanes;         /* Number of color planes */  
    unsigned short biBitCount;       /* Number of bits per pixel */  
    unsigned int   biCompression;    /* Type of compression to use */  
    unsigned int   biSizeImage;      /* Size of image data */  
    int            biXPelsPerMeter;  /* X pixels per meter */  
    int            biYPelsPerMeter;  /* Y pixels per meter */  
    unsigned int   biClrUsed;        /* Number of colors used */  
    unsigned int   biClrImportant;   /* Number of important colors */  
} BITMAPINFOHEADER;  


void MySaveBmp(const char *filename,unsigned char *rgbbuf,int width,int height)  
{  
    BITMAPFILEHEADER bfh;  
    BITMAPINFOHEADER bih;  
    /* 
     * Magic number for file. It does not fit in the header structure due to 
     * alignment requirements, so put it outside 
     * 文件的魔术字,由于对齐的需要,没办法将魔术字作为BITMAPFILEHEADER的成员,所以
     * 这里将魔术字放在BITMAPFILEHEADER开头外面的位置。
     */  
    unsigned short bfType=0x4d42;    //'BM'             
    bfh.bfReserved1 = 0;  
    bfh.bfReserved2 = 0;  
    bfh.bfSize = 2/* 2B魔术字 */+sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+width*height*4;  
    bfh.bfOffBits = 2/* 2B魔术字 */ + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);  
  
    bih.biSize = sizeof(BITMAPINFOHEADER); 

    printf("filesize = %u header size = %u \n", bfh.bfSize, bfh.bfOffBits);

    bih.biWidth = width;  
    bih.biHeight = height;  
    bih.biPlanes = 1;  
    bih.biBitCount = 32;  //一个像素对应的32bit
    bih.biCompression = 0;  
    bih.biSizeImage = 0;  
    bih.biXPelsPerMeter = 5000;  
    bih.biYPelsPerMeter = 5000;  
    bih.biClrUsed = 0;  
    bih.biClrImportant = 0;  
  
    FILE *file = fopen(filename, "w+");  
    if (!file)  
    {  
        printf("Could not write file\n");  
        return;  
    }  
  
    /*Write headers*/  
    fwrite(&bfType,sizeof(bfType),1,file);  
    fwrite(&bfh,sizeof(bfh),1, file);  
    fwrite(&bih,sizeof(bih),1, file);  
  
    fwrite(rgbbuf,width*height*4,1,file);  
    fclose(file);  
}

int main(void)
{
    unsigned int len = 0, i = 0;
    unsigned char *dest = NULL;
    unsigned char *dest2 = NULL;
    int ret = 0;

    printf("unsigned int = %ld\n", sizeof(unsigned int));
    printf("unsigned short = %ld\n", sizeof(unsigned short));

    dest = (char *)malloc(sizeof(unsigned char) * 4 * 128 * 128);
    if(!dest) {
        ret = -1;
        goto fail;
    }

    dest2 = (char *)malloc(sizeof(unsigned char) * 4 * 128 * 128);
    if(!dest2) {
        ret = -1;
        goto fail;
    }

    ret = system("ffmpeg -i origin.png -s 128x128 -pix_fmt bgra origin.rgb");
    if(ret)
        goto fail;

    FILE *fp = fopen("origin.rgb", "r");
    if(!fp) {
        ret = 1;
        goto fail;
    }
    
    ret = fseek(fp, 0, SEEK_END);       //读写位置指针移动到文件尾
    if(ret) {
        ret = -1;
        goto fail;
    }

    len = ftell(fp);
    if(!len) {
        ret = -1;
        goto fail;
    }

    ret = fseek(fp, 0, SEEK_SET);         //读写位置指针移动到文件头
    if(ret) {
        ret = -1;
        goto fail;
    }

    len = fread(dest, sizeof(unsigned char), len, fp);
    if(!len) {
        ret = -1;
        goto fail;
    }
    printf("bgra file len= %u\n", len);

    fclose(fp);

    for(i = 0; i < 128; i++)
        memcpy(&dest2[i * sizeof(unsigned char) * 4 * 128], &dest[(127-i) * sizeof(unsigned char) * 4 * 128], sizeof(unsigned char) * 4 * 128);

    MySaveBmp("origin.bmp", dest2, 128, 128);

    ret = system("rm -rf origin.rgb");

fail:
    free(dest);
    free(dest2);
    return ret;
}

参考文章:(14条消息) 图片格式之RGB转BMP格式(含代码)_Huo的藏经阁的博客-CSDN博客_rgb转bmp/

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

denglin12315

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

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

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

打赏作者

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

抵扣说明:

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

余额充值