字段 |
含义 |
PBYTE *ppRow |
①指向位图视觉上最上面的一行像素。(不管是自下而上,还是自上而下) ②放在第一个字段,为的是后面定义宏时可方便访问到 |
int iSignature |
=“Dib ”,是这个结构体的标志 |
HBITMAP hBitmap |
存储了由CreateDIBSection返回的位图句柄(注意,实质是DIB,但兼有DDB的特点,可直接BitBlt) |
BYTE *pBits |
指向像素阵列的指针,其指针值在CreateDIBSection中设定,而所指向的内存由操作系统管理,删除位图句柄后会自动释放。 |
DIBSECTION |
在DibCreateFromInfo中调用GetObject来填充该结构体,以方便使用(注意DibCreateFromInfo函数被本例所有创建DIB的函数所调用)。 |
int iRShift[3] |
是个数组,3个元素分别为R、G、B颜色遮罩需右移的位数 |
int iLShift[3] |
是个数组,3个元素分别为R、G、B颜色遮罩需左移的位数 |
16.4.2 信息获取函数
(1)DibIsValid函数——用来确保DIBSTRUCT结构的有效性
(2)DibIsAddressable(也可定义为DibIsNotCompression):判断位图是否被压缩
(3)DibInfoHeaderSize等一组函数用于获取DIB区块各部分大小,这些函数可用来将一个DIB Section转换为紧凑DIB。
(4)获得各类指针的函数:如DibInfoHeaderPtr(获取BITMAPINFOHEADER指针)
16.4.3 读写像素信息
(1)DibPixelPtr:用来获取像素的内存指针。注意DIBSTRUCT结构的ppRow是一个指向从上向下排列的DIB像素行的指针,即ppRow[0]是位图视觉上的最上面的一行。如果位图被压缩时返回NULL。
(2)DibGetColor和DibSetColor:像素点在颜色表的值。对于1、4、8位,其RGB值就是要通过颜色表来查找。(对于16、24、32位的,不能通过这两个函数获取,其RGB值要通过掩码和位移获得)
16.4.4 创建和转换
(1)DibCreateFromInfo函数:是DIBHELP库中唯一一个调用CreateDIBSection并为DIBSTRUCT分配内存的函数。其他所有创建或复制都要通过调用该函数来完成。
①参数:BITMAPINFO结构的指针
②该函数调用CreateDIBSeciton后会初始化DIBSTRUCT的所有字段,第一个字段ppRow总是指向DIB的最上面的一行。
(2)DibDelete用来删除由DibCreateFromInfo创建的位图,并释放内存。
(3)DibCopyToPackedDib和DibCopyFromPackedDib常用于应用程序与剪贴板交换DIB
(4)DibCopyToDdb:从一个DIB创建一个GDI位图对象。
16.4.5 宏——快速读写像素位的宏(在DIBHELP.H头文件中)
16.4.6 Dibble程序
(1)三个重要的静态变量hdib、hPalette、hBitmap
(2)WM_USER_SETSCROLL和WM_USER_CREATEPAL消息:用来重置滚动条和创建调色板
(3)DisplayDib:显示位图,提供正常、居中、满拉到客户区、各向同性等4种方式。
①WM_PAINT消息中:位图句柄来自于DibCopyToDdb函数。(因可能要用调色板来显示)
②打印时:从DitbitmapHandle得到DIB Section位图的句柄。
(4)剪贴板:调用DibCopyToPackedDib和DibCopyFromPackedDib函数
(5)Flip函数——上下翻转;Rotate——顺时针转90度。
①DibFlipHorizontal函数:演示通过DibGetPixel和DibSetPixel,效率较低
②DibRotateRight函数:通过DIBHELP.H中定义的宏来读写像素,效率高。
16.4.7 简单的调色板和优化的调色板——在256色的视频模式下,可选择不同调色板
(1)创建调色板的函数
①半色调调色板——系统API提供的。会使用万能调色板与抖动技术来实现该调色板。
②DibPalDibTable:根据DIB颜色表来创建调色板
③DibPalAllPurpose:创建通用的调色板,其颜色见DibPal.C文件
④DibPalUniformGrays:创建一个只有灰度色阶的调色板
(2)优化调色板
①均匀分布算法:DibPalUniformColors——创建iNumR×iNumG×iNumB调色板,一般8级红色、8级绿色和4级蓝色,因为人眼为蓝色比较不敏感。
②流行度算法——DibPalPopularity函数
A、使用位图中被使用最多的256种RGB色值来构成调色板。但24位RGB,可表示2^24种颜色,如果每种颜色用1个int型保存使用次数的话,共需要64M左右,内存消耗大。
B、解决办法是只用RGB权重最高的几位,如用6位而非8位表示R值(因为显示器的解析度也是6位)。这样只需1M,而5位时只需32768字节。
③中分算法——DibPalMedianCut(PaulHeckbert发明)
A、中分算法中RGB值被映射到一个三维坐标中,三个坐标轴分别表示R、G、B
B、每个像素点的RGB值都能在这个坐标系中找到相应的点
C、找到一个能包含所有图像像素的长方体,取最长的一条边,将长方体分成两部分,使划分后的每个部分含有相同的像素数量。
D、然后对这两个盒子做同样的划分,这样2个分为4个、4个分为8个,8个分为16个,然后是32个,64个、128个、256个。
E、现在得到256个盒子,每个都包含了相等的像素数。对每个盒子的颜色取其平均值,并利用这个结构来改变调色板。
16.4.8 格式转换——参考DIbConv.c文件
(1)GetNearestPaletteIndex返回获得调色板中最接近的颜色的索引值
UINT GetNearestPaletteIndex
(
HPALETTE hpal, // 逻辑调色板
COLORREF crColor // 要匹配的颜色
)
(2)DibPalVga:获取标准16色显示器颜色值
(3)HDIBDibConvert(HDIB hdibSrc, int iBitCountDst);用来进行格式转换的函数
【Dibble程序】
效果图
//Dibble.c主程序
/*------------------------------------------------------------ DIBBLE.C -- Bitmap and Palette Program (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> #include "resource.h" #include "DibHelp.h" #include "DibConv.h" #include "DibPal.h" #define WM_USER_SETSCROLLS (WM_USER + 1) #define WM_USER_DELETEDIB (WM_USER + 2) #define WM_USER_DELETEPAL (WM_USER + 3) #define WM_USER_CREATEPAL (WM_USER + 4) LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); static TCHAR szAppName[] = TEXT("Dibble"); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { HWND hwnd; MSG msg; WNDCLASSEX wndclass; HACCEL hAccel; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.cbSize = sizeof(WNDCLASSEX); wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(hInstance, szAppName); wndclass.hIconSm = LoadIcon(hInstance, szAppName); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = szAppName; wndclass.lpszClassName = szAppName; if (!RegisterClassEx(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, // window class name szAppName, // window caption WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); hAccel = LoadAccelerators(hInstance, szAppName); while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(hwnd, hAccel, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam; } /*------------------------------------------------------------------------------- DisplayDib:根据菜单项的选择来显示(打印)DIB的实际大小图像或缩放的图像 --------------------------------------------------------------------------------*/ int DisplayDib(HDC hdc, HBITMAP hBitmap, int x, int y, int cxClient, int cyClient, WORD wShow, BOOL fHalftonePalette) { BITMAP bitmap; HDC hdcMem; int cxBitmap, cyBitmap, iReturn; GetObject(hBitmap, sizeof(BITMAP), &bitmap); cxBitmap = bitmap.bmWidth; cyBitmap = bitmap.bmHeight; SaveDC(hdc); if (fHalftonePalette) SetStretchBltMode(hdc, HALFTONE); else SetStretchBltMode(hdc, COLORONCOLOR); hdcMem = CreateCompatibleDC(hdc); SelectObject(hdcMem, hBitmap); switch (wShow) { case IDM_SHOW_NORMAL: if (fHalftonePalette) { iReturn = StretchBlt(hdc, 0, 0, min(cxClient, cxBitmap - x), min(cyClient, cyBitmap - y), hdcMem, x, y, min(cxClient, cxBitmap - x), min(cyClient, cyBitmap - y), SRCCOPY); } else { iReturn = BitBlt(hdc, 0, 0, min(cxClient, cxBitmap - x), min(cyClient, cyBitmap - y), hdcMem, x, y, SRCCOPY); } break; case IDM_SHOW_CENTER: if (fHalftonePalette) { iReturn = StretchBlt(hdc, (cxClient - cxBitmap) / 2, (cyClient - cyBitmap) / 2, cxBitmap, cyBitmap, hdcMem, 0, 0, cxBitmap, cyBitmap, SRCCOPY); } else { iReturn = BitBlt(hdc, (cxClient - cxBitmap) / 2, (cyClient - cyBitmap) / 2, cxBitmap, cyBitmap, hdcMem, 0, 0, SRCCOPY); } break; case IDM_SHOW_STRETCH: iReturn = StretchBlt(hdc, 0, 0, cxClient, cyClient, hdcMem, 0, 0, cxBitmap, cyBitmap, SRCCOPY); break; case IDM_SHOW_ISOSTRETCH: SetMapMode(hdc, MM_ISOTROPIC); SetWindowExtEx(hdc, cxBitmap, cyBitmap, NULL); SetViewportExtEx(hdc, cxClient, cyClient, NULL); SetWindowOrgEx(hdc, cxBitmap / 2, cyBitmap / 2, NULL); SetViewportOrgEx(hdc, cxClient / 2, cyClient / 2, NULL); //iReturn = StretchBlt(hdc, 0, 0, // cxBitmap, cyBitmap, // hdcMem, 0, 0, // cxBitmap, cyBitmap, // SRCCOPY); iReturn = BitBlt(hdc, 0, 0, cxBitmap, cyBitmap, hdcMem, 0, 0, SRCCOPY); break; } DeleteDC(hdcMem); RestoreDC(hdc, -1); return iReturn; } /*------------------------------------------------------------------------------- PaletteMenu:设置“Palette”各菜单项的Check属性 --------------------------------------------------------------------------------*/ void PaletteMenu(HMENU hMenu, WORD wItemNew) { static WORD wItem = IDM_PAL_NONE; CheckMenuItem(hMenu, wItem, MF_UNCHECKED); wItem = wItemNew; CheckMenuItem(hMenu, wItem, MF_CHECKED); } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static OPENFILENAME ofn; static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH]; static TCHAR szFilter[] = TEXT("Bitmap Files (*.BMP) *.bmp ") TEXT("All Files (*.*) *.* "); static TCHAR* szCompression[] = { TEXT("BI_RGB"), TEXT("BI_RLE8"), TEXT("BI_RLE4"), TEXT("BI_BITFIELDS"), TEXT("Unknown") }; static HDIB hdib; static HPALETTE hPalette; static HBITMAP hBitmap; static BOOL fHalftonePalette; static HMENU hMenu; BOOL fSuccess; static int cxClient, cyClient, iHscroll, iVscroll; static WORD wShow = IDM_SHOW_NORMAL; static PRINTDLG printdlg = { sizeof(PRINTDLG) }; static DOCINFO di = { sizeof(DOCINFO), TEXT("Dibble:Printing") }; int cxPage, cyPage; HDC hdc, hdcPrn; HGLOBAL hGlobal; BYTE* pGlobal; HDIB hdibNew; PAINTSTRUCT ps; SCROLLINFO si; int iEnable, iConvert = 0; TCHAR szBuffer[256]; switch (message) { case WM_CREATE: //将菜单句柄保存在静态变量hMenu中 hMenu = GetMenu(hwnd); //初始化打开文件对话框 memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hwnd; ofn.lpstrFilter = szFilter; ofn.lpstrFile = szFileName; ofn.nMaxFile = MAX_PATH; ofn.lpstrFileTitle = szTitleName; ofn.nMaxFileTitle = MAX_PATH; ofn.Flags = OFN_OVERWRITEPROMPT; ofn.lpstrDefExt = TEXT("bmp"); return 0; case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); wParam = FALSE; //贯穿功能,继续执行下面的代码 //用户自定义消息,设置滚动条,如果显示模式是正常模式,则隐藏滚动条。如果 //wParam==TRUE,则复位滚动条的位置 case WM_USER_SETSCROLLS: if (hdib == NULL || wShow != IDM_SHOW_NORMAL) { si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_RANGE; si.nMin = 0; si.nMax = 0; SetScrollInfo(hwnd, SB_VERT, &si, TRUE); //隐藏 SetScrollInfo(hwnd, SB_HORZ, &si, TRUE); } else { //垂直滚动条 si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_ALL; GetScrollInfo(hwnd, SB_VERT, &si); si.nMin = 0; si.nMax = DibHeight(hdib); si.nPage = cyClient; if ((BOOL)wParam) //恢复到0的默认位置 si.nPos = 0; SetScrollInfo(hwnd, SB_VERT, &si, TRUE); GetScrollInfo(hwnd, SB_VERT, &si); iVscroll = si.nPos; //水平滚动条 GetScrollInfo(hwnd, SB_HORZ, &si); si.nMin = 0; si.nMax = DibWidth(hdib); si.nPage = cxClient; if ((BOOL)wParam) //恢复到0的默认位置 si.nPos = 0; SetScrollInfo(hwnd, SB_HORZ, &si, TRUE); GetScrollInfo(hwnd, SB_HORZ, &si); iHscroll = si.nPos; } return 0; case WM_VSCROLL: si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_ALL; GetScrollInfo(hwnd, SB_VERT, &si); iVscroll = si.nPos; switch (LOWORD(wParam)) { case SB_LINEUP: si.nPos -= 1; break; case SB_LINEDOWN: si.nPos += 1; break; case SB_PAGEUP: si.nPage -= si.nPage; break; case SB_PAGEDOWN: si.nPage += si.nPage; break; case SB_THUMBTRACK: si.nPos = si.nTrackPos; break; default: break; } si.fMask = SIF_POS; SetScrollInfo(hwnd, SB_VERT, &si, TRUE); GetScrollInfo(hwnd, SB_VERT, &si); if (si.nPos != iVscroll) { ScrollWindow(hwnd, 0, iVscroll - si.nPos, NULL, NULL); iVscroll = si.nPos; UpdateWindow(hwnd); //立即更新窗口,这行可以注释掉 } return 0; case WM_HSCROLL: si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_ALL; GetScrollInfo(hwnd, SB_HORZ, &si); iHscroll = si.nPos; switch (LOWORD(wParam)) { case SB_LINELEFT: si.nPos -= 1; break; case SB_LINERIGHT: si.nPos += 1; break; case SB_PAGELEFT: si.nPage -= si.nPage; break; case SB_PAGERIGHT: si.nPage += si.nPage; break; case SB_THUMBTRACK: si.nPos = si.nTrackPos; break; default: break; } si.fMask = SIF_POS; SetScrollInfo(hwnd, SB_HORZ, &si, TRUE); GetScrollInfo(hwnd, SB_HORZ, &si); if (si.nPos != iHscroll) { ScrollWindow(hwnd, iHscroll - si.nPos, 0, NULL, NULL); iHscroll = si.nPos; UpdateWindow(hwnd); //立即更新窗口,这行可以注释掉 } return 0; case WM_INITMENUPOPUP: if (hdib) iEnable = MF_ENABLED; else iEnable = MF_GRAYED; EnableMenuItem(hMenu, IDM_FILE_SAVE, iEnable); EnableMenuItem(hMenu, IDM_FILE_PRINT, iEnable); EnableMenuItem(hMenu, IDM_FILE_PROPERTIES, iEnable); EnableMenuItem(hMenu, IDM_EDIT_CUT, iEnable); EnableMenuItem(hMenu, IDM_EDIT_COPY, iEnable); EnableMenuItem(hMenu, IDM_EDIT_DELETE, iEnable); if (DibIsAddressable(hdib)) iEnable = MF_ENABLED; else iEnable = MF_GRAYED; EnableMenuItem(hMenu, IDM_EDIT_ROTATE, iEnable); EnableMenuItem(hMenu, IDM_EDIT_FLIP, iEnable); EnableMenuItem(hMenu, IDM_CONVERT_01, iEnable); EnableMenuItem(hMenu, IDM_CONVERT_04, iEnable); EnableMenuItem(hMenu, IDM_CONVERT_08, iEnable); EnableMenuItem(hMenu, IDM_CONVERT_16, iEnable); EnableMenuItem(hMenu, IDM_CONVERT_24, iEnable); EnableMenuItem(hMenu, IDM_CONVERT_32, iEnable); switch (DibBitCount(hdib)) { case 1: EnableMenuItem(hMenu, IDM_CONVERT_01, MF_GRAYED); break; case 4: EnableMenuItem(hMenu, IDM_CONVERT_04, MF_GRAYED); break; case 8: EnableMenuItem(hMenu, IDM_CONVERT_08, MF_GRAYED); break; case 16: EnableMenuItem(hMenu, IDM_CONVERT_16, MF_GRAYED); break; case 24: EnableMenuItem(hMenu, IDM_CONVERT_24, MF_GRAYED); break; case 32: EnableMenuItem(hMenu, IDM_CONVERT_32, MF_GRAYED); break; } if (hdib && DibColorSize(hdib) > 0) iEnable = MF_ENABLED; else iEnable = MF_GRAYED; EnableMenuItem(hMenu, IDM_PAL_DIBTABLE, iEnable); if (DibIsAddressable(hdib) && DibBitCount(hdib)>8) iEnable = MF_ENABLED; else iEnable = MF_GRAYED; EnableMenuItem(hMenu, IDM_PAL_OPT_POP4, iEnable); EnableMenuItem(hMenu, IDM_PAL_OPT_POP5, iEnable); EnableMenuItem(hMenu, IDM_PAL_OPT_POP6, iEnable); EnableMenuItem(hMenu, IDM_PAL_OPT_MEDCUT, iEnable); EnableMenuItem(hMenu, IDM_EDIT_PASTE, IsClipboardFormatAvailable(CF_DIB) ? MF_ENABLED : MF_GRAYED); return 0; case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_FILE_OPEN: //显示“打开文件”对话框 if (!GetOpenFileName(&ofn)) return 0; //如果DIB和调色板己经存在,则删除它们 SendMessage(hwnd, WM_USER_DELETEDIB, 0, 0); //加载DIB文件到内存 SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); hdib = DibFileLoad(szFileName); SetCursor(LoadCursor(NULL, IDC_ARROW)); ShowCursor(FALSE); //重置滚动条 SendMessage(hwnd, WM_USER_SETSCROLLS, TRUE, 0); //创建调色板和DDB SendMessage(hwnd, WM_USER_CREATEPAL, TRUE, 0); //根据调色板,创建DDB——hBitmap if (!hdib) { MessageBox(hwnd, TEXT("Cannot load DIB file!"), szAppName, MB_OK | MB_ICONEXCLAMATION); } InvalidateRect(hwnd, NULL, TRUE); return 0; case IDM_FILE_SAVE: //打开“保存”对话框 if (!GetSaveFileName(&ofn)) return 0; //将DIB保存到文件中 SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); fSuccess = DibFileSave(hdib, szFileName); SetCursor(LoadCursor(NULL, IDC_ARROW)); ShowCursor(FALSE); if (!fSuccess) { MessageBox(hwnd, TEXT("Cannot Save DIB file!"), szAppName, MB_OK | MB_ICONEXCLAMATION); } return 0; case IDM_FILE_PRINT: if (!hdib) return 0; //获得打印机DC printdlg.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION; if (!PrintDlg(&printdlg)) return 0; if (NULL == (hdcPrn = printdlg.hDC)) { MessageBox(hwnd, TEXT("Cannot obtain Printer DC"), szAppName, MB_ICONEXCLAMATION | MB_OK); return 0; } //检查打印机是否支持打印位图 if (!(RC_BITBLT & GetDeviceCaps(hdcPrn, RASTERCAPS))) { DeleteDC(hdcPrn); MessageBox(hwnd, TEXT("Printer cannot print bitmaps"), szAppName, MB_ICONEXCLAMATION | MB_OK); return 0; } //获取打机印的可打印区域 cxPage = GetDeviceCaps(hdcPrn, HORZRES); cyPage = GetDeviceCaps(hdcPrn, VERTRES); fSuccess = FALSE; //将DIB发送到打印机 SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); if ((StartDoc(hdcPrn, &di) > 0) && (StartPage(hdcPrn) > 0)) { DisplayDib(hdcPrn, DibBitmapHandle(hdib), 0, 0, cxPage, cyPage, wShow, FALSE); if (EndPage(hdcPrn) > 0) { fSuccess = TRUE; EndDoc(hdcPrn); } } ShowCursor(FALSE); SetCursor(LoadCursor(NULL, IDC_ARROW)); DeleteDC(hdcPrn); if (!fSuccess) MessageBox(hwnd, TEXT("Cannot print bitmaps"), szAppName, MB_ICONEXCLAMATION | MB_OK); return 0; case IDM_FILE_PROPERTIES: if (!hdib) return 0; wsprintf(szBuffer, TEXT("Pixel %i ") //%i与%d一样的 TEXT("Pixel Height: %i ") TEXT("Bits per pixel: %i ") TEXT("Number of colors: %i ") TEXT("Compression: %s "), DibWidth(hdib), DibHeight(hdib), DibBitCount(hdib), DibNumColors(hdib), szCompression[min(3, DibCompression(hdib))]); MessageBox(hwnd, szBuffer, szAppName, MB_ICONEXCLAMATION | MB_OK); return 0; case IDM_APP_EXIT: SendMessage(hwnd, WM_CLOSE, 0, 0); return 0; case IDM_EDIT_COPY: case IDM_EDIT_CUT: if (!(hGlobal = DibCopyToPackedDib(hdib, TRUE))) return 0; OpenClipboard(hwnd); EmptyClipboard(); SetClipboardData(CF_DIB, hGlobal); CloseClipboard(); if (LOWORD(wParam) == IDM_EDIT_COPY) return 0; //剪切时,继续执行下去 case IDM_EDIT_DELETE: SendMessage(hwnd, WM_USER_DELETEDIB, 0, 0); InvalidateRect(hwnd, NULL, TRUE); return 0; case IDM_EDIT_PASTE: OpenClipboard(hwnd); hGlobal = GetClipboardData(CF_DIB); pGlobal = GlobalLock(hGlobal); //如果己经存在DIB位图和调色板,则删除它们 if (pGlobal) { SendMessage(hwnd, WM_USER_DELETEDIB, 0, 0); hdib = DibCopyFromPackedDib((BITMAPINFO*)pGlobal); SendMessage(hwnd, WM_USER_CREATEPAL, TRUE, 0); } GlobalUnlock(hGlobal); CloseClipboard(); //重置滚动条 SendMessage(hwnd, WM_USER_SETSCROLLS, TRUE, 0); InvalidateRect(hwnd, NULL, TRUE); return 0; case IDM_EDIT_ROTATE: if (hdibNew = DibRotateRight(hdib)) { DibDelete(hdib); DeleteObject(hBitmap); hdib = hdibNew; hBitmap = DibCopyToDdb(hdib, hwnd, hPalette); SendMessage(hwnd, WM_USER_SETSCROLLS, TRUE, 0); InvalidateRect(hwnd, NULL, TRUE); } else { MessageBox(hwnd, TEXT("Not enough memory"), szAppName, MB_OK | MB_ICONEXCLAMATION); } return 0; case IDM_EDIT_FLIP: if (hdibNew = DibFlipHorizontal(hdib)) { DibDelete(hdib); DeleteObject(hBitmap); hdib = hdibNew; hBitmap = DibCopyToDdb(hdib, hwnd, hPalette); InvalidateRect(hwnd, NULL, TRUE); } else { MessageBox(hwnd, TEXT("Not enough memory"), szAppName, MB_OK | MB_ICONEXCLAMATION); } return 0; case IDM_SHOW_NORMAL: case IDM_SHOW_STRETCH: case IDM_SHOW_CENTER: case IDM_SHOW_ISOSTRETCH: CheckMenuItem(hMenu, wShow, MF_UNCHECKED); wShow = LOWORD(wParam); CheckMenuItem(hMenu, wShow, MF_CHECKED); SendMessage(hwnd, WM_USER_SETSCROLLS, TRUE, 0); InvalidateRect(hwnd, NULL, TRUE); return 0; case IDM_CONVERT_32:iConvert += 8; case IDM_CONVERT_24:iConvert += 8; case IDM_CONVERT_16:iConvert += 8; case IDM_CONVERT_08:iConvert += 4; case IDM_CONVERT_04:iConvert += 3; case IDM_CONVERT_01:iConvert += 1; SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); hdibNew = DibConvert(hdib, iConvert); ShowCursor(FALSE); SetCursor(LoadCursor(NULL, IDC_ARROW)); if (hdibNew) { SendMessage(hwnd, WM_USER_DELETEDIB, 0, 0); hdib = hdibNew; SendMessage(hwnd, WM_USER_CREATEPAL, TRUE, 0); InvalidateRect(hwnd, NULL, TRUE); } else { MessageBox(hwnd, TEXT("Not enough memory"), szAppName, MB_OK | MB_ICONEXCLAMATION); } return 0; case IDM_APP_ABOUT: MessageBox(hwnd, TEXT("Dibble (c) Charles Petzold,1998"), szAppName, MB_OK | MB_ICONEXCLAMATION); return 0; } //其余所有的WM_COMMAND消息都是来自调色板项目。如果删除己经存在的调色板,光标将被 //设置为沙漏的形状 SendMessage(hwnd, WM_USER_DELETEPAL, 0, 0); SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); //提醒,所有的调色板消息都以break结束而不是return,这允许后面进行一些额外的处理 switch (LOWORD(wParam)) { case IDM_PAL_DIBTABLE: hPalette = DibPalDibTable(hdib); break; case IDM_PAL_HALFTONE: hdc = GetDC(hwnd); if (hPalette = CreateHalftonePalette(hdc)) fHalftonePalette = TRUE; ReleaseDC(hwnd, hdc); break; case IDM_PAL_ALLPURPOSE: hPalette = DibPalAllPurpose(); break; case IDM_PAL_GRAY2: hPalette = DibPalUniformGrays(2); break; case IDM_PAL_GRAY3: hPalette = DibPalUniformGrays(3); break; case IDM_PAL_GRAY4: hPalette = DibPalUniformGrays(4); break; case IDM_PAL_GRAY8: hPalette = DibPalUniformGrays(8); break; case IDM_PAL_GRAY16: hPalette = DibPalUniformGrays(16); break; case IDM_PAL_GRAY32: hPalette = DibPalUniformGrays(32); break; case IDM_PAL_GRAY64: hPalette = DibPalUniformGrays(64); break; case IDM_PAL_GRAY128: hPalette = DibPalUniformGrays(128); break; case IDM_PAL_GRAY256: hPalette = DibPalUniformGrays(256); break; case IDM_PAL_RGB222: hPalette = DibPalUniformColors(2, 2, 2); break; case IDM_PAL_RGB333: hPalette = DibPalUniformColors(3, 3, 3); break; case IDM_PAL_RGB444: hPalette = DibPalUniformColors(4, 4, 4); break; case IDM_PAL_RGB555: hPalette = DibPalUniformColors(5, 5, 5); break; case IDM_PAL_RGB666: hPalette = DibPalUniformColors(6, 6, 6); break; case IDM_PAL_RGB775: hPalette = DibPalUniformColors(7, 7, 5); break; case IDM_PAL_RGB757: hPalette = DibPalUniformColors(7, 5, 7); break; case IDM_PAL_RGB577: hPalette = DibPalUniformColors(5, 7, 7); break; case IDM_PAL_RGB884: hPalette = DibPalUniformColors(8, 8, 4); break; case IDM_PAL_RGB848: hPalette = DibPalUniformColors(8, 4, 8); break; case IDM_PAL_RGB488: hPalette = DibPalUniformColors(4, 8, 8); break; case IDM_PAL_OPT_POP4: hPalette = DibPalPopularity(hdib, 4); break; case IDM_PAL_OPT_POP5: hPalette = DibPalPopularity(hdib, 5); break; case IDM_PAL_OPT_POP6: hPalette = DibPalPopularity(hdib, 6); break; case IDM_PAL_OPT_MEDCUT: hPalette = DibPalMedianCut(hdib, 6); break; } //当处理完菜单中的调色板项目后,光标恢复为箭头的形状,该项被设为Checked,并 //且刷新客户区 hBitmap = DibCopyToDdb(hdib, hwnd, hPalette); ShowCursor(FALSE); SetCursor(LoadCursor(NULL, IDC_ARROW)); if (hPalette) PaletteMenu(hMenu, (LOWORD(wParam))); InvalidateRect(hwnd, NULL, TRUE); return 0; //WM_COMMAND消息处理完毕 //该消息中删除一个己经存在的DIB,为获取一个新DIB作准备。 //该消息会被打开、粘贴或其它菜单命令所调用 case WM_USER_DELETEDIB: if (hdib) { DibDelete(hdib); hdib = NULL; } SendMessage(hwnd, WM_USER_DELETEPAL, 0, 0); return 0; //基于一个新DIB创建一个调色板。如果wParam==TRUE,则同时创建DDB case WM_USER_CREATEPAL: if (hdib) { hdc = GetDC(hwnd); if (!(RC_PALETTE & GetDeviceCaps(hdc, RASTERCAPS))) //不支持调色调 { PaletteMenu(hMenu, IDM_PAL_NONE); } else if (hPalette = CreateHalftonePalette(hdc)) //创建半色调调色板 { fHalftonePalette = TRUE; PaletteMenu(hMenu, IDM_PAL_HALFTONE); } ReleaseDC(hwnd, hdc); if ((BOOL)wParam) hBitmap = DibCopyToDdb(hdib, hwnd, hPalette); } return 0; //删除一个己经存在的调色板,为创建新调色板做准备 case WM_USER_DELETEPAL: if (hPalette) { DeleteObject(hPalette); hPalette = NULL; fHalftonePalette = FALSE; PaletteMenu(hMenu, IDM_PAL_NONE); } if (hBitmap) { DeleteObject(hBitmap); } return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); if (hPalette) { SelectPalette(hdc, hPalette, FALSE); RealizePalette(hdc); } if (hBitmap) { DisplayDib(hdc, fHalftonePalette ? DibBitmapHandle(hdib) : hBitmap, iHscroll, iVscroll, cxClient, cyClient, wShow, fHalftonePalette); } EndPaint(hwnd, &ps); return 0; case WM_QUERYNEWPALETTE: if (!hPalette) return FALSE; hdc = GetDC(hwnd); SelectPalette(hdc, hPalette, FALSE); RealizePalette(hdc); InvalidateRect(hwnd, NULL, TRUE); ReleaseDC(hwnd, hdc); return TRUE; case WM_PALETTECHANGED: if (!hPalette || (HWND)wParam == hwnd) return FALSE; hdc = GetDC(hwnd); SelectPalette(hdc, hPalette, FALSE); RealizePalette(hdc); UpdateColors(hdc); ReleaseDC(hwnd, hdc); break; case WM_DESTROY: if (hdib) DibDelete(hdib); if (hBitmap) DeleteObject(hBitmap); if (hPalette) DeleteObject(hPalette); PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
//resource.h
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 Dibble.rc 使用 // #define IDM_FILE_OPEN 40001 #define IDM_FILE_SAVE 40002 #define IDM_FILE_PRINT 40003 #define IDM_FILE_PROPERTIES 40004 #define IDM_APP_EXIT 40005 #define IDM_EDIT_CUT 40006 #define IDM_EDIT_COPY 40007 #define IDM_EDIT_PASTE 40008 #define IDM_EDIT_DELETE 40009 #define IDM_EDIT_FLIP 40010 #define IDM_EDIT_ROTATE 40011 #define IDM_SHOW_NORMAL 40012 #define IDM_SHOW_CENTER 40013 #define IDM_SHOW_STRETCH 40014 #define IDM_SHOW_ISOSTRETCH 40015 #define IDM_PAL_NONE 40016 #define IDM_PAL_DIBTABLE 40017 #define IDM_PAL_HALFTONE 40018 #define IDM_PAL_ALLPURPOSE 40019 #define IDM_PAL_GRAY2 40020 #define IDM_PAL_GRAY3 40021 #define IDM_PAL_GRAY4 40022 #define IDM_PAL_GRAY8 40023 #define IDM_PAL_GRAY16 40024 #define IDM_PAL_GRAY32 40025 #define IDM_PAL_GRAY64 40026 #define IDM_PAL_GRAY128 40027 #define IDM_PAL_GRAY256 40028 #define IDM_PAL_RGB222 40029 #define IDM_PAL_RGB333 40030 #define IDM_PAL_RGB444 40031 #define IDM_PAL_RGB555 40032 #define IDM_PAL_RGB666 40033 #define IDM_PAL_RGB775 40034 #define IDM_PAL_RGB757 40035 #define IDM_PAL_RGB577 40036 #define IDM_PAL_RGB884 40037 #define IDM_PAL_RGB848 40038 #define IDM_PAL_RGB488 40039 #define IDM_CONVERT_01 40040 #define IDM_CONVERT_04 40041 #define IDM_CONVERT_08 40042 #define IDM_CONVERT_16 40043 #define IDM_CONVERT_24 40044 #define IDM_CONVERT_32 40045 #define IDM_APP_ABOUT 40046 #define IDM_PAL_OPT_POP4 40047 #define IDM_PAL_OPT_POP5 40048 #define IDM_PAL_OPT_POP6 40049 #define IDM_PAL_OPT_MEDCUT 40050 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_COMMAND_VALUE 40040 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//Dibble.rc
// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // 中文(简体,中国) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h " END 2 TEXTINCLUDE BEGIN "#include ""winres.h"" " "