(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) *.bmp ") TEXT("All Files(*.*) *.* "); 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 " END 2 TEXTINCLUDE BEGIN "#include ""winres.h"" " "