zoukankan      html  css  js  c++  java
  • DIB位图文件的格式、读取、保存和显示(转载)

    一、位图文件结构

    位图文件由三部分组成:文件头 + 位图信息 + 位图像素数据

    1、位图文件头:BitMapFileHeader。位图文件头主要用于识别位图文件。以下是位图文件头结构的定义:

    typedef struct tagBITMAPFILEHEADER { // bmfh    

             WORD    bfType;                   //bfType指定文件类型。其值必须是0x4d42,即字符串“MB”,也就是说所有“.bmp”文件的头两个字节都是”MB“,标志该文件是位图文件。

             DWORD   bfSize;                  //bfSize的值是位图文件的大小,包括4个字节。

             WORD    bfReserved1;  

             WORD    bfReserved2;         //bfReserved1,bfReserved2为保留字,不用考虑。

             DWORD   bfOffBits;        //为从文件头到实际的位图数据的偏移字节数,

    } BITMAPFILEHEADER

    该结构的长度是固定的,为14个字节(WORD 为无符号16位整数,DWORD为无符号32位整数)。

    2、位图信息:BitMapInfo位图信息中所记录的值用于分配内存,设置调色板信息,读取像素值等。
    以下是位图信息结构的定义:

    1. typedef struct tagBITMAPINFO {  
    2.     BITMAPINFOHEADER    bmiHeader;     //位图信息头
    3.     RGBQUAD             bmiColors[1];       //颜色表
    4. } BITMAPINFO;

    可见位图信息也是由两部分组成的:位图信息头 + 颜色表/调色板(Palette)

    2.1 、位图信息头:BitMapInfoHeader

         位图信息头包含了单个像素所用字节数以及描述颜色的格式,此外还包括位图的宽度、高度、目标设备的位平面数、图像的压缩格式。以下是位图信息头结构的定义:

    1. typedef struct tagBITMAPINFOHEADER{ // bmih    
    2.     DWORD  biSize;              //指定结构BITMAPINFOHEADER的字节数,为40个字节,即sizeof(BITMAPINFOHEADER)*
    3.     LONG   biWidth;               //以像素为单位的图像宽度*
    4.     LONG   biHeight;              // 以像素为单位的图像长度*
    5.     WORD   biPlanes;             //目标设备的位平面数,必须是1,不用考虑。
    6.     WORD   biBitCount           //指定表示颜色时每个像素的位数,常用的值为1(黑白二色图)、4(16色图)、8(256色)、24(真彩色)、*(1)
    7.     DWORD  biCompression;   //图像的压缩格式(这个值几乎总是为0),有效地值为BI_RGB,BI_RLE8,BI_RLE4,BI_BITFIELDS(这些都是Windows定义好的常量)
    8.     DWORD  biSizeImage;       //以字节为单位的图像数据的大小(对BI_RGB压缩方式而言)
    9.     LONG   biXPelsPerMeter;    //指定目标设备的水平分辨率,单位是像素/米。
    10.     LONG   biYPelsPerMeter;    //指定目标设备的垂直分辨率,单位是像素/米。
    11.     DWORD  biClrUsed;          //指定本图像实际用到的颜色数,如果该值为零,则用到的颜色数为2的biBitCount次幂。(2)
    12.     DWORD  biClrImportant;   //指定本图像中重要的颜色数,如果该值为零,则认为所有的颜色都是重要的。(3)
    13. } BITMAPINFOHEADER;

    说明:*是需要加以注意的部分,因为它们是我们在进行位图操作时经常参考的变量
    (1)对于每个像素的字节数,分别有一下意义:
              0,用在JPEG格式中
             1,单色图,调色板中含有两种颜色,也就是我们通常说的黑白图片
             4,16色图
             8,256色图,通常说的灰度图
             16,64K图,一般没有调色板,图像数据中每两个字节表示一个像素,5个或6个位表示一个RGB分量
             24,16M真彩色图,一般没有调色板,图像数据中每3个字节表示一个像素,每个字节表示一个RGB分量
             32,4G真彩色,一般没有调色板,每4个字节表示一个像素,相对24位真彩图而言,加入了一个透明度,即RGBA模式

    (2)这个值通常为0,表示使用biBitCount确定的全部颜色,例外是使用的颜色数目小于制定的颜色深度的颜色数目的最大值。

    (3)这个值通常为0,表示所有的颜色都是必需的。

    位图信息头结构的长度也是固定的,为40个字节(LONG为32位整数)。

    2.2、颜色表/调色板:RGBQuad/Palette。

    调色板一般是针对16位以下的图像而设置的,对于16位和16位以上的图像,由于其位图像素数据中直接对对应像素的RGB(A)颜色进行描述,因而省却了调色板,他们的BITMAPINFOHEADER后面直接是位图数据。而对于16位以下的图像,由于其位图像素数据中记录的只是调色板索引值,因而需要根据这个索引到调色板去取得相应的RGB(A)颜色。颜色表的作用就是创建调色板。调色板实际上是一个数组,共有biClrUsed个元素(如果该值为零,则有2的biBitCount次幂个元素)。数组中每个元素的类型是一个RGBQUAD结构,占4个字节。

    颜色表是由颜色表项组成的,颜色表项结构的定义如下:

    1. typedef struct tagRGBQUAD { // rgbq    
    2.     BYTE    rgbBlue;   
    3.     BYTE    rgbGreen;   
    4.     BYTE    rgbRed;   
    5.     BYTE    rgbReserved;   //保留值
    6. } RGBQUAD;  

    其中需要注意的问题是,RGBQUAD结构中的颜色顺序是BGR,而不是平常的RGB

    3、位图数据。最后,在位图文件头、位图信息头、位图颜色表之后,便是位图的主体部分:位图数据。根据不同的位图,位图数据所占据的字节数也是不同的,比如,对于8位位图,每个字节代表了一个像素,对于16位位图,每两个字节代表了一个像素,对于24位位图,每三个字节代表了一个像素,对于32位位图,每四个字节代表了一个像素

    二、位图文件的读取、保存和显示

    头文件中定义

    1. private:  
    2.  DWORD m_dwDibSize;  
    3.  CPalette m_Palette;  
    4.  int m_nPaletteEntries;  
    5.  RGBQUAD *m_pPalette;     //颜色表指针
    6.  unsigned char *m_pDib, *m_pDibBits;  
    7.  BITMAPINFOHEADER *m_pBIH;     //位图信息头指针

    1、读取位图

    1. //加载图片   
    2. void CImageDisposeDlg::OnBtnloadimage()   
    3. {  
    4.  // TODO: Add your control notification handler code here   
    5.   
    6.  //文件路径名称   
    7.  CString pszFilename;  
    8.   
    9.  //浏览文件对话框   
    10.  CFileDialog hFileDlg(TRUE,"bmp",  
    11.     NULL,  
    12.     OFN_FILEMUSTEXIST|OFN_READONLY|OFN_PATHMUSTEXIST|OFN_NOCHANGEDIR,  
    13.     TEXT("BMP (*.bmp)|*.bmp|所有文件(*.*)|*.*|"),  
    14.     NULL);  
    15.   
    16.  if(hFileDlg.DoModal() == IDOK)  
    17.  {  
    18.     //获得文件路径名称   
    19.     pszFilename=hFileDlg.GetPathName();   
    20.  }  
    21.    
    22.  //文件类   
    23.  CFile cf;  
    24.   
    25.  //文件打开失败,程序返回   
    26.  if( !cf.Open( pszFilename, CFile::modeRead ) )  
    27.  {  
    28.   return;  
    29.  }  
    30.   
    31.  //获得位图信息文件大小   
    32.  DWORD dwDibSize;  
    33.  dwDibSize = cf.GetLength() - sizeof( BITMAPFILEHEADER );  
    34.   
    35.  //申请一块内存存放位图信息   
    36.  unsigned char *pDib;  
    37.  pDib = new unsigned char [dwDibSize];  
    38.  if( pDib == NULL )  
    39.  {  
    40.   return;  
    41.  }  
    42.   
    43.  //位图文件头   
    44.  BITMAPFILEHEADER BFH;  
    45.   
    46.  //从文件读取位图文件头和位图数据   
    47.  try{  
    48.   // 判断读取位图文件头是否成功   
    49.   if( cf.Read( &BFH, sizeof( BITMAPFILEHEADER ) )  
    50.    != sizeof( BITMAPFILEHEADER ) ||  
    51.   
    52.    // 判断是否是位图类型   
    53.    BFH.bfType != 'MB' ||  
    54.   
    55.    // 判断读取位图数据是否成功   
    56.    cf.Read( pDib, dwDibSize ) != dwDibSize ){  
    57.   
    58.    //释放位图数据指针   
    59.    delete [] pDib;  
    60.   
    61.    //读取失败,程序返回   
    62.    return;  
    63.    }  
    64.   }  
    65.  catch( CFileException *e ){  
    66.    e->Delete();  
    67.    delete [] pDib;  
    68.    return;  
    69.   }  
    70.    
    71.  //重置全局位图信息指针   
    72.  if( m_pDib != NULL )  
    73.  {  
    74.   delete m_pDib;  
    75.  }  
    76.     
    77.  //将位图信息指针和位图信息大小赋值给全局变量   
    78.  m_pDib = pDib;  
    79.  m_dwDibSize = dwDibSize;  
    80.   
    81.  //获取位图信息头指针   
    82.  m_pBIH = (BITMAPINFOHEADER *) m_pDib;  
    83.   
    84.  //获取位图调色板指针   
    85.  m_pPalette = (RGBQUAD *) &m_pDib[sizeof(BITMAPINFOHEADER)];  
    86.   
    87.  // 计算调色板中实际颜色数量   
    88.  m_nPaletteEntries = 1 << m_pBIH->biBitCount;//1左移   
    89.  if( m_pBIH->biBitCount > 8 )  
    90.  {  
    91.   m_nPaletteEntries = 0;  
    92.  }  
    93.  else if( m_pBIH->biClrUsed != 0 )  
    94.  {  
    95.   m_nPaletteEntries = m_pBIH->biClrUsed;  
    96.  }  
    97.   
    98.  // 获取位图数据指针   
    99.  m_pDibBits = &m_pDib[sizeof(BITMAPINFOHEADER)+m_nPaletteEntries*sizeof(RGBQUAD)];  
    100.   
    101.  // 重置全局调色板   
    102.  if( m_Palette.GetSafeHandle() != NULL )  
    103.  {  
    104.   m_Palette.DeleteObject();  
    105.  }  
    106.    
    107.  //如果调色板颜色数量不为零,则通过逻辑调色板创建调色板   
    108.  if( m_nPaletteEntries != 0 ){  
    109.   
    110.   //为逻辑调色板分配内存   
    111.   LOGPALETTE *pLogPal = (LOGPALETTE *) new char  
    112.     [sizeof(LOGPALETTE)+  
    113.     m_nPaletteEntries*sizeof(PALETTEENTRY)];  
    114.   
    115.   if( pLogPal != NULL ){  
    116.   
    117.    //设置逻辑调色板的版本   
    118.    pLogPal->palVersion = 0x300;  
    119.    //设置逻辑调色板的颜色数量   
    120.    pLogPal->palNumEntries = m_nPaletteEntries;  
    121.   
    122.    //为每个颜色实体赋颜色值   
    123.    for( int i=0; i<m_nPaletteEntries; i++ ){  
    124.     pLogPal->palPalEntry[i].peRed =  
    125.      m_pPalette[i].rgbRed;  
    126.     pLogPal->palPalEntry[i].peGreen =  
    127.      m_pPalette[i].rgbGreen;  
    128.     pLogPal->palPalEntry[i].peBlue =  
    129.      m_pPalette[i].rgbBlue;  
    130.     }  
    131.   
    132.    //创建调色板   
    133.    m_Palette.CreatePalette( pLogPal );  
    134.    //释放内存   
    135.    delete [] pLogPal;  
    136.    }  
    137.   }  
    138.  //重绘   
    139.  Invalidate();  

    2、保存位图

    1. //保存图片   
    2. void CImageDisposeDlg::OnBtnsave()   
    3. {  
    4.  // TODO: Add your control notification handler code here   
    5.  //文件路径名称   
    6.  CString pszFilename;  
    7.   
    8.  //浏览文件对话框   
    9.  CFileDialog hFileDlg(FALSE,"bmp",  
    10.     NULL,  
    11.     OFN_FILEMUSTEXIST|OFN_READONLY|OFN_PATHMUSTEXIST|OFN_NOCHANGEDIR,  
    12.     TEXT("BMP (*.bmp)|*.bmp|所有文件(*.*)|*.*|"),  
    13.     NULL);   
    14.   
    15.  if(hFileDlg.DoModal() == IDOK)  
    16.  {  
    17.     //获得文件路径名称   
    18.     pszFilename=hFileDlg.GetPathName();   
    19.  }  
    20.   
    21.  // 如果位图信息为空则程序返回   
    22.  if( m_pDib == NULL )  
    23.   return;  
    24.    
    25.  //文件类   
    26.  CFile cf;  
    27.   
    28.  // 创建文件   
    29.  if( !cf.Open( pszFilename,  
    30.   CFile::modeCreate | CFile::modeWrite ) )  
    31.   return;  
    32.    
    33.  // 写入数据   
    34.  try{  
    35.     
    36.   //创建位图文件头   
    37.   BITMAPFILEHEADER BFH;  
    38.   memset( &BFH, 0, sizeof( BITMAPFILEHEADER ) );  
    39.   BFH.bfType = 'MB';  
    40.   BFH.bfSize = sizeof( BITMAPFILEHEADER ) + m_dwDibSize;  
    41.   BFH.bfOffBits = sizeof( BITMAPFILEHEADER ) +  
    42.    sizeof( BITMAPINFOHEADER ) +  
    43.    m_nPaletteEntries * sizeof( RGBQUAD );  
    44.   
    45.   //将数据写入文件   
    46.   cf.Write( &BFH, sizeof( BITMAPFILEHEADER ) );  
    47.   cf.Write( m_pDib, m_dwDibSize );  
    48.   }  
    49.  catch( CFileException *e ){  
    50.   e->Delete();  
    51.   return;  
    52.   }  
    53.   

    3、显示位图

    1. void CImageDisposeDlg::OnPaint()   
    2. {  
    3.   
    4.  CPaintDC dc(this);   
    5.   
    6.  //如果位图信息为空,程序返回   
    7.  if( m_pDib == NULL )  
    8.   return;  
    9.   
    10.  //获得位图宽高   
    11.  int nWidth,nHeight;  
    12.  nWidth = m_pBIH->biWidth;  
    13.  nHeight = m_pBIH->biHeight;  
    14.   
    15.  //如果有调色板则使用调色板   
    16.  if( m_Palette.GetSafeHandle() != NULL )  
    17.  {  
    18.   CPalette *pOldPalette;  
    19.   pOldPalette = dc.SelectPalette( &m_Palette, FALSE );//选择调色板   
    20.   dc.RealizePalette();//实现调色板   
    21.   
    22.   //绘图   
    23.   StretchDIBits( dc.m_hDC, 0, 0,  
    24.    nWidth, nHeight,  
    25.    0, 0,  
    26.    m_pBIH->biWidth, m_pBIH->biHeight,  
    27.    m_pDibBits,  
    28.    (BITMAPINFO *) m_pBIH,  
    29.    BI_RGB, SRCCOPY );  
    30.   
    31.   //恢复调色板   
    32.   dc.SelectPalette( pOldPalette, FALSE );  
    33.  }  
    34.  else//没有调色板,直接绘制   
    35.  {  
    36.   StretchDIBits( dc.m_hDC, 0, 0,  
    37.    nWidth, nHeight,  
    38.    0, 0,  
    39.    m_pBIH->biWidth, m_pBIH->biHeight,  
    40.    m_pDibBits,  
    41.    (BITMAPINFO *) m_pBIH,  
    42.    BI_RGB, SRCCOPY );  
    43.  }  
    44. }  
  • 相关阅读:
    面试官:反射都不会,还敢说自己会Java?
    nginx 开启x-forward
    不写代码,从0到1教你制作炫酷可视化大屏
    5G 专网部署方案
    Mac运行pygame一直显示空白屏幕
    数据库大咖解读“新基建”,墨天轮四重好礼相送!
    Oracle 20c 新特性:自动的区域图
    4000多人全靠报表自动化,效率提高60%,这套数据平台方法论真强
    EBS开发性能优化之查找需要优化的程序
    EBS开发性能优化之SQL语句优化
  • 原文地址:https://www.cnblogs.com/xuepei/p/4026247.html
Copyright © 2011-2022 走看看