【数字图像】BMP文件格式详解

BMP文件格式详解

-------------------------------------------------------------------------------------------------------

Lena

摘录百科:BMP是英文Bitmap(位图)的简写,它是Windows操作系统中的标准图像文件格式,能够被多种Windows应用程序所支持。

BMP文件存储的是原始的BGR数据,格式非常简单,研究数字图入门必备。因为数据没有经过任何压缩,所以BMP文件都比较大。

BMP文件格式

  • 文件信息  -->BITMAPFILEHEADER
  • 图像信息  -->BITMAPINFOHEADER
  • 调色板     -->由颜色索引数决定
  • 图像数据  -->由图像尺寸决定

1. BITMAPFILEHEADER

typedef struct {

WORD  bfType;

DWORD bfSize;

WORD  bfReserved1;

WORD  bfReserved2;

DWORD bfOffBits;

} BITMAP_FILE_HEADER;

WORD --> unsigned short

DWORD --> unsigned long (32位占4位,64位占8位)


变量名


大小(字节)


作用


bfType


2


文件标头BM


bfSize


4


整个文件大小


bfReserved1


2


保留


bfReserved2


2


保留


bfOffBits


4


偏移,一般偏移长度是BITMAPFILEHEADER+BITMAPINFOHEADER,如果存在调色板则随着调色板长度变化

2.BITMAPINFOHEADER

typedef struct BITMAP_INFO_HEADER {

DWORD biSize;

int     biWidth;

int     biHeight;

WORD  biPlanes;

WORD  biBitCount;

DWORD biCompression;

DWORD biSizeImage;

int     biXPelsPerMeter;

int     biYPelsPerMeter;

DWORD biClrUsed;

DWORD biClrImportant;

} BITMAP_INFO_HEADER;

这里的int原来是long,64位下会出问题改了下。


变量名


大小(字节)


作用


biSize


4


sizeof(BITMAP_INFO_HEADER)


biWidth


4


宽度


biHeight


4


高度

BMP文件图像是倒着存储的,所以如果biHeight>0表示图像是倒立的,如果biHeight<0表示图像是正的。


biPlanes


2


颜色平面数


biBitCount


2


位数(1,4,8,16,24,32)


biCompression


4


压缩

0 BI_RGB(BMP文件不压缩)

1 BI_RLE8

2 BI_RLE4

3 BI_BITFILELDS

4 BI_JPEG

5 BI_PNG


biSizeImage


4


图像数据大小


biXPelsPerMeter


4


水平分辨率


biYPelsPerMeter


4


垂直分辨率


biClrUsed


4


实际使用的颜色索引数


biClrImportant


4


对图像显示有重要影响的颜色索引的数目,如果是0表示都重要

3.调色板

调色板实际上是一种颜色索引表,因为常见的BMP文件都是24和32位的,而24和32位不需要调色板,所以这里不做过多研究。

4.图像数据

24位位图 -->  bgr,bgr,bgr

32位位图 -->  bgra,bgra,bgra

5.内存对齐

Windows默认是4字节对齐,如果不了解内存对齐可以研究一下,c语言sizeof(结构体)的大小。内存对齐的主要目的是为了加速,BMP文件也需要进行内存对齐处理,简单来说就是每一行的字节数%4==0,如果不足则由0补足。比如:一个24位BMP,宽度为99,那么他的图像部分字节数位 99 * 3 ==> 297 % 4 = 1,需要补3个字节0。

参考文章:

https://www.cnblogs.com/Matrix_Yao/archive/2009/12/02/1615295.html

/*****************************************************
   BMP文件读写
   [email protected]
*****************************************************/

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

typedef unsigned short WORD;
typedef unsigned int DWORD;

#pragma pack(1)
typedef struct {
    WORD  bfType;
    DWORD bfSize;
    WORD  bfReserved1;
    WORD  bfReserved2;
    DWORD bfOffBits;
} BITMAP_FILE_HEADER;

typedef struct BITMAP_INFO_HEADER {
    DWORD biSize;
    int   biWidth;
    int   biHeight;
    WORD  biPlanes;
    WORD  biBitCount;
    DWORD biCompression;
    DWORD biSizeImage;
    int   biXPelsPerMeter;
    int   biYPelsPerMeter;
    DWORD biClrUsed;
    DWORD biClrImportant;
} BITMAP_INFO_HEADER;
#pragma pack()

/**
 * 32->24
 */
static void bmp_remove_aplpha (unsigned char *data, unsigned char *buf, size_t *size, size_t w, size_t h) {
    size_t i = 0, j = 0, dst_fix = 0;

    dst_fix = 4 - ((w * 24)>>3) & 3;
    *size = ((((w * 24) + 31) >> 5) << 2) * h;

    for (j = 0; j < h; j++) {
        for (i = 0; i < w; i++) {
            memcpy(buf, data, 3);
            data += 4;
            buf += 3;
        }
        buf += dst_fix;
    }
}

/**
 * 倒转图像
 */
static void bmp_reverse (unsigned char *data, unsigned char *buf, size_t size, size_t w, size_t h) {
    unsigned char *src = NULL;
    int i = 0, j = 0, preline = 0;

    preline = size / h;
    for (i = 0, j = h - 1; j >= 0; i++, j--) {
        src = data + j * preline;
        memcpy(buf + i * preline, src, preline);
    }
}

/**
 * bmp_read
 *
 * 读取一个BMP文件
 * 只支持24/32位,32位会转为24位,倒转的图像会摆正
 */
unsigned char *bmp_read (const char *path, size_t *size, size_t *w, size_t *h) {
    FILE *fp = NULL;
    BITMAP_FILE_HEADER file = {0};
    BITMAP_INFO_HEADER info = {0};
    unsigned char *data = NULL, *buf = NULL;

    if (!path || *path == 0 || !size || !w || !h)
        return NULL;

    if (!(fp = fopen(path, "rb")))
        return NULL;

    if (fread(&file, 1, sizeof(BITMAP_FILE_HEADER), fp) != sizeof(BITMAP_FILE_HEADER)) {
        fclose(fp);
        return NULL;
    }

    if (fread(&info, 1, sizeof(BITMAP_INFO_HEADER), fp) != sizeof(BITMAP_INFO_HEADER)) {
        fclose(fp);
        return NULL;
    }

    //非BM开头
    if (file.bfType != 0x4d42) {
        fclose(fp);
        return NULL;
    }

    //暂时只能支持24与32位
    if (info.biBitCount != 24 && info.biBitCount != 32) {
        fclose(fp);
        return NULL;
    }

    if (info.biSizeImage == 0) {
        info.biSizeImage = info.biWidth * abs(info.biHeight) * (info.biBitCount == 24 ? 3 : 4);
    }

    data = (unsigned char *)malloc(sizeof(unsigned char) * info.biSizeImage);
    buf = (unsigned char *)malloc(sizeof(unsigned char) * info.biSizeImage);
    if (!data || !buf) {
        if (data) free(data);
        if (buf) free(buf);
        fclose(fp);
        return NULL;
    }

    if (fread(data, 1, info.biSizeImage, fp) != info.biSizeImage) {
        free(data);
        free(buf);
        fclose(fp);
        return NULL;
    }

    fclose(fp);

    *size = info.biSizeImage;
    *w = info.biWidth;
    *h = abs(info.biHeight);

    //32转24
    if (info.biBitCount == 32) {
        bmp_remove_aplpha(data, buf, size, *w, *h);
        memcpy(data, buf, *size);
    }

    //图像倒转
    if (info.biHeight > 0) {
        bmp_reverse(data, buf, *size, *w, *h);
        memcpy(data, buf, *size);
    }

    free(buf);
    return data;
}

/**
 * bmp_write
 */
int bmp_write (unsigned char *data, size_t size, size_t w, size_t h, const char *path) {
    FILE *fp = NULL;
    BITMAP_FILE_HEADER file = {0};
    BITMAP_INFO_HEADER info = {0};
    unsigned char *src = NULL;
    int hsrc = 0, preline = 0;

    if (!data || size == 0 || w == 0 || h == 0 || !path || *path == 0)
        return 0;

    if (!(fp = fopen(path, "wb+")))
        return 0;

    file.bfType = 0x4d42;
    file.bfSize = sizeof(BITMAP_FILE_HEADER) + sizeof(BITMAP_INFO_HEADER) + size;
    file.bfReserved1 = 0;
    file.bfReserved2 = 0;
    file.bfOffBits = sizeof(BITMAP_FILE_HEADER) + sizeof(BITMAP_INFO_HEADER);

    info.biSize = sizeof(BITMAP_INFO_HEADER);
    info.biWidth = w;
    info.biHeight = h;
    info.biPlanes = 1;
    info.biBitCount = 24;
    info.biCompression = 0L;
    info.biSizeImage = size;
    info.biXPelsPerMeter = 0;
    info.biYPelsPerMeter = 0;
    info.biClrUsed = 0;
    info.biClrImportant = 0;

    fwrite(&file, 1, sizeof(BITMAP_FILE_HEADER), fp);
    fwrite(&info, 1, sizeof(BITMAP_INFO_HEADER), fp);

    //倒转写入图像数据
    preline = size / h;
    for (hsrc = h - 1; hsrc >= 0; hsrc--) {
        src = data + hsrc * preline;
        fwrite(src, 1, preline, fp);
    }

    fclose(fp);
    return 1;
}

int main (int argc, char *argv[]) {
    unsigned char *data = NULL;
    size_t size = 0, w = 0, h = 0;

    data = bmp_read("1.bmp", &size, &w, &h);
    bmp_write(data, size, w, h, "2.bmp");
    return 1;
}

原文地址:https://www.cnblogs.com/hatsusakana/p/12643850.html

时间: 2024-10-25 23:45:27

【数字图像】BMP文件格式详解的相关文章

BMP格式详解

BMP格式详解 BMP文件格式详解(BMP file format) BMP文件格式,又称为Bitmap(位图)或是DIB(Device-Independent Device,设备无关位图),是Windows系统中广泛使用的图像文件格式.由于它可以不作任何变换地保存图像像素域的数据,因此成为我们取得RAW数据的重要来源.Windows的图形用户界面(graphical user interfaces)也在它的内建图像子系统GDI中对BMP格式提供了支持. 下面以Notepad++为分析工具,结合

Android逆向之旅---SO(ELF)文件格式详解

第一.前言 从今天开始我们正式开始Android的逆向之旅,关于逆向的相关知识,想必大家都不陌生了,逆向领域是一个充满挑战和神秘的领域.作为一名Android开发者,每个人都想去探索这个领域,因为一旦你破解了别人的内容,成就感肯定爆棚,不过相反的是,我们不仅要研究破解之道,也要研究加密之道,因为加密和破解是相生相克的.但是我们在破解的过程中可能最头疼的是native层,也就是so文件的破解.所以我们先来详细了解一下so文件的内容下面就来看看我们今天所要介绍的内容.今天我们先来介绍一下elf文件的

LinuxELF文件格式详解--Linux进程的管理与调度(十二)

日期 内核版本 架构 作者 GitHub CSDN 2016-06-04 Linux-4.5 X86 & arm gatieme LinuxDeviceDrivers Linux进程管理与调度-之-进程的描述 对象文件格式 对象文件 首先,你需要知道的是所谓对象文件(Object files)有三个种类: 可重定位的对象文件(Relocatable file) 可执行的对象文件(Executable file) 可被共享的对象文件(Shared object file) 可重定位的对象文件(Re

转发:ZIP文件格式详解(一)——文件数据格式

ZIP文件格式详解(一)——文件数据格式 ---------------------------------------------------------------------------------- 文档说明 ZIP 格式的压缩文件是我们常用的压缩格式之一,他以其通用性.压缩比高而在全球范围内有很多的用户,本文简单介绍 ZIP 文件格式和算法.本文主要参照 http://www.pkware.com 提供的 appnote.txt 文件,你可以从http://www.pkware.com

Carbondata源码系列(二)文件格式详解

在上一章当中,写了文件的生成过程.这一章主要讲解文件格式(V3版本)的具体细节. 1.字典文件格式详解 字典文件的作用是在存储的时候将字符串等类型转换为int类型,好处主要有两点: 1.减少存储占用空间 2.用在需要group by的字段上比较合适,可以减少计算时的shuffle的数据量. 每一个字典列都有对应的三种文件.dict, .sortindex, .dictmeta文件,输出格式都是thrift格式 1.1 .dict文件 字典的值每满1000就作为一个chunk输出一次,具体的类是C

PE文件格式详解(四)

PE文件格式详解(四) 0x00 前言 上一篇介绍了区块表的信息,以及如何在hexwrokshop找到区块表.接下来,我们继续深入了解区块,并且学会文件偏移和虚拟地址转换的知识. 0x01 区块对齐值 首先我们要知道啥事区块对齐?为啥要区块对齐?这个问题其实困扰了我很久,只能怪我操作系统没学好...我现在的理解是由于内存和磁盘存在分页的问题所以使得不同区块一般要放到不同的分页中,当然也可以多个区块合并以节省空间,但是对于不能合并的区块如代码和数据块就不得不放在不同分页上了.学过操作系统的都知道不

BMP位图文件格式详解及编程建议

BMP文件渊源流长,虽然对JPG.PNG等格式图像文件来说,确实有点土,但是毕竟BMP文件格式相对简单,容易理解,至于BMP众多的位图格式也不能责怪微软,主要是早期谁也没料到图片技术会发展的这么快,而且每次升级还要兼容,所以只能如此了(有点麻烦但并不复杂).天缘撰写本文以便留档和各位编程爱好者参考. BMP位图文件的结构主要由:BMP文件头.位图信息头.颜色表和图形数据四个部分组成,对于24位.32位则没有色彩表字段,低位图则存在色彩索引表. 一.BMP的文件头结构 BMP文件头数据结构包含有B

【转】jpeg文件格式详解

JPEG(Joint Photographic Experts Group)是联合图像专家小组的英文缩写.它由国际电话与电报咨询委员会CCITT(The International Telegraph and Telephone Consultative Committee)与国际标准化组织ISO于1986年联合成立的一个小组,负责制定静态数字图像的编码标准. 小组一直致力于标准化工作,开发研制出连续色调.多级灰度.静止图像的数字图像压缩编码方法,即JPEG算法.JPEG算法被确定为国际通用标准

BMP结构详解

位图BITMAPINFOHEADER 与BITMAPFILEHEADER: 先来看BITMAPINFOHEADER,只写几个主要的biSize包含的是这个结构体的大小(包括颜色表)    biWidth和biHeight分别是图片的长宽    biPlanes是目标绘图设备包含的层数,必须设置为1    biBitCount是图像的位数,例如24位,8位等    biXPelsPerMeter, biYPelsPerMeter 是现实世界中每米包含的像素数 设为3780即可    biSizeI