标签:
(1)DIB文件的结构
整个文件 |
紧凑DIB(整个文件除文件头) |
文件头(File Header) |
信息头(Information Header) |
信息头(Information Header) |
颜色表(Color Table) |
颜色表(Color Table) |
像素位(Pixel Bits) |
像素位(Pixel Bits) |
|
注意:①紧凑DIB在内存中是连续的,即整个DIB存在单个内存块中
②DIB载入内存时,像素位与信息头可以分别存在两个内存块,即内存不连续。
(2)像素位指针的求法
15.2.2 从像素到像素
(1)SetDIBitsToDevice函数——显示没有拉伸和压缩的DIB
参数 |
含义 |
||
hdc |
设备环境句柄 |
||
xDst |
目标矩形左上角x坐标(逻辑单位),这里的“左上角”指视觉上图像的左上角。 |
||
yDst |
目标矩形左上角y坐标(逻辑单位) |
||
cxSrc |
源矩形宽度 |
1、这四个参数可以决定是显示整个DIB或只显示一部分。 2、对于自上而下的DIB,因BITMAPINFOHEADER的biHeight为负数,所以cySrc应设置为biHeight的绝对值,即biHeight永远要设为正数。 3、无论映射模式怎样,在输出设备上显示的DIB总是cxSrc像素宽,cySrc像素高。 |
|
cySrc |
源矩形高度 |
||
xSrc |
源x坐标 |
||
ySrc |
源y坐标 |
||
yScan |
指定DIB中起始扫描线的编号(见后面的详细分析)。 |
用来每次按顺序显示DIB的一部分。 通常yScan=0,cyScan=DIB的高度。 |
|
cyScan |
DIB扫描线数目 |
||
pBits |
像素位指针 |
||
pInfo |
DIB信息头指针 |
||
fClrUse |
指向BITMAPINFO结构中的成员bmiColors是否包含明确的RGB值或对调色板进行索引的值。取值为下列之一,这些值的含义如下: DIB_PAL_COLORS(1):表示颜色表由16位的索引值数组组成,利用这些值可对当前选中的逻辑调色板进行索引。 DIB_RGB_COLORS(0):表示颜色表包含原义的RGB值。 |
返回值:返回函数调用后,显示DIB的所用的扫描行个数。
【ShowDib1程序】
效果图
/*------------------------------------------------------------ SHOWDIB1.C -- Show a DIB in the client area (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> #include "resource.h" #include "DibFile.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); static TCHAR szAppName[] = TEXT("ShowDib1"); 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 TEXT("Show DIB #1"), // window caption WS_OVERLAPPEDWINDOW, // 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; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static BITMAPFILEHEADER* pbmfh; static BITMAPINFO* pbmi; static BYTE* pBits; static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH]; static int cxClient, cyClient, cxDib, cyDib; HDC hdc; PAINTSTRUCT ps; BOOL bSuccess; switch (message) { case WM_CREATE: DibFileInitialize(hwnd); return 0; case WM_INITMENUPOPUP: EnableMenuItem((HMENU)wParam, IDM_FILE_SAVE, pbmfh ? MF_ENABLED : MF_GRAYED); return 0; case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_FILE_OPEN: //显示打开对话框 if (!DibFileOpenDlg(hwnd, szFileName, szTitleName)) return 0; //如果DIB文件己被载入,释放内存 if (pbmfh) { free(pbmfh); pbmfh = NULL; } //将整个DIB加载到内存中 SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); pbmfh = DibLoadImage(szFileName); ShowCursor(FALSE); SetCursor(LoadCursor(NULL, IDC_ARROW)); //使客户区无效,以便后面的绘图并擦除以前客户区显示的内容 InvalidateRect(hwnd, NULL, TRUE); if (pbmfh == NULL) { MessageBox(hwnd, TEXT("Cannot load DIB file"), szAppName, 0); return 0; } //获取指向DIB信息头的指针和指向像素位的指针 pbmi = (BITMAPINFO*)(pbmfh + 1); pBits = (BYTE*)pbmfh + pbmfh->bfOffBits; //获取图像的宽度和高度 if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) { cxDib = ((BITMAPCOREHEADER*)pbmi)->bcWidth; cyDib = ((BITMAPCOREHEADER*)pbmi)->bcHeight; } else { cxDib = pbmi->bmiHeader.biWidth; cyDib = abs(pbmi->bmiHeader.biHeight); } return 0; case IDM_FILE_SAVE: //显示保存对话框 if (!DibFileSaveDlg(hwnd, szFileName, szTitleName)) return 0; //将DIB位图保存到文件中 SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); bSuccess = DibSaveImage(szFileName, pbmfh); ShowCursor(FALSE); SetCursor(LoadCursor(NULL, IDC_ARROW)); if (!bSuccess) MessageBox(hwnd, TEXT("Cannot save DIB file"), szAppName, 0); return 0; } break; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); if (pbmfh) { SetDIBitsToDevice(hdc, 0, 0, cxDib, //像素宽度 cyDib, //像素高度 0, //xSrc 0, //ySrc 0, //第一扫描线 cyDib, //扫描线数目 pBits, //像素位 pbmi, DIB_RGB_COLORS); } EndPaint(hwnd, &ps); return 0; case WM_DESTROY: if (pbmfh) free(pbmfh); PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
//DibFile.h
/*----------------------------------------------------- DIBFILE.H ---- Header File for DIBFILE.C ------------------------------------------------------*/ #pragma once #include <windows.h> void DibFileInitialize(HWND hwnd); BOOL DibFileOpenDlg(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName); BOOL DibFileSaveDlg(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName); BITMAPFILEHEADER* DibLoadImage(PTSTR pstrFileName); BOOL DibSaveImage(PTSTR pstrFileName, BITMAPFILEHEADER*);
//DibFile.c
#include "DibFile.h" static OPENFILENAME ofn; void DibFileInitialize(HWND hwnd) { static TCHAR szFilter[] = TEXT("Bitmap Files (*.BMP)\0*.bmp\0") TEXT("All Files(*.*)\0*.*\0\0"); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hwnd; ofn.hInstance = NULL; ofn.lpstrFilter = szFilter; ofn.lpstrCustomFilter = NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 0; ofn.lpstrFile = NULL; //在打开和关闭中设置 ofn.nMaxFile = MAX_PATH; ofn.lpstrFileTitle = NULL; //在打开和关闭函数中设置 ofn.nMaxFileTitle = MAX_PATH; ofn.lpstrInitialDir = NULL; ofn.lpstrTitle = NULL; ofn.Flags = 0; //在打开和关闭函数中设置 ofn.nFileOffset = 0; ofn.nFileExtension = 0; ofn.lpstrDefExt = TEXT("bmp"); //默认扩展名 ofn.lCustData = 0; ofn.lpfnHook = NULL; ofn.lpTemplateName = NULL; } BOOL DibFileOpenDlg(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName) { ofn.hwndOwner = hwnd; ofn.lpstrFile = pstrFileName; ofn.lpstrFileTitle = pstrTitleName; ofn.Flags = 0; return GetOpenFileName(&ofn); } BOOL DibFileSaveDlg(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName) { ofn.hwndOwner = hwnd; ofn.lpstrFile = pstrFileName; ofn.lpstrFileTitle = pstrTitleName; ofn.Flags = OFN_OVERWRITEPROMPT; return GetSaveFileName(&ofn); } BITMAPFILEHEADER* DibLoadImage(PTSTR pstrFileName) { BOOL bSuccess; DWORD dwFileSize, dwHighSize, dwBytesRead; HANDLE hFile; BITMAPFILEHEADER* pbmfh; hFile = CreateFile(pstrFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (hFile == INVALID_HANDLE_VALUE) return NULL; //返回文件大小的低位字,保存在dwFileSize中,高位字保存在dwHighSize中 dwFileSize = GetFileSize(hFile, &dwHighSize); if (dwHighSize) //文件太大,超过4G则dwHighSize不为0,退出 { CloseHandle(hFile); return NULL; } //为位图文件分配内存,内存指针由文件头指针保管 pbmfh = malloc(dwFileSize); if (!pbmfh) { CloseHandle(hFile); return NULL; } //读位图文件到内存 bSuccess = ReadFile(hFile, pbmfh, dwFileSize, &dwBytesRead, NULL); CloseHandle(hFile); if ((!bSuccess) || (dwBytesRead != dwFileSize) || (pbmfh->bfType != *(WORD*)"BM") || //位图标志“BM” (pbmfh->bfSize != dwFileSize)) { free(pbmfh); return NULL; } return pbmfh; } BOOL DibSaveImage(PTSTR pstrFileName, BITMAPFILEHEADER* pbmfh) { BOOL bSuccess; DWORD dwBytesWritten; HANDLE hFile; hFile = CreateFile(pstrFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return FALSE; bSuccess = WriteFile(hFile, pbmfh, pbmfh->bfSize, &dwBytesWritten, NULL); CloseHandle(hFile); if ((!bSuccess) || (dwBytesWritten != pbmfh->bfSize)) { DeleteFile(pstrFileName); return FALSE; } return TRUE; }
//resource.h
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 ShowDib1.rc 使用 // #define IDM_FILE_OPEN 40001 #define IDM_FILE_SAVE 40002 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_COMMAND_VALUE 40007 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//ShowDib1.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\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Menu // SHOWDIB1 MENU BEGIN POPUP "&File" BEGIN MENUITEM "&Open...\tCtrl+O", IDM_FILE_OPEN MENUITEM "&Save...\tCtrl+S", IDM_FILE_SAVE END END ///////////////////////////////////////////////////////////////////////////// // // Accelerator // SHOWDIB1 ACCELERATORS BEGIN "^O", IDM_FILE_OPEN, ASCII, NOINVERT "^S", IDM_FILE_SAVE, ASCII, NOINVERT END #endif // 中文(简体,中国) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED
(1)自下而上DIB坐标说明
源矩形 |
目标矩形 |
①(xSrc,ySrc)—内存中第一个像素! |
①(xDst,yDst+cySrc-1) |
②(xSrc+cxSrc-1,ySrc) |
②(xDst+cxSrc-1,yDst+cySrc-1) |
③(xSrc,ySrc+cySrc-1) |
③(xDst,yDst) |
④(xSrc+cxSrc-1,ySrc+cySrc-1)—内存最后1个像素 |
④(xDst+cxSrc-1,yDst) |
注意:1、cxSrc,cySrc为区域宽度和高度,因为坐标从0开始,所以上面式子出现减1现象。 2、原点(0,0)位于DIB图的左下角(左图中的①),第一行的第1个像素。 |
(2)自上而下DIB坐标说明
源矩形 |
目标矩形 |
①(xSrc,ySrc+cySrc-1)—内存中第1个像素! |
①(xDst,yDst) |
②(xSrc+cxSrc-1,ySrc+cySrc-1) |
②(xDst+cxSrc-1,yDst) |
③(xSrc,ySrc)—这里不是第1 个像素! |
③(xDst,yDst+cySrc-1) |
④(xSrc+cxSrc-1,ySrc)—内存中最后1个像素 |
④(xDst+cxSrc-1,yDst+cySrc-1) |
注意:1、cxSrc,cySrc为区域宽度和高度,因为坐标从0开始,所以上面式子出现减1现象。 2、原点(0,0)或(xSrc,ySrc)不是DIB图中第1 个像素,也不是最后1个像素,而是③,在图的左下角,即最后一行的第1个像素。 |
/*------------------------------------------------------------ APOLLO11.C -- Program for screen captures (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> #include "..\\DibHeads\\DibFile.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); static TCHAR szAppName[] = TEXT("Apollo11"); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { HWND hwnd; MSG msg; WNDCLASSEX wndclass; 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 = NULL; 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 TEXT("Apollo 11"), // window caption WS_OVERLAPPEDWINDOW, // 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); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; static BITMAPFILEHEADER* pbmfh[2]; static BITMAPINFO* pbmi[2]; static BYTE* pBits[2]; static int cxClient, cyClient, cxDib[2], cyDib[2]; switch (message) { case WM_CREATE: pbmfh[0] = DibLoadImage(TEXT("Apollo11.bmp")); pbmfh[1] = DibLoadImage(TEXT("ApolloTD.bmp")); if (pbmfh[0] == NULL || pbmfh[1] == NULL) { MessageBox(hwnd, TEXT("Cannot load DIB file"), szAppName, 0); return 0; } //获得信息头和像素位指针 pbmi[0] = (BITMAPINFO*)(pbmfh[0] + 1); pbmi[1] = (BITMAPINFO*)(pbmfh[1] + 1); pBits[0] = (BYTE*)pbmfh[0] + pbmfh[0]->bfOffBits; pBits[1] = (BYTE*)pbmfh[1] + pbmfh[1]->bfOffBits; //获取图像大小(为方便,这里只处理BITMAPINFOHEADER结构的DIB) cxDib[0] = pbmi[0]->bmiHeader.biWidth; cyDib[0] = abs(pbmi[0]->bmiHeader.biHeight); //绝对值! cxDib[1] = pbmi[1]->bmiHeader.biWidth; cyDib[1] = abs(pbmi[1]->bmiHeader.biHeight); //绝对值! return 0; case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); //从下到上DIB整图显示 SetDIBitsToDevice(hdc, 0, cyClient / 4, //yDst cxDib[0], //整幅图宽度 cyDib[0], //整幅图高度 0, 0, 0, //第一扫描线 cyDib[0], //扫描线数量 pBits[0], pbmi[0], DIB_RGB_COLORS); //从下到上DIB局部图显示 SetDIBitsToDevice(hdc, 240, cyClient / 4, //yDst 80, //图的局部(宽度) 166, //图的局部(高度) 80, //源的X坐标,在图左下角的附近 60, //源的Y坐标,在图左下角附近 0, //第一扫描线 cyDib[0], //扫描线数量 pBits[0], pbmi[0], DIB_RGB_COLORS); //从上到下DIB整图显示 SetDIBitsToDevice(hdc, 340, cyClient / 4, //yDst cxDib[1], //整幅图宽度 cyDib[1], //整幅图高度 0, 0, 0, //第一扫描线 cyDib[1], //扫描线数量 pBits[1], pbmi[1], DIB_RGB_COLORS); //从上到下DIB局部图显示 SetDIBitsToDevice(hdc, 580, cyClient / 4, //yDst 80, //图的局部(宽度) 166, //图的局部(高度) 80, //源的X坐标,在图左下角的附近 60, //源的Y坐标,在图左下角附近 0, //第一扫描线 cyDib[1], //扫描线数量 pBits[1], pbmi[1], DIB_RGB_COLORS); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
(1)SetDIBitsToDevice扫描线的工作原理
SetDIBitsToDevice(hdc,xDst,yDst,cxSrc,cySrc,xSrc,ySrc,yScan,cyScans,pBits,fClrUse);
①根据xSrc,ySrc,cxSrc,cySrc确定要显示的源矩形的范围(如图1),再根据xDst,yDst,cxSrc,cySrc确定DIB图像在逻辑坐标系中的输出位置和范围(如图2,用红色虚线框表示的矩形范围)。
②为pBits所在数据块按像素行划分出若干条扫描线。第1行(也称为第一扫描线),编号为yScan号(一般为0,但这里为了更具普遍性,假设yScan等于20,即第1条扫描线编号为20号),第2条为21号,第3条为22号,以此类推……。直到pBits所有的像素行(或叫扫描线)都编号完毕。本例中DIB位图的高度为240,所以最后一行编号为20+240,即260号。
③开始扫描,此时当前扫描线会从A扫描到B。由图中可知,它将扫过从编号60到240的之间范围。假设当前的扫描位置是在编号为70的绿线上。
④当在图1中确定好当前扫描线编号以后,再根据当前扫描线的位置,计算出在逻辑坐标系中的输出位置(假设在图2中的绿线位置),而该处输出的数据来自于pBits中扫描线被编号为70号的那行数据,即pBits中第90行的数据。
⑤继续扫描其他行,直至AB间的所有像素行都扫描完毕,即结束。
【注意】
①本例中,pBits像素的扫描线编号(20-260),但源矩形中只要求输出编号为60至240号的扫描行数据。也就是说,pBits中第40行至220行的数据。所以最终结果如图2所示(要特别注意,源和目标中,显示的图像己经不同了(见红色虚线框内的内容),主要原因是我们将pBits的第1行编号为20,如果编为0(即yScan=0)则显示的内容就会完全相同)。
②由于pBits扫描线编号在20-260之间,所以如果当前扫描线要扫描图1中y轴20以下的那些范围,则在pBits中会因找不到对应的扫描线,从而导致那部分的数据在逻辑坐标系中会显示为空白。
(2)SetDIBitsToDevice实例分析
【SeqDisp程序】
效果图
/*------------------------------------------------------------ SEQDISP.C -- Sequential Display of DIBs (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); static TCHAR szAppName[] = TEXT("SeqDisp"); 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 TEXT("DIB Sequential Display"), // window caption WS_OVERLAPPEDWINDOW, // 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; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; static BITMAPINFO* pbmi; static BYTE* pBits; static int cxDib, cyDib, cBits; static OPENFILENAME ofn; static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH]; static TCHAR szFilter[] = TEXT("Bitmap Files(*.BMP)\0*.bmp\0") TEXT("All Files(*.*)\0*.*\0\0"); BITMAPFILEHEADER bmfh; BOOL bSuccess, bTopDown; DWORD dwBytesRead; HANDLE hFile; int iInfoSize, iBitsSize, iRowLength; switch (message) { case WM_CREATE: ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hwnd; ofn.hInstance = NULL; ofn.lpstrFilter = szFilter; ofn.lpstrCustomFilter = NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 0; ofn.lpstrFile = szFileName; ofn.nMaxFile = MAX_PATH; ofn.lpstrFileTitle = szTitleName; ofn.nMaxFileTitle = MAX_PATH; ofn.lpstrInitialDir = NULL; ofn.lpstrTitle = NULL; ofn.Flags = 0; //在打开和关闭函数中设置 ofn.nFileOffset = 0; ofn.nFileExtension = 0; ofn.lpstrDefExt = TEXT("bmp"); //默认扩展名 ofn.lCustData = 0; ofn.lpfnHook = NULL; ofn.lpTemplateName = NULL; return 0; case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_FILE_OPEN: //显示打开文件对话框 if (!GetOpenFileName(&ofn)) return 0; //清除之前打开的位图文件 if (pbmi) { free(pbmi); pbmi = NULL; } if (pBits) { free(pBits); pBits = NULL; } //擦掉客户区上的位图 InvalidateRect(hwnd, NULL, TRUE); UpdateWindow(hwnd); //可注释掉看下 //打开文件 hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (hFile == INVALID_HANDLE_VALUE) { MessageBox(hwnd, TEXT("Cannot open file."), szAppName, MB_ICONWARNING | MB_OK); return 0; } //读取BITMAPFILEHEADER bSuccess = ReadFile(hFile, &bmfh, sizeof(BITMAPFILEHEADER), &dwBytesRead, NULL); if (!bSuccess || dwBytesRead != sizeof(BITMAPFILEHEADER)) { MessageBox(hwnd, TEXT("Cannot open file."), szAppName, MB_ICONWARNING | MB_OK); CloseHandle(hFile); return 0; } //检验是否是位图文件,第1-2个字节为“BM” if (bmfh.bfType != *(WORD*)"BM") { MessageBox(hwnd, TEXT("File is not a bitmap."), szAppName, MB_ICONWARNING | MB_OK); CloseHandle(hFile); return 0; } //为文件信息头和像素位数据分配内存 iInfoSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER); iBitsSize = bmfh.bfSize - bmfh.bfOffBits; pbmi = malloc(iInfoSize); pBits = malloc(iBitsSize); if (pbmi == NULL || pBits == NULL) { MessageBox(hwnd, TEXT("Cannot allocate memory."), szAppName, MB_ICONWARNING | MB_OK); if (pbmi) { free(pbmi); pbmi = NULL; } if (pBits) { free(pBits); pBits = NULL; } CloseHandle(hFile); return 0; } //读取信息头 bSuccess = ReadFile(hFile, pbmi, iInfoSize, &dwBytesRead, NULL); if (!bSuccess || iInfoSize != dwBytesRead) { MessageBox(hwnd, TEXT("Cannot allocate memory."), szAppName, MB_ICONWARNING | MB_OK); if (pbmi) { free(pbmi); pbmi = NULL; } if (pBits) { free(pBits); pBits = NULL; } CloseHandle(hFile); return 0; } //获取像素数据和高度 bTopDown = FALSE; if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) { cxDib = ((BITMAPCOREHEADER*)pbmi)->bcWidth; cyDib = ((BITMAPCOREHEADER*)pbmi)->bcHeight; cBits = ((BITMAPCOREHEADER*)pbmi)->bcBitCount; } else { bTopDown = (pbmi->bmiHeader.biHeight < 0); cxDib = pbmi->bmiHeader.biWidth; cyDib = abs(pbmi->bmiHeader.biHeight); cBits = pbmi->bmiHeader.biBitCount; if (pbmi->bmiHeader.biCompression != BI_RGB && pbmi->bmiHeader.biCompression != BI_BITFIELDS) { MessageBox(hwnd, TEXT("File is compressed."), szAppName, MB_ICONWARNING | MB_OK); if (pbmi) { free(pbmi); pbmi = NULL; } if (pBits) { free(pBits); pBits = NULL; } CloseHandle(hFile); return 0; } } //计算每行像素宽度,4的倍数 iRowLength = ((cxDib*cBits + 31)& ~31) >> 3; //显示位图 SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); hdc = GetDC(hwnd); for (int y = 0; y < cyDib; y++) { ReadFile(hFile, pBits + y*iRowLength, iRowLength, &dwBytesRead, NULL); /* 1、每次扫描时,源矩形0,y,cxDib,cyDib-y,目标矩形0,0,cxDib,cyDib-y 2、每次调用函数时,像素的数据在改变,pBits+y*iRowLength; 3、每次都为像素位的第一行数据编号为y或cyDib-y-1 */ SetDIBitsToDevice(hdc, 0, //xDst 0, //yDst cxDib, //cxSrc cyDib - y, //cySrc,课本这里为cyDib。 0, //xSrc y, //ySrc,课本这里为0,这两处的更改,效率更高。 bTopDown ? cyDib - y - 1 : y, //给第一行扫描行编号 1, //每次扫描一行 pBits + y*iRowLength, //第一行扫描行的数据 pbmi, DIB_RGB_COLORS); } ReleaseDC(hwnd, hdc); CloseHandle(hFile); SetCursor(LoadCursor(NULL, IDC_ARROW)); ShowCursor(FALSE); return 0; } break; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); if (pbmi && pBits) { SetDIBitsToDevice(hdc, 0, //xDst 0, //yDst cxDib, //cxSrc cyDib, //cySrc 0, //xSrc 0, //ySrc 0, //第一行扫描行编号 cyDib, pBits, pbmi, DIB_RGB_COLORS); } EndPaint(hwnd, &ps); return 0; case WM_DESTROY: if (pbmi) free(pbmi); if (pBits) free(pBits); PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
//resouce.h
//{{NO_DEPENDENCIES}} // Microsoft Developer Studio generated include file. // Used by SeqDisp.rc // #define IDM_FILE_OPEN 40001 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 101 #define _APS_NEXT_COMMAND_VALUE 40002 #define _APS_NEXT_CONTROL_VALUE 1000 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//SeqDisp.rc
//Microsoft Developer Studio generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "afxres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0" END 2 TEXTINCLUDE DISCARDABLE BEGIN "#include ""afxres.h""\r\n" "\0" END 3 TEXTINCLUDE DISCARDABLE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Accelerator // SEQDISP ACCELERATORS DISCARDABLE BEGIN "O", IDM_FILE_OPEN, VIRTKEY, CONTROL, NOINVERT END ///////////////////////////////////////////////////////////////////////////// // // Menu // SEQDISP MENU DISCARDABLE BEGIN POPUP "&File" BEGIN MENUITEM "&Open...\tCtrl+O", IDM_FILE_OPEN END END #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED
15.2.5 拉伸到合适大小
(1)StretchDIBits函数说明
参数 |
说明 |
hdc |
设备环境句柄 |
xDst |
目标x坐标 |
yDst |
目标y坐标 |
cxDst |
目标图像的像素宽度(字节),可正可负,实现翻转 |
cyDst |
目标图像的像素高度(字节),可正可负,实现翻转 |
xSrc |
源x坐标(有符号) |
ySrc |
源y坐标 |
cxSrc |
源图像的像素宽度(字节),可正可负,实现翻转 |
cySrc |
源图像的像素高度(字节),可正可负,实现翻转 |
pBits |
像素位数据 |
fClrUse |
使用颜色标记:DIB_PAL_COLORS或DIB_RGB_COLORS |
dwRop |
光栅操作 |
(2)StretchDIBits坐标说明
源矩形 |
目标矩形 |
①(xSrc,ySrc)—内存中第一个像素! |
①(xDst,yDst+cyDst-1) |
②(xSrc+cxSrc-1,ySrc) |
②(xDst+cxDst-1,yDst+cyDst-1) |
③(xSrc,ySrc+cySrc-1) |
③(xDst,yDst) |
④(xSrc+cxSrc-1,ySrc+cySrc-1)—内存最后1个像素 |
④(xDst+cxDst-1,yDst) |
注意:1、右列式子出现减1并不准确,因为拉伸和映射模式的影响。 2、原点(0,0)位于DIB图的左下角(左图中的①),第一行的第1个像素。 |
(3)判断图像是否上下翻转或左右翻转
if(!Sign(xMM*cxSrc*cxDst)) DIB沿垂直轴翻转(镜像) |
1、xMM为映射模式x从左到右增加,取1,相反取-1。 2、yMM为映射模式y从上到下增加,取1,相反取-1。 |
if(!Sign(yMM*cySrc*cyDst)) DIB沿水平轴翻转(上下翻转) |
【ShowDib2程序】
标签:
原文地址:http://www.cnblogs.com/5iedu/p/4699013.html