はじめに |
なぜにLinux UnknownなのにWin32のプログラムが置いてあるのか、疑問にもつ人
が多いと思います。しかし、作ったものはしょうがない。製造元責任として、
ここに置かせといて下さい(コンテンツが少ないのが、本音)。
このJPEG,GIF,BMP画像Viewerは、そのプログラム名にあるとおり、
MDIでBITMAP, GIF, JPEGフォーマットの画像ファイルを表示します。
また表示したBITMAP,GIF,JPEGフォーマットの画像に対してモノクロ、
反転(ネガポジ)処理を実行できます。
ここでは、JPEG,GIF,BMP画像Viewerの作成において、最も重要なビットマップ
について説明します。
目次 |
ビットマップ(DDBとDIB) |
デバイス依存ビットマップ(DDB) |
typedef struct tagBITMAP { int bmType; int bmWidth; int bmHeight; int bmWidthBytes; BYTE bmPlanes; BYTE bmBitsPixel; LPVOID bmBits; }BITMAP;
IDB_REDBLOCKS BITMAP DISCARDABLE "res\\RedBlocks.bmp" CMyView::OnDraw(CDC* pDC) { CBitmap bitmap; CDC dcDisplayMemory; bitmap.LoadBitmap(IDB_REDBLOCKS); dcDisplayMemory.CreateCompatibleDC(pDC); dcDisplayMemory.SelectObject(&bitmap); pDC->BitBlt(100, 100, 54, 96, &dcDisplayMemory, 0, 0, SRCCOPY); }
デバイス独立ビットマップ(DIB) |
DIBはカラー情報の形式が決まっているため、プログラム内で直接配列を書き換 えることが出来るため、非常に便利です。
typedef struct tagBITMAPINFOHEADER { DWORD biSize; // BITMAPINFOHEADERのサイズ LONG biWidth; // 幅(ピクセル単位) LONG biHeight; // 高さ(ピクセル単位) WORD biPlanes=1; WORD biBitCount; // 1ピクセルあたりのカラービット数 DWORD biCompression; // BI_RGB, BI_RLE4, BI_RLE8のいづれか DWORD biSizeImage; // DIBビットイメージのバイト数(BI_RLE4,8の場合) LONG biXPelsPerMeter=0; LONG biYPelsPerMeter=0; DWORD biClrUsed; // カラーテーブルエントリの数 DWORD biClrImportant; // カラーテーブルエントリの数 }BITMAPINFOHEADER, *LPBITMAPINFOHEADER;
typedef struct tagRGBQUAD { BYTE rgbBlue; // 青色用カラーテーブル BYTE rgbGreen; // 緑色用カラーテーブル BYTE rgbRed; // 赤色用カラーテーブル BYTE rgbReserved; // フラグ用カラーテーブル }RGBQUAD; // 32ビットカラーテーブルエントリ
IDB_REDBLOCKS BITMAP DISCARDABLE "res\\RedBlocks.bmp" ---CMyView.cpp--- LPBITMAPINFO lpBitmapInfo; void CMyView::OnInitailUpdate() { CScrollView::OnInitailUpdate(); CSize totalSize(30000, 40000); //30 x 40 cm CSize lineSize = CSize(totalsize.cx / 100, totalSize.cy / 100); SetScrollSizes(MM_HIMETRIC, totalSize, totalSize, lineSize); // リソース読み込み LPVOID lpvResource = (LPVOID) ::LoadResource(NULL, ::FindResource(NULL,MAKEINTRESOURCE(IDB_REDBLOCKS), RT_BITMAP)); lpBitmapInfo = (LPBITMAPINFO)::LockResource(lpvResource); CClientDC dc(this); } void CMyView::OnDraw(CDC* pDC) { // DIBビットイメージの先頭アドレスを求める int nNumColors; switch(lpBitmap->biBitCount) { case 1: nNumColors = 2; break; case 4: nNumColors = 16; break; case 8: nNumColors = 256; break; default: nNumColors = 0; break; } LPBYTE lpvBits = (LPBYTE)lpBitmapInfo + sizeof(LPBITMAPINFO) + sizof(RGBQUAD) * nNumColors; // DIBリソース表示 ::StretchDIBits(pDC->mhDC, 0, 0, (int) lpBitmapInfo->biWidth, (int) lpBitmapInfo->biHeight, lpvBits, lpBitmapInfo, DIB_RGB_COLORS, SRCCOPY); }
ピクチャ(CPictureHolder) |
ピクチャは、Visual Basic のPictureプロパティとして知られています。ビット マップ、アイコン、メタファイルの他にJpeg,Gif画像も扱うことが出来ます。 CPictureHolderクラスは、このPictureプロパティをインプリメントしたもの です。
---CMyView.cpp--- #include < afxctl.h > CPictureHolder* m_pPicture; BOOL CMyView::OnOpenDocument(LPCTSTR lpszPathName) { LPSISPATCH pDisp; COleVariant varName(lpszPathName); if (SUCCEEDED(OleLoadPictureFile(varName, &pDisp))) { if (m_pPicture != NULL) DeleteContents(); m_pPicture = new CPictureHolder; m_pPicture->SetPictureDispatch(LPPICTUREDISP)pDisp); return TRUE; } return FALSE; } void CMyView::DeleteContents() { delete m_pPicture; m_pPicture = NULL; } void CMyView::OnDraw(CDC* pDC) { CSize size(0,0); OLE_XSIZE_HIMETRIC width; OLE_YSIZE_HIMETRIC height; // ピクチャをウィンドウの中央に描画 if (m_pPicture != NULL) { CRect rect; GetClientRect(&rect); if (SUCCEEDED(m_pPicture.m_pPict->get_Width(&width)) && SUCCEEDED(m_pPicture.m_pPict->get_Height(&height))) size = CSize(width, height); else return; // 左上の位置を計算 CPoint ptOffset((rect.right - size.cx) / 2, (rect.left - size.cy) / 2); if (ptOffset.x < 0) ptOffset.x = 0; if (ptOffset.y < 0) ptOffset.y = 0; // ピクチャのレンダリング rect = CRect(ptOffset, size); m_pPicture->Render(pDC, &rect, &rect); } }
ピクチャ => デバイス依存ビットマップ(DDB)変換 |
---CMyDoc.cpp--- #include < afxctl.h > CPictureHolder* m_pPicture; BOOL CMyDoc::OnOpenDocument(LPCTSTR lpszPathName) { LPSISPATCH pDisp; COleVariant varName(lpszPathName); if (SUCCEEDED(OleLoadPictureFile(varName, &pDisp))) { if (m_pPicture != NULL) DeleteContents(); m_pPicture = new CPictureHolder; m_pPicture->SetPictureDispatch(LPPICTUREDISP)pDisp); if(!GetPictureBitmap()) return FALSE; return TRUE; } return FALSE; } void CMyDoc::DeleteContents() { delete m_pPicture; m_pPicture = NULL; CDocument::DeleteContents(); } HBitmap CMyDoc::GetBitmap() { short type; OLE_HANDLE hBitmap; if (!m_pPicture) return NULL; IPicture *pPict = m_pPicture->m_pPict; ASSERT(pPict); pPict->get_Type(&type); return type == PICTYPE_BITMAP && SUCCEEDED(pPict->get_Handle(&hBitmap)) ? (HBITMAP)hBitmap : NULL; } BOOL CMyDoc::GetPictureBitmap() { HBITMAP hBitmap = GetBitmap(); if (hBitmap == NULL) return FALSE; m_pBitmap = new CBitmap; m_pPitmap = CBitmap::FromHandle(hBitmap); if (m_pBitmap == NULL) return FALSE; return TRUE; }
ピクチャ => デバイス独立ビットマップ(DIB)変換 |
---CMyView.cpp--- #include < afxctl.h > LPBITMAPINFOHEADER m_lpBMIH; CPalette* m_lpPalette; LPVOID m_lpvColorTable; char* m_lpImage; DWORD m_dwSizeImage; CMyView::CMyView() { m_lpPalette = new CPalette; } CMyView::~CMyView() { delete m_lpPalette; delete m_lpImage; delete m_lpBMIH; m_lpImage = NULL; m_lpBMIH = NULL; } CSize CMyView::GetPictureSize(CPictureHolder *pHolder) { ASSERT(pHolder); CSize size(0,0); OLE_XSIZE_HIMETRIC width; OLE_YSIZE_HIMETRIC height; if (pHolder && pHolder->m_pPict && SUCCEEDED(m_pPicture.m_pPict->get_Width(&width)) && SUCCEEDED(m_pPicture.m_pPict->get_Height(&height))) { CDC *pDC = getDC(); ASSERT(pDC); size = CSize(width, height); pDC->HIMETRICtoDP(&size); ReleaseDC(pDC); } return size; } // 透明GIF使用時の背景の消去しきれないゴミを消去 BOOL CMyView::OnEraseBkgnd(CDC* pDC) { CRect rectClip; if (pDC->GetClipBox(&rectClip) != NULLREGION) pDC->FillSolidRect(&rectClip, ::GetSysColor(COLOR_APPWORKSPACE)); return TRUE; } void CMyView::OnDraw(CDC* pDC) { CMyDoc* pDoc->GetDocument(); ASSERT_VALID(pDoc); CPoint orgin; CSize size; origin.x = 20; origin.y = -20; size.cx = m_lpBMIH->biWidth; size.cy = m_lpBMIH->biHeight; //表示用パレットを前景パレットで設定 CPalette* oldPalette = pDC->SelectPalette(m_lpPalette, FALSE); pDC->RealizePalette(); ::StretchDIBits(pDC->GetSafeHdc(), origin.x, origin.y, size.cx,size.cy, 0, 0, m_lpBMIH->biWidth, m_lpBMIH->biHeight, m_lpImage, (LPBITMAPINFO) m_lpBMIH, DIB_RGB_COLORS, SRCCOPY); //残りのパレットは背景パレットで設定 pDC->SelectPalette(oldPalette, TRUE); } void CMyView::OnInitailUpdate() { CScrollView::OnInitailUpdate(); CSize sizeTotal(0, 0); SetScrollSizes(MM_HIMETRIC, sizeTotal); CMyDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); CDC* pDC = new CDC; BITMAP bm; HDC hdc = pDC->GetSafeHdc(); if (hcd == NULL) { CClientDC dc(this); OnprepareDC(&dc); HBITMAP hBitmap = pDoc->GetBitmap(); pDC->CreateCompatibleDC(&DC); ::SelectObject(pDC->GetSafeHdc(), hBitmap); ::GetObject(hBitmap, sizeof(bm), &bm); if (PictureCnvDIB(pDC->GetSafeHdc(), &bm) == NULL) return; ReleseDC(&dc); } delete pDC; } int CMyView::PictureCnvDIB(HDC hdc, BITMAP* pBitmap) { CMyDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // 1ビットあたりのカラービット数からパレットのエントリ数を確認 int m_nColorTableEntries = 0; switch(pBitmap->bmBitsPixel) { case 1: m_nColorTableEntries = 2; break; case 4: m_nColorTableEntries = 16; break; case 8: m_nColorTableEntries = 256; break; default: m_nColorTableEntries = 0; } // BITMAPINFOHEADER 作成 int nSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries; m_lpBMIH = (LPBITMAPINFOHEADER) new char[nSize]; m_lpvColorTable = (LPBYTE) m_lpBMIH->sizeof(BITMAPINFOHEADER); memset(m_lpvColorTable, 0, sizeof(RGBQUAD) * m_nColorTableEntries); m_lpBMIH->biSize = sizeof(BITMAPINFOHEADER); m_lpBMIH->biWidth = pBitmap->bmWidth; m_lpBMIH->biHeight = pBitmap->bmHeight; m_lpBMIH->biPlanes = 1; m_lpBMIH->biBitCount = pBitmap->bmBitsPixel; m_lpBMIH->biCommpression = BI_RGB; m_lpBMIH->biSizeImage = 0; m_lpBMIH->biXpelsPerMeter = 0; m_lpBMIH->biYpelsPerMeter = 0; m_lpBMIH->biClrUsed = m_nColorTableEntries; m_lpBMIH->biClrImportant = m_nColorTableEntries; dwBytes = ((DWORD) m_lpBMIH->biWidth * m_lpBMIH->biBitCount) / 32; if (((DWORD) m_lpBMIH->biWidth * m_lpBMIH->biBitCount) % 32) dwBytes++; dwBytes *= 4; m_dwSizeImage = dwBytes * m_lpBMIH->biHeight; m_lpImage = new char[m_dwSizeImage]; int res = ::GetDIBits(hdc, pDoc->GetBitmap(), (UINT)0, (UINT)m_lpBMIH->biHeight, (LPVOID)m_lpImage, (LPBITMAPINFO)m_lpBMIH, DIB_RGB_COLORS); //論理パレット作成 LPLOGPALETTE pLogPal = (LPLOGPALETTE) new char[2 * sizeof(WORD) + m_nColorTableEntries * sizeof(PALETTEENTRY)]; //バージョンとパレットのエントリ数を設定 pLogPal->palVersion = 0x300; pLogPal->palNumEntries = m_nColorTableEntries; // システムパレットを取得する ::GetSystemPaletteEntries(hdc, 0, m_nColorTableEntries, pLogPal->palPalEntry); m_lpPalette->CreatePalette(pLogPal); delete pLogPal; return res; }
サンプルプログラム |
問題点 |
今回のプログラムでは Win32 API ::OleLoadPictureFile 関数を使用して
BITMAP, GIF, JPEG画像を取得しています。この関数はパレット調節に不具合が
あるため、画面を256色表示に設定した場合に、原画像を正確に描画できません。