Chinaunix首页 | 论坛 | 博客
  • 博客访问: 232343
  • 博文数量: 17
  • 博客积分: 547
  • 博客等级: 中士
  • 技术积分: 276
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-23 20:35
文章分类

全部博文(17)

文章存档

2011年(17)

分类: 嵌入式

2011-08-19 12:34:44

    BMP(全称Bitmap)是标准图像文件格式,可以分成两类:设备相关位图(DDB)和设备无关位图(DIB),使用非常广。它采用位映射存储格式,除了图象深度可选以外,不采用其他任何压缩。BMP文件的图像深度可选lbit、4bit、8bit及24bit。
   NETC下面详细解说BMP图象格式,BMP解码及BMP在LCD显示程序!
一.BMP文件格式
1.位图文件头:14字节
2.位图信息头:40字节
3.彩色表(调色板):4N字节
4.位图数据:根据文件大小
二. 位图文件结构体
1.头包含文件类型、文件大小、存放位置等信息。结构定义如下:
 typedef struct tagBITMAPFILEHEADER
  {
      UNIT bfType;      // 位图文件的类型,必须为BM(0-1字节)
      DWORD bfSize;     // 位图文件的大小,以字节为单位(2-5字节) 
      UINT bfReserved1; // 位图文件保留字,必须为0(6-7字节) 
      UINT bfReserved2; // 位图文件保留字,必须为0(8-9字节) 
      DWORD bfOffBits;  //
说明实际图形数据的偏移量(10-13字节) 
  }BITMAPFILEHEADER;
2.位图信息头包含位图的大小、压缩类型、和颜色格式,结构定义如下:
 typedef struct tagBITMAPINFOHEADER
  {
      DWORD biSize;       //说明BITMAPINFOHEADER结构所需字节数
      LONG biWidth;       //说明图像宽度
      LONG biHeight;      //说明图像高度
      WORD biPlanes;      //为目标设备说明位面数,其值设为1
      WORD biBitCount;    //每个像素的位数,单色位图为1,256色为8,24bit为24。
      DWORD biCompression; //压缩说明,BI_RGB:无压缩,BI_RLE8:8位RLE压缩,BI_RLE4:4位RLE压缩
      DWORD biSizeImage;    //说明图像大小,如无压缩,可设为0
      LONG biXPelsPerMerer; //水平分辨率
      LONG biYPelsPerMerer;  //垂直分辨率
      DWORD biClrUsed;       //位图使用的颜色数
      DWORD biClrImportant;  //重要颜色数目
  }BITMAPINFOHEADER;
3.彩色表包含的元素与位图所具有的颜色数目相同,像素颜色用结构RGBQUAD来表示:
typedef struct tagRGBQUAD
{
    BYTE rgbBlue;      // 指定蓝色强度
    BYTE rgbGreen;     //指定绿色强度
    BYTE rgbRed;       //指定红色强度
    BYTE rgbReserved;  //保留,设为0
 }RGBQUAD;
三.位图数据
    位图数据紧跟在彩色表后的是图像数据阵列,图像每一扫描行有连续的字节组成 扫描行由底向上存储,从左向右,阵列中第一字节为左下角像素,最后一字节为右上角像素.
四.BMP位图解码和LCD显示程序
  BMP要在LCD上显示最首先要对BMP进行解码,LCD显示需要的是16位的BMP(RGB565 ) R 11111 G 111111 B 11111.也就是提取出BMP的位图数据,可用现成的工具,也可编写解码程序解码。
1.程序解码BMP显示
/******************** (C) COPYRIGHT 2011 NETCreate ****************************
* 文件名称 : bmpdisplay.c
* 程序作者 : NETCreate (陈建长) - netc.blog.chinaunix.net
* 程序版本 : V1.1.0
* 编制日期 : 2011/8/20
* 功能描述 : BMP解码程序.
*******************************************************************************
* CPU : STM32F103ZET6
* 时钟: 72MHz
* 声明:算法均有NETC编写,转载请注明出处.
******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include
#include
#include "stm32100e_eval_lcd.h"
/* SDIO_SD include */
#include "stm32_eval_sdio_sd.h"
#include "ff.h"
#include "diskio.h"
 
#define NULL 0
#define BYTE_PER_PIXEL 2
#define MAX_X 320
#define MAX_Y 240
#pragma pack(1) /* 设置结构体的边界对齐为1个字节,也就是所有数据在内存中是连续存储的 */
/* 头包含文件类型、文件大小、存放位置等信息 */
typedef  struct 

      short      bfType;       /* 位图文件的类型,必须为BM(0-1字节) */                       
      long       bfSize;       /* 位图文件的大小,以字节为单位(2-5字节) */                
      short      bfReserved1;  /* 位图文件保留字,必须为0(6-7字节) */         
      short      bfReserved2;  /* 位图文件保留字,必须为0(8-9字节)  */        
      long       bfoffBits;    /* 说明实际图形数据的偏移量(10-13字节) */         
}  BITMAPFILEHEADER;
#pragma pack()
/* Private functions ---------------------------------------------------------*/
/* 私有函数------------------------------------------------------------------*/
/*******************************************************************************
* 函数名称: displaybmp.
* 功能描述: 从FATFS文件系统中读一张BMP并在指定的坐标显示.
* 输入参数: x,y, *path (path 为路径 如“test.bmp”).        
* 输出参数: None
* 返回参数: None
*******************************************************************************/
void displaybmp(unsigned int x,unsigned int y, const char *path)
{
 
    /* FATFS */
 FRESULT res;               /* FatFs 函数公共结果代码 */
 FIL  fbmp;                   /* 文件对象 */
 UINT br;             /* 文件读写字节字节计数 */
  long height;
  long width;
  unsigned int i,j;
  BITMAPFILEHEADER bfile;
  unsigned char *pDIBData = NULL;
  unsigned char r = 0, g = 0, b = 0;
  unsigned short R = 0, G = 0, B = 0;
  unsigned short color = 0;
   /* OPEN FILE */
  res = f_open(&fbmp,path, FA_OPEN_EXISTING | FA_READ);
  if (res == FR_OK )
   printf(" Open file OK! \n\r");
 else
  printf(" Open file fail! \n\r");
  /* READ FILE 读取文件头信息 */
  res = f_read(&fbmp, &bfile, sizeof(bfile), &br);
  printf(" bfsize=%d, bfoffbits=%d \n\r",bfile.bfSize, bfile.bfoffBits);
   
  /* 获取文件的宽度 高度 f_lseek 从18个字节开始读*/
  f_lseek(&fbmp, 18);
  f_read(&fbmp, (void *)&width, sizeof(long),&br);
  f_read(&fbmp, (void *)&height, sizeof(long),&br);
  printf(" width  =%d \n\r",width);
  printf(" height =%d \n\r",height);
  for (i = 0; i < height; i++)
     for (j = 0; j < width; j++)
     {
  
    /* 分配图像数据3个字节存储空间,实际的图像数据大小:文件大小 - 图像数据与文件头的偏移量 */
    /* 如果RAM够大 可以分配整个文件 pDIBData = (unsigned char *)malloc(bfile.bfSize -  bfile.bfoffBits); */
    pDIBData = (unsigned char *) malloc(3);
    if(pDIBData == NULL)
    {
      printf("mem allocate failed\n");
      break;    
    }
    /* 读取图像数据3个字节至分配的存储空间 */
    /*
     **lseek( fp_bmp, bfile.bfoffBits, SEEK_SET ); 如果RAM够大一次读出
           **read( fp_bmp, pDIBData, bfile.bfSize -  bfile.bfoffBits);
     */
    f_lseek(&fbmp, bfile.bfoffBits +=3);
    f_read(&fbmp, pDIBData,3,&br);
      /* 显示图像,这里需要注意如何将RGB24转换为RGB565 */
      /* 注意从bmp文件中读出的图像数据连续的三个字节BGR */
   /* 红色r占5为屏蔽低三位  绿色g占6为屏蔽低两位   蓝色b占5为屏蔽低三位 */
   /* 先读出的三个字节对应的是图像中的左下角的那个像素,最后三个字节对应图像 右上角*/
      b = *pDIBData ; g = *(pDIBData + 1) ; r = *(pDIBData + 2);
   r = r & (~(0x07)); g = g & (~(0x03)); b = b & (~(0x7));
   R = (unsigned short)r << 8;
   G = (unsigned short)g << 3;
   B = (unsigned short)b >> 3;
   color = R | G | B;
     
   /* 画图 左下开始 */
   if ( ( (0+j) < MAX_X) && ( (0+i) < MAX_Y) )
    DrawPoint(x+j,y+height-i,color);     
    free(pDIBData);
 }
  f_close(&fbmp);  
}
 
 
 
2.用现成的软件工具解码得出位图数据
解码工具: Image2LCD.rar   
     a.直接取一张16位BMP位图时,biBitCount=16,1个像素占2个字节,从R -> G -> B bit(15-0)左到右,上到下取数据 ,把G往R和B分三位。如:
R 0XF8,0X00
  11111000 00000000
G 0X07,0XE0
  00000111 11100000
B 0X00,0X1F
00000000 00011111
程序实现:
/*******************************************************************************
* 函数名称: Paint_Bmp16.
* 功能描述: 在LCD屏幕上指定坐标点画一个指定大小的BMP图片 NETC-陈建长 程序.
* 输入参数: unsigned int x,unsigned int y,显示起始位置
             unsigned int width,unsigned int high,BMP大小
     unsigned char bmp[] BMP数据数组首地址 如 gImage_LCDTEST.        
* 输出参数: None
* 返回参数: None
*******************************************************************************/
void paint_Bmp16(unsigned int x,unsigned int y,unsigned int width,unsigned int high, unsigned char bmp[])
{
 unsigned short color;    /* 像素颜色 */
 unsigned int p = 0,i,j;   
 for(i=0;i G -> B bit(15-0),左到右,上到下左起为最高位存数据 */
 {         /* 为两个8位的数据 存一个像素 把G往R和B分三位  */
  for(j=0;j  {           /* RGB565 分为2个数据保存 第一个X 0x100 | 第二个后还原一点像素 */
      color = ( (bmp[p] * 0x100) | (bmp[p+1]) );
   if ( ( (x+j) < SCR_XSIZE_TFT) && ( (y+i) < SCR_YSIZE_TFT) )
   PutPixel(x+j,y+i,color);
   p = p + 2;
  }
 }
}

    b.24位BMP RGB24转RGB565显示程序:

/*******************************************************************************
* 函数名称:  Paint_Bmp24.
* 功能描述:  在LCD屏幕上指定坐标点画一个指定大小的BMP图片,RGB24转换为RGB565
     按BMP位图数据的存放格式, 读出的三个字节对应的是图像中的左下角的像素,
     最后三个字节对应图像.右上角的像素,连续的三个字节中第一个字节是蓝色分量,
     第二是绿色分量,第三个字节为红色分量,只需把BMP数据指针给函数即可转换.
      NETC-陈建长 程序.
* 输入参数: unsigned int x,unsigned int y,显示起始位置
             unsigned int width,unsigned int high,BMP大小
     unsigned char *pDIBData BMP数据数组首地址 如 gImage_LCDTEST.        
* 输出参数: None
* 返回参数: None
*******************************************************************************/
void paint_Bmp24(unsigned int x,unsigned int y,unsigned int width,unsigned int high,unsigned char *pDIBData)
{
 unsigned short color;    /* 像素颜色 */
 unsigned int i,j;
 unsigned short r,g,b,R,G,B;
   for (i = 0; i < high; i++)
     for (j = 0; j < width; j++)
     {
          /* 从bmp文件中读出的图像数据连续的三个字节中第一个字节为蓝色分量 */
          /* 第二个字节为绿色分量 第三个字节为红色分量 */
          b = *pDIBData ; g = *(pDIBData + 1) ; r = *(pDIBData + 2);
           /* RGB24转换为RGB565 */
          /* 红色r占5为屏蔽低三位  绿色g占6为屏蔽低两位   蓝色b占5为屏蔽低三位 */
          r = r & (~(0x07)); g = g & (~(0x03)); b = b & (~(0x7));
          R = (unsigned short)r << 8;
          G = (unsigned short)g << 3;
          B = (unsigned short)b >> 3;
          color = R | G | B;
         /*
   ** 计算偏移量,最先读出的三个字节对应的是图像中的左下角的那个像素
   ** 最后三个字节对应图像 右上 角 的那个像素
   */
    if ( ( (0+j) < SCR_XSIZE_TFT) && ( (0+i) < SCR_YSIZE_TFT) )
    PutPixel(x+j,y+high-i,color);
         pDIBData += 3;
     }
}
 
阅读(4335) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~