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個字節(R\G\B)組成。

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("\n");
    }
    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("文件打開失敗\r\n");
		return 0;
	}
	
	printf("圖像寬度:%d\n",getBmpWidth(fp_read));
	printf("圖像高度:%d\n",getBmpHeight(fp_read));
	printf("文件大小:%d字節\n",getBmpFileSize(fp_read));
	printf("像素位數:%d\n",getBmpPixBits(fp_read));
	printf("偏移:%d\n",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("\n");
    }
    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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM