vs2010 mfc 对话框 显示 24位 BMP 文件

win7 64 :
使用 vs2010 建立一个 MFC的对话框工程,
然后添加一个按钮,给按钮添加一个点击事件 函数:

代码如下:

void CbmpTestDlg::OnBnClickedBtnSelBmp()
{
    // TODO: 在此添加控件通知处理程序代码

    CString strFileName;
    CBitmap ccBitmap; 


    LPTSTR  lpstrPath = NULL;
    TCHAR   tszTempPath[_MAX_PATH];

    ZeroMemory(tszTempPath, MAX_PATH);

    GetCurrentDirectory(MAX_PATH, tszTempPath);

    lpstrPath = tszTempPath;



    CFileDialog filedlg(TRUE, NULL, NULL,
                        OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
                        _T("图像(*.bmp)|*.bmp"));

    filedlg.m_ofn.lpstrInitialDir=lpstrPath ; //打开当前文件夹所在目录

    if (filedlg.DoModal() == IDOK)  
        strFileName = filedlg.GetFileName();
    else
        return;

    HBITMAP hBitmap = (HBITMAP) LoadImage(NULL, strFileName, IMAGE_BITMAP,
                    0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
              //CBitmap m_bitmap; 
              ccBitmap.Attach(hBitmap); 


    CDC dcImage;
    CDC *pDC = GetDC();

    if (!dcImage.CreateCompatibleDC(pDC))
        return;

    BITMAP bm;
    ccBitmap.GetBitmap(&bm);
    // show the image.
    dcImage.SelectObject(&ccBitmap);
    pDC->BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcImage, 0, 0, SRCCOPY);

}

显示效果如下:
这里写图片描述

代码工程下载链接:
https://download.csdn.net/download/wowocpp/10496032

遇到问题

1 如何 在MFC中打开 console:

    AllocConsole();
    SetConsoleTitle(_T("debug console"));
    freopen("CONOUT$","w",stdout);

    printf("Hello\r\n");

2 如何 FileDialog 默认打开的是当前的exe所在的目录:

    LPTSTR  lpstrPath = NULL;
    TCHAR   tszTempPath[_MAX_PATH];

    ZeroMemory(tszTempPath, MAX_PATH);

    GetCurrentDirectory(MAX_PATH, tszTempPath);

    lpstrPath = tszTempPath;

    CFileDialog filedlg(TRUE, NULL, NULL,
                        OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
                        _T("图像(*.bmp)|*.bmp"));

    filedlg.m_ofn.lpstrInitialDir=lpstrPath ; //打开当前文件夹所在目录

    if (filedlg.DoModal() == IDOK)  
        strFileName = filedlg.GetFileName();
    else
        return;

注意:

该程序并不能显示所有的bmp格式的图片。
具体原因是:
LoadImage 这个函数有问题:

LoadImage 加载 Bmp 文件失败之我的理解!
http://www.cctry.com/thread-278857-1-1.html

QQ截图之后的BMP图片名字是:qq.bmp,之后我用 mspaint 将 qq.bmp 另存为 24位位图的 ok.bmp

我分别对这两个文件按照 bmp 的文件格式将文件头读出来。关于 bmp 的文件格式,大家网上找下,有很多说明的,bmp文件的第一个文件头结构是:BITMAPFILEHEADER,占用 14 个字节,第二个文件头结构是:BITMAPINFOHEADER,占用 40 个字节。

BITMAPFILEHEADER bitmap_file_header = { 0 };
int file_header_len = sizeof(BITMAPFILEHEADER);

BITMAPINFOHEADER bitmap_info_header = { 0 };
int file_info_len = sizeof(BITMAPINFOHEADER);

CFile mFile;
BOOL bRet = mFile.Open(strImgFile, CFile::modeReadWrite);
bRet = mFile.Read(&bitmap_file_header, file_header_len);
bRet = mFile.Read(&bitmap_info_header, file_info_len);

mFile.Close();

这里写图片描述

扫描二维码关注公众号,回复: 1755342 查看本文章

这里写图片描述
看到了吧,bitmap_info_header 的 biHeight 成员,qq.bmp 的是 -275,ok.bmp 的是正的 275。差别就在这。

于是到网上找关于 biHeight 是负数的情况。找到的资料如下:

图像的高度可以为负值。负数值表示接下来的像素内容将从左上角从左到右、从上到下读取;而正数值表示接下来的像素内容将从右下角从左到右、从下到上读取。位图信息头BITMAPINFOHEADER中的 biHeight 不仅体现位图高度,还标记此位图的存储方式。对于一幅位图:
这里写图片描述

位图信息头BITMAPINFOHEADER中的biHeight不仅体现位图高度,还标记此位图的存储方式。对于一幅位图:
高度为正
这里写图片描述

高度为负
这里写图片描述

此类情况模式常用的场合是:用户自己产生一幅图像,譬如在数据采集系统中常常需要将数据进行图像显示。这时用户需要开辟一块内存并按一定方式填充该内存。由于顺序存储方式对用户来说更加直观,操作更加方便,所有常使用第二种模式。这时,在显示和保存位图时将BITMAPINFOHEADER中的biHeight设为负数即可。

这回明白了吧。看来还是 LoadImage 支持的不够好啊。。。好了原因找到了,解决方案也就有了,大家可以自己写一个转换函数,将 Top-Down 与 Bottom-Up 相互转换。如果嫌麻烦的话可以直接使用其他的一些现成的类,比如 ATL 中的 CImage,或者开源的 CxImage 来加载任意格式的图片文件。他们都能无缝对接 BITMAP 对象。方便在 VC 中使用啊。
遇到过这种情况 索性直接用CXImage了
参考文档:

关于BMP
http://blog.csdn.net/u010839382/article/details/51576335

Top-Down vs. Bottom-Up DIBs
https://msdn.microsoft.com/en-us … 07212(v=vs.85).aspx

LoadImage() with QRCode bitmap failing unless file is opened/saved with MS Paint first
https://stackoverflow.com/questi … saved-with-ms-paint

BITMAPINFOHEADER structure
https://msdn.microsoft.com/en-us … 18229(v=vs.85).aspx

BMP文件格式详解(BMP file format)
https://www.cnblogs.com/Matrix_Y … /12/02/1615295.html

参考

https://support.microsoft.com/zh-cn/help/158898/howto-how-to-use-loadimage-to-read-a-bmp-file
如何: 如何使用 LoadImage() 来读取BMP 文件

LoadImage API 可用于从 BMP 文件加载位图。但是,它不返回调色板信息。这篇文章提供了示例代码,并描述如何使用LoadImage检索位图的调色板信息。

查看原始的英语文章:158898
概要
LoadImage API 可用于从 BMP 文件加载位图。但是,它不返回调色板信息。这篇文章提供了示例代码,并描述如何使用LoadImage检索位图的调色板信息。
详细信息
下面的代码使用 LoadImage API 来加载该位图作为 DIBSection,然后从 DIBSection 的颜色表中创建一个调色板。如果颜色表不存在,则使用半色调调色板:

BOOL LoadBitmapFromBMPFile( LPTSTR szFileName, HBITMAP *phBitmap,
   HPALETTE *phPalette )
   {

   BITMAP  bm;

   *phBitmap = NULL;
   *phPalette = NULL;

   // Use LoadImage() to get the image loaded into a DIBSection
   *phBitmap = (HBITMAP)LoadImage( NULL, szFileName, IMAGE_BITMAP, 0, 0,
               LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE );
   if( *phBitmap == NULL )
     return FALSE;

   // Get the color depth of the DIBSection
   GetObject(*phBitmap, sizeof(BITMAP), &bm );
   // If the DIBSection is 256 color or less, it has a color table
   if( ( bm.bmBitsPixel * bm.bmPlanes ) <= 8 )
   {
   HDC           hMemDC;
   HBITMAP       hOldBitmap;
   RGBQUAD       rgb[256];
   LPLOGPALETTE  pLogPal;
   WORD          i;

   // Create a memory DC and select the DIBSection into it
   hMemDC = CreateCompatibleDC( NULL );
   hOldBitmap = (HBITMAP)SelectObject( hMemDC, *phBitmap );
   // Get the DIBSection's color table
   GetDIBColorTable( hMemDC, 0, 256, rgb );
   // Create a palette from the color tabl
   pLogPal = (LOGPALETTE *)malloc( sizeof(LOGPALETTE) + (256*sizeof(PALETTEENTRY)) );
   pLogPal->palVersion = 0x300;
   pLogPal->palNumEntries = 256;
   for(i=0;i<256;i++)
   {
     pLogPal->palPalEntry[i].peRed = rgb[i].rgbRed;
     pLogPal->palPalEntry[i].peGreen = rgb[i].rgbGreen;
     pLogPal->palPalEntry[i].peBlue = rgb[i].rgbBlue;
     pLogPal->palPalEntry[i].peFlags = 0;
   }
   *phPalette = CreatePalette( pLogPal );
   // Clean up
   free( pLogPal );
   SelectObject( hMemDC, hOldBitmap );
   DeleteDC( hMemDC );
   }
   else   // It has no color table, so use a halftone palette
   {
   HDC    hRefDC;

   hRefDC = GetDC( NULL );
   *phPalette = CreateHalftonePalette( hRefDC );
   ReleaseDC( NULL, hRefDC );
   }
   return TRUE;

   }

下面的代码演示如何使用LoadBitmapFromBMPFile函数:

   case WM_PAINT:
   {
     PAINTSTRUCT   ps;
     HBITMAP       hBitmap, hOldBitmap;
     HPALETTE      hPalette, hOldPalette;
     HDC           hDC, hMemDC;
     BITMAP        bm;

   hDC = BeginPaint( hWnd, &ps );

   if( LoadBitmapFromBMPFile( szFileName, &hBitmap, &hPalette ) )
   {
      GetObject( hBitmap, sizeof(BITMAP), &bm );
      hMemDC = CreateCompatibleDC( hDC );
      hOldBitmap = (HBITMAP)SelectObject( hMemDC, hBitmap );
      hOldPalette = SelectPalette( hDC, hPalette, FALSE );
      RealizePalette( hDC );

      BitBlt( hDC, 0, 0, bm.bmWidth, bm.bmHeight,
              hMemDC, 0, 0, SRCCOPY );

      SelectObject( hMemDC, hOldBitmap );
      DeleteObject( hBitmap );
      SelectPalette( hDC, hOldPalette, FALSE );
      DeleteObject( hPalette );
   }
   EndPaint( hWnd, &amp;ps );

   }
   break;

猜你喜欢

转载自blog.csdn.net/wowocpp/article/details/80790470