C语言读取和存储bmp格式图片

开发过程中有时候需要解析bmp数据,下面先简单介绍bmp数据组成,后面附上C语言读取和存储bmp格式图片代码。

典型的位图文件格式通常包含下面几个数据块:

1、BMP文件头:保存位图文件的总体信息。
2、位图信息头:保存位图图像的详细信息。位图信息:保存位图图像的详细信息。
3、调色板:保存所用颜色的定义。调色板:保存所用颜色的定义。
4、位图数据:保存一个又一个像素的实际图像。位图数据:保存一个又一个像素的实际图像。

1. BMP文件头(14字节)

BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。

这部分是识别信息,典型的应用程序会首先普通读取这部分数据以确保的确是位图文件并且没有损坏。

位图头结构体定义如下:

typedef struct
{
    uint16_t type;  //位图文件的类型,必须为BM(1-2字节)
    uint32_t size;  //位图文件的大小,以字节为单位(3-6字节,低位在前)
    uint16_t reserved1;  //位图文件保留字,必须为0(7-8字节)
    uint16_t reserved2;  //位图文件保留字,必须为0(9-10字节)
    uint32_t off_bits;  //位图数据位置的地址偏移,即起始位置,以相对于位图(11-14字节,低位在前)
}__attribute__ ((packed)) bmp_file_header_t;

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

这部分告诉应用程序图像的详细信息,在屏幕上显示图像将会使用这些信息,它从文件的第15个字节开始。

位图信息头结构体定义如下:

typedef struct
{
    uint32_t size;
    int32_t width;
    int32_t height;
    uint16_t planes;
    uint16_t bit_count;
    uint32_t compression;
    uint32_t size_image;
    uint32_t x_pels_permeter;
    uint32_t y_pels_permeter;
    uint32_t clr_used;
    uint32_t clr_important;
} bmp_info_header_t;

结构体变量解析如下:

  • uint32_t size; 15-18字节:定义以下用来描述影像的区块(BitmapInfoHeader)的大小,即本结构所占用字节数,它的值是:40
  • int32_t width; 19-22字节:位图宽度,以像素为单位。
  • int32_t height; 23-26字节:位图高度,以像素为单位。
  • uint16_t planes; 27-28字节:保存所用彩色位面的个数。不经常使用。
  • uint16_t bit_count; 29-30字节:保存每个像素的位数,它是图像的颜色深度。常用值是1(双色灰阶)、4(16色灰阶)、8(256色灰阶)和24(彩色)。
  • uint32_t compression; 31-34字节:定义所用的压缩算法。允许的值是0、1、2、3、4、5。
  • 0 - 没有压缩(也用BI_RGB表示)

1 - 行程长度编码 8位/像素(也用BI_RLE8表示)
2 - 行程长度编码4位/像素(也用BI_RLE4表示)
3 - Bit field(也用BI_BITFIELDS表示)
4 - JPEG图像(也用BI_JPEG表示)
5 - PNG图像(也用BI_PNG表示)

  • uint32_t size_image; 35-38字节:位图的大小(其中包含了为了补齐行数是4的倍数而添加的空字节),以字节为单位。这是原始位图数据的大小,不要与文件大小混淆。
  • uint32_t x_pels_permeter; 39-42字节:位图水平分辨率,每米像素数。
  • uint32_t y_pels_permeter; 43-46字节:位图垂直分辨率,每米像素数。
  • uint32_t clr_used; 47-50字节:位图实际使用的颜色表中的颜色数。
  • uint32_t clr_important; 51-54字节:位图显示过程中重要的颜色数,当每个颜色都重要时这个值与颜色数目(clr_used)相等。

3. 调色板

BMP调色板结构体定义如下:

typedef struct _tagRGBQUAD
{
BYTE  rgbBlue;       //指定蓝色强度
BYTE  rgbGreen;      //指定绿色强度
BYTE  rgbRed;        //指定红色强度
BYTE  rgbReserved;  //保留,设置为0
} RGBQUAD;

1,4,8位图像才会使用调色板数据,16,24,32位图像不需要调色板数据,即调色板最多只需要256项(索引0 - 255)。

颜色表的大小根据所使用的颜色模式而定:2色图像为8字节;16色图像位64字节;256色图像为1024字节。其中,每4字节表示一种颜色,并以B(蓝色)、G(绿色)、R(红色)、alpha(32位位图的透明度值,一般不需要)。即首先4字节表示颜色号1的颜色,接下来表示颜色号2的颜色,依此类推。

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

  • 当biBitCount=1时,为2色图像,BMP位图中有2个数据结构RGBQUAD,一个调色板占用4字节数据,所以2色图像的调色板长度为2*4为8字节。
  • 当biBitCount=4时,为16色图像,BMP位图中有16个数据结构RGBQUAD,一个调色板占用4字节数据,所以16像的调色板长度为16*4为64字节。
  • 当biBitCount=8时,为256色图像,BMP位图中有256个数据结构RGBQUAD,一个调色板占用4字节数据,所以256色图像的调色板长度为256*4为1024字节。
  • 当biBitCount=16,24或32时,没有颜色表。

4. 位图数据

位图数据记录了位图的每一个像素值。

像素是从下到上、从左到右保存的。

每个像素使用一个或者多个字节表示。

如果一个图像水平线的字节数不是4的倍数,这行就使用空字节补齐,通常是ASCII码0。

例如:

1、一张5 * 6的图片,有30个pixels,因为列数6不是4的倍数,所以会显示成:
xxxxxx00 xxxxxx00 xxxxxx00 xxxxxx00 xxxxxx00
其中,x代表调色盘的编号,0代表补齐的空字节

2、一张4 * 4的图片,有16个pixels,因为列数刚好是4的倍数,所以会显示成:
xxxx xxxx xxxx xxxx

C语言读取和存储bmp示例代码

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

typedef struct
{
    uint16_t type;
    uint32_t size;
    uint16_t reserved1;
    uint16_t reserved2;
    uint32_t off_bits;
}__attribute__ ((packed)) bmp_file_header_t;

typedef struct
{
    uint32_t size;
    int32_t width;
    int32_t height;
    uint16_t planes;
    uint16_t bit_count;
    uint32_t compression;
    uint32_t size_image;
    uint32_t x_pels_permeter;
    uint32_t y_pels_permeter;
    uint32_t clr_used;
    uint32_t clr_important;
} bmp_info_header_t;

static bmp_file_header_t s_bmp_file_header = { 0x4d42, 0, 0, 0, 0 };
static bmp_info_header_t s_bmp_info_header = { 0, 0, 0, 1, 8, 0, 0, 0, 0, 0, 0 };

static uint8_t s_bmpdata[200 * 200] = { 0 };
static uint32_t s_bmp_col = 0;
static uint32_t s_bmp_row = 0;
char in_file_path[256] = "in.bmp";
char out_file_path[256] = "out.bmp";

int32_t bmp_file_to_image(const char *file_path, uint8_t *image, uint32_t *col, uint32_t *row)
{
    FILE *file = NULL;
    uint32_t line_width = 0;
    uint32_t width = 0;
    uint32_t height = 0;
    int32_t err = 0;
    uint8_t buf[200 * 200] = { 0 };
    char temp[2048] = { 0 };
    int i = 0;

    do {
        if (NULL == file_path || NULL == image)
        {
            err = -1;
            break;
        }
        printf("[%s] file_path = %s\n", __func__, file_path);

        file = fopen(file_path, "rb");
        if (NULL == file)
        {
   err = -1;
            break;
        }
        fread(&s_bmp_file_header, sizeof(s_bmp_file_header), 1, file);

        fread(&s_bmp_info_header, sizeof(s_bmp_info_header), 1, file);
        fread(temp, 4*256, 1, file);
        width = s_bmp_info_header.width;
        height = s_bmp_info_header.height;
        *col = width;
        *row = height;
        line_width = (width + 3) / 4 * 4;
        printf("[%s] line_width = %d, width = %d, height = %d\n", __func__, line_width, width, height);

        for (i = height - 1; i >= 0; i--)
        {
   if (line_width == width)
   {
    fread(buf + i * width, width, 1, file);
      }
      else if (line_width > width)
   {
    fread(buf + i * width, width, 1, file);
    fread(temp, line_width-width, 1, file);
   }
        }
        memcpy(image, buf, width * height);

    } while (0);

    if (file != NULL)
    {
        fclose(file);
    }
    return err;
}

int32_t dump_image_to_bmp_file(const char *file_path, uint8_t *image, uint32_t width, uint32_t height)
{
    FILE *file = NULL;
    int32_t err = 0;

    do {
        if (NULL == file_path || NULL == image)
        {
            err = -1;
            break;
        }

        uint32_t line_width = (width + 3) / 4 * 4;
        s_bmp_file_header.off_bits = sizeof(bmp_file_header_t) + sizeof(bmp_info_header_t)
                + 4 * 256;
        s_bmp_file_header.size = s_bmp_file_header.off_bits + line_width * height;

        s_bmp_info_header.size = sizeof(bmp_info_header_t);
        s_bmp_info_header.width = width;
        s_bmp_info_header.height = height;
        s_bmp_info_header.size_image = line_width * height;

        printf("[%s] line_width = %d, width = %d, height = %d\n", __func__, line_width, width, height);

        file = fopen(file_path, "wb");
        if (NULL == file)
        {
   err = -1;
            break;
        }

        fwrite(&s_bmp_file_header.type, 1, sizeof(s_bmp_file_header.type), file);
        fwrite(&s_bmp_file_header.size, 1, sizeof(s_bmp_file_header.size), file);
        fwrite(&s_bmp_file_header.reserved1, 1, sizeof(s_bmp_file_header.reserved1), file);
        fwrite(&s_bmp_file_header.reserved2, 1, sizeof(s_bmp_file_header.reserved2), file);
        fwrite(&s_bmp_file_header.off_bits, 1, sizeof(s_bmp_file_header.off_bits), file);

        fwrite(&s_bmp_info_header, 1, sizeof(bmp_info_header_t), file);
        uint8_t alpha = 0;
        int32_t i;
        for (i = 0; i < 256; i++)
        {
            fwrite(&i, 1, sizeof(uint8_t), file);
            fwrite(&i, 1, sizeof(uint8_t), file);
            fwrite(&i, 1, sizeof(uint8_t), file);
            fwrite(&alpha, 1, sizeof(uint8_t), file);
        }

        for (i = height - 1; i >= 0; i--)
        {
            fwrite(image + i * width, 1, width, file);
            if (line_width > width)
            {
                uint8_t line_align[4] = { 0 };
                fwrite(line_align, 1, line_width - width, file);
            }
        }

        fflush(file);
    } while (0);

    if (file != NULL)
    {
        fclose(file);
    }

    return err;
}

int main()
{
 int32_t err = 0;
 err = bmp_file_to_image(in_file_path, s_bmpdata, &s_bmp_col, &s_bmp_row);
 if (err != 0)
 {
  return -1;
    }
 printf("[%s] s_bmp_col = %d, s_bmp_row = %d\n", __func__, s_bmp_col, s_bmp_row);
 dump_image_to_bmp_file(out_file_path, s_bmpdata, s_bmp_col, s_bmp_row);
 return 0;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C语言实现BMP图像的读写功能

    C语言实现BMP图像的读写 对于刚接触数字图像的同学,应该都有一个疑问,如何把一个BMP格式的图像用纯C语言读入呢,我相信这也是数字图像处理的第一步,如果有幸看到这篇文档,我就有幸的成为你数字图像处理路上的第一盏明灯! 了解BMP的构成 这就是BMP图像的理论知识,有个大概的了解就行,最主要的是从理论到实践!!! 废话不多说,直接上干货. 代码 定义头文件为"bmp.h",定义read_bmp函数为读函数,write_bmp函数为写函数 读bmp图 #include <stdli

  • c语言解析bmp图片的实例

    心血来潮想了解下常用图片的格式解析,翻看了一些资料后,发现最简单的是bmp格式,所以先拿它开刀. BMP格式 这种格式内的数据分为三到四个部分,依次是: 文件信息头 (14字节)存储着文件类型,文件大小等信息 图片信息头 (40字节)存储着图像的尺寸,颜色索引,位平面数等信息 调色板 (由颜色索引数决定)[可以没有此信息] 位图数据 (由图像尺寸决定)每一个像素的信息在这里存储 一般的bmp图像都是24位,也就是真彩.每8位为一字节,24位也就是使用三字节来存储每一个像素的信息,三个字节对应存放

  • C语言读取BMP图像数据的源码

    复制代码 代码如下: /* File name:   bmpTest.c   Author:      WanChuan XianSheng    Date:        Oct 01, 2011   Description: Show all Info a bmp file has. including    FileHeader Info, InfoHeader Info and Data Part. Reference: BMP图像数据的C语言读取源码*/ #include <stdio

  • C语言读取和存储bmp格式图片

    开发过程中有时候需要解析bmp数据,下面先简单介绍bmp数据组成,后面附上C语言读取和存储bmp格式图片代码. 典型的位图文件格式通常包含下面几个数据块: 1.BMP文件头:保存位图文件的总体信息. 2.位图信息头:保存位图图像的详细信息.位图信息:保存位图图像的详细信息. 3.调色板:保存所用颜色的定义.调色板:保存所用颜色的定义. 4.位图数据:保存一个又一个像素的实际图像.位图数据:保存一个又一个像素的实际图像. 1. BMP文件头(14字节) BMP文件头数据结构含有BMP文件的类型.文

  • C语言实现BMP格式图片转化为灰度

    本文实例为大家分享了C语言将BMP格式图片转化为灰度的具体代码,供大家参考,具体内容如下 代码如下: #include<stdio.h> #include<malloc.h> #include<stdlib.h> #pragma pack(1) typedef struct tagBITMAPFILEHEADER { unsigned char bfType[2];//文件格式 unsigned long bfSize;//文件大小 unsigned short bfR

  • PHP处理bmp格式图片的方法分析

    本文分析了PHP处理bmp格式图片的方法.分享给大家供大家参考,具体如下: 白天QA提出项目上传图片有问题,具体为:上传成功,预览失败.我去了之后,又上传了几张其他的图片可以上传,然后仔细问了下他上传的是哪张图片,看了后使用getimagesize函数打印了下. Array ( [0] => 494 [1] => 260 [2] => 6 [3] => width="494" height="260" [bits] => 24 [mim

  • R语言读取xls与xlsx格式文件过程

    目录 1. ROOBC 2. xlsReadWrite 3. XLConnect 4. xlsx 1)装Java 2)装xlsx 3)实际使用 在数据分析的过程中,第一步就是读取数据. 通常我们遇到的数据是csv格式或者txt格式的数据,这时我们使用系统自带的read.csv()与read.table()就可对这些格式的数据进行读取,只是读取时需注意编码格式.对于大型csv格式的数据(当然小数据也可以),可以使用data.table包中的fread()进行读取可以极大地提升读取速度. 但当遇到了

  • C语言实现对bmp格式图片打码

    相信大家看到上面的标题一定觉的是上面高大上的技术,其实很简单. 前提准备:一张bmp格式的图片,如果没有的话,可以用Windows的画图软件来才裁剪.设置像素大小为(1024,768): 程序原理:将图片读入数组,然后给数组的指定位置存入随机数,最后再写入文件,这样图片就相应的位置就被置为乱码了. 源代码: <span style="font-size:14px;">#include<stdio.h> #include<stdlib.h> #incl

  • Android中把bitmap存成BMP格式图片的方法

    最近的项目,做图片的另存为功能,需要把图片存成jpg,png,bmp.对于jpg和png来说相对简单,android提供了bitmap.compress()方法可以马上解决.但是对于BMP这种格式,没有很好的支持.我花了几天时间在网上找了很久,都没有找到有用的答案,同样也发了疑问,没有合适的解答. package com.test.bitmap; import java.io.FileNotFoundException; import java.io.FileOutputStream; impo

  • 关于图片存储格式的整理(BMP格式介绍)

    BMP BMP(全称Bitmap)是Window操作系统中的标准图像文件格式 可以分成两类:设备相关位图(DDB)和设备无关位图(DIB),使用非常广. 它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP文件所占用的空间很大.BMP文件的图像深度可选lbit.4bit.8bit及24bit.BMP文件存储数据时,图像的扫描方式是按从左到右.从下到上的顺序.由于BMP文件格式是Windows环境中交换与图有关的数据的一种标准,因此在Windows环境中运行的图形图像软件都

  • 在python下读取并展示raw格式的图片实例

    raw文件可能有些人没有,因此,先用一张图片创建一个raw格式的文件(其实可以是其他类型的格式文件) import numpy as np import cv2 img = cv2.imread('cat.jpg') # 这里需要我们在当前目录下放一张名为cat.jpg的文件 img.tofile('cat.raw') #利用numpy中array的函数tofile将数据写入文件 #这时我们发现当前目录下新增了一个文件,名为cat.raw 有了raw文件,我们就可以读取这个文件,并显示出来. #

  • python如何读取和存储dict()与.json格式文件

    目录 读取和存储dict()与.json格式文件 读取.json格式文件并将数据保存到字典中 保存字典数据到.json文件中 在命令行中输出字典时的乱码问题 将字符串数据转化为字典数据 将dict数据写入json文件中 读取和存储dict()与.json格式文件 读取.json格式文件并将数据保存到字典中 数据文件:hg.json {"商家名称": "珍滋味港式粥火锅(工体店)", "评分": 27.0, "地址": &quo

随机推荐