5836|1

6473

帖子

8

TA的资源

管理员

楼主
 

BMP位图显示(五)简易数码相框的设计 [复制链接]

文章节选自:《ARM Cortex-M0从这里开始》 作者:zhaojun_xf   https://bbs.eeworld.com.cn/thread-324656-1-1.html

 

1概述
    数码相框常见的支持格式有BMP\GIF\JPG\TIF等,由于使用LPC1100微处理器实现数码相框,只能是达到原理性的效果,特殊效果是没法实现的。再加上除了BMP格式外,都要涉及到解码问题,而使用微处理器软件解码也是非常缓慢的。所以,本书只讲解BMP格式的显示。
2 BMP结构
BMP是Windows操作系统中的标准图像文件格式,使用非常广泛。它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP占用的空间很大。BMP文件的图像深度可选1Bit、4Bit、8Bit、16Bit、24Bit、32Bit等。BMP文件存储数据时,图像的扫描方式是按照从左到右、从下到上的顺序。典型的BMP图像文件由四部组成,如表7-5所示。

                

下面就以一副24位位图来说明其文件结构。如图7-26所示,为这幅图的属性。

                   

(1)位图文件头
由14字节数据组成,包含文件的标志、文件大小和实际数据偏移量等信息。为了直观显示文件头信息,下面定义一个结构体来表示文件头。
typedef struct tagBITMAPFILEHEADER
{
 uint16 bfType;    // 说明文件类型,在windows系统中为BM
 uint32 bfSize;    // 说明文件大小
 uint16 bfReserved1;  // 保留,设置为0
 uint16 bfReserved2;  // 保留,设置为0
 uint32 bfOffBits;   // 说明实际图形数据的偏移量
}BITMAPFILEHEADER;    // 14Byte
如图7-27所示,为一副图的文件头信息,已经用黑色线条把14字节的位图文件头标出。同样是使用WinHex软件打开的,需要注意的是,这里采用的是小端格式存储。
                

文件头说明:
 bfType:2字节组成,数据为42 4D,是BM的ASCII值,表示此图为位图;
 bfSize :4字节数据为36 84 03 00,表示文件大小,转换一下为0x00038436 = 230454字节;
 bfReserved1:2字节组成,数据为00 00,保留;
 bfReserved2:2字节组成,数据为00 00,保留;
 bfOffBits: 4字节数据为36 00 00 00,表示图像数据是从0x00000036 = 54开始。
(2)位图信息头
由40字节数据组成,包含图像宽度、高度、数据位数、压缩、分辨率等信息。为了直观显示信息头结构,下面定义一个结构体来表示文件头。
typedef struct tagBITMAPINFOHEADER
{
 uint32 biSize;          // 说明BITMAPINFOHEADER结构所需字节数,在windows系
// 统中为28h
 uint32 biWidth;   // 说明图像宽度         
 uint32 biHeight;   // 说明图像高度
 uint16 biPlanes;   // 为目标设备说明位面数,其值设为1
 uint16 biBitCount;      // 每个像素的位数,单色位图为1,256色为8,16bit为
// 16,24bit为24
 uint32 biCompression;  // 压缩说明,BI_RGB:无压缩,BI_RLE8:8位RLE压缩,
// BI_RLE4:4位RLE压缩
 uint32 biSizeImage;  // 说明图像大小,如无压缩,可设为0
 uint32 biXPelsPerMerer; // 水平分辨率  
 uint32 biYPelsPerMerer; // 垂直分辨率  
 uint32 biClrUsed;   // 位图使用的颜色数
 uint32 biClrImportant;  // 重要颜色数目
}BITMAPINFOHEADER;    // 40Byte
如图7-28所示为位图信息头数据。

                

信息头说明:
 biSize:4字节数据28 00 00 00,即0x00000028 = 40,表示信息头占用40字节空间;
 biWidth:4字节数据40 01 00 00,即0x00000140 = 320,表示图像宽320像素;
 biHeight:4字节数据F0 00 00 00,即0x0000000F = 240,表示图像高240像素;
 biplanes:2字节数据01 00,即0x0001 = 1,为目标设备说明位面数;
 biBitCount:2字节数据18 00,即0x0018 = 24,表示为24位位图;
 biSizeImage:4字节数据00 84 03 00,即0x00038400 = 230400字节,表示实际图像数据大小。
(3)彩色表
包含的元素与位图所具有的颜色数目相同,像素颜色用结构RGBQUAD存储。只有biBitCount等于1、4、8时才有调色板。调色板实际上是一个数组,元素的个数由biBitCount和biClrUsed决定。
typedef struct tagRGBQUAD
{
 uint8 rgbBlue;   // 指定蓝色强度
 uint8 rgbGreen;   // 指定绿色强度
 uint8 rgbRed;    // 指定红色强度
 uint8 rgbReserved;  // 保留,设为0
}RGBQUAD;      // 4Byte
(4)图像数据
图像数据扫描方式如7-29所示,在彩色表后的是图像数据阵列,图像每一扫描行由连续的字节组成,扫描行由底向上存储,阵列中第一字节为左下角像素,最后一字节为右上角像素。

                                                                

3 BMP显示
    本数码相框实现16位和24位位图的显示。
    (1)获取文件头信息
    显示图像之前先获取文件的一些信息,上面讲过位图的文件头信息一共占用54字节,而这里只读取需要的部分信息数据,如程序清单7-17所示。
/****************************** 程序清单7-17  **********************************/
/********************************************************************************
* FunctionName   : Bmp_GetHeadInfo()
* Description    : 获取BMP头信息
* EntryParameter : buf - 信息
* ReturnValue    : None
********************************************************************************/
BMP_HEADER Bmp_GetHeadInfo(uint8 *buf)
{
 BMP_HEADER bmpHead;

 bmpHead.bfType  = (buf[0]<<8)+buf[1];                               // BM
 bmpHead.bfSize  = (buf[5]<<24 +(buf[4]<<16)+(buf[3]<<8)+buf[2];     // 大小
 bmpHead.biWidth = (buf[21]<<24)+(buf[20]<<16)+(buf[19]<<8)+buf[18]; // 宽度
 bmpHead.biHeight= (buf[25]<<24)+(buf[24]<<16)+(buf[23]<<8)+buf[22]; // 高度
 bmpHead.biBitCount = (buf[29] << 8) + buf[28];    // 每个像素的位数
 return bmpHead;
}
(2)1555格式转换
在PC机上创建的16位位图中,用16位表示一个像素,所以两个字节可以表示1个像素。默认情况下16位DIB是555格式,最高位无效。所以要在TFT上显示时,必须先转换成RGB565,否则显示是有问题的。
    说明:在RGB555转换RGB565格式时要注意:
 RGB555格式中,最高位无效:1+5+5+5;
 RGB565中G的最低位可以不管,也可以根据G的最高位的值来补"1"还是补"0"。
/****************************** 程序清单7-18  **********************************/ /********************************************************************************
* FunctionName   : Bmp_555To565()
* Description    : 颜色数据格式转换,默认情况下16位DIB是555格式
* EntryParameter : RGB555转换到RGB565; dat - 数据
* ReturnValue    : None
********************************************************************************/
uint16 Bmp_555To565(uint16 dat)

    return  (uint16)(((dat & 0x7C00) << 1) | ((dat & 0x03E0) << 1) | (dat & 0x001F));
}
(3)24位格式转换
在PC机创建位图时,一般都采用24位真彩色,结构比较简单。用24位表示一个像素,所以三个字节可以表示1个像素。需要注意的是存储顺序一般是BGR,而不是传统的RGB。由于TFT为565格式的16位数据格式,所以要显示24位位图在TFT上也必须转换一下。转换方法和很简单,B和R直接去掉最高3位数据,G去掉最高2位数据,之后组合成为565格式的16位数据即可,如程序清单7-19所示。
/****************************** 程序清单7-19  **********************************/
/********************************************************************************
* FunctionName   : Bmp_24To565()
* Description    : 颜色数据格式转换,把24位转换成RGB565
* EntryParameter : RGB555转换到RGB565;
* ReturnValue    : None
********************************************************************************/
uint16 Bmp_24To565(uint8 r, uint8 g, uint8 b)

 return (((uint16)(r >> 3) << 11) | ((uint16)(g >> 2) << 5) | ((uint16)b >> 3));
}
(4)16位位图显示
16位位图显示比较简单,直接从数据缓冲区中读取两个字节数据,先转换成TFT的565格式后,发送给TFT即显示了相应像素点。如程序清单7-20所示。
/****************************** 程序清单7-20  **********************************/
    /********************************************************************************
* FunctionName   : Bmp_Disp16Bits()
* Description    : 显示16位位图
* EntryParameter : p - 数据指针
* ReturnValue    : None
********************************************************************************/
void Bmp_Disp16Bits(uint8 *pData)
{
    uint16 i;

 for (i=0; i<MMC_BUFF_SIZE/2; i++)
 {
  TFTWriteData(Bmp_555To565((*(pData+i*2+1) << 8) + *(pData+i*2)));
 }
}
(5)24位位图显示
24位位图显示比较复杂一点,这是因为,一般情况下SD卡读取一扇区数据为512字节,而512字节并不能存储完整的RGB信息。在最后一个RGB数据中会少一个数据,一就是说512字节,前面510字节存放了170个像素点的颜色信息,而后面两字节只存放了一个像素点的部分信息,需要从下次读取是信息中获取一字节数据来补齐,这样就给显示带来了不少麻烦。
在读取第1个扇区时会缺少1字节,读取第2个扇区时会缺少2个字节,在读取第3个扇区时刚好构成完整数据。所以需要按照3个扇区为周期进行数据处理。具体代码如程序清单7-21所示。
/****************************** 程序清单7-21  **********************************/
  /********************************************************************************
* FunctionName   : Bmp_Disp24Bits()
* Description    : 显示24位位图。每读取512*3个字节数据,完成一次完整数据读取
* EntryParameter : pData - 数据指针
* ReturnValue    : None
********************************************************************************/
void Bmp_Disp24Bits(uint8 *pData)
{
    uint16 i = 0;

 while (1)
 {
     if (0 == Offset24Bits%3)
  {
         Blue24Bits   = *(pData+(Offset24Bits%MMC_BUFF_SIZE)); // 获取蓝色数据
   if (0 == ++Offset24Bits%(512*3))    // 判断是否为一个周期
   {
       Offset24Bits = 0;
   }
 
   if (++i >= MMC_BUFF_SIZE)        // 判断是否读完数据
   {
       break;
   }
  }

  if (1 == Offset24Bits%3)        // 获取绿色数据
  {
      Green24Bits = *(pData+(Offset24Bits%MMC_BUFF_SIZE));
   if (0 == ++Offset24Bits%(512*3))
   {
       Offset24Bits = 0;
   }
 
   if (++i >= MMC_BUFF_SIZE)
   {
       break;
   }
  }

     if (2 == Offset24Bits%3)
  {
      Red24Bits  = *(pData+(Offset24Bits%MMC_BUFF_SIZE));  // 获取红色数据
            // 三个数据都获取,发生到TFT显示
   TFTWriteData(Bmp_24To565(Red24Bits,Green24Bits,Blue24Bits));

   if (0 == ++Offset24Bits%(512*3))
   {
       Offset24Bits = 0;
   }
 
   if (++i >= MMC_BUFF_SIZE)
   {
       break;
   }
  }
 }
}
(6)位图读取并显示
位图显示是通过函数参数,传递文件名,通过文件名读取文件数据。读取位图数据时,先读取54字节的头信息,在根据头信息判断是否为位图图像。如果不是位图,直接返回不再读取数据;如果是位图图像,再判断是16位还是24位。并循环读取数据信息,经过数据转换后发送到TFT进行显示。
读取位图文件需要调用FatFs文件系统的API函数,在读取文件时需要注意一下几点:
 首先要f_mount函数注册工作区,在文件读取完成后,再调用这个函数来注销工作区;
 打开文件需要调用f_open函数,当文件读取完成后,再调用f_close函数关闭文件,所以这两个函数必须成对出现;
 在读取文件时,可以同f_read函数返回的结果和次函数的读取结果来判断数据是否读取完成。
/****************************** 程序清单7-22  **********************************/
/********************************************************************************
* FunctionName   : BmpDisplay()
* Description    : bmp图片显示,实现位图的读取和显示
* EntryParameter : None
* ReturnValue    : None
********************************************************************************/
uint8 BmpDisplay(uint8 *bmpName)
{
    FATFS fs;               /*Work area (file system object) for logical drive*/
    FIL file;               /*file objects    */
 UINT  br;               /*File R/W count  */
 FRESULT res;
 BMP_HEADER bmpHead;     // 获取头信息

    f_mount(0, &fs);
 res = f_open(&file, (const TCHAR *)bmpName, FA_OPEN_EXISTING|FA_READ);
 if(res != FR_OK)
    {
  return res;
    }
 else
 {
     res = f_read(&file, MMCBuf, 54, &br);        // 读取头文件
  if(res != FR_OK)
     {
   return res;
     }
  else
  {
      bmpHead = Bmp_GetHeadInfo(MMCBuf);     // 获取头信息
   if (bmpHead.bfType == BMP)       // 判断是否为BMP图像
   {
                // 设置图片显示窗口
    TFTSetWindows(0, 0, bmpHead.biHeight, bmpHead.biWidth);
    TFT_CS_CLR();
    TFTWriteIndex(0x0022);
    TFT_RS_SET();
    Offset24Bits = 0;          // 偏移清零

       while (1)
    {
        res = f_read(&file, MMCBuf, MMC_BUFF_SIZE, &br);
     if ((res != FR_OK) || (br < MMC_BUFF_SIZE))// 判断数据是否读完
     {
      break;
     }

     if (bmpHead.biBitCount == 16)       
     {
      Bmp_Disp16Bits(MMCBuf);     // 显示16位位图
     }

     if (bmpHead.biBitCount == 24)    // 显示24位位图
     {
      Bmp_Disp24Bits(MMCBuf);     // 显示24位位图
     }
    }
 
    TFT_CS_SET();
   }
  }
 }

    f_close(&file);      // 关闭文件,必须和f_open函数成对出现
    f_mount(0, 0); 
 return FR_OK;
}

此帖出自NXP MCU论坛
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身

最新回复

  详情 回复 发表于 2012-4-28 18:43
点赞 关注
 

回复
举报

4996

帖子

19

TA的资源

裸片初长成(初级)

沙发
 
此帖出自NXP MCU论坛
 
个人签名我的博客
 
 

回复
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表