RGB24转BMP实现

/*
    RGB24转BMP
    BMP图像内部实际上存储的就是RGB数据,
    BMP格式:
    |---------------------------------|
    | bmp文件头bitmap_file_header(14)    |
    |-------------------------------- |
    |位图信息头bitmap_info_header(40)      |
    |---------------------------------|
    |          位图数据                   |
    |---------------------------------|
*/

#ifdef WIN32
    #pragma pack(1)
    #define PACKED_ALIGN
#else
    #define PACKED_ALIGN __attribute__((packed))
#endif


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

// bitmap file header
typedef struct BitmapFileHeader
{
    char identifier[2];            //文件类型,必须为BM
    unsigned int   fileSize;       //整个BMP文件大小,单位字节
    unsigned short reserved1;      //保留,必须为0
    unsigned short reserved2;      //保留,必须为0
    unsigned int   dataOffset;     //文件头到实际图像数据之间的偏移
} PACKED_ALIGN BITMAP_FILE_HEADER;

// bitmap info header
typedef struct BitmapInfoHeader
{
    unsigned int infoSize;          //BitmapInfoHeader结构体大小,单位字节
    unsigned int width;             //图形宽度,单位像素
    unsigned int height;            //图形高度,单位像素
    short planes;                   //目标设备级别,必须为1
    short bitsPerPixel;             //颜色深度,每个像素所需的位数
    unsigned int compression;       //位图的压缩类型
    unsigned int dataSize;          //位图的大小,单位字节
    unsigned int hresolution;       //位图水平分辨率,每米像素数
    unsigned int vresolution;       //位图垂直分辨率,每米像素数
    unsigned int useColors;         //位图实际使用的颜色表中的颜色数
    unsigned int importantColors;   //位图显示过程中重要的颜色数
} PACKED_ALIGN BITMAP_INFO_HEADER;

// 将rgb24图片转成bmp图像
int rgb24_to_bmp(const char *file_rgb24, int width, int height, const char *file_bmp)
{
    int i = 0;
    int j = 0;
    BITMAP_FILE_HEADER bmpFileHeader = {0};
    BITMAP_INFO_HEADER bmpInfoHeader = {0};
    FILE *fp_rgb24 = NULL;
    FILE *fp_bmp = NULL;

    unsigned int headSize = sizeof(BITMAP_FILE_HEADER) + sizeof(BITMAP_INFO_HEADER);

    if ((fp_rgb24 = fopen(file_rgb24, "rb")) == NULL)
    {
        printf("fopen error: cannot open file %s\n", file_rgb24);
        return -1;
    }

    if ((fp_bmp = fopen(file_bmp, "wb")) == NULL)
    {
        printf("fopen error: cannot open file %s\n", file_bmp);
        fclose(fp_rgb24);
        return -1;
    }

    unsigned int   rgb24_size = width * height * 3;
    unsigned char *rgb24_buf = (unsigned char *)malloc(rgb24_size);
    if (rgb24_buf == NULL)
    {
        printf("malloc error: alloc rgb24 memory fail\n");
        fclose(fp_rgb24);
        fclose(fp_bmp);
        return -1;
    }

    fread(rgb24_buf, 1, rgb24_size, fp_rgb24);

    // 填充bmpFileHeader结构体
    bmpFileHeader.identifier[0] = 'B';
    bmpFileHeader.identifier[1] = 'M';
    bmpFileHeader.fileSize = headSize + rgb24_size;
    bmpFileHeader.reserved1 = 0;
    bmpFileHeader.reserved2 = 0;
    bmpFileHeader.dataOffset = headSize;

    // 填充bmpInfoHeader结构体
    bmpInfoHeader.infoSize = sizeof(BITMAP_INFO_HEADER);
    bmpInfoHeader.width = width;

    // BMP在Y轴的相反方向(从下到上)存储像素数据, height取反
    bmpInfoHeader.height = -height;
    bmpInfoHeader.planes = 1;
    bmpInfoHeader.bitsPerPixel = 24;
    bmpInfoHeader.dataSize = rgb24_size;

    //printf("sizeof(BITMAP_FILE_HEADER): %d\n", sizeof(BITMAP_FILE_HEADER));
    //printf("sizeof(BITMAP_INFO_HEADER): %d\n", sizeof(BITMAP_INFO_HEADER));

    // 写bitmap file header
    fwrite(&bmpFileHeader, 1, sizeof(BITMAP_FILE_HEADER), fp_bmp);

    // 写bitmap info header
    fwrite(&bmpInfoHeader, 1, sizeof(BITMAP_INFO_HEADER), fp_bmp);

    /* 写rgb数据 */
    /* BMP是按小端格式存储RGB数据,低地址存低位数据,高地址存高位数据
       RGB一个像素是按R|G|B排列,转BMP时需要按小端格式存储RGB值,小端格式需要将
       RGB排列转换成BGR排列

       二进制高低位
       00011000 00011100 00000000
       高位                    低位

       内存地址
       -------------------------->
       低地址 往右地址增加 高地址
       所以Little Endian小端格式需要将右端的低位与左端的高位调换
    */

    for (j = 0; j < height; j++)
    {
        for (i = 0; i < width; i++)
        {
            // 获取第j行的第i个像素的B
            char temp = rgb24_buf[(j * width + i) * 3 + 2];
            // 将第j行的第i个像素的R值赋值给第j行的第i个像素的B
            rgb24_buf[(j * width + i) * 3 + 2] = rgb24_buf[(j * width + i) * 3 + 0];
            // 将原第j行的第i个像素的B值赋值给第j行的第i个像素的R
            rgb24_buf[(j * width + i) * 3 + 0] = temp;
        }
    }

    // 写RGB数据
    fwrite(rgb24_buf, 1, rgb24_size, fp_bmp);
    fclose(fp_rgb24);
    fclose(fp_bmp);
    free(rgb24_buf);

    return 0;
}

int main(void)
{
    const char *file_rgb24 = "lena_256x256_rgb24.rgb";
    const char *file_bmp = "output_lena.bmp";

    return rgb24_to_bmp(file_rgb24, 256, 256, file_bmp);
}

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要实现24BMP8位BMP,需要进行以下步骤: 首先,读取24BMP文件的头部信息,包括文件大小、宽度、高度和颜色位数等信息。可以使用相关的bmp库或者自定义函数来读取头部信息。 接下来,创建一个新的8位BMP文件,并设置其头部信息。新文件的宽度和高度与原文件相同,但是颜色位数为8位。 然后,需要对每个像素点进行颜色换。由于8位BMP只能表示256种颜色,而24BMP可以表示更多的颜色,因此需要将24位颜色值映射到8位颜色值。这可以通过查表的方式实现。可以创建一个颜色映射表,包含256个颜色值,将原24位颜色对应地映射到8位颜色。 接下来,遍历所有像素点,将24位颜色值换为对应的8位颜色值。可以使用像素点的RGB值在颜色映射表中查找对应的索引,得到8位颜色值,并将其写入新的8位BMP文件。 最后,将新的8位BMP文件保存到指定的路径中。 需要注意的是,在颜色换过程中可能会出现颜色丢失的情况。因为8位BMP只能表示256种颜色,而24BMP可以表示更多的颜色,所以在换过程中,可能会出现某些颜色无法准确映射的情况。可以考虑使用一些颜色量化算法,如误差扩散等,来尽量减少颜色丢失的程度。 ### 回答2: 将24BMP换为8位BMP可以简单地理解为将每个像素点的RGB换为相应的8位灰度值。下面是一种可能的实现方法: 1. 读取24BMP文件的头部信息,包括像的宽度、高度和像素位深度等。 2. 创建一个新的8位BMP文件,并设置相应的头部信息,如宽度、高度和像素位深度为8位。 3. 遍历24BMP文件中的每个像素点。 4. 对于每个像素点,获取其RGB值,即红色、绿色和蓝色的分量。 5. 将RGB换为灰度值,可以使用以下公式:Gray = (0.299 * R) + (0.587 * G) + (0.114 * B),其中R、G和B分别表示红、绿和蓝的分量值。 6. 将灰度值存储到新创建的8位BMP文件对应的像素点位置。 7. 重复步骤3-6,直到遍历完所有的像素点。 8. 将换后的8位BMP文件保存到磁盘上。 这样,就完成了将24BMP文件换成8位BMP文件的过程。通过将RGB换为灰度值,可以将原本的24位色彩表示缩减为256级灰度表示,实现了从24BMP到8位BMP换。 ### 回答3: 实现24BMP8位BMP的过程中,主要需要做以下几个步骤: 1. 首先读取24BMP文件的头文件信息,包括像的宽度、高度、颜色深度等信息。 2. 创建一个8位BMP文件的头文件,并将相应的信息填写进去,包括像的宽度、高度、颜色深度等。 3. 创建一个256色的调色板,用来储存颜色索引值。这里需要注意,由于8位BMP最大只能表示256种颜色,所以需要对原始24BMP中的所有颜色进行量化处理,将其映射到256色调色板中。 4. 逐个像素地将24BMP像中的RGB值映射到对应的索引值,并写入到8位BMP文件中,形成新的像。 5. 最后保存修改后的8位BMP文件。 在实现的过程中,我们可以使用编程语言如C或Python来进行操作。通过读取和写入文件的操作,以及相应的数值处理和位运算等操作,可以实现24BMP8位BMP的功能。 总之,实现24BMP8位BMP需要读取原始BMP像信息,创建8位BMP文件头部和调色板,对原始颜色进行量化处理和映射,最后将映射后的颜色值写入新的8位BMP文件中。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值