zoukankan      html  css  js  c++  java
  • BMP文件解析

    BMP文件简介

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

    BMP文件格式

    BMP文件主要有四部分组成,位图头、位图信息、调色板、位图数据。

    位图头

    保存文件的总体信息

    • 字节 #0-1 保存位图文件的标识符,用于标识BMP和DIB文件的魔数,一般为0x42 0x4D,即ASCII的BM。以下为可能的取值:
      BM – Windows 3.1x, 95, NT, … etc.
      BA – OS/2 struct Bitmap Array
      CI – OS/2 struct Color Icon
      CP – OS/2 const Color Pointer
      IC – OS/2 struct Icon
      PT – OS/2 Pointer
    • 字节 #2-5 使用一个dword保存位图文件大小。
    • 字节 #6-9 是保留部分,留做以后的扩展使用,对实际的解码格式没有影响。
    • 字节 #10-13 保存位图数据位置的地址偏移,也就是起始地址。

    位图信息

    这部分告诉应用程序图像的详细信息,在屏幕上显示图像将会使用这些信息

    • 字节 #14-17 定义以下用来描述影像的区块(BitmapInfoHeader)的大小。
    • 字节 #18-21 保存位图宽度(以像素个数表示)。
    • 字节 #22-25 保存位图高度(以像素个数表示)。
    • 字节 #26-27 保存所用彩色位面的个数。不经常使用。
    • 字节 #28-29 保存每个像素的位数,它是图像的颜色深度。常用值是1、4、8(灰阶)和24(彩色)。
    • 字节 #30-33 定义所用的压缩算法。允许的值是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表示)

    调色板

    暂时不做介绍

    位图数据

    在典型的24位位图下,一个像素由24bit,即3个字节(RGB)组成。

    C语言代码

    获取文件大小

    int getBmpFileSize(FILE * fpbmp)
    {
    	int size = 0;
    	
        fseek(fpbmp, 2, SEEK_SET);
        fread(&size, sizeof(char), 4, fpbmp);
        
        return size;
    }
    

    获取文件尺寸

    int getBmpWidth(FILE* fpbmp)
    {
        int width = 0;
    
        fseek(fpbmp, 18L, SEEK_SET);
        fread(&width, sizeof(char), 4, fpbmp);
    
        return width;
    }
    
    int getBmpHeight( FILE* fpbmp )
    {
        int height = 0;
    
        fseek(fpbmp, 22L, SEEK_SET);
        fread(&height, sizeof(char), 4, fpbmp);
    
        return height;
    }
    

    获取文件偏移量

    int getOffset(FILE * fpbmp)
    {
    	int offset = 0;
    
        fseek(fpbmp, 10L, SEEK_SET);
        fread(&offset, sizeof(char), 4, fpbmp);
    
        return offset;
    }
    

    读取文件数据示例

    对于一个3*3的BMP文件,三行分别是纯色的RGB分量

    int readBmpData( FILE* fpbmp )
    {
        int i = 0, j = 0;
        
        int offset = getOffset(fpbmp);
        int width = getBmpWidth(fpbmp);
        int height = getBmpHeight(fpbmp);
        
        unsigned char * pix = NULL;
    
        //one pix have 3 byte data( R G B )
        pix = malloc( 4 * sizeof( unsigned char ) );
    
        fseek(fpbmp, offset, SEEK_SET); // Jump to data part
    
        for( i = 0; i < height; i++ )
        {
            for( j = 0; j < width; j++ )
            {
                fread(pix, 3, 1, fpbmp);
                printf("(%3d,%3d,%3d)  ",pix[0],pix[1],pix[2]);
            }
            
            /*printf(",");
            for(;(j)%4!=0;j++)
            {
    			fread(pix, 3, 1, fpbmp);
                printf("(%3d,%3d,%3d) ",pix[0],pix[1],pix[2]);
    		}*/
            printf("
    ");
        }
        return 0;
    }
    

    一个问题

    等等,头部54字节,图像9个像素=27字节,加起来一共81字节,可是文件有90字节啊!剩下的4个字节呢?
    不妨把注释部分取消注释试一下!

    原来,windows里每行不足4字节的整数倍,会自动补0!所以三行多出了3个像素=9字节

    完整程序

    #include <stdio.h>
    
    int getBmpWidth(FILE* fpbmp);
    int getBmpHeight( FILE* fpbmp );
    int getBmpFileSize(FILE * fpbmp);
    int getBmpPixBits(FILE * fpbmp); 
    int getOffset(FILE * fpbmp);
    int readBmpData( FILE* fpbmp );
    
    int main()
    {
    	FILE * fp_read ;
    	
    	fp_read = fopen("test.bmp","rb");
    	
    	if(fp_read == NULL)
    	{
    		printf("文件打开失败
    ");
    		return 0;
    	}
    	
    	printf("图像宽度:%d
    ",getBmpWidth(fp_read));
    	printf("图像高度:%d
    ",getBmpHeight(fp_read));
    	printf("文件大小:%d字节
    ",getBmpFileSize(fp_read));
    	printf("像素位数:%d
    ",getBmpPixBits(fp_read));
    	printf("偏移:%d
    ",getOffset(fp_read));
    	
    	readBmpData(fp_read);
    	
    	return 0;
    }
    
    int readBmpData( FILE* fpbmp )
    {
        int i = 0, j = 0;
        
        int offset = getOffset(fpbmp);
        int width = getBmpWidth(fpbmp);
        int height = getBmpHeight(fpbmp);
        
        unsigned char * pix = NULL;
    
        //one pix have 3 byte data( R G B )
        pix = malloc( 4 * sizeof( unsigned char ) );
    
        fseek(fpbmp, offset, SEEK_SET); // Jump to data part
    
        for( i = 0; i < height; i++ )
        {
            for( j = 0; j < width; j++ )
            {
                fread(pix, 3, 1, fpbmp);
                printf("(%3d,%3d,%3d)  ",pix[0],pix[1],pix[2]);
            }
            
            printf(",");
            for(;(j)%4!=0;j++)
            {
    			fread(pix, 3, 1, fpbmp);
                printf("(%3d,%3d,%3d) ",pix[0],pix[1],pix[2]);
    		}
            printf("
    ");
        }
        return 0;
    }
    
    
    //获取像素位数 
    int getBmpPixBits(FILE * fpbmp)
    {
    	int bits = 0;
    	
        fseek(fpbmp, 28, SEEK_SET);
        fread(&bits, sizeof(char), 2, fpbmp);
        
        return bits;
    } 
    
    int getBmpFileSize(FILE * fpbmp)
    {
    	int size = 0;
    	
        fseek(fpbmp, 2, SEEK_SET);
        fread(&size, sizeof(char), 4, fpbmp);
        
        return size;
    } 
    
    int getBmpWidth(FILE* fpbmp)
    {
        int width = 0;
    
        fseek(fpbmp, 18L, SEEK_SET);
        fread(&width, sizeof(char), 4, fpbmp);
    
        return width;
    }
    
    int getBmpHeight( FILE* fpbmp )
    {
        int height = 0;
    
        fseek(fpbmp, 22L, SEEK_SET);
        fread(&height, sizeof(char), 4, fpbmp);
    
        return height;
    }
    
    int getOffset(FILE * fpbmp)
    {
    	int offset = 0;
    
        fseek(fpbmp, 10L, SEEK_SET);
        fread(&offset, sizeof(char), 4, fpbmp);
    
        return offset;
    }
    
    
  • 相关阅读:
    2017-2018-1 20145237、20155205、20155218实验一 开发环境的熟悉
    作业三总结
    作业二总结
    作业总结1
    自我介绍
    计科16-4刘悦
    第九次作业
    作业八
    作业七
    作业六
  • 原文地址:https://www.cnblogs.com/velscode/p/10475040.html
Copyright © 2011-2022 走看看