第177章 ビットマップリソースを印刷する


さて、皆さんの中にはプリンタのデバイスコンテキストハンドル を取得して、LoadBitmap, CreateCompatibleDC, SelectObject, BitBlt関数を使って リソースのビットマップを印刷しようとして失敗した人はいませんか。 多分SelectObject関数あたりで失敗したのではないかと思います。 実はこれは、いままで何回も出てきたSetDIBitsToDevice関数または、 StretchDIBits関数で簡単に実現できます。

1.DOCINFO構造体に必要項目をセットする(docinfo) 2.プリンタのデバイスコンテキストハンドルを取得する(hdc_prn) 3.StartDoc(hdc_prn, &docinfo); StartPage(hdc_prn);を実行 4.SetDIBitsToDeviceまたはStretchDIBits関数の実行 5.EndPage(hdc_prn); EndDoc(hdc_prn); DeleteDC(hdc_prn);の実行

たったこれだけで実現できます。 プリンタのデバイスコンテキストハンドルの取得方法は 第79章を参照して下さい。

では、プログラムを見てみることにしましょう。

// res03.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "リソースの読みこみ", IDM_READ MENUITEM "保存(&S)", IDM_SAVE MENUITEM SEPARATOR MENUITEM "印刷(&P)", IDM_PRINT MENUITEM SEPARATOR MENUITEM "終了(&X)", IDM_END END POPUP "表示(&V)" BEGIN MENUITEM "情報表示(&I)", IDM_INFO END END ///////////////////////////////////////////////////////////////////////////// // // Bitmap // MYBMP1 BITMAP DISCARDABLE "my59.BMP" MYBMP2 BITMAP DISCARDABLE "mybmp2.bmp" MYBMP3 BITMAP DISCARDABLE "mybmp3.bmp" MYBMP4 BITMAP DISCARDABLE "bitmap1.bmp" ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYDLG DIALOG DISCARDABLE 0, 0, 130, 53 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "ビットマップリソースの選択" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,70,7,50,14 PUSHBUTTON "キャンセル",IDCANCEL,70,24,50,14 COMBOBOX IDC_COMBO1,7,7,60,79,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP END

メニュー項目が一部増えました。

// res03.cpp #ifndef STRICT #define STRICT #endif #include <windows.h> #include <windowsx.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyDlgProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); int ReadRes(HWND); int SaveRes(HWND); int ShowInfo(HWND); int GetSaveName(HWND, char *); int PrintRes(HWND hWnd); HDC GetPrintInfo(void); char szClassName[] = "res03"; //ウィンドウクラス char szBMPName[64]; //ビットマップリソース名 HINSTANCE hInst; HPALETTE hPalette; int nClr; BOOL bLoad = FALSE; PRINTER_INFO_5 prninfo[10]; int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; hInst = hCurInst; //グローバル変数にコピー if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } //ウィンドウ・クラスの登録 ATOM InitApp(HINSTANCE hInst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; //インスタンス wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "MYMENU"; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return (RegisterClassEx(&wc)); } //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "猫でもわかるリソース", //タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 CW_USEDEFAULT, //幅 CW_USEDEFAULT, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }

このへんは前回と同じです。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; HDC hdc; PAINTSTRUCT ps; HRSRC hRsrc; HANDLE hRes; LPBITMAPINFO lpBinfo; char *szBuf; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_READ: ReadRes(hWnd); break; case IDM_SAVE: SaveRes(hWnd); break; case IDM_INFO: ShowInfo(hWnd); break; case IDM_PRINT: PrintRes(hWnd); break; } break; case WM_PAINT: if (!bLoad) return (DefWindowProc(hWnd, msg, wp, lp)); hdc = BeginPaint(hWnd, &ps); if (nClr) { SelectPalette(hdc, hPalette, FALSE); RealizePalette(hdc); } hRsrc = FindResource(hInst, szBMPName, RT_BITMAP); hRes = LoadResource(hInst, hRsrc); lpBinfo = (LPBITMAPINFO)LockResource(hRes); szBuf = (char *)lpBinfo + sizeof(BITMAPINFOHEADER) + nClr * sizeof(RGBQUAD); SetDIBitsToDevice(hdc, 0, 0, lpBinfo->bmiHeader.biWidth, lpBinfo->bmiHeader.biHeight, 0, 0, 0, lpBinfo->bmiHeader.biHeight, szBuf, lpBinfo, DIB_RGB_COLORS); EndPaint(hWnd, &ps); break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { if (hPalette) DeleteObject(hPalette); DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }

メニューからIDM_PRINTが選択されたら自作関数PrintResを 呼び出します。

int ReadRes(HWND hWnd) { HANDLE hResource, hPalMem; HRSRC hRsrc; LPBITMAPINFO lpbi; LPLOGPALETTE lplp; int i, id, index; char str[256]; char szCl[5][64] = { "フルカラー", "モノクロ", "16色", "256色", "その他"}; id = DialogBox(hInst, "MYDLG", hWnd, (DLGPROC)MyDlgProc); if (id == IDCANCEL) return -1; hRsrc = FindResource(hInst, szBMPName, RT_BITMAP); if (hRsrc == NULL) { MessageBox(hWnd, "FindResource Error", "Error", MB_OK); return -1; } hResource = LoadResource(hInst, hRsrc); if (hResource == NULL) { MessageBox(hWnd, "LoadResource Error", "Error", MB_OK); return -1; } lpbi = (LPBITMAPINFO)LockResource(hResource); if (lpbi->bmiHeader.biClrUsed != 0) nClr = lpbi->bmiHeader.biClrUsed; else { if (lpbi->bmiHeader.biBitCount == 24) nClr = 0; else nClr = 1 << (lpbi->bmiHeader.biBitCount); } if (nClr) { hPalMem = GlobalAlloc(GHND, sizeof(LOGPALETTE) + nClr * sizeof(PALETTEENTRY)); lplp = (LPLOGPALETTE)GlobalLock(hPalMem); lplp->palNumEntries = nClr; lplp->palVersion = 0x300; for (i = 0; i < nClr; i++) { lplp->palPalEntry[i].peRed = lpbi->bmiColors[i].rgbRed; lplp->palPalEntry[i].peGreen = lpbi->bmiColors[i].rgbGreen; lplp->palPalEntry[i].peBlue = lpbi->bmiColors[i].rgbBlue; lplp->palPalEntry[i].peFlags = NULL; } hPalette = CreatePalette(lplp); GlobalUnlock(hPalMem); GlobalFree(hPalMem); } bLoad = TRUE; switch (nClr) { case 0: index = 0; break; case 2: index = 1; break; case 16: index = 2; break; case 256: index = 3; break; default: index = 4; break; } wsprintf(str, "%sのリソースを読みこみます", szCl[index]); MessageBox(hWnd, str, "ビットマップ情報", MB_OK); InvalidateRect(hWnd, NULL, TRUE); return 0; }

これは、前回と全く同じです。

LRESULT CALLBACK MyDlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { static HWND hCtrl; switch (msg) { case WM_INITDIALOG: hCtrl = GetDlgItem(hDlg, IDC_COMBO1); ComboBox_AddString(hCtrl, "MYBMP1"); ComboBox_AddString(hCtrl, "MYBMP2"); ComboBox_AddString(hCtrl, "MYBMP3"); ComboBox_AddString(hCtrl, "MYBMP4"); if (bLoad) ComboBox_SetText(hCtrl, szBMPName); else ComboBox_SetText(hCtrl, "MYBMP1"); return TRUE; case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: ComboBox_GetText(hCtrl, szBMPName, sizeof(szBMPName) - 1); EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; } return FALSE; } return FALSE; }

これも、前回と同じです。

int SaveRes(HWND hWnd) { HRSRC hRsrc; HANDLE hResource; LPBITMAPINFO lpbmp_info; HANDLE hF; DWORD dwImgSize, dwPalSize, dwWritten; BITMAPFILEHEADER bmFH; char szSaveName[MAX_PATH]; if (bLoad == FALSE) { MessageBox(hWnd, "リソースがロードされていません", "Error", MB_OK); return -1; } hRsrc = FindResource(hInst, szBMPName, RT_BITMAP); if (hRsrc == NULL) { MessageBox(hWnd, "FindResource Error", "Error", MB_OK); } hResource = LoadResource(hInst, hRsrc); if (hResource == NULL) { MessageBox(hWnd, "LoadResource Error", "Error", MB_OK); return -1; } lpbmp_info = (LPBITMAPINFO)LockResource(hResource); GetSaveName(hWnd, szSaveName); hF = CreateFile(szSaveName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(hF == NULL) { MessageBox(hWnd, "CreateFile Error", "Error", MB_OK); return -1; } dwPalSize = nClr * sizeof(RGBQUAD); dwImgSize = lpbmp_info->bmiHeader.biSizeImage; //BITMAPFILEHEADER構造体の準備 memset(&bmFH , 0 , sizeof(bmFH)); bmFH.bfType = 0x4d42; bmFH.bfOffBits = dwPalSize + sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER); bmFH.bfSize = dwImgSize + bmFH.bfOffBits; //BITMAPFILEHEADE構造体を書き込む WriteFile(hF, &bmFH, sizeof(bmFH), &dwWritten, NULL); //BITMAPINFOHEADER構造体以下を書き込む WriteFile(hF, lpbmp_info, (DWORD)(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * nClr + dwImgSize), &dwWritten, NULL); CloseHandle(hF); return 0; }

ここも前回に同じです。

int ShowInfo(HWND hWnd) { HRSRC hRsrc; HANDLE hResource; LPBITMAPINFO lpbmp_info; DWORD dwSizeImage, dwClrUsed, dwMySizeImage, LnWidth; LONG wx, wy; WORD wPlanes, wBitCount; char str[512]; if (bLoad == FALSE) { MessageBox(hWnd, "リソースがロードされていません", "Error", MB_OK); return -1; } hRsrc = FindResource(hInst, szBMPName, RT_BITMAP); if (hRsrc == NULL) { MessageBox(hWnd, "FindResource Error", "Error", MB_OK); } hResource = LoadResource(hInst, hRsrc); if (hResource == NULL) { MessageBox(hWnd, "LoadResource Error", "Error", MB_OK); return -1; } lpbmp_info = (LPBITMAPINFO)LockResource(hResource); dwSizeImage = lpbmp_info->bmiHeader.biSizeImage; dwClrUsed = lpbmp_info->bmiHeader.biClrUsed; wx = lpbmp_info->bmiHeader.biWidth; wy = lpbmp_info->bmiHeader.biHeight; wPlanes = lpbmp_info->bmiHeader.biPlanes; wBitCount = lpbmp_info->bmiHeader.biBitCount; //自分でSizeImageを計算する if ((((wx * wBitCount) / 8) % 4) == 0) LnWidth = wx * wBitCount / 8; else LnWidth = wx * wBitCount / 8 + (4 - ((wx * wBitCount / 8) % 4)); dwMySizeImage = LnWidth * wy; wsprintf(str, "dwSizeImage = %d, wx = %d, wy = %d\n" "dwClrUsed = %d, wPlanes = %d, wBitCount = %d\n" "dwMySizeImage = %d", dwSizeImage, wx, wy, dwClrUsed, wPlanes, wBitCount, dwMySizeImage); MessageBox(hWnd, str, "情報表示", MB_OK); return 0; }

これも同じです。

int GetSaveName(HWND hWnd, char *szF) { OPENFILENAME ofn; char szSaveN[MAX_PATH]; strcpy(szSaveN, szBMPName); strcat(szSaveN, ".bmp"); strcpy(szF, szSaveN); memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hWnd; ofn.lpstrFilter = "Bitmap (*.BMP)\0*.BMP\0\0"; ofn.nFilterIndex = 1; ofn.lpstrFile = szF; ofn.nMaxFile = 128; ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; if (GetSaveFileName((LPOPENFILENAME)&ofn)) return 0; return -1; }

これまた同じです。

int PrintRes(HWND hWnd) { HDC hdc_prn; HRSRC hRsrc; HANDLE hResource; LPBITMAPINFO lpbmp_info; DOCINFO docinfo; char *szBuffer; if (bLoad == FALSE) { MessageBox(hWnd, "リソースがロードされていません", "Error", MB_OK); return -1; } hRsrc = FindResource(hInst, szBMPName, RT_BITMAP); if (hRsrc == NULL) { MessageBox(hWnd, "FindResource Error", "Error", MB_OK); } hResource = LoadResource(hInst, hRsrc); if (hResource == NULL) { MessageBox(hWnd, "LoadResource Error", "Error", MB_OK); return -1; } lpbmp_info = (LPBITMAPINFO)LockResource(hResource); szBuffer = (char *)lpbmp_info + sizeof(BITMAPINFOHEADER) + nClr * sizeof(RGBQUAD); memset(&docinfo, 0, sizeof(docinfo)); docinfo.cbSize = sizeof(DOCINFO); docinfo.lpszDocName = "testprint"; hdc_prn = GetPrintInfo(); StartDoc(hdc_prn, &docinfo); StartPage(hdc_prn); if (hdc_prn) { StretchDIBits(hdc_prn, 0, 0, lpbmp_info->bmiHeader.biWidth * 5, lpbmp_info->bmiHeader.biHeight * 5, 0, 0, lpbmp_info->bmiHeader.biWidth, lpbmp_info->bmiHeader.biHeight, szBuffer, lpbmp_info, DIB_RGB_COLORS, SRCCOPY); } else { MessageBox(hWnd, "Print Error", "Error", MB_OK); return -1; } EndPage(hdc_prn); EndDoc(hdc_prn); DeleteDC(hdc_prn); return 0; }

StretchDIBitsのところを見て下さい。コピー先の幅、高さを5倍にしています。 なぜ5倍にするのでしょうか(筆者の環境では5倍前後が適当でした)。 実はそのままですと大変小さく印刷されてしまいます。 そのヒントは第136章に出ています。

また、プリンタのデパイスコンテキストに対してパレット関係の操作は 不要です。

HDC GetPrintInfo(void){ DWORD dwNeeded, dwReturned; if (EnumPrinters(PRINTER_ENUM_DEFAULT, NULL, 5, (LPBYTE)&prninfo, sizeof(prninfo), &dwNeeded, &dwReturned)) { return CreateDC(NULL, prninfo[0].pPrinterName, NULL, NULL); } return 0; }

これは、第79章のものをそのまま流用しました。

さて、実際に印刷をしてみるとまあまあのできです。 フルカラーのビットマップを印刷すると若干全体の色が薄い感じがします。 同じものをLViewProなどのソフトで印刷してみても同じようなものでした。 まあ、こんなものでしょう。


[SDK第2部 Index] [総合Index] [Previous Chapter] [Next Chapter]

Update 19/Feb/1999 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。