Новичок
Профиль
Группа: Участник
Сообщений: 3
Регистрация: 9.7.2016
Репутация: нет Всего: нет
|
Доброго времени суток, в ходе разработки небольшой программы для демонстрации графических фильтров возникла следующая проблема: Есть класс BitImage - Обертка над HBITMAP Код | #include "hdcmanager.h" #include "pixel.h" #include <windows.h>
class BitImage { public: inline BitImage() { m_bIsEmpty = true; } inline BitImage(LPCTSTR lpszName) { m_hbmpHandle = (HBITMAP) LoadImage( NULL, lpszName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); BITMAP bmData; GetObject(m_hbmpHandle, sizeof(BITMAP), &bmData); m_lWidth = bmData.bmWidth; m_lHeight = bmData.bmHeight; m_bIsEmpty = !m_hbmpHandle; } inline BitImage(const BitImage& btimPrototype) { formFromPrototype(btimPrototype); } inline BitImage& operator=(const BitImage& btimPrototype) { clear(); formFromPrototype(btimPrototype); return *this; } inline void Draw(HDC hdcDest, int iXPos, int iYPos) { HDCManager::instance().freeHDC(m_hbmpHandle); HDC hdcService = CreateCompatibleDC(hdcDest); HGDIOBJ hgdioDefault = SelectObject(hdcService, m_hbmpHandle); BOOL bResult = BitBlt(hdcDest, iXPos, iYPos, m_lWidth, m_lHeight, hdcService, 0,0, SRCCOPY); SelectObject(hdcService, hgdioDefault); DeleteDC(hdcService); } inline LONG height() const { return m_lHeight; } inline LONG width() const { return m_lWidth; } inline void setPixel(const Pixel& pxlValue, int iX, int iY) { SetPixel(HDCManager::instance()[m_hbmpHandle], iX, iY, pxlValue.m_clrrValue); } inline Pixel getPixel(int iX, int iY) { return Pixel(GetPixel(HDCManager::instance()[m_hbmpHandle], iX, iY)); } inline ~BitImage() { clear(); } protected: inline void formFromPrototype(const BitImage& btimPrototype) { m_bIsEmpty = btimPrototype.m_bIsEmpty; if(!m_bIsEmpty) { m_lWidth = btimPrototype.m_lWidth; m_lHeight = btimPrototype.m_lHeight; HDC hdcDisplay = HDCManager::instance().baseContext(); m_hbmpHandle = CreateCompatibleBitmap(hdcDisplay, m_lWidth, m_lHeight); HDC hdcSource = CreateCompatibleDC (hdcDisplay); HDC hdcDest = CreateCompatibleDC (hdcDisplay); HGDIOBJ hgdioDefaultSource = SelectObject (hdcSource, btimPrototype.m_hbmpHandle); HGDIOBJ hgdioDefaultDest = SelectObject (hdcDest, m_hbmpHandle); BitBlt (hdcDest, 0, 0, m_lWidth, m_lHeight, hdcSource, 0, 0, SRCCOPY); SelectObject (hdcSource, hgdioDefaultSource); SelectObject (hdcDest, hgdioDefaultDest); DeleteDC (hdcSource); DeleteDC (hdcDest); } } inline void clear() { HDCManager::instance().freeHDC(m_hbmpHandle); if(!m_bIsEmpty) { DeleteObject(m_hbmpHandle); m_bIsEmpty = true; } } protected: HBITMAP m_hbmpHandle; bool m_bIsEmpty; LONG m_lWidth, m_lHeight; };
|
Класс HDCManager для хранения HDC, связанного с HBITMA в процессе серии GetPixel/SetPixel: Код | #include <map> #include <windows.h>
using namespace std;
class HDCManager { public: static inline HDCManager& instance() { if(s_hdcmInstance == NULL) { s_hdcmInstance = new HDCManager(); } return *s_hdcmInstance; } inline HDC& operator[](const HBITMAP& hbmpKey) { map<HBITMAP, pair<HDC, HGDIOBJ> >::iterator it = m_mpContexts.find(hbmpKey); if(it == m_mpContexts.end()) { HDC hdcContext = CreateCompatibleDC(m_hdcBase); m_mpContexts.insert(make_pair(hbmpKey, make_pair(hdcContext, SelectObject(hdcContext, hbmpKey)))); return m_mpContexts.find(hbmpKey)->second.first; } return it->second.first; } inline HDC& baseContext() { return m_hdcBase; } inline void freeHDC(const HBITMAP& hbmpFree) { map<HBITMAP, pair<HDC, HGDIOBJ> >::iterator it = m_mpContexts.find(hbmpFree); if(it != m_mpContexts.end()) { SelectObject(it->second.first, it->second.second); DeleteDC (it->second.first); m_mpContexts.erase(it); } } inline ~HDCManager() { map<HBITMAP, pair<HDC, HGDIOBJ> >::iterator it = m_mpContexts.begin(); while(it != m_mpContexts.end()) { SelectObject(it->second.first, it->second.second); DeleteDC (it->second.first); m_mpContexts.erase(it); it = m_mpContexts.begin(); } ::ReleaseDC(NULL, m_hdcBase); } protected: inline HDCManager() { m_hdcBase = ::GetDC(NULL); } protected: HDC m_hdcBase; map<HBITMAP, pair<HDC, HGDIOBJ> > m_mpContexts; private: HDCManager(const HDCManager& hdcmPrototype); HDCManager& operator=(const HDCManager& hdcmPrototype); private: static HDCManager* s_hdcmInstance; };
HDCManager* HDCManager::s_hdcmInstance = NULL;
|
Класс Pixel - обертка над COLORREF Код | #include <windows.h>
class Pixel { friend class BitImage; public: inline Pixel() { m_clrrValue = CLR_INVALID; } inline Pixel(COLORREF clrrValue) { m_clrrValue = clrrValue; } inline Pixel(BYTE btRed, BYTE btGreen, BYTE btBlue) { m_clrrValue = RGB(btRed, btGreen, btBlue); } inline Pixel(const Pixel& pxlPrototype) { m_clrrValue = pxlPrototype.m_clrrValue; } inline BYTE red() const { return GetRValue(m_clrrValue); } inline BYTE green() const { return GetGValue(m_clrrValue); } inline BYTE blue() const { return GetBValue(m_clrrValue); } inline Pixel& operator=(const Pixel& pxlPrototype) { m_clrrValue = pxlPrototype.m_clrrValue; return *this; } inline ~Pixel() { } protected: COLORREF m_clrrValue; };
|
Ну и собственно код основного окна Код | #include <windows.h> #include "bitimage.h"
HMENU hmnNext = (HMENU)1;
BitImage* g_bmiFront; BitImage* g_bmiBack = NULL;
HWND g_hwndMain; HINSTANCE hinstGlobal;
HMENU GetNextElement() { HMENU hmnNew = hmnNext; hmnNext++; return hmnNew; }
WNDCLASSEX InitWindow(const LPCTSTR& lstrClassName, LRESULT CALLBACK (*pfWndProc)(HWND, UINT, WPARAM, LPARAM), const HINSTANCE& hInstance, const HBRUSH& hbrBackground, const HCURSOR& hcrCursor, const HICON& hicMain, const HICON& hicMini) { WNDCLASSEX wcNew; memset(&wcNew, 0, sizeof(wcNew)); wcNew.cbSize = sizeof(WNDCLASSEX); wcNew.lpszClassName = lstrClassName; wcNew.lpfnWndProc = pfWndProc; wcNew.hInstance = hInstance; wcNew.hbrBackground = hbrBackground; wcNew.hCursor = hcrCursor; wcNew.hIcon = hicMain; wcNew.hIconSm = hicMini; if(!RegisterClassEx(&wcNew)) { throw "Îøèáêà ïðè ðåãèñòðàöèè îêíà!"; } return wcNew; }
HWND SaveCreateWindow(LPCTSTR lstrClassName, LPCTSTR lstrWindowTitle, DWORD dwStyle, int iXPos, int iYPos, int iWidth, int iHeight, HWND hwndParent, HMENU hmnuBase, HINSTANCE hInstance, LPVOID lpvParam) { HWND hwndNew = CreateWindowEx(WS_EX_CLIENTEDGE, lstrClassName, lstrWindowTitle, dwStyle, iXPos, iYPos, iWidth, iHeight, hwndParent, hmnuBase, hInstance, lpvParam); if(hwndNew == NULL) { throw "Îøèáêà ïðè ñîçäàíèè îêíà!"; } return hwndNew; }
void ProcessImage(WPARAM wParam) { if(g_bmiBack != NULL) { delete g_bmiBack; } g_bmiBack = g_bmiFront; BitImage* bmiTemp = new BitImage(*g_bmiBack); for(int iY = 0; iY < bmiTemp->height(); iY++) { for(int iX = 0; iX < bmiTemp->width(); iX++) { Pixel pxlCur = g_bmiBack->getPixel(iX, iY); bmiTemp->setPixel(Pixel(255 - pxlCur.red(), 255 - pxlCur.green(), 255 - pxlCur.blue()), iX, iY); } } g_bmiFront = bmiTemp; }
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) { switch(Message) { case WM_CREATE: { CreateWindow("button", "Îáðàáîòàòü", WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON, 550, 180, 120, 30, hwnd, GetNextElement(), hinstGlobal, NULL); break; } case WM_COMMAND: { ProcessImage(wParam); RedrawWindow(g_hwndMain, NULL, NULL, RDW_INTERNALPAINT); break; } case WM_PAINT: { PAINTSTRUCT psImage; HDC hdcDisplayContext = BeginPaint(hwnd, &psImage); g_bmiFront->Draw(hdcDisplayContext, 0, 0); EndPaint(hwnd, &psImage); break; } case WM_DESTROY: { PostQuitMessage(0); break; } default: { return DefWindowProc(hwnd, Message, wParam, lParam); } } return 0; }
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msgSystem; hinstGlobal = hInstance; try { g_bmiFront = new BitImage("Lenna.bmp"); LPCTSTR lstrClassName = "ImageFilters"; HICON hicGeneral = LoadIcon(NULL, IDI_APPLICATION); WNDCLASSEX wcMain = InitWindow(lstrClassName, WndProc, hInstance, (HBRUSH)(COLOR_WINDOW+1), LoadCursor(NULL, IDC_ARROW), hicGeneral, hicGeneral); g_hwndMain = SaveCreateWindow(lstrClassName, "Ïðîãðàììà äëÿ îáó÷åíèÿ ïðèìåíåíèþ ãðàôè÷åñêèõ ôèëüòðîâ", WS_VISIBLE|WS_OVERLAPPED|WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT, 1024, 550, NULL, NULL, hInstance, NULL); while(GetMessage(&msgSystem, NULL, 0, 0) > 0) { TranslateMessage(&msgSystem); DispatchMessage(&msgSystem); } } catch(LPCTSTR lpstrError) { MessageBox(NULL, lpstrError,"Error!",MB_ICONEXCLAMATION|MB_OK); }
return msgSystem.wParam; }
|
Идея текущей версии программы при запуске загружатьи отображать изображение, а по нажатию на кнопку отображать его негатив. При запуске программы функции отрабатывают корректно ни одна не возвращает ошибку (проверено отладчиком), однако изображение не изменяется. Что у меня реализовано неправильно? Заранее благодарю. PS: К сожалению из-за компилятора не могу использовать ни MFC, ни gdi+, так что прошу не предлагать их использовать. Это сообщение отредактировал(а) Count0 - 13.7.2016, 16:48
|