15.2.1 探究DIB

(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程序】
效果图

  1. /*------------------------------------------------------------
  2. SHOWDIB1.C -- Show a DIB in the client area
  3. (c) Charles Petzold, 1998
  4. ------------------------------------------------------------*/
  5.  
  6. #include <windows.h>
  7. #include "resource.h"
  8. #include "DibFile.h"
  9.  
  10. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  11.  
  12. static TCHAR szAppName[] = TEXT("ShowDib1");
  13. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  14. PSTR szCmdLine, int iCmdShow)
  15. {
  16. HWND hwnd;
  17. MSG msg;
  18. WNDCLASSEX wndclass;
  19. HACCEL hAccel;
  20.  
  21. wndclass.style = CS_HREDRAW | CS_VREDRAW;
  22. wndclass.cbSize = sizeof(WNDCLASSEX);
  23. wndclass.lpfnWndProc = WndProc;
  24. wndclass.cbClsExtra = ;
  25. wndclass.cbWndExtra = ;
  26. wndclass.hInstance = hInstance;
  27. wndclass.hIcon = LoadIcon(hInstance, szAppName);
  28. wndclass.hIconSm = LoadIcon(hInstance, szAppName);
  29. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  30. wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  31. wndclass.lpszMenuName = szAppName;
  32. wndclass.lpszClassName = szAppName;
  33.  
  34. if (!RegisterClassEx(&wndclass))
  35. {
  36. MessageBox(NULL, TEXT("This program requires Windows NT!"),
  37. szAppName, MB_ICONERROR);
  38. return ;
  39. }
  40.  
  41. hwnd = CreateWindow(szAppName, // window class name
  42. TEXT("Show DIB #1"), // window caption
  43. WS_OVERLAPPEDWINDOW, // window style
  44. CW_USEDEFAULT, // initial x position
  45. CW_USEDEFAULT, // initial y position
  46. CW_USEDEFAULT, // initial x size
  47. CW_USEDEFAULT, // initial y size
  48. NULL, // parent window handle
  49. NULL, // window menu handle
  50. hInstance, // program instance handle
  51. NULL); // creation parameters
  52.  
  53. ShowWindow(hwnd, iCmdShow);
  54. UpdateWindow(hwnd);
  55. hAccel = LoadAccelerators(hInstance, szAppName);
  56. while (GetMessage(&msg, NULL, , ))
  57. {
  58. if (!TranslateAccelerator(hwnd, hAccel, &msg))
  59. {
  60. TranslateMessage(&msg);
  61. DispatchMessage(&msg);
  62. }
  63. }
  64. return msg.wParam;
  65. }
  66.  
  67. LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  68. {
  69. static BITMAPFILEHEADER* pbmfh;
  70. static BITMAPINFO* pbmi;
  71. static BYTE* pBits;
  72.  
  73. static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH];
  74. static int cxClient, cyClient, cxDib, cyDib;
  75. HDC hdc;
  76. PAINTSTRUCT ps;
  77. BOOL bSuccess;
  78.  
  79. switch (message)
  80. {
  81. case WM_CREATE:
  82.  
  83. DibFileInitialize(hwnd);
  84. return ;
  85.  
  86. case WM_INITMENUPOPUP:
  87. EnableMenuItem((HMENU)wParam, IDM_FILE_SAVE, pbmfh ? MF_ENABLED : MF_GRAYED);
  88. return ;
  89.  
  90. case WM_SIZE:
  91. cxClient = LOWORD(lParam);
  92. cyClient = HIWORD(lParam);
  93. return ;
  94.  
  95. case WM_COMMAND:
  96. switch (LOWORD(wParam))
  97. {
  98. case IDM_FILE_OPEN:
  99. //显示打开对话框
  100. if (!DibFileOpenDlg(hwnd, szFileName, szTitleName))
  101. return ;
  102.  
  103. //如果DIB文件己被载入,释放内存
  104. if (pbmfh)
  105. {
  106. free(pbmfh);
  107. pbmfh = NULL;
  108. }
  109.  
  110. //将整个DIB加载到内存中
  111. SetCursor(LoadCursor(NULL, IDC_WAIT));
  112. ShowCursor(TRUE);
  113.  
  114. pbmfh = DibLoadImage(szFileName);
  115.  
  116. ShowCursor(FALSE);
  117. SetCursor(LoadCursor(NULL, IDC_ARROW));
  118.  
  119. //使客户区无效,以便后面的绘图并擦除以前客户区显示的内容
  120. InvalidateRect(hwnd, NULL, TRUE);
  121.  
  122. if (pbmfh == NULL)
  123. {
  124. MessageBox(hwnd, TEXT("Cannot load DIB file"), szAppName, );
  125. return ;
  126. }
  127.  
  128. //获取指向DIB信息头的指针和指向像素位的指针
  129. pbmi = (BITMAPINFO*)(pbmfh + );
  130. pBits = (BYTE*)pbmfh + pbmfh->bfOffBits;
  131.  
  132. //获取图像的宽度和高度
  133. if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
  134. {
  135. cxDib = ((BITMAPCOREHEADER*)pbmi)->bcWidth;
  136. cyDib = ((BITMAPCOREHEADER*)pbmi)->bcHeight;
  137. } else
  138. {
  139. cxDib = pbmi->bmiHeader.biWidth;
  140. cyDib = abs(pbmi->bmiHeader.biHeight);
  141. }
  142. return ;
  143.  
  144. case IDM_FILE_SAVE:
  145.  
  146. //显示保存对话框
  147. if (!DibFileSaveDlg(hwnd, szFileName, szTitleName))
  148. return ;
  149.  
  150. //将DIB位图保存到文件中
  151. SetCursor(LoadCursor(NULL, IDC_WAIT));
  152. ShowCursor(TRUE);
  153.  
  154. bSuccess = DibSaveImage(szFileName, pbmfh);
  155.  
  156. ShowCursor(FALSE);
  157. SetCursor(LoadCursor(NULL, IDC_ARROW));
  158.  
  159. if (!bSuccess)
  160. MessageBox(hwnd, TEXT("Cannot save DIB file"), szAppName, );
  161.  
  162. return ;
  163. }
  164. break;
  165.  
  166. case WM_PAINT:
  167. hdc = BeginPaint(hwnd, &ps);
  168.  
  169. if (pbmfh)
  170. {
  171. SetDIBitsToDevice(hdc,
  172. ,
  173. ,
  174. cxDib, //像素宽度
  175. cyDib, //像素高度
  176. , //xSrc
  177. , //ySrc
  178. , //第一扫描线
  179. cyDib, //扫描线数目
  180. pBits, //像素位
  181. pbmi,
  182. DIB_RGB_COLORS);
  183. }
  184.  
  185. EndPaint(hwnd, &ps);
  186. return ;
  187.  
  188. case WM_DESTROY:
  189. if (pbmfh)
  190. free(pbmfh);
  191.  
  192. PostQuitMessage();
  193. return ;
  194. }
  195. return DefWindowProc(hwnd, message, wParam, lParam);
  196. }

//DibFile.h

  1. /*-----------------------------------------------------
  2. DIBFILE.H ---- Header File for DIBFILE.C
  3. ------------------------------------------------------*/
  4. #pragma once
  5. #include <windows.h>
  6.  
  7. void DibFileInitialize(HWND hwnd);
  8.  
  9. BOOL DibFileOpenDlg(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName);
  10. BOOL DibFileSaveDlg(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName);
  11.  
  12. BITMAPFILEHEADER* DibLoadImage(PTSTR pstrFileName);
  13.  
  14. BOOL DibSaveImage(PTSTR pstrFileName, BITMAPFILEHEADER*);

//DibFile.c

  1. #include "DibFile.h"
  2.  
  3. static OPENFILENAME ofn;
  4. void DibFileInitialize(HWND hwnd)
  5. {
  6. static TCHAR szFilter[] = TEXT("Bitmap Files (*.BMP)\0*.bmp\0")\
  7. TEXT("All Files(*.*)\0*.*\0\0");
  8.  
  9. ofn.lStructSize = sizeof(OPENFILENAME);
  10. ofn.hwndOwner = hwnd;
  11. ofn.hInstance = NULL;
  12. ofn.lpstrFilter = szFilter;
  13. ofn.lpstrCustomFilter = NULL;
  14. ofn.nMaxCustFilter = ;
  15. ofn.nFilterIndex = ;
  16. ofn.lpstrFile = NULL; //在打开和关闭中设置
  17. ofn.nMaxFile = MAX_PATH;
  18. ofn.lpstrFileTitle = NULL; //在打开和关闭函数中设置
  19. ofn.nMaxFileTitle = MAX_PATH;
  20. ofn.lpstrInitialDir = NULL;
  21. ofn.lpstrTitle = NULL;
  22. ofn.Flags = ; //在打开和关闭函数中设置
  23. ofn.nFileOffset = ;
  24. ofn.nFileExtension = ;
  25. ofn.lpstrDefExt = TEXT("bmp"); //默认扩展名
  26. ofn.lCustData = ;
  27. ofn.lpfnHook = NULL;
  28. ofn.lpTemplateName = NULL;
  29. }
  30.  
  31. BOOL DibFileOpenDlg(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName)
  32. {
  33. ofn.hwndOwner = hwnd;
  34. ofn.lpstrFile = pstrFileName;
  35. ofn.lpstrFileTitle = pstrTitleName;
  36. ofn.Flags = ;
  37. return GetOpenFileName(&ofn);
  38. }
  39.  
  40. BOOL DibFileSaveDlg(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName)
  41. {
  42. ofn.hwndOwner = hwnd;
  43. ofn.lpstrFile = pstrFileName;
  44. ofn.lpstrFileTitle = pstrTitleName;
  45. ofn.Flags = OFN_OVERWRITEPROMPT;
  46. return GetSaveFileName(&ofn);
  47. }
  48.  
  49. BITMAPFILEHEADER* DibLoadImage(PTSTR pstrFileName)
  50. {
  51. BOOL bSuccess;
  52. DWORD dwFileSize, dwHighSize, dwBytesRead;
  53. HANDLE hFile;
  54. BITMAPFILEHEADER* pbmfh;
  55.  
  56. hFile = CreateFile(pstrFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
  57. OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  58.  
  59. if (hFile == INVALID_HANDLE_VALUE)
  60. return NULL;
  61.  
  62. //返回文件大小的低位字,保存在dwFileSize中,高位字保存在dwHighSize中
  63. dwFileSize = GetFileSize(hFile, &dwHighSize);
  64.  
  65. if (dwHighSize) //文件太大,超过4G则dwHighSize不为0,退出
  66. {
  67. CloseHandle(hFile);
  68. return NULL;
  69. }
  70.  
  71. //为位图文件分配内存,内存指针由文件头指针保管
  72. pbmfh = malloc(dwFileSize);
  73. if (!pbmfh)
  74. {
  75. CloseHandle(hFile);
  76. return NULL;
  77. }
  78.  
  79. //读位图文件到内存
  80. bSuccess = ReadFile(hFile, pbmfh, dwFileSize, &dwBytesRead, NULL);
  81. CloseHandle(hFile);
  82.  
  83. if ((!bSuccess) || (dwBytesRead != dwFileSize) ||
  84. (pbmfh->bfType != *(WORD*)"BM") || //位图标志“BM”
  85. (pbmfh->bfSize != dwFileSize))
  86. {
  87. free(pbmfh);
  88. return NULL;
  89. }
  90.  
  91. return pbmfh;
  92. }
  93.  
  94. BOOL DibSaveImage(PTSTR pstrFileName, BITMAPFILEHEADER* pbmfh)
  95. {
  96. BOOL bSuccess;
  97. DWORD dwBytesWritten;
  98. HANDLE hFile;
  99.  
  100. hFile = CreateFile(pstrFileName, GENERIC_WRITE, , NULL,
  101. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  102.  
  103. if (hFile == INVALID_HANDLE_VALUE)
  104. return FALSE;
  105.  
  106. bSuccess = WriteFile(hFile, pbmfh, pbmfh->bfSize, &dwBytesWritten, NULL);
  107. CloseHandle(hFile);
  108.  
  109. if ((!bSuccess) || (dwBytesWritten != pbmfh->bfSize))
  110. {
  111. DeleteFile(pstrFileName);
  112. return FALSE;
  113. }
  114. return TRUE;
  115. }

//resource.h

  1. //{{NO_DEPENDENCIES}}
  2. // Microsoft Visual C++ 生成的包含文件。
  3. // 供 ShowDib1.rc 使用
  4. //
  5. #define IDM_FILE_OPEN 40001
  6. #define IDM_FILE_SAVE 40002
  7.  
  8. // Next default values for new objects
  9. //
  10. #ifdef APSTUDIO_INVOKED
  11. #ifndef APSTUDIO_READONLY_SYMBOLS
  12. #define _APS_NEXT_RESOURCE_VALUE 103
  13. #define _APS_NEXT_COMMAND_VALUE 40007
  14. #define _APS_NEXT_CONTROL_VALUE 1001
  15. #define _APS_NEXT_SYMED_VALUE 101
  16. #endif
  17. #endif

//ShowDib1.rc

  1. // Microsoft Visual C++ generated resource script.
  2. //
  3. #include "resource.h"
  4.  
  5. #define APSTUDIO_READONLY_SYMBOLS
  6. /////////////////////////////////////////////////////////////////////////////
  7. //
  8. // Generated from the TEXTINCLUDE 2 resource.
  9. //
  10. #include "winres.h"
  11.  
  12. /////////////////////////////////////////////////////////////////////////////
  13. #undef APSTUDIO_READONLY_SYMBOLS
  14.  
  15. /////////////////////////////////////////////////////////////////////////////
  16. // 中文(简体,中国) resources
  17.  
  18. #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
  19. LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
  20.  
  21. #ifdef APSTUDIO_INVOKED
  22. /////////////////////////////////////////////////////////////////////////////
  23. //
  24. // TEXTINCLUDE
  25. //
  26.  
  27. TEXTINCLUDE
  28. BEGIN
  29. "resource.h\0"
  30. END
  31.  
  32. TEXTINCLUDE
  33. BEGIN
  34. "#include ""winres.h""\r\n"
  35. "\0"
  36. END
  37.  
  38. TEXTINCLUDE
  39. BEGIN
  40. "\r\n"
  41. "\0"
  42. END
  43.  
  44. #endif // APSTUDIO_INVOKED
  45.  
  46. /////////////////////////////////////////////////////////////////////////////
  47. //
  48. // Menu
  49. //
  50.  
  51. SHOWDIB1 MENU
  52. BEGIN
  53. POPUP "&File"
  54. BEGIN
  55. MENUITEM "&Open...\tCtrl+O", IDM_FILE_OPEN
  56. MENUITEM "&Save...\tCtrl+S", IDM_FILE_SAVE
  57. END
  58. END
  59.  
  60. /////////////////////////////////////////////////////////////////////////////
  61. //
  62. // Accelerator
  63. //
  64.  
  65. SHOWDIB1 ACCELERATORS
  66. BEGIN
  67. "^O", IDM_FILE_OPEN, ASCII, NOINVERT
  68. "^S", IDM_FILE_SAVE, ASCII, NOINVERT
  69. END
  70.  
  71. #endif // 中文(简体,中国) resources
  72. /////////////////////////////////////////////////////////////////////////////
  73.  
  74. #ifndef APSTUDIO_INVOKED
  75. /////////////////////////////////////////////////////////////////////////////
  76. //
  77. // Generated from the TEXTINCLUDE 3 resource.
  78. //
  79.  
  80. /////////////////////////////////////////////////////////////////////////////
  81. #endif // not APSTUDIO_INVOKED
 15.2.3 DIB的颠倒世界

(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程序】

 效果图

  1. /*------------------------------------------------------------
  2. APOLLO11.C -- Program for screen captures
  3. (c) Charles Petzold, 1998
  4. ------------------------------------------------------------*/
  5.  
  6. #include <windows.h>
  7. #include "..\\DibHeads\\DibFile.h"
  8.  
  9. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  10.  
  11. static TCHAR szAppName[] = TEXT("Apollo11");
  12. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  13. PSTR szCmdLine, int iCmdShow)
  14. {
  15. HWND hwnd;
  16. MSG msg;
  17. WNDCLASSEX wndclass;
  18.  
  19. wndclass.style = CS_HREDRAW | CS_VREDRAW;
  20. wndclass.cbSize = sizeof(WNDCLASSEX);
  21. wndclass.lpfnWndProc = WndProc;
  22. wndclass.cbClsExtra = ;
  23. wndclass.cbWndExtra = ;
  24. wndclass.hInstance = hInstance;
  25. wndclass.hIcon = LoadIcon(hInstance, szAppName);
  26. wndclass.hIconSm = LoadIcon(hInstance, szAppName);
  27. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  28. wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  29. wndclass.lpszMenuName = NULL;
  30. wndclass.lpszClassName = szAppName;
  31.  
  32. if (!RegisterClassEx(&wndclass))
  33. {
  34. MessageBox(NULL, TEXT("This program requires Windows NT!"),
  35. szAppName, MB_ICONERROR);
  36. return ;
  37. }
  38.  
  39. hwnd = CreateWindow(szAppName, // window class name
  40. TEXT("Apollo 11"), // window caption
  41. WS_OVERLAPPEDWINDOW, // window style
  42. CW_USEDEFAULT, // initial x position
  43. CW_USEDEFAULT, // initial y position
  44. CW_USEDEFAULT, // initial x size
  45. CW_USEDEFAULT, // initial y size
  46. NULL, // parent window handle
  47. NULL, // window menu handle
  48. hInstance, // program instance handle
  49. NULL); // creation parameters
  50.  
  51. ShowWindow(hwnd, iCmdShow);
  52. UpdateWindow(hwnd);
  53.  
  54. while (GetMessage(&msg, NULL, , ))
  55. {
  56. TranslateMessage(&msg);
  57. DispatchMessage(&msg);
  58. }
  59. return msg.wParam;
  60. }
  61.  
  62. LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  63. {
  64. HDC hdc;
  65. PAINTSTRUCT ps;
  66. static BITMAPFILEHEADER* pbmfh[];
  67. static BITMAPINFO* pbmi[];
  68. static BYTE* pBits[];
  69. static int cxClient, cyClient, cxDib[], cyDib[];
  70.  
  71. switch (message)
  72. {
  73. case WM_CREATE:
  74. pbmfh[] = DibLoadImage(TEXT("Apollo11.bmp"));
  75. pbmfh[] = DibLoadImage(TEXT("ApolloTD.bmp"));
  76. if (pbmfh[] == NULL || pbmfh[] == NULL)
  77. {
  78. MessageBox(hwnd, TEXT("Cannot load DIB file"), szAppName, );
  79. return ;
  80. }
  81.  
  82. //获得信息头和像素位指针
  83. pbmi[] = (BITMAPINFO*)(pbmfh[] + );
  84. pbmi[] = (BITMAPINFO*)(pbmfh[] + );
  85.  
  86. pBits[] = (BYTE*)pbmfh[] + pbmfh[]->bfOffBits;
  87. pBits[] = (BYTE*)pbmfh[] + pbmfh[]->bfOffBits;
  88.  
  89. //获取图像大小(为方便,这里只处理BITMAPINFOHEADER结构的DIB)
  90. cxDib[] = pbmi[]->bmiHeader.biWidth;
  91. cyDib[] = abs(pbmi[]->bmiHeader.biHeight); //绝对值!
  92.  
  93. cxDib[] = pbmi[]->bmiHeader.biWidth;
  94. cyDib[] = abs(pbmi[]->bmiHeader.biHeight); //绝对值!
  95. return ;
  96.  
  97. case WM_SIZE:
  98. cxClient = LOWORD(lParam);
  99. cyClient = HIWORD(lParam);
  100. return ;
  101.  
  102. case WM_PAINT:
  103. hdc = BeginPaint(hwnd, &ps);
  104.  
  105. //从下到上DIB整图显示
  106. SetDIBitsToDevice(hdc,
  107. ,
  108. cyClient / , //yDst
  109. cxDib[], //整幅图宽度
  110. cyDib[], //整幅图高度
  111. ,
  112. ,
  113. , //第一扫描线
  114. cyDib[], //扫描线数量
  115. pBits[],
  116. pbmi[],
  117. DIB_RGB_COLORS);
  118.  
  119. //从下到上DIB局部图显示
  120. SetDIBitsToDevice(hdc,
  121. ,
  122. cyClient / , //yDst
  123. , //图的局部(宽度)
  124. , //图的局部(高度)
  125. , //源的X坐标,在图左下角的附近
  126. , //源的Y坐标,在图左下角附近
  127. , //第一扫描线
  128. cyDib[], //扫描线数量
  129. pBits[],
  130. pbmi[],
  131. DIB_RGB_COLORS);
  132.  
  133. //从上到下DIB整图显示
  134. SetDIBitsToDevice(hdc,
  135. ,
  136. cyClient / , //yDst
  137. cxDib[], //整幅图宽度
  138. cyDib[], //整幅图高度
  139. ,
  140. ,
  141. , //第一扫描线
  142. cyDib[], //扫描线数量
  143. pBits[],
  144. pbmi[],
  145. DIB_RGB_COLORS);
  146.  
  147. //从上到下DIB局部图显示
  148. SetDIBitsToDevice(hdc,
  149. ,
  150. cyClient / , //yDst
  151. , //图的局部(宽度)
  152. , //图的局部(高度)
  153. , //源的X坐标,在图左下角的附近
  154. , //源的Y坐标,在图左下角附近
  155. , //第一扫描线
  156. cyDib[], //扫描线数量
  157. pBits[],
  158. pbmi[],
  159. DIB_RGB_COLORS);
  160.  
  161. EndPaint(hwnd, &ps);
  162. return ;
  163.  
  164. case WM_DESTROY:
  165. PostQuitMessage();
  166. return ;
  167. }
  168. return DefWindowProc(hwnd, message, wParam, lParam);
  169. }
 //DibFile.h和DibFile.C文件见【ShowDib1程序】

15.2.4 顺序显示——扫描线

(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程序】
效果图

  1. /*------------------------------------------------------------
  2. SEQDISP.C -- Sequential Display of DIBs
  3. (c) Charles Petzold, 1998
  4. ------------------------------------------------------------*/
  5.  
  6. #include <windows.h>
  7. #include "resource.h"
  8.  
  9. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  10. static TCHAR szAppName[] = TEXT("SeqDisp");
  11.  
  12. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  13. PSTR szCmdLine, int iCmdShow)
  14. {
  15. HWND hwnd;
  16. MSG msg;
  17. WNDCLASSEX wndclass;
  18. HACCEL hAccel;
  19.  
  20. wndclass.style = CS_HREDRAW | CS_VREDRAW;
  21. wndclass.cbSize = sizeof(WNDCLASSEX);
  22. wndclass.lpfnWndProc = WndProc;
  23. wndclass.cbClsExtra = ;
  24. wndclass.cbWndExtra = ;
  25. wndclass.hInstance = hInstance;
  26. wndclass.hIcon = LoadIcon(hInstance, szAppName);
  27. wndclass.hIconSm = LoadIcon(hInstance, szAppName);
  28. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  29. wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  30. wndclass.lpszMenuName = szAppName;
  31. wndclass.lpszClassName = szAppName;
  32.  
  33. if (!RegisterClassEx(&wndclass))
  34. {
  35. MessageBox(NULL, TEXT("This program requires Windows NT!"),
  36. szAppName, MB_ICONERROR);
  37. return ;
  38. }
  39.  
  40. hwnd = CreateWindow(szAppName, // window class name
  41. TEXT("DIB Sequential Display"), // window caption
  42. WS_OVERLAPPEDWINDOW, // window style
  43. CW_USEDEFAULT, // initial x position
  44. CW_USEDEFAULT, // initial y position
  45. CW_USEDEFAULT, // initial x size
  46. CW_USEDEFAULT, // initial y size
  47. NULL, // parent window handle
  48. NULL, // window menu handle
  49. hInstance, // program instance handle
  50. NULL); // creation parameters
  51.  
  52. ShowWindow(hwnd, iCmdShow);
  53. UpdateWindow(hwnd);
  54. hAccel = LoadAccelerators(hInstance, szAppName);
  55. while (GetMessage(&msg, NULL, , ))
  56. {
  57. if (!TranslateAccelerator(hwnd, hAccel, &msg))
  58. {
  59. TranslateMessage(&msg);
  60. DispatchMessage(&msg);
  61. }
  62. }
  63. return msg.wParam;
  64. }
  65.  
  66. LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  67. {
  68. HDC hdc;
  69. PAINTSTRUCT ps;
  70. static BITMAPINFO* pbmi;
  71. static BYTE* pBits;
  72. static int cxDib, cyDib, cBits;
  73. static OPENFILENAME ofn;
  74. static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH];
  75. static TCHAR szFilter[] = TEXT("Bitmap Files(*.BMP)\0*.bmp\0")\
  76. TEXT("All Files(*.*)\0*.*\0\0");
  77.  
  78. BITMAPFILEHEADER bmfh;
  79. BOOL bSuccess, bTopDown;
  80. DWORD dwBytesRead;
  81. HANDLE hFile;
  82. int iInfoSize, iBitsSize, iRowLength;
  83.  
  84. switch (message)
  85. {
  86. case WM_CREATE:
  87. ofn.lStructSize = sizeof(OPENFILENAME);
  88. ofn.hwndOwner = hwnd;
  89. ofn.hInstance = NULL;
  90. ofn.lpstrFilter = szFilter;
  91. ofn.lpstrCustomFilter = NULL;
  92. ofn.nMaxCustFilter = ;
  93. ofn.nFilterIndex = ;
  94. ofn.lpstrFile = szFileName;
  95. ofn.nMaxFile = MAX_PATH;
  96. ofn.lpstrFileTitle = szTitleName;
  97. ofn.nMaxFileTitle = MAX_PATH;
  98. ofn.lpstrInitialDir = NULL;
  99. ofn.lpstrTitle = NULL;
  100. ofn.Flags = ; //在打开和关闭函数中设置
  101. ofn.nFileOffset = ;
  102. ofn.nFileExtension = ;
  103. ofn.lpstrDefExt = TEXT("bmp"); //默认扩展名
  104. ofn.lCustData = ;
  105. ofn.lpfnHook = NULL;
  106. ofn.lpTemplateName = NULL;
  107. return ;
  108.  
  109. case WM_COMMAND:
  110. switch (LOWORD(wParam))
  111. {
  112. case IDM_FILE_OPEN:
  113.  
  114. //显示打开文件对话框
  115. if (!GetOpenFileName(&ofn))
  116. return ;
  117.  
  118. //清除之前打开的位图文件
  119. if (pbmi)
  120. {
  121. free(pbmi);
  122. pbmi = NULL;
  123. }
  124.  
  125. if (pBits)
  126. {
  127. free(pBits);
  128. pBits = NULL;
  129. }
  130.  
  131. //擦掉客户区上的位图
  132. InvalidateRect(hwnd, NULL, TRUE);
  133. UpdateWindow(hwnd); //可注释掉看下
  134.  
  135. //打开文件
  136. hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  137.  
  138. if (hFile == INVALID_HANDLE_VALUE)
  139. {
  140. MessageBox(hwnd, TEXT("Cannot open file."), szAppName, MB_ICONWARNING | MB_OK);
  141. return ;
  142. }
  143.  
  144. //读取BITMAPFILEHEADER
  145. bSuccess = ReadFile(hFile, &bmfh, sizeof(BITMAPFILEHEADER), &dwBytesRead, NULL);
  146.  
  147. if (!bSuccess || dwBytesRead != sizeof(BITMAPFILEHEADER))
  148. {
  149. MessageBox(hwnd, TEXT("Cannot open file."), szAppName, MB_ICONWARNING | MB_OK);
  150. CloseHandle(hFile);
  151. return ;
  152. }
  153.  
  154. //检验是否是位图文件,第1-2个字节为“BM”
  155. if (bmfh.bfType != *(WORD*)"BM")
  156. {
  157. MessageBox(hwnd, TEXT("File is not a bitmap."), szAppName, MB_ICONWARNING | MB_OK);
  158. CloseHandle(hFile);
  159. return ;
  160. }
  161.  
  162. //为文件信息头和像素位数据分配内存
  163. iInfoSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);
  164. iBitsSize = bmfh.bfSize - bmfh.bfOffBits;
  165.  
  166. pbmi = malloc(iInfoSize);
  167. pBits = malloc(iBitsSize);
  168.  
  169. if (pbmi == NULL || pBits == NULL)
  170. {
  171. MessageBox(hwnd, TEXT("Cannot allocate memory."), szAppName, MB_ICONWARNING | MB_OK);
  172. if (pbmi)
  173. {
  174. free(pbmi);
  175. pbmi = NULL;
  176. }
  177.  
  178. if (pBits)
  179. {
  180. free(pBits);
  181. pBits = NULL;
  182. }
  183.  
  184. CloseHandle(hFile);
  185. return ;
  186. }
  187.  
  188. //读取信息头
  189. bSuccess = ReadFile(hFile, pbmi, iInfoSize, &dwBytesRead, NULL);
  190. if (!bSuccess || iInfoSize != dwBytesRead)
  191. {
  192. MessageBox(hwnd, TEXT("Cannot allocate memory."), szAppName, MB_ICONWARNING | MB_OK);
  193. if (pbmi)
  194. {
  195. free(pbmi);
  196. pbmi = NULL;
  197. }
  198.  
  199. if (pBits)
  200. {
  201. free(pBits);
  202. pBits = NULL;
  203. }
  204.  
  205. CloseHandle(hFile);
  206. return ;
  207. }
  208.  
  209. //获取像素数据和高度
  210. bTopDown = FALSE;
  211. if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
  212. {
  213. cxDib = ((BITMAPCOREHEADER*)pbmi)->bcWidth;
  214. cyDib = ((BITMAPCOREHEADER*)pbmi)->bcHeight;
  215. cBits = ((BITMAPCOREHEADER*)pbmi)->bcBitCount;
  216. } else
  217. {
  218. bTopDown = (pbmi->bmiHeader.biHeight < );
  219.  
  220. cxDib = pbmi->bmiHeader.biWidth;
  221. cyDib = abs(pbmi->bmiHeader.biHeight);
  222. cBits = pbmi->bmiHeader.biBitCount;
  223.  
  224. if (pbmi->bmiHeader.biCompression != BI_RGB && pbmi->bmiHeader.biCompression != BI_BITFIELDS)
  225. {
  226. MessageBox(hwnd, TEXT("File is compressed."), szAppName, MB_ICONWARNING | MB_OK);
  227. if (pbmi)
  228. {
  229. free(pbmi);
  230. pbmi = NULL;
  231. }
  232.  
  233. if (pBits)
  234. {
  235. free(pBits);
  236. pBits = NULL;
  237. }
  238.  
  239. CloseHandle(hFile);
  240. return ;
  241. }
  242. }
  243.  
  244. //计算每行像素宽度,4的倍数
  245. iRowLength = ((cxDib*cBits + )& ~) >> ;
  246.  
  247. //显示位图
  248. SetCursor(LoadCursor(NULL, IDC_WAIT));
  249. ShowCursor(TRUE);
  250.  
  251. hdc = GetDC(hwnd);
  252.  
  253. for (int y = ; y < cyDib; y++)
  254. {
  255. ReadFile(hFile, pBits + y*iRowLength, iRowLength, &dwBytesRead, NULL);
  256. /*
  257. 1、每次扫描时,源矩形0,y,cxDib,cyDib-y,目标矩形0,0,cxDib,cyDib-y
  258. 2、每次调用函数时,像素的数据在改变,pBits+y*iRowLength;
  259. 3、每次都为像素位的第一行数据编号为y或cyDib-y-1
  260. */
  261. SetDIBitsToDevice(hdc,
  262. , //xDst
  263. , //yDst
  264. cxDib, //cxSrc
  265. cyDib - y, //cySrc,课本这里为cyDib。
  266. , //xSrc
  267. y, //ySrc,课本这里为0,这两处的更改,效率更高
  268. bTopDown ? cyDib - y - : y, //给第一行扫描行编号
  269. , //每次扫描一行
  270. pBits + y*iRowLength, //第一行扫描行的数据
  271. pbmi,
  272. DIB_RGB_COLORS);
  273. }
  274.  
  275. ReleaseDC(hwnd, hdc);
  276. CloseHandle(hFile);
  277. SetCursor(LoadCursor(NULL, IDC_ARROW));
  278. ShowCursor(FALSE);
  279.  
  280. return ;
  281. }
  282. break;
  283. case WM_PAINT:
  284. hdc = BeginPaint(hwnd, &ps);
  285. if (pbmi && pBits)
  286. {
  287. SetDIBitsToDevice(hdc,
  288. , //xDst
  289. , //yDst
  290. cxDib, //cxSrc
  291. cyDib, //cySrc
  292. , //xSrc
  293. , //ySrc
  294. , //第一行扫描行编号
  295. cyDib,
  296. pBits,
  297. pbmi,
  298. DIB_RGB_COLORS);
  299. }
  300. EndPaint(hwnd, &ps);
  301. return ;
  302.  
  303. case WM_DESTROY:
  304. if (pbmi) free(pbmi);
  305.  
  306. if (pBits) free(pBits);
  307.  
  308. PostQuitMessage();
  309. return ;
  310. }
  311. return DefWindowProc(hwnd, message, wParam, lParam);
  312. }

//resouce.h

  1. //{{NO_DEPENDENCIES}}
  2. // Microsoft Developer Studio generated include file.
  3. // Used by SeqDisp.rc
  4. //
  5. #define IDM_FILE_OPEN 40001
  6.  
  7. // Next default values for new objects
  8. //
  9. #ifdef APSTUDIO_INVOKED
  10. #ifndef APSTUDIO_READONLY_SYMBOLS
  11. #define _APS_NEXT_RESOURCE_VALUE 101
  12. #define _APS_NEXT_COMMAND_VALUE 40002
  13. #define _APS_NEXT_CONTROL_VALUE 1000
  14. #define _APS_NEXT_SYMED_VALUE 101
  15. #endif
  16. #endif

//SeqDisp.rc

  1. //Microsoft Developer Studio generated resource script.
  2. //
  3. #include "resource.h"
  4.  
  5. #define APSTUDIO_READONLY_SYMBOLS
  6. /////////////////////////////////////////////////////////////////////////////
  7. //
  8. // Generated from the TEXTINCLUDE 2 resource.
  9. //
  10. #include "afxres.h"
  11.  
  12. /////////////////////////////////////////////////////////////////////////////
  13. #undef APSTUDIO_READONLY_SYMBOLS
  14.  
  15. /////////////////////////////////////////////////////////////////////////////
  16. // English (U.S.) resources
  17.  
  18. #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
  19. #ifdef _WIN32
  20. LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
  21. #pragma code_page(1252)
  22. #endif //_WIN32
  23.  
  24. #ifdef APSTUDIO_INVOKED
  25. /////////////////////////////////////////////////////////////////////////////
  26. //
  27. // TEXTINCLUDE
  28. //
  29.  
  30. TEXTINCLUDE DISCARDABLE
  31. BEGIN
  32. "resource.h\0"
  33. END
  34.  
  35. TEXTINCLUDE DISCARDABLE
  36. BEGIN
  37. "#include ""afxres.h""\r\n"
  38. "\0"
  39. END
  40.  
  41. TEXTINCLUDE DISCARDABLE
  42. BEGIN
  43. "\r\n"
  44. "\0"
  45. END
  46.  
  47. #endif // APSTUDIO_INVOKED
  48.  
  49. /////////////////////////////////////////////////////////////////////////////
  50. //
  51. // Accelerator
  52. //
  53.  
  54. SEQDISP ACCELERATORS DISCARDABLE
  55. BEGIN
  56. "O", IDM_FILE_OPEN, VIRTKEY, CONTROL, NOINVERT
  57. END
  58.  
  59. /////////////////////////////////////////////////////////////////////////////
  60. //
  61. // Menu
  62. //
  63.  
  64. SEQDISP MENU DISCARDABLE
  65. BEGIN
  66. POPUP "&File"
  67. BEGIN
  68. MENUITEM "&Open...\tCtrl+O", IDM_FILE_OPEN
  69. END
  70. END
  71.  
  72. #endif // English (U.S.) resources
  73. /////////////////////////////////////////////////////////////////////////////
  74.  
  75. #ifndef APSTUDIO_INVOKED
  76. /////////////////////////////////////////////////////////////////////////////
  77. //
  78. // Generated from the TEXTINCLUDE 3 resource.
  79. //
  80.  
  81. /////////////////////////////////////////////////////////////////////////////
  82. #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程序】

  1. /*------------------------------------------------------------
  2. SHOWDIB2.C -- Shows a DIB in the client area
  3. (c) Charles Petzold, 1998
  4. ------------------------------------------------------------*/
  5.  
  6. #include <windows.h>
  7. #include "resource.h"
  8. #include "..\\ShowDib1\\DibFile.h"
  9.  
  10. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  11.  
  12. static TCHAR szAppName[] = TEXT("ShowDib2");
  13. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  14. PSTR szCmdLine, int iCmdShow)
  15. {
  16. HWND hwnd;
  17. MSG msg;
  18. WNDCLASSEX wndclass;
  19. HACCEL hAccel;
  20.  
  21. wndclass.style = CS_HREDRAW | CS_VREDRAW;
  22. wndclass.cbSize = sizeof(WNDCLASSEX);
  23. wndclass.lpfnWndProc = WndProc;
  24. wndclass.cbClsExtra = ;
  25. wndclass.cbWndExtra = ;
  26. wndclass.hInstance = hInstance;
  27. wndclass.hIcon = LoadIcon(hInstance, szAppName);
  28. wndclass.hIconSm = LoadIcon(hInstance, szAppName);
  29. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  30. wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  31. wndclass.lpszMenuName = szAppName;
  32. wndclass.lpszClassName = szAppName;
  33.  
  34. if (!RegisterClassEx(&wndclass))
  35. {
  36. MessageBox(NULL, TEXT("This program requires Windows NT!"),
  37. szAppName, MB_ICONERROR);
  38. return ;
  39. }
  40.  
  41. hwnd = CreateWindow(szAppName, // window class name
  42. TEXT("Show DIB #2"), // window caption
  43. WS_OVERLAPPEDWINDOW, // window style
  44. CW_USEDEFAULT, // initial x position
  45. CW_USEDEFAULT, // initial y position
  46. CW_USEDEFAULT, // initial x size
  47. CW_USEDEFAULT, // initial y size
  48. NULL, // parent window handle
  49. NULL, // window menu handle
  50. hInstance, // program instance handle
  51. NULL); // creation parameters
  52.  
  53. ShowWindow(hwnd, iCmdShow);
  54. UpdateWindow(hwnd);
  55. hAccel = LoadAccelerators(hInstance, szAppName);
  56. while (GetMessage(&msg, NULL, , ))
  57. {
  58. if (!TranslateAccelerator(hwnd, hAccel, &msg))
  59. {
  60. TranslateMessage(&msg);
  61. DispatchMessage(&msg);
  62. }
  63. }
  64. return msg.wParam;
  65. }
  66.  
  67. int ShowDib(HDC hdc, BITMAPINFO* pbmi, BYTE* pBits, int cxDib, int cyDib, int cxClient, int cyClient, WORD wShow)
  68. {
  69. switch (wShow)
  70. {
  71. case IDM_SHOW_NORMAL: //正常显示
  72. return SetDIBitsToDevice(hdc, , , cxDib, cyDib, , , , cyDib, pBits, pbmi, DIB_RGB_COLORS);
  73.  
  74. case IDM_SHOW_CENTER: //居中显示
  75. return SetDIBitsToDevice(hdc, (cxClient - cxDib) / ,
  76. (cyClient - cyDib) / ,
  77. cxDib, cyDib, , ,
  78. , cyDib, pBits, pbmi, DIB_RGB_COLORS);
  79. case IDM_SHOW_STRETCH: //拉伸到整个客户区
  80. SetStretchBltMode(hdc, COLORONCOLOR); //缩小时,直接去掉颜色值
  81. return StretchDIBits(hdc, , , cxClient, cyClient,
  82. , , cxDib, cyDib,
  83. pBits, pbmi, DIB_RGB_COLORS, SRCCOPY);
  84. case IDM_SHOW_ISOSTRETCH:
  85. SetStretchBltMode(hdc, COLORONCOLOR);
  86. SetMapMode(hdc, MM_ISOTROPIC);
  87. SetWindowExtEx(hdc, cxDib, cyDib, NULL);
  88. SetViewportExtEx(hdc, cxClient, cyClient, NULL);
  89. SetWindowOrgEx(hdc, cxDib / , cyDib / , NULL);
  90. SetViewportOrgEx(hdc, cxClient / , cyClient / , NULL);
  91.  
  92. return StretchDIBits(hdc, , , cxDib, cyDib, //逻辑坐标系的范围
  93. , , cxDib, cyDib,
  94. pBits, pbmi, DIB_RGB_COLORS, SRCCOPY);
  95. }
  96. return ;
  97. }
  98.  
  99. LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  100. {
  101. static BITMAPFILEHEADER* pbmfh;
  102. static BITMAPINFO* pbmi;
  103. static BYTE* pBits;
  104.  
  105. static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH];
  106. static int cxClient, cyClient, cxDib, cyDib;
  107. HDC hdc, hdcPrn;
  108. static DOCINFO di = { sizeof(DOCINFO), TEXT("ShowDib2:Printing") };
  109. PAINTSTRUCT ps;
  110. BOOL bSuccess;
  111. int iEnable, cxPage, cyPage;
  112. static WORD wShow = IDM_SHOW_NORMAL;
  113. HMENU hMenu;
  114. HGLOBAL hGlobal;
  115. BYTE *pGlobal;
  116.  
  117. static PRINTDLG printdlg = { sizeof(PRINTDLG) };
  118.  
  119. switch (message)
  120. {
  121. case WM_CREATE:
  122.  
  123. DibFileInitialize(hwnd);
  124. return ;
  125.  
  126. case WM_INITMENUPOPUP:
  127. if (pbmfh)
  128. iEnable = MF_ENABLED;
  129. else
  130. iEnable = MF_GRAYED;
  131.  
  132. EnableMenuItem((HMENU)wParam, IDM_FILE_SAVE, iEnable);
  133. EnableMenuItem((HMENU)wParam, IDM_FILE_PRINT, iEnable);
  134. EnableMenuItem((HMENU)wParam, IDM_EDIT_CUT, iEnable);
  135. EnableMenuItem((HMENU)wParam, IDM_EDIT_COPY, iEnable);
  136. EnableMenuItem((HMENU)wParam, IDM_EDIT_DELETE, iEnable);
  137. return ;
  138.  
  139. case WM_SIZE:
  140. cxClient = LOWORD(lParam);
  141. cyClient = HIWORD(lParam);
  142. return ;
  143.  
  144. case WM_COMMAND:
  145. hMenu = GetMenu(hwnd);
  146.  
  147. switch (LOWORD(wParam))
  148. {
  149. case IDM_FILE_OPEN:
  150. //显示打开对话框
  151. if (!DibFileOpenDlg(hwnd, szFileName, szTitleName))
  152. return ;
  153.  
  154. //如果DIB文件己被载入,释放内存
  155. if (pbmfh)
  156. {
  157. free(pbmfh);
  158. pbmfh = NULL;
  159. }
  160.  
  161. //将整个DIB加载到内存中
  162. SetCursor(LoadCursor(NULL, IDC_WAIT));
  163. ShowCursor(TRUE);
  164.  
  165. pbmfh = DibLoadImage(szFileName);
  166.  
  167. ShowCursor(FALSE);
  168. SetCursor(LoadCursor(NULL, IDC_ARROW));
  169.  
  170. //使客户区无效,以便后面的绘图并擦除以前客户区显示的内容
  171. InvalidateRect(hwnd, NULL, TRUE);
  172.  
  173. if (pbmfh == NULL)
  174. {
  175. MessageBox(hwnd, TEXT("Cannot load DIB file"), szAppName, );
  176. return ;
  177. }
  178.  
  179. //获取指向DIB信息头的指针和指向像素位的指针
  180. pbmi = (BITMAPINFO*)(pbmfh + );
  181. pBits = (BYTE*)pbmfh + pbmfh->bfOffBits;
  182.  
  183. //获取图像的宽度和高度
  184. if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
  185. {
  186. cxDib = ((BITMAPCOREHEADER*)pbmi)->bcWidth;
  187. cyDib = ((BITMAPCOREHEADER*)pbmi)->bcHeight;
  188. } else
  189. {
  190. cxDib = pbmi->bmiHeader.biWidth;
  191. cyDib = abs(pbmi->bmiHeader.biHeight);
  192. }
  193. return ;
  194.  
  195. case IDM_FILE_SAVE:
  196.  
  197. //显示保存对话框
  198. if (!DibFileSaveDlg(hwnd, szFileName, szTitleName))
  199. return ;
  200.  
  201. //将DIB位图保存到文件中
  202. SetCursor(LoadCursor(NULL, IDC_WAIT));
  203. ShowCursor(TRUE);
  204.  
  205. bSuccess = DibSaveImage(szFileName, pbmfh);
  206.  
  207. ShowCursor(FALSE);
  208. SetCursor(LoadCursor(NULL, IDC_ARROW));
  209.  
  210. if (!bSuccess)
  211. MessageBox(hwnd, TEXT("Cannot save DIB file"), szAppName, );
  212. return ;
  213.  
  214. case IDM_FILE_PRINT:
  215. if (!pbmfh)
  216. return ;
  217.  
  218. //获取打印机DC
  219. printdlg.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION;
  220. if (!PrintDlg(&printdlg))
  221. return ;
  222. hdcPrn = printdlg.hDC;
  223. if (NULL == hdcPrn)
  224. {
  225. MessageBox(hwnd, TEXT("Cannot obtain Printer DC"),
  226. szAppName, MB_ICONEXCLAMATION | MB_OK);
  227. return ;
  228. }
  229.  
  230. //检查打印机是否可以打印位图
  231. if (!(RC_BITBLT)&GetDeviceCaps(hdcPrn, RASTERCAPS))
  232. {
  233. DeleteDC(hdcPrn);
  234. MessageBox(hwnd, TEXT("Printer cannot print bitmaps"),
  235. szAppName, MB_ICONEXCLAMATION | MB_OK);
  236. return ;
  237. }
  238.  
  239. //获得可打印区域的大小
  240. cxPage = GetDeviceCaps(hdcPrn, HORZRES);
  241. cyPage = GetDeviceCaps(hdcPrn, VERTRES);
  242.  
  243. bSuccess = FALSE;
  244.  
  245. //将位图输程打印机
  246. SetCursor(LoadCursor(NULL, IDC_WAIT));
  247. ShowCursor(TRUE);
  248. //StartDoc、StartPage、EndPage、EndDoc返回值>0说明执行成功。
  249. if ((StartDoc(hdcPrn, &di)>) && (StartPage(hdcPrn)>))
  250. {
  251. ShowDib(hdcPrn, pbmi, pBits, cxDib, cyDib, cxPage, cyPage, wShow);
  252. if (EndPage(hdcPrn)>)
  253. {
  254. bSuccess = TRUE;
  255. EndDoc(hdcPrn);
  256. }
  257. }
  258. ShowCursor(FALSE);
  259. SetCursor(LoadCursor(NULL, IDC_ARROW));
  260. DeleteDC(hdcPrn);
  261. if (!bSuccess)
  262. MessageBox(hwnd, TEXT("Could not print bitmap"),
  263. szAppName, MB_ICONEXCLAMATION | MB_OK);
  264. return ;
  265.  
  266. case IDM_EDIT_COPY:
  267. case IDM_EDIT_CUT:
  268. if (!pbmfh)
  269. return ;
  270.  
  271. //生成一个紧凑型DIB
  272. hGlobal = GlobalAlloc(GHND | GMEM_SHARE,
  273. pbmfh->bfSize - sizeof(BITMAPFILEHEADER));
  274. pGlobal = GlobalLock(hGlobal);
  275. CopyMemory(pGlobal, (BYTE*)pbmfh + sizeof(BITMAPFILEHEADER),
  276. pbmfh->bfSize - sizeof(BITMAPFILEHEADER));
  277. GlobalUnlock(hGlobal);
  278.  
  279. //传输到剪贴板
  280. OpenClipboard(hwnd);
  281. EmptyClipboard();
  282. SetClipboardData(CF_DIB, hGlobal);
  283. CloseClipboard();
  284.  
  285. if (LOWORD(wParam) == IDM_EDIT_COPY)
  286. return ;
  287. //IDM_EDIT_CUT则继续执行下去
  288.  
  289. case IDM_EDIT_DELETE:
  290. if (pbmfh)
  291. {
  292. free(pbmfh);
  293. pbmfh = NULL;
  294. InvalidateRect(hwnd, NULL, TRUE);
  295. }
  296.  
  297. return ;
  298.  
  299. case IDM_SHOW_CENTER:
  300. case IDM_SHOW_ISOSTRETCH:
  301. case IDM_SHOW_NORMAL:
  302. case IDM_SHOW_STRETCH:
  303. CheckMenuItem(hMenu, wShow, MF_GRAYED);
  304. wShow = LOWORD(wParam);
  305. CheckMenuItem(hMenu, wShow, MF_CHECKED);
  306. InvalidateRect(hwnd, NULL, TRUE);
  307. return ;
  308. }
  309. break;
  310.  
  311. case WM_PAINT:
  312. hdc = BeginPaint(hwnd, &ps);
  313.  
  314. if (pbmfh)
  315. {
  316. ShowDib(hdc, pbmi, pBits, cxDib, cyDib, cxClient, cyClient, wShow);
  317. }
  318.  
  319. EndPaint(hwnd, &ps);
  320. return ;
  321.  
  322. case WM_DESTROY:
  323. if (pbmfh)
  324. free(pbmfh);
  325. PostQuitMessage();
  326. return ;
  327. }
  328. return DefWindowProc(hwnd, message, wParam, lParam);
  329. }

//resource.h

  1. //{{NO_DEPENDENCIES}}
  2. // Microsoft Visual C++ 生成的包含文件。
  3. // 供 ShowDib2.rc 使用
  4. //
  5. #define IDM_FILE_OPEN 40001
  6. #define IDM_FILE_SAVE 40002
  7. #define IDM_FILE_PRINT 40003
  8. #define IDM_EDIT_CUT 40004
  9. #define IDM_EDIT_COPY 40005
  10. #define IDM_EDIT_CLEAR 40006
  11. #define IDM_EDIT_DELETE 40007
  12. #define IDM_SHOW_NORMAL 40008
  13. #define IDM_SHOW_CENTER 40009
  14. #define IDM_SHOW_STRETCH 40010
  15. #define IDM_SHOW_ISOSTRETCH 40011
  16. // Next default values for new objects
  17. //
  18. #ifdef APSTUDIO_INVOKED
  19. #ifndef APSTUDIO_READONLY_SYMBOLS
  20. #define _APS_NEXT_RESOURCE_VALUE 103
  21. #define _APS_NEXT_COMMAND_VALUE 40028
  22. #define _APS_NEXT_CONTROL_VALUE 1001
  23. #define _APS_NEXT_SYMED_VALUE 101
  24. #endif
  25. #endif

//ShowDib2.rc

  1. // Microsoft Visual C++ generated resource script.
  2. //
  3. #include "resource.h"
  4. #define APSTUDIO_READONLY_SYMBOLS
  5. /////////////////////////////////////////////////////////////////////////////
  6. //
  7. // Generated from the TEXTINCLUDE 2 resource.
  8. //
  9. #include "winres.h"
  10. /////////////////////////////////////////////////////////////////////////////
  11. #undef APSTUDIO_READONLY_SYMBOLS
  12. /////////////////////////////////////////////////////////////////////////////
  13. // 中文(简体,中国) resources
  14. #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
  15. LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
  16. #ifdef APSTUDIO_INVOKED
  17. /////////////////////////////////////////////////////////////////////////////
  18. //
  19. // TEXTINCLUDE
  20. //
  21. TEXTINCLUDE
  22. BEGIN
  23. "resource.h\0"
  24. END
  25. TEXTINCLUDE
  26. BEGIN
  27. "#include ""winres.h""\r\n"
  28. "\0"
  29. END
  30. TEXTINCLUDE
  31. BEGIN
  32. "\r\n"
  33. "\0"
  34. END
  35. #endif // APSTUDIO_INVOKED
  36. /////////////////////////////////////////////////////////////////////////////
  37. //
  38. // Menu
  39. //
  40. SHOWDIB2 MENU
  41. BEGIN
  42. POPUP "&File"
  43. BEGIN
  44. MENUITEM "&Open...\tCtrl+O", IDM_FILE_OPEN
  45. MENUITEM "&Save...\tCtrl+S", IDM_FILE_SAVE
  46. MENUITEM SEPARATOR
  47. MENUITEM "&Print\tCtrl+P", IDM_FILE_PRINT
  48. END
  49. POPUP "&Edit"
  50. BEGIN
  51. MENUITEM "Cu&t\tCtrl+X", IDM_EDIT_CUT
  52. MENUITEM "&Copy\tCtrl+C", IDM_EDIT_COPY
  53. MENUITEM "&Delete\tDelete", IDM_EDIT_DELETE
  54. END
  55. POPUP "&Show"
  56. BEGIN
  57. MENUITEM "&Actual Size", IDM_SHOW_NORMAL, CHECKED
  58. MENUITEM "&Center", IDM_SHOW_CENTER
  59. MENUITEM "&Stretch toWindow", IDM_SHOW_STRETCH
  60. MENUITEM "Stretch &Isotropically ", IDM_SHOW_ISOSTRETCH
  61. END
  62. END
  63. /////////////////////////////////////////////////////////////////////////////
  64. //
  65. // Accelerator
  66. //
  67. SHOWDIB2 ACCELERATORS
  68. BEGIN
  69. "^O", IDM_FILE_OPEN, ASCII, NOINVERT
  70. "^S", IDM_FILE_SAVE, ASCII, NOINVERT
  71. "^P", IDM_FILE_PRINT, ASCII, NOINVERT
  72. "^C", IDM_EDIT_COPY, ASCII, NOINVERT
  73. VK_DELETE, IDM_EDIT_DELETE, VIRTKEY, SHIFT, NOINVERT
  74. "^X", IDM_EDIT_CUT, ASCII, NOINVERT
  75. END
  76. #endif // 中文(简体,中国) resources
  77. /////////////////////////////////////////////////////////////////////////////
  78. #ifndef APSTUDIO_INVOKED
  79. /////////////////////////////////////////////////////////////////////////////
  80. //
  81. // Generated from the TEXTINCLUDE 3 resource.
  82. //
  83. /////////////////////////////////////////////////////////////////////////////
  84. #endif // not APSTUDIO_INVOKED

//DibFile.h和DibFile.c见ShowDib1程序

第15章 设备无关位图_15.2 显示和打印DIB的更多相关文章

  1. 第15章 设备无关位图_15.3 DIB和DDB的结合

    第15章 设备相关位图_15.3 DIB和DDB的结合 15.3.1 从DIB创建DDB (1)hBitmap =CreateDIBitmap(…)——注意这名称会误导,实际上创建的是DDB 参数 说 ...

  2. 第15章 设备无关位图_15.1 DIB文件格式

    15.1 DIB文件格式(一种文件格式,扩展名为BMP) 15.1.1 OS/2风格的DIB 文件格式 字段 说明 文件头 (BITMAPFILEHEADER) 1.共14个字节 2.缩写建议用bmf ...

  3. device-independent bitmap (DIB) 设备无关位图

    设备无关位图即独立于设备的位图(DIB)与"Device-Dependent Bitmaps (DDB) 设备相关位图"相比,它不再依赖于具体的设备,从而更适合在不同的计算机之间传 ...

  4. windows设备相关位图与设备无关位图

    windows支持两种位图格式,DDB(device-dependent bitmap),DIB(device-independent bitmap).设备相关位图用于windows显示系统中,其图像 ...

  5. Device-Dependent Bitmaps (DDB) 设备相关位图

    设备相关的位图(DDB)使用单一结构BITMAP结构描述.该结构的成员指定矩形区域的宽度和高度,以像素为单位;将条目从设备调色板映射到像素的数组的宽度;以及器件的颜色格式,在每个像素的颜色平面和位数方 ...

  6. ASM:《X86汇编语言-从实模式到保护模式》第15章:任务切换

    15章其实应该是和14章相辅相成的(感觉应该是作者觉得14章内容太多了然后切出来了一点).任务切换和14章的某些概念是分不开的. ★PART1:任务门与任务切换的方法 1. 任务管理程序 14章的时候 ...

  7. Linux就这个范儿 第15章 七种武器 linux 同步IO: sync、fsync与fdatasync Linux中的内存大页面huge page/large page David Cutler Linux读写内存数据的三种方式

    Linux就这个范儿 第15章 七种武器  linux 同步IO: sync.fsync与fdatasync   Linux中的内存大页面huge page/large page  David Cut ...

  8. unix network programming(3rd)Vol.1 [第13~15章]《读书笔记系列》

    第13章 守护进程和inetd 超级服务器 syslog() daemon_init() setuid() setgid() 第14章 高级IO 标准I/O函数库,支持3种缓冲 缓冲(读写存储设备(硬 ...

  9. 【RL-TCPnet网络教程】第15章 RL-TCPnet之创建多个TCP连接

    第15章     RL-TCPnet之创建多个TCP连接 本章节为大家讲解RL-TCPnet的TCP多客户端实现,因为多客户端在实际项目中用到的地方还挺多,所以我们也专门开启一个章节做讲解.另外,学习 ...

随机推荐

  1. HTML中tr标签设置边框不显示的解决办法

    今天在操作表格的时候发现设置表格中行的边框没有显示,然后自己新建了一个表格发现确实不显示 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Tr ...

  2. arcgis engine 调用arcgis server服务

    首先需要添加两个引用: using ESRI.ArcGIS.GISClient;using ESRI.ArcGIS.DataSourcesRaster; /// <summary> /// ...

  3. SharePoint Online 创建门户网站系列之创建栏目

    前 言 SharePoint Online的栏目,简单描述即显示在首页上的各个模块信息,这里,我们主要介绍我们首页上的栏目,包括简介类型.新闻列表类型.图片类型: 下面,让我们开始在SharePoin ...

  4. 如何保护在Autodesk应用程序商店的应用不被盗版 - 1

    Autodesk应用程序商店如火如荼,但来自中国的应用却还是寥寥无几.大家在担心什么呢?可能其中一个因素就是担心自己的应用上线后被盗版的问题.对应用的版权保护和授权管理是每个应用开发者都应该认真考虑的 ...

  5. 通过API找出Autodesk Vault中某个用户组可以访问的Vault

    首先在Vault Explorer中可以这样查看和更改某个用户组有权访问的vault Tools –> Administration –> Global Settings –> Gr ...

  6. Xcode中XVim的常用操作

  7. Hbase Java API详解

    HBase是Hadoop的数据库,能够对大数据提供随机.实时读写访问.他是开源的,分布式的,多版本的,面向列的,存储模型. 在讲解的时候我首先给大家讲解一下HBase的整体结构,如下图: HBase ...

  8. iOS runtime的理解和应用

    项目中经常会有一些的功能模块用到runtime,最近也在学习它.对于要不要阅读runtime的源码,我觉得仅仅是处理正常的开发,那真的没有必要,只要把常用的一些函数看下和原理理解下就可以了. 但是如果 ...

  9. android deep link(深度链接)与自定义协议!

    此自定义仅供参考! 首先打开androidManifest.xml 在MainActivity中添加如下内容: <activity android:name=".MainActivit ...

  10. 访客至上的Web、移动可用性设计--指导原则

    文章出自:听云博客 关于可用性设计,之前写过一个“纸上谈兵”版本的,那篇帖子主要是根据A/B test的方式来进行的. 但是最近找了本Steve krug写的Don't make me think,我 ...