BMP图片解码代码

http://weibo.com/GTY55IW

 

 

 

 

 

在液晶显示需要图片的点阵代码有时需要将BMP图片解码以获取点阵代码,以下为解码分析:

 

 

 

/* 解析
 "file1.txt"           a file on drive 0
 "/file1.txt"          (same as above)
 "dir1/dir2/file1.txt" a file on drive 0
 "2:dir3/file2.txt"    a file on drive 2
 "2:/dir5"             a directory on drive 2
 ""                    the root directory on drive 0
 "/"                   (same as above)
 "2:"                  the root directory on drive 2
*/
//支持24bit BMP图片显示
#include "config.h"
#include "./BMP/BMP.h" 
#include "GUI_Private.h"
#include "./FATFS/src/ff.h"

static U16 _Read16(const U8 ** ppData)
{
    const U8 *pData;
  
    U16 Value;
    pData = *ppData;
    Value = *pData;
    Value |= (U16)(*(pData + 1) << 8);
    pData += 2;
    *ppData = pData;
    return Value;
}

static U32 _Read32(const U8 ** ppData)
{
    const U8 * pData;
   
 U32  Value;
    pData = *ppData;
    Value = *pData;
    Value |= (     *(pData + 1) << 8);
    Value |= ((U32)*(pData + 2) << 16);
    Value |= ((U32)*(pData + 3) << 24);
    pData += 4;
    *ppData = pData;

    return Value;
}

static int _GetStep(int *pYSize,int *pY)
{
    if(*pYSize>0)
    {
        *pY=*pYSize-1 ;
        return -1 ;
    }
    else if(*pYSize<0)
    {
        *pYSize=-*pYSize ;
        *pY=0 ;
        return 1 ;
    }
    else
    {
        return 0 ;
    }
}

//BMP文件数据缓冲区
INT8U BMP_Buffer[960];

static bool Get_BMP_Info(char *file, BMP_FILEHEADER *BmpHead)
{
    FATFS fs ;
    FIL fsrc;
    FRESULT res ;
    UINT br;

 //获取bmp文件长度、宽度等信息
    const U8 *pSrc=BMP_Buffer;

 //读取bmp文件
    f_mount(0,&fs);
// f_mount(1,&fs);
// f_mount(2,&fs);
    res=f_open(&fsrc,file,FA_OPEN_EXISTING|FA_READ);
 if(res) return FALSE;
    res=f_read(&fsrc,BMP_Buffer,sizeof(BMP_Buffer),&br);
 if(res) return FALSE;
    f_close(&fsrc);
    f_mount(0,NULL);
// f_mount(1,NULL);
// f_mount(2,NULL);

 //BMP位图文件头
 BmpHead->bfType          = _Read16(&pSrc);//Offset:0x0000,文件标志.只对'BM',用来识别BMP位图类型
 BmpHead->bfSize          = _Read32(&pSrc);//Offset:0x0002,文件大小,占四个字节;注意是大字节序还是小字节序,实际BMP格式中是小字节序
 BmpHead->bfReserved1     = _Read16(&pSrc);//Offset:0x0006,保留
 BmpHead->bfReserved2     = _Read16(&pSrc);//Offset:0x0008,保留
 BmpHead->bfOffBits       = _Read32(&pSrc);//Offset:0x000A,从文件开始到位图数据(bitmap data)开始之间的的偏移量

 //BMP位图信息头
 BmpHead->biSize          = _Read32(&pSrc);//Offset:0x000E,位图信息头字节数量。一般为0x28,最好取其实际值
 BmpHead->biWidth         = _Read32(&pSrc);//Offset:0x0012,说明图象的宽度,以象素为单位
 BmpHead->biHeight        = _Read32(&pSrc);//Offset:0x0016,说明图象的高度,以象素为单位,如果这是一个正数,说明图像数据是从图像左下角到右上角排列的。
 BmpHead->biPlanes        = _Read16(&pSrc);//Offset:0x001A,为目标设备说明位面数,其值将总是被设为1
 BmpHead->biBitCount      = _Read16(&pSrc);//Offset:0x001C,说明比特数/象素,其值为1、4、8、16、24、或32
 BmpHead->biCompression   = _Read32(&pSrc);//Offset:0x001E,说明图象数据压缩的类型 0表示没有压缩
 BmpHead->biSizeImage     = _Read32(&pSrc);//Offset:0x0022,说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0
 BmpHead->biXPelsPerMeter = _Read32(&pSrc);//Offset:0x0026,说明水平分辨率,用象素/米表示,有符号整数
 BmpHead->biYPelsPerMeter = _Read32(&pSrc);//Offset:0x002A,说明垂直分辨率,用象素/米表示,有符号整数
 BmpHead->biClrUsed       = _Read32(&pSrc);//Offset:0x002E,说明位图实际使用的彩色表中的颜色索引数
 BmpHead->biClrImportant  = _Read32(&pSrc);//Offset:0x0032,说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。

 printf("/r/n【BMP位图文件头】");
 printf("/r/nBmpHead->bfType         =0x%0X",BmpHead->bfType);
 printf("/r/nBmpHead->bfSize         =%d",BmpHead->bfSize);
 printf("/r/nBmpHead->bfReserved1    =%d",BmpHead->bfReserved1);
 printf("/r/nBmpHead->bfReserved2    =%d",BmpHead->bfReserved2);
 printf("/r/nBmpHead->bfOffBits      =%d",BmpHead->bfOffBits);
 
 printf("/r/n【BMP位图信息头】");
 printf("/r/nBmpHead->biSize         =%d",BmpHead->biSize);
 printf("/r/nBmpHead->biWidth        =%d",BmpHead->biWidth);
 printf("/r/nBmpHead->biHeight       =%d",BmpHead->biHeight);
 printf("/r/nBmpHead->biPlanes       =%d",BmpHead->biPlanes);
 printf("/r/nBmpHead->biBitCount     =%d",BmpHead->biBitCount);
 printf("/r/nBmpHead->biCompression  =%d",BmpHead->biCompression);
 printf("/r/nBmpHead->biSizeImage    =%d",BmpHead->biSizeImage);
 printf("/r/nBmpHead->biXPelsPerMeter=%d",BmpHead->biXPelsPerMeter);
 printf("/r/nBmpHead->biYPelsPerMeter=%d",BmpHead->biYPelsPerMeter);
 printf("/r/nBmpHead->biClrUsed      =%d",BmpHead->biClrUsed);
 printf("/r/nBmpHead->biClrImportant =%d",BmpHead->biClrImportant);

 return TRUE;
}

bool GUI_BMP_Draw_From_SD(char *file,int x0,int y0)
{
 BMP_FILEHEADER BmpHead;

    int Width,Height ;
    U16 Type ;
    U32 OffBits,Compression ;

 FATFS fs;
    FIL fsrc;
    FRESULT res;
    UINT br;

 int x=0,y=0,BytesPerLine,Step ;
 
//获得BMP头文件信息
    if(Get_BMP_Info(file, &BmpHead)==FALSE)
 {
     return FALSE;
 }

 Type        = BmpHead.bfType;
    Width       = BmpHead.biWidth;
    Height      = BmpHead.biHeight;
    //BitCount    = BmpHead.biBitCount;
    Compression = BmpHead.biCompression;
    //ClrUsed     = BmpHead.biClrUsed;
 OffBits  = BmpHead.bfOffBits;//bmp颜色数据起始位置
   
 if((Type!=0x4d42)||(Compression))
    {
        printf("/r/n不支持该图片显示!");
  return FALSE;
    }
 //if((Width>320)||(Height>240))
 if(Width>320)//图片宽度不能超过320,因为缓冲数组为960
    {
        printf("/r/n图片太大,无法显示!");
  return FALSE;
    }

//开始画图
 f_mount(0,&fs);
// f_mount(1,&fs);
// f_mount(2,&fs);
    res=f_open(&fsrc,file,FA_OPEN_EXISTING|FA_READ);
 if(res) return FALSE;
    res=f_lseek(&fsrc,OffBits); //找到bmp颜色数据起始位置
 if(res) return FALSE;
   
    Step=_GetStep(&Height,&y);  //判断是否从底向上读数据
 if(!Step) return FALSE;
    BytesPerLine=((24*Width+31)>>5)<<2 ;

    for(;(y=0);y+=Step)
    {
        //每次读取一行数据进行显示,然后再读取下一行数据,行数据个数为BytesPerLine
  //对TFT320*240,16bpp,每行320*3=960个字节
  res=f_read(&fsrc,BMP_Buffer,BytesPerLine,&br);
  if(res) return FALSE;
       
  for(x=0;x         {
            const U8 *pColor=BMP_Buffer+3*x ;
            U8 r,g,b ;
            //U16 color ;
           
   b=*(pColor);
            g=*(pColor+1);
            r=*(pColor+2);
            LCD_SetPixelIndex(x0+x,y0+y,LCD_Color2Index(((U32)b<<16)|(g<<8)|r));
        }
    }
   
    f_close(&fsrc);
    f_mount(0,NULL);
// f_mount(1,NULL);
// f_mount(2,NULL);

 return TRUE;
}
/*************************** End of file ****************************/

 

 

 

以下为头文件:


//1、位图中头的信息是按小字节序存储的,注意编译器如果是大字节序的需要字节顺序调整才可以。
//2、位图中图象信息的第一个像素在图象中是左下角的像素,先最下一行从左往右,然后上面一行
//3、文档中有这样的说法:像素数据的长度(按字节计)要是4的倍数,这个4的倍数是怎么体现的呢?
//    首先,这个规定并不是可遵守不可遵守的,一旦不遵守,图象水平方向上像素数是4的倍数还好,不然肯定会出错。
//    这个4的倍数该怎么理解呢?我的像素怎么排?是不是每个像素占4个字节?
//    经过实际用画图板制作各种尺寸的图象得到下面的结论:
//    每个像素只占3个字节,水平方向上所有像素连续排列,
//统计水平方向像素所占的字节数(像素数*3),如果得到的结果是4的倍数,就继续下一行数据,
//    如果不是4的倍数,在最后一个像素数据后面补0,使这一行的总字节数等于4的倍数,然后开始下一行数据
//    如:
//    3*5的图象:
//    水平方向有3个像素,像素占的字节数为9,不是4的倍数,在第三个像素数据后面补3个0,使这一行的总字节数为12,补完0,开始下一行数据。
//    5*3的图象:
//    水平方向有5个像素,像素占的字节数为15,不是4的倍数,在第五个像素后面补1个0,使此行的总字节数为16,继续下一行数据
//bmp文件头(bmp file header):提供文件的格式、大小等信息
//1/位图信息头(bitmap information):提供图像数据的尺寸、位平面数、压缩方式、颜色索引等信息
//2/调色板(color palette):可选,如使用索引来表示图像,调色板就是索引与其对应的颜色的映射表
//  调色板其实是一张映射表,标识颜色索引号与其代表的颜色的对应关系。
//  它在文件中的布局就像一个二维数组palette[N][4],其中N表示总的颜色索引数,
//  每行的四个元素分别表示该索引对应的B、G、R和Alpha的值,每个分量占一个字节。
//  如不设透明通道时,Alpha为0。因为前面知道,本图有256个颜色索引,因此N = 256。
//  索引号就是所在行的行号,对应的颜色就是所在行的四个元素。
//3/位图数据(bitmap data):就是图像数据啦^_^

#ifndef __BMP_H__
#define __BMP_H__

#include "def.h"

typedef struct
{
//BMP位图文件头
    INT16U bfType;         //Offset:0x0000,文件标志.只对'BM',用来识别BMP位图类型
    INT32U bfSize;        //Offset:0x0002,文件大小,占四个字节;注意是大字节序还是小字节序,实际BMP格式中是小字节序
    INT16U bfReserved1;    //Offset:0x0006,保留
 INT16U bfReserved2;    //Offset:0x0008,保留
    INT32U bfOffBits;      //Offset:0x000A,从文件开始到位图数据(bitmap data)开始之间的的偏移量,看后面的图象信息头的多少定,图象信息头大小为0x28则本字段值为0x36,本字段的值实际上为"图象信息头长度+14+调色板信息长度"

//BMP位图信息头
 INT32U biSize;     //Offset:0x000E,位图信息头字节数量。一般为0x28,最好取其实际值
    INT32S biWidth;        //Offset:0x0012,说明图象的宽度,以象素为单位
    INT32S biHeight;    //Offset:0x0016,说明图象的高度,以象素为单位,如果这是一个正数,说明图像数据是从图像左下角到右上角排列的。
    INT16U biPlanes;    //Offset:0x001A,为目标设备说明位面数,其值将总是被设为1
    INT16U biBitCount;    //Offset:0x001C,说明比特数/象素,其值为1、4、8、16、24、或32
    INT32U biCompression;  //Offset:0x001E,说明图象数据压缩的类型。其值可以是下述值之一:
                                         //BI_RGB:没有压缩;
                                         //BI_RLE8:每个象素8比特的RLE压缩编码,压缩格式由2字节组成(重复象素计数和颜色索引); 
                                            //BI_RLE4:每个象素4比特的RLE压缩编码,压缩格式由2字节组成
                                           //BI_BITFIELDS:每个象素的比特由指定的掩码决定。
    INT32U biSizeImage;    //Offset:0x0022,说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0 
    INT32U biXPelsPerMeter;//Offset:0x0026,说明水平分辨率,用象素/米表示,有符号整数
    INT32U biYPelsPerMeter;//Offset:0x002A,说明垂直分辨率,用象素/米表示,有符号整数
    INT32U biClrUsed;    //Offset:0x002E,说明位图实际使用的彩色表中的颜色索引数
    INT32U biClrImportant; //Offset:0x0032,说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。

}BMP_FILEHEADER;

//从SD卡获取bmp文件,并显示
bool GUI_BMP_Draw_From_SD(char *file,int x0,int y0);

#endif

 

你可能感兴趣的:(BMP图片解码代码)