为什么我的代码不呈现灰度效果

时间:2014-09-04 08:42:47

标签: c++ winapi bitmap gdi

这是我的代码

// GrayScale.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "GrayScale.h"

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst;                                // current instance
TCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name

// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
BOOL                LoadBitmapFromBMPFile( LPTSTR, HBITMAP * );

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: Place code here.
    MSG msg;
    HACCEL hAccelTable;

    // Initialize global strings
    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadString(hInstance, IDC_GRAYSCALE, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_GRAYSCALE));

    // Main message loop:
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
//    This function and its usage are only necessary if you want this code
//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
//    function that was added to Windows 95. It is important to call this function
//    so that the application will get 'well formed' small icons associated
//    with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_GRAYSCALE));
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_GRAYSCALE);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassEx(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // Store instance handle in our global variable

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;
    HBITMAP hBMP;

    switch (message)
    {
    case WM_COMMAND:
        wmId    = LOWORD(wParam);
        wmEvent = HIWORD(wParam);
        // Parse the menu selections:
        switch (wmId)
        {
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            break;
        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
    case WM_PAINT:

     PAINTSTRUCT   ps;
     HBITMAP       hBitmap, hOldBitmap;
     HDC           hdc, hMemDC;
     BITMAP        bm;

    hdc = BeginPaint(hWnd, &ps);

   if( LoadBitmapFromBMPFile( L"C://sample.bmp", &hBitmap ) )
   {
      GetObject( hBitmap, sizeof(BITMAP), &bm );
      hMemDC = CreateCompatibleDC( hdc );
      hOldBitmap = (HBITMAP)SelectObject( hMemDC, hBitmap );
      RealizePalette( hdc );

        RGBQUAD rgbColors[256];
        UINT cColors = GetDIBColorTable(hdc, 0, 256, rgbColors);
        for (UINT iColor = 0; iColor < cColors; iColor++) {
         BYTE b = (BYTE)((30 * rgbColors[iColor].rgbRed +
                         59 * rgbColors[iColor].rgbGreen +
                         11 * rgbColors[iColor].rgbBlue) / 100);
        rgbColors[iColor].rgbRed = b;
        rgbColors[iColor].rgbGreen = b;
        rgbColors[iColor].rgbBlue = b;
        }
        SetDIBColorTable(hMemDC, 0, cColors, rgbColors);

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

      SelectObject( hMemDC, hOldBitmap );
      DeleteObject( hBitmap );
   }
        EndPaint(hWnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

BOOL LoadBitmapFromBMPFile( LPTSTR szFileName, HBITMAP *phBitmap )
   {
   BITMAP  bm;
   *phBitmap = 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;
   return TRUE;
   }

我使用了来自http://blogs.msdn.com/b/oldnewthing/archive/2006/11/15/1081320.aspx的想法来渲染灰度,但显然没有像原始图像那样的颜色反射。

1 个答案:

答案 0 :(得分:1)

要将加载的HBITMAP转换为灰度,您还可以修改像素本身。我从前一段时间写的更大的代码块中提取了以下函数:

BOOL convert2GrayScale(HBITMAP hBitmap)
{
    BOOL result = FALSE;
    DIBSECTION dib;
    unsigned char *pPixel;
    unsigned char *pEnd;
    int gray;


    if (GetObject(data->hGrayScale, sizeof(dib), (LPVOID)&dib) > 0)
    {
        result = TRUE;   // assume success from now on...

        pPixel = dib.dsBm.bmBits;
        pEnd = &(pPixel[dib.dsBmih.biSizeImage]);
        while (pPixel < pEnd)
        {
            switch (dib.dsBmih.biBitCount)
            {
//            case 8:
//                todo...
//                break;

//            case 16:
//                todo...
//                break;

            case 24:
                /* average RGB value of pixel */
                gray = (int)pPixel[0] + (int)pPixel[1] + (int)pPixel[2];            
                gray /= 3;

                /* modify RGB of current pixel */
                *pPixel++ = (unsigned char)gray;
                *pPixel++ = (unsigned char)gray;
                *pPixel++ = (unsigned char)gray;
                break;

            default:
                result = FALSE;
                pPixel = pEnd;   // unsupported format ... leave everything as it is!
                break;
            }
        }
    }

    return (result);
}

肯定会有更好的色彩转换 - &gt;灰度级,但对于平均RGB值的演示,可以完成工作。请注意(目前)此实现只能转换24位位图。

另外一个注意事项: 您可能不希望在每次接收WM_PAINT消息时加载位图...根据用户的操作,您的窗口可能每秒接收许多这些消息。加载位图一次(WM_CREATE)并将其保存在某处(例如,在与窗口关联的已分配结构中 - &gt; SetWindowLongPtr(.., GWLP_USERDATA, ..))。