// ** View2D.cpp : View2D クラスの動作の定義 for Win32 MFC VS2005 (View2D.cpp) // ** クラス:Array, Color, View2D // ** // ** 著作権者:東京工芸大学 工学部 メディア画像学科 降旗 隆 T.Furuhata (2007.9) #include "StdAfx.h" // 標準インクルード // これをインクルードしないと「プリコンパイルヘッダーを検索中に不明な EOF が見つかりました」 // のエラーとなる #include "MainFrm.h" // メインフレームクラス (CMainFrame) を使用する場合にインクルード #include "View2D.h" #include #include #include // View2D クラスのためにインクルード #include "math.h" #define PI 3.14159265359 double RAD = PI/180; // degree を radian に変換する係数 // usage:double a = 45 * RAD; // ******** Array クラスの実装 ******************************************************************** // ** コンストラクタ Array の実装 // ** 二次元配列(引数付きコンストラクタ)の初期化 Array::Array(int i, int j) { p = new double[i*j]; // 動的一次元配列 p[] を生成 isize = i; // 引数でメンバ変数を初期化 jsize = j; } // 引数付きのコンストラクタでは、クラス型変数を宣言するときに、 // Array a(10, 10); のように、引数をコンストラクタに渡す必要がある。 // ** メンバ関数 &put(参照を返す関数)の実装 // ** 二次元配列にデータを格納する double &Array::put(int i, int j) { return p[i*jsize + j]; // 配列 p[i][j] への参照を返す。 } // put(i,j)=10 → p[i*jsize + j]=10 // 関数 put(i,j) によって返される参照に 10 を代入することを意味する。 // これにより、put(i,j)=10 のように、データ入力が簡単に行えるようになる。 // ** メンバ関数 get の実装 // ** 二次元配列からデータを取得する double Array::get(int i, int j) { return p[i*jsize + j]; // 配列 p[i][j] の内容を返す } // ** メンバ関数 ArrayP の実装 // ** 二次元配列の先頭アドレスを取得する double *Array::ArrayP() { double *pa; pa = &p[0]; return pa; // 配列 p[i][j] の先頭アドレス(ポインタ)を返す } // ** メンバ関数 del の実装 // ** 二次元配列用のメモリを解放 int Array::del() { delete [] p; // 動的一次元配列 p[] を削除 return 0; } // ******** Color クラスの実装 ******************************************************************** // ** コンストラクタ Color の実装 Color::Color() { R = G = B = 0; CREF = RGB(0, 0, 0); } // ** 引数付きコンストラクタ Color(・・・) の実装 Color::Color(double r, double g, double b) { R = r; G = g; B = b; CREF = RGB(255 * R, 255 * G, 255 * B); } // ** Color クラスの演算とフレンド関数の実装 ** // フレンド関数:クラスのメンバー関数ではなく、クラスの外で宣言される一般関数 // 引数2つの演算子を多重定義する場合は、クラス内で friend 宣言が必要 // ** 彩度変換:a * cb Color operator*(double a, Color cb) { Color cc = Color(a * cb.R, a * cb.G, a * cb.B); if(cc.R > 1.0) cc.R = 1.0; if(cc.G > 1.0) cc.G = 1.0; if(cc.B > 1.0) cc.B = 1.0; return cc; } // ** 彩度変換:ca * b Color operator*(Color ca, double b) { Color cc = Color(ca.R * b, ca.G * b, ca.B * b); if(cc.R > 1.0) cc.R = 1.0; if(cc.G > 1.0) cc.G = 1.0; if(cc.B > 1.0) cc.B = 1.0; return cc; } // ** 彩度変換:ca / b Color operator/(Color ca, double b) { Color cc = Color(ca.R / b, ca.G / b, ca.B / b); if(cc.R > 1.0) cc.R = 1.0; if(cc.G > 1.0) cc.G = 1.0; if(cc.B > 1.0) cc.B = 1.0; return cc; } // ** 加色変換:ca + cb Color operator+(Color ca, Color cb) { Color cc = Color(ca.R + cb.R, ca.G + cb.G, ca.B + cb.B); if(cc.R > 1.0) cc.R = 1.0; if(cc.G > 1.0) cc.G = 1.0; if(cc.B > 1.0) cc.B = 1.0; return cc; } // ******** View2D クラスの実装 ******************************************************************* // ** グローバル変数 HBITMAP HBMP; // ビットマップ情報(DIBSECTION のハンドル)格納用 HDC hdcWnd; // ウィンドウクライアント領域のデバイスコンテキスト(のハンドル)格納用 HDC hdcMem; // メモリデバイスコンテキスト(のハンドル)格納用 CSize WinSize; // ウィンドウサイズ格納用 COLORREF WinColor = RGB(255, 255, 255); // ウィンドウ背景色(default 白色) // ** コンストラクタ View2D の実装 View2D::View2D() { // ** メンバ変数の初期化 // ** 動的配列のポインタを無効化 rr = 0; gg = 0; bb = 0; } // usage : View2D w; // ** 引数付きコンストラクタ View2D(CSize&) [#1] の実装 View2D::View2D(CSize& imgsize) { // 画像処理用の一次元動的配列を生成 int lx = imgsize.cx; int ly = imgsize.cy; rr = new double[lx*ly]; gg = new double[lx*ly]; bb = new double[lx*ly]; } // usage : View2D w(imagesize); // ** 引数付きコンストラクタ View2D(CDC* pDC) [#2] の実装 View2D::View2D(CDC* pDC) { // メンバ変数の初期化 pdc = pDC; // ビュークラス C**View のデバイスコンテキスト pDC で初期化 // 動的配列のポインタを無効化 rr = 0; gg = 0; bb = 0; } // usage : View2D w(pDC); // ** 引数付きコンストラクタ View2D(・・・) [#3] の実装 // ** ウィンドウサイズを CMainFrame::PreCreateWindow() の default 値で指定、 // ウィンドウ背景色(default は WHITE)を変更し、クラス内で pDC で描画できるように準備 View2D::View2D(CDC* pDC, HWND m_hWnd, Color c) { // ** メンバ変数の初期化 hWnd = m_hWnd; // ウィンドウハンドル m_hWnd でメンバ変数 hWnd を初期化 pdc = pDC; // ビュークラス C**View のデバイスコンテキスト pDC で初期化 // ** ウィンドウ描画領域(クライアント領域)のサイズを取得 CRect crect; ::GetClientRect(m_hWnd, crect); // クライアント矩形領域を取得 // ** 2D 描画の初期化 Width = crect.right - crect.left; // メンバ変数 Width, Height を初期化 Height = crect.bottom - crect.top; WinColor = SetWinColor(c); // ウィンドウ背景色を変更しグローバル変数 WinColor を初期化 // ** 動的配列のポインタを無効化 rr = 0; gg = 0; bb = 0; } // usage : View2D w(pDC, m_hWnd, GRAY); // ** 引数付きコンストラクタ View2D(・・・) [#4] の実装 // ** m_hWnd のウィンドウサイズ (外枠サイズ:width×height) と背景色 c (default は白色)を指定し、 // クラス内で pDC で描画できるように準備 View2D::View2D(CDC* pDC, HWND m_hWnd, int width, int height, Color c) { // ** メンバ変数の初期化 hWnd = m_hWnd; // ウィンドウハンドル m_hWnd でメンバ変数 hWnd を初期化 pdc = pDC; // メンバ変数 pdc を引数により初期化 // ** ウィンドウのサイズを設定 HWND hwnd = ::GetParent(m_hWnd); // m_hWnd で指定される(子)ウィンドウの親ウィンドウへのハンドル hwnd を取得 // (指定したウィンドウが親ウィンドウを持たないときは NULL を返す) SetWindowPos(hwnd, HWND_TOP, 0, 0, width, height, SWP_NOMOVE); // hwnd で指定されるウィンドウを Z 順の先頭に置き(HWND_TOP) // 現在位置を保持したままで(SWP_NOMOVE)ウィンドウサイズのみを変更 // MoveWindow(hwnd, 0, 0, width, height, TRUE); // でも可 // hwnd で指定されるウィンドウの位置とサイズを変更 // TRUE で再描画され、FALSE で再描画されない // ** ウィンドウ描画領域(クライアント領域)のサイズを取得 CRect crect; ::GetClientRect(m_hWnd, crect); // クライアント矩形領域を取得 // ** 2D 描画の初期化 Width = crect.right - crect.left; // メンバ変数 Width, Height を初期化 // Width = width - 12; // でも可 Height = crect.bottom - crect.top; // Height = height - 106; // でも可 WinColor = SetWinColor(c); // ウィンドウ背景色を変更しグローバル変数 WinColor を初期化 // ** 動的配列のポインタを無効化 rr = 0; gg = 0; bb = 0; } // usage : View2D w(pDC, m_hWnd, 768, 512, GRAY); // ** 引数付きコンストラクタ View2D(・・・) [#5] の実装 // ** m_hWnd のウィンドウサイズ (外枠サイズ:width×height スクリーン座標位置:x_posit, y_posit) // ** と背景色 c (default は白色)を指定し、クラス内で pDC で描画できるように準備 View2D::View2D(CDC* pDC, HWND m_hWnd, int width, int height, int x_posit, int y_posit, Color c) { // ** メンバ変数の初期化 hWnd = m_hWnd; // ウィンドウハンドル m_hWnd でメンバ変数 hWnd を初期化 pdc = pDC; // メンバ変数 pdc を引数により初期化 // ** ウィンドウのサイズを設定 HWND hwnd = ::GetParent(m_hWnd); // m_hWnd で指定される(子)ウィンドウの親ウィンドウへのハンドル hwnd を取得 // (指定したウィンドウが親ウィンドウを持たないときは NULL を返す) // SetWindowPos(hwnd, HWND_TOP, 0, 0, width, height, SWP_NOMOVE); // hwnd で指定されるウィンドウを Z 順の先頭に置き(HWND_TOP) // 現在位置を保持したままで(SWP_NOMOVE)ウィンドウサイズのみを変更 MoveWindow(hwnd, x_posit, y_posit, width, height, TRUE); // hwnd で指定されるウィンドウの位置とサイズを変更 // TRUE で再描画され、FALSE で再描画されない // ** ウィンドウ描画領域(クライアント領域)のサイズを取得 CRect crect; ::GetClientRect(m_hWnd, crect); // クライアント矩形領域を取得 // ** 2D 描画の初期化 Width = crect.right - crect.left; // メンバ変数 Width, Height を初期化 // Width = width - 12; // でも可 Height = crect.bottom - crect.top; // Height = height - 106; // でも可 WinColor = SetWinColor(c); // ウィンドウ背景色を変更しグローバル変数 WinColor を初期化 // ** 動的配列のポインタを無効化 rr = 0; gg = 0; bb = 0; } // usage : View2D w(pDC, m_hWnd, 768, 512, 10, 10, GRAY); // ** デストラクタ ~View2D の実装 View2D::~View2D() { // メンバ変数の解放 hWnd = NULL; // ウィンドウのハンドル pdc = NULL; // デバイスコンテキストのポインタ Width = 0, Height = 0; // ウィンドウ・クライアント領域のサイズ mhBmp = NULL; // ビットマップオブジェクト(DIBSECTION)のハンドル // グローバル変数の解放 // HBMP = NULL; // ビットマップオブジェクト(DIBSECTION)のハンドル // hdcWnd = NULL; // ウィンドウデバイスコンテキストのハンドル // hdcMem = NULL; // メモリデバイスコンテキストのハンドル // WinSize = NULL; // ウィンドウサイズ // 一次元動的配列用メモリの解放 delete [] rr, gg, bb; } // usage : デストラクタの記述は不要(プログラム終了時に自動的に実行される) // ******** View2D クラスで使用する構造体のメンバー ******** // ** BITMAPFILEHEADER 構造体のメンバー :bmfh 14 byte // WORD bfType[2]; // ファイルタイプ:常に"BM"(0x4D42 or 19778) 2 // DWORD bfSize; // ファイル全体のサイズ 4 // WORD bfReserved1; // 予約:常に0 2 // WORD bfReserved2; // 予約:常に0 2 // DWORD bfOffBits; // BITMAPイメージまでのオフセット値(ヘッダサイズ) 4 // ** BITMAPINFOHEADER 構造体のメンバー :bmih 40 byte // DWORD biSize; // BITMAPINFOHEADERのサイズ(バイト数) 4 // LONG biWidth; // BITMAPイメージの横幅(画素数) 4 // LONG biHeight; // BITMAPイメージの縦幅(画素数) 4 // WORD biPlanes; // 対象デバイスのカラープレーン数:常に1 2 // WORD biBitCount; // 画素当たりのビット数(1,4,8,24ビット) 2 // DWORD biCompression; // BITMAPの圧縮形式:非圧縮0 4 // DWORD biSizeImage; // BITMAPイメージサイズ(バイト数) 4 // LONG biXPelsPerMeter; // 1m当たりの水平解像度(ピクセル単位) 4 // LONG biYPelsPerMeter; // 1m当たりの垂直解像度(ピクセル単位) 4 // DWORD biClrUsed; // 使用されるカラーインデックス数:通常0 4 // DWORD biClrImportant; // 表示に必要なカラーインデックス数:通常0 4 // ** DIBSECTION 構造体のメンバー :dib 84 byte // BITMAP dsBm; // BITMAP 構造体 24 // BITMAPINFOHEADER dsBmih; // BITMAPINFOHEADER 構造体 40 // DWORD dsBitfields[3]; // DIB カラーマスク 4 // HANDLE dshSection; // ファイルマッピングオブジェクトへのハンドル 4 // DWORD dsOffset; // BITMAPイメージまでのオフセット値 4 // ** BITMAP 構造体のメンバー :bmap 24 byte // LONG bmType; // ビットマップタイプ:常に0 4 // LONG bmWidth; // BITMAPイメージの横幅(画素数) 4 // LONG bmHeight; // BITMAPイメージの縦幅(画素数) 4 // LONG bmWidthBytes; // スキャンラインのバイト数 4 // WORD bmPlanes; // カラープレーン数 2 // WORD bmBitsPixel; // カラービット数 2 // LPVOID bmBits; // BITMAPイメージへのポインタ 4 // ** BITMAPINFO 構造体のメンバー :bmif 44 byte // BITMAPINFOHEADER bmiHeader; 40 // RGBQUAD bmiColors[1]; 4 // ** RGBQUAD 構造体のメンバー :colortbl // BYTE rgbBlue; // BYTE rgbGreen; // BYTE rgbRed; // BYTE rgbReserved; // ******** View2D クラスで使用するビットマップ画像処理関数 ******** // ** メンバ関数 ReadBmp(#1) の実装 // ** filepath のファイルを読み込みビットマップ情報をグローバル変数 HBMP に取得 void View2D::ReadBmp(CString filepath) { // ** 引数のファイルをオープン CFile file; if(!file.Open( filepath, // 目的とするファイルへのパスを表す文字列を指定 CFile::modeRead | CFile::typeBinary // ファイルの共有モードとアクセスモードを指定 )) { // ファイルのパス(filename)を指定し、読取モード・バイナリモードでファイルをオープン // fp=_open(fname, _O_RDONLY|_O_BINARY); に相当 return; } // ** BMP ファイルの先頭ヘッダー BITMAPFILEHEADER を読み込む BITMAPFILEHEADER bmfh; if(file.Read(&bmfh, sizeof(bmfh)) != sizeof(bmfh)) { AfxThrowArchiveException(CArchiveException::endOfFile); } // ** BITMAPFILEHEADER のファイルタイプ(bfType)をチェック if(bmfh.bfType != 0x4d42){ // "BM" AfxThrowArchiveException(CArchiveException::badIndex); } // ** ファイルの残りを BYTE 型動的配列 buf に読み込む UINT sz = bmfh.bfSize - sizeof(bmfh); // ファイルの残りサイズ BYTE *buf = new BYTE[sz]; // 動的配列の生成 // ** try, catch, throw で例外処理 // 例外処理:エラーが発生した場所からそれを処理する場所にエラー情報を通知して制御を移す try{ // try 文でエラー発生の可能性があるコードを記述 if(file.Read(buf, sz) != sz){ // ファイルの長さがおかしい場合 AfxThrowArchiveException(CArchiveException::endOfFile); } // ** buf の最初の部分(BITMAPINFOHEADER 構造体)にポインタ指定 BITMAPINFOHEADER *pbmih = (BITMAPINFOHEADER *)buf; // buf に格納した BYTE 型配列の先頭アドレスを BITMAPINFOHEADER 型に // キャストして pbmih に格納 // これにより pbmih を使って BITMAPINFOHEADER を参照できる // ** 圧縮フォーマット(biCompression)はサポートしない if(pbmih->biCompression != BI_RGB) { // 非圧縮の場合 biCompression = BI_RGB AfxThrowArchiveException(CArchiveException::badIndex); } // ** カラーテーブル(RGBQUAD 構造体)の先頭アドレスを取得 RGBQUAD *pcolortbl = NULL; // カラーテーブルの初期化 // biBitCount が 8bit 以下の場合は BITMAPINFOHEADER の後に RGBQUAD 構造体がくる if(pbmih->biBitCount <= 8) { pcolortbl = (RGBQUAD *)(buf + pbmih->biSize); // BITMAPINFOHEADER の実際のサイズ(biSize)から RGBQUAD の位置を計算 } // ここでは 24bit フルカラー以外はサポートしない // ** イメージデータの先頭アドレスを取得 BYTE *pdata = buf + bmfh.bfOffBits - sizeof(bmfh); // BITMAPFILEHEADER の情報からイメージデータの先頭アドレスを計算 // メモリアクセス速度アップのために、イメージデータの先頭アドレスは、4の倍数に // なるようにダミーデータが挿入されている(詰め物:パディング) // このためイメージデータの先頭アドレスは BITMAPFILEHEADER の bfOffBits から計算 // ** ビットマップオブジェクトとして、デバイスコンテキストに依存しない DIBSECTION を作成し // そのハンドルをグローバル変数 HBMP に取得 BYTE *pbits; // イメージデータ格納用の配列を生成 HBMP = ::CreateDIBSection // Win32 API (0, // デバイスコンテキストのハンドル. DIBSECTION は // デバイスコンテキストに依存しないため 0 を指定 (BITMAPINFO *)pbmih, // BITMAPINFO 構造体のポインタを指定 // BITMAPINFO は BITMAPINFOHEADER と RGBQUAD をまとめた構造体につき、 // BITMAPINFOHEADER 構造体のポインタ pbmih を BITMAPINFO にキャスト DIB_RGB_COLORS, // 常に DIB_RGB_COLORS を指定 (void **)&pbits, // イメージデータ格納用配列 pbits の先頭アドレスを指定 // これによりイメージデータの格納に必要なメモリーが確保される 0, // メモリーマップトファイルを使用する場合に指定 0); // 通常は 0 を指定 // CreateDIBSection で割り当てたメモリーのアドレスが DIBSECTION のハンドルとして // HBMP に渡される // この DIBSECTION のハンドルを使ってビューでの描画などが行えるようになる if(HBMP == 0 || pbits == NULL) { AfxThrowMemoryException(); } // ** DIBSECTION で確保されたメモリーにイメージデータをコピー long szImage = (pbmih->biWidth * pbmih->biBitCount + 31) / 32 * 4 * pbmih->biHeight; // コピーするバイト数を計算(1ライン分のバイト数が4の倍数になるように調整) // ** バッファ間でデータコピー memcpy(pbits, pdata, szImage); // pdata より szImage のサイズ分を pbits にコピー // ** 動的配列のメモリを解放 delete []buf; } // ** try 文でエラーが発生した場合、そこで実行中断され catch 文以降に制御が移り、 // throw 文でエラーを通知 catch(CException *e){ // ** エラーが起きた場合,確保しているメモリーを解放してから例外を呼び出し元へ再 throw する delete []buf; throw e; } } // usage : w.ReadBmp(filepath); // ** メンバ関数 ReadBmp(#2) の実装 // ** filepath のファイルを読み込みビットマップ情報を取得し引数 hBmp に渡す void View2D::ReadBmp(CString filepath, HBITMAP& hBmp) { // ** 簡易化のためにファイルチェックは行わない場合を示す // ここでは 24bit フルカラー以外はサポートしない // ** 引数のファイルをオープン CFile file; file.Open(filepath, // 目的とするファイルへのパスを表す文字列を指定 CFile::modeRead | CFile::typeBinary); // ファイルの共有モードとアクセスモードを指定 // ** BMP ファイルの先頭ヘッダー BITMAPFILEHEADER を bmfh に読み込む BITMAPFILEHEADER bmfh; file.Read(&bmfh, sizeof(bmfh)); // ** BYTE 型動的配列 buf を割り当ててファイルの残りを読み込む UINT sz = bmfh.bfSize - sizeof(bmfh); // ファイルの残りサイズを計算 BYTE *buf = new BYTE[sz]; if(file.Read(buf, sz) != sz){ // ファイルの長さがおかしい場合 AfxThrowArchiveException(CArchiveException::endOfFile); } // ** buf の最初の部分(BITMAPINFOHEADER 構造体)にポインタ指定 BITMAPINFOHEADER *pbmih = (BITMAPINFOHEADER *)buf; // buf に格納した BYTE 型配列の先頭アドレスを BITMAPINFOHEADER 型に // キャストして pbmih に格納 // これにより pbmih を使って BITMAPINFOHEADER を参照できる // ** イメージデータの先頭アドレスを取得 BYTE *pdata = buf + bmfh.bfOffBits - sizeof(bmfh); // BITMAPFILEHEADER の情報からイメージデータの先頭アドレスを計算 // メモリアクセス速度アップのために、イメージデータの先頭アドレスは、4の倍数に // なるようにダミーデータが挿入されている(詰め物:パディング) // このためイメージデータの先頭アドレスは BITMAPFILEHEADER の bfOffBits から計算 // ** ビットマップオブジェクトとして、デバイスコンテキストに依存しない DIBSECTION を作成し // ** そのハンドルを HBITMAP 型の引数 hBmp に渡す BYTE *pbits; // イメージデータ格納用の配列を生成 hBmp = ::CreateDIBSection // Win32 API (0, // デバイスコンテキストのハンドル. DIBSECTION は // デバイスコンテキストに依存しないため 0 を指定 (BITMAPINFO *)pbmih, // BITMAPINFO 構造体のポインタを指定 // BITMAPINFO は BITMAPINFOHEADER と RGBQUAD をまとめた構造体につき、 // BITMAPINFOHEADER 構造体のポインタ pbmih を BITMAPINFO にキャスト DIB_RGB_COLORS, // 常に DIB_RGB_COLORS を指定 (void **)&pbits, // イメージデータ格納用配列 pbits の先頭アドレスを指定 // これによりイメージデータの格納に必要なメモリーが確保される 0, // メモリーマップトファイルを使用する場合に指定 0); // 通常は 0 を指定 // CreateDIBSection で割り当てたメモリーのアドレスが DIBSECTION のハンドルとして // hBmp に渡される // この DIBSECTION のハンドルを使って、ビューでの描画などが行えるようになる // ** DIBSECTION で確保されたメモリーにイメージデータをコピー long szImage = (pbmih->biWidth * pbmih->biBitCount + 31) / 32 * 4 * pbmih->biHeight; // コピーするバイト数を計算(1ライン分のバイト数が4の倍数になるように調整) // ** バッファ間でデータコピー memcpy(pbits, pdata, szImage); // pdata より szImage のサイズ分を pbits にコピー // ** 動的配列のメモリを解放 delete []buf; } // usage : w.ReadBmp(filepath, hbmp); // ** メンバ関数 LoadBmp(#1) の実装 // ** ReadBmp(#1) によりグローバル変数 HBMP に取得されるビットマップ情報から // 8bit のイメージデータを引数の double 型一次元配列 rr, gg, bb へロード // 一次元配列 rr, gg, bb は呼び出し側で動的に作成 void View2D::LoadBmp(double* rr, double* gg, double* bb) { int i, j; int lx; // x方向画素数 int ly; // y方向画素数 double r, g, b; // double 型 R,G,B 画素値 // ** グローバル変数 HBMP より DIBSECTION 構造体に画像情報を格納 DIBSECTION dib; GetObject(HBMP, sizeof(dib), &dib); // ** DIBSECTION より BITMAPINFOHEADER を取得 BITMAPINFOHEADER bmih; bmih = dib.dsBmih; // ** 24bit FullColor (1677216色 TrueColor) 画像の確認 if(bmih.biBitCount<24) { CString stop; stop = "LoadBmp:24bitフルカラー画像ではありません。処理を中止します!"; AfxMessageBox(stop); AfxThrowArchiveException(CArchiveException::badIndex); // badIndex:「ファイルフォーマットが正しくありません」を意味する } // biBitCount が 24bit 未満の場合は処理を中止 // ** DIBSECTION より BITMAP を取得 BITMAP bmap; bmap = dib.dsBm; // ** BITMAP のピクセルデータ(用配列)を取得 BYTE *lpBMP = (BYTE*)bmap.bmBits; // ** BITMAPINFOHEADER よりイメージサイズを取得 (横:imgsize.cx × 縦:imgsize.cy) // ** イメージサイズ取得用 CSize クラスのオブジェクト生成 CSize imgsize; lx = bmih.biWidth; // x方向画素数取得 ly = bmih.biHeight; // y方向画素数取得 // ** パディング:ダミー画素の算出(4の倍数問題に対応) int dummy; if(lx % 4 == 0) dummy = 0; else dummy = int(4-(lx*3)%4); // 水平画素数 lx が 4 の倍数になっていない場合は、1 ラインの総バイト数が 4 の倍数になる // ようにダミーデータが各ラインの最後に書き込まれている // 例えば lx = 430 の場合は dummy = 2 個の空の画素がラインの最後に書き込まれている // ** イメージデータの読み込み // ** 配列の先頭 [0] にイメージの左上の画素が来るように読み込む int n = 0; for(j=0; jbfType = 0x4D42; // ファイルタイプ:常に"BM"(0x4D42 or 19778) pbmfh->bfSize = 54L+(long)(line*ly)+2L; // ファイル全体のサイズ(ダミー追加) pbmfh->bfReserved1 = 0; // 予約:常に0 pbmfh->bfReserved2 = 0; // 予約:常に0 pbmfh->bfOffBits = 54L; // BITMAPイメージまでのオフセット値(ヘッダサイズ) // ** BITMAPINFOHEADER型構造体のメンバーを指定してイメージファイルに格納 pbmih->biSize = 40L; // BITMAPINFOHEADERのサイズ(バイト数) pbmih->biWidth = (long)lx; // BITMAPイメージの横幅(画素数) pbmih->biHeight = (long)ly; // BITMAPイメージの縦幅(画素数) pbmih->biPlanes = 1; // 対象デバイスのカラープレーン数:常に1 pbmih->biBitCount = 24; // 画素当たりのビット数(1,4,8,24ビット) pbmih->biCompression = 0L; // BITMAPの圧縮形式:非圧縮0 pbmih->biSizeImage = 0L; // BITMAPイメージサイズ(バイト数) pbmih->biXPelsPerMeter = 0L; // 1m当たりの水平解像度(ピクセル単位) pbmih->biYPelsPerMeter = 0L; // 1m当たりの垂直解像度(ピクセル単位) pbmih->biClrUsed = 0L; // 使用されるカラーインデックス数:通常0 pbmih->biClrImportant = 0L; // 表示に必要なカラーインデックス数:通常0 // ** イメージデータの書き込み // ** 引数の一次元配列 rr, gg, bb のイメージデータをイメージファイルに格納 // ** 画像処理された double 型イメージデータを反転チェックしてから unsigned char 型に変換 short rx, gx, bx; int n = 0; for(j=0; j= 0x1000) { bx = 0x0ff0; // B画素 upper clip } else if(bx <= 0x000f) { bx = 0x0000; // B画素 lower clip } if(gx >= 0x1000) { gx = 0x0ff0; // G画素 upper clip } else if(gx <= 0x000f) { gx = 0x0000; // G画素 lower clip } if(rx >= 0x1000) { rx = 0x0ff0; // R画素 upper clip } else if(rx <= 0x000f) { rx = 0x0000; // R画素 lower clip } // ** 16bit to 8bit 変換 bx = bx >> 4; // LSB側へ 4bit 右シフト(ビット演算) gx = gx >> 4; // (MSB)0000 0000 XXXX XXXX(LSB) rx = rx >> 4; // ** unsigned short(2 byte) → unsigned char(1 byte) 変換 pdata[i*3+0+j*lx*3 +n] = (unsigned char)bx; pdata[i*3+1+j*lx*3 +n] = (unsigned char)gx; pdata[i*3+2+j*lx*3 +n] = (unsigned char)rx; } n = n + dummy; // ラインの最後にダミー追加 } // ** 書き込み用にファイルをオープン CFile file; if(!file.Open( filepath, // 目的とするファイルへのパスを表す文字列を指定 CFile::modeCreate | CFile::modeWrite | CFile::typeBinary )) { // ファイルの共有モードとアクセスモードを指定 // ファイルのパス(filepath)を指定し書き込みモード・バイナリモードでファイルをオープン // fp=_open(filepath, _O_WRONLY|_O_CREAT|_O_BINARY); に相当 return; } // ** イメージファイルの書き込み file.Write(buf, imagefilesize); // CFile オブジェクトに関連付けられたファイル file に // バッファ buf 内のデータを全て(サイズ:imagefilesize) 書き込む // _write(fp, buf, imagefilesize); に相当 // ** ファイルクローズ file.Close(); // このオブジェクトに関連付けられているファイルを閉じ、 // ファイルに対する読み出しや書き込みをできないようにする } // usage : w.SaveBmp(filepath, imagesize, rr, gg, bb); // ** メンバ関数 SaveBmp(#2) の実装 // ** View2D クラス内の double 型一次元配列 rr, gg, bb に取得されている imgsize のイメージデータを // クリップ処理、8bit 変換しイメージファイルにしてから filepath の BMP ファイルへセーブする // 一次元配列 rr, gg, bb は View2D クラス内で動的に作成され呼び出し側でイメージデータを格納 void View2D::SaveBmp(CString filepath, CSize& imgsize) { int i, j; int lx = imgsize.cx; // x方向画素数 int ly = imgsize.cy; // y方向画素数 // ** パディング:ダミー画素の算出(4の倍数問題に対応) int dummy; if(lx % 4 == 0) dummy = 0; else dummy = int(4-(lx*3)%4); // 水平画素数 lx が 4 の倍数になっていない場合は、1 ラインの総バイト数が 4 の倍数になる // ようにダミーデータを各ラインの最後に書き込む // 例えば lx = 430 の場合は dummy = 2 個の空の画素をラインの最後に書き込む int line = lx * 3 + dummy; // ** メモリ上にイメージファイルを作成してファイルに書き込む // ** イメージファイル作成用バッファ int imagefilesize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + line * ly + 2; BYTE *buf = new BYTE[imagefilesize]; // ** イメージファイル用のポインタを設定 // イメージファイルの構成:BITMAPFILEHEADER + BITMAPINFOHEADER + pdata[] BITMAPFILEHEADER *pbmfh = (BITMAPFILEHEADER *)buf; // バッファの1番目に BITMAPFILEHEADER 構造体を格納しそれを参照するために BYTE 型配列の // 先頭アドレス buf を BITMAPFILEHEADER 型にキャストしてポインタ *pbmfh に格納. // これによりポインタ pbmfh を使ってバッファ内の BITMAPFILEHEADER のメンバを参照できる BITMAPINFOHEADER *pbmih = (BITMAPINFOHEADER *)(buf + sizeof(BITMAPFILEHEADER)); // バッファの2番目に BITMAPINFOHEADER 構造体を格納しそれを参照するために、それが // 格納されるアドレスを BITMAPINFOHEADER 型にキャストしてポインタ *pbmih に格納. // これによりポインタ pbmih を使ってバッファ内の BITMAPINFOHEADER のメンバを参照できる BYTE *pdata = buf + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // バッファの3番目に BYTE 型1次元配列 pdata[] を格納しそれを参照するために、それが // 格納されるアドレスをポインタ *pdata に格納. // これによりポインタ pdata を使ってバッファ内の1次元配列 pdata[] を参照できる // ** BITMAPFILEHEADER 型構造体のメンバーを指定してイメージファイルに格納 pbmfh->bfType = 0x4D42; // ファイルタイプ:常に"BM"(0x4D42 or 19778) pbmfh->bfSize = 54L+(long)(line*ly)+2L; // ファイル全体のサイズ(ダミー追加) pbmfh->bfReserved1 = 0; // 予約:常に0 pbmfh->bfReserved2 = 0; // 予約:常に0 pbmfh->bfOffBits = 54L; // BITMAPイメージまでのオフセット値(ヘッダサイズ) // ** BITMAPINFOHEADER型構造体のメンバーを指定してイメージファイルに格納 pbmih->biSize = 40L; // BITMAPINFOHEADERのサイズ(バイト数) pbmih->biWidth = (long)lx; // BITMAPイメージの横幅(画素数) pbmih->biHeight = (long)ly; // BITMAPイメージの縦幅(画素数) pbmih->biPlanes = 1; // 対象デバイスのカラープレーン数:常に1 pbmih->biBitCount = 24; // 画素当たりのビット数(1,4,8,24ビット) pbmih->biCompression = 0L; // BITMAPの圧縮形式:非圧縮0 pbmih->biSizeImage = 0L; // BITMAPイメージサイズ(バイト数) pbmih->biXPelsPerMeter = 0L; // 1m当たりの水平解像度(ピクセル単位) pbmih->biYPelsPerMeter = 0L; // 1m当たりの垂直解像度(ピクセル単位) pbmih->biClrUsed = 0L; // 使用されるカラーインデックス数:通常0 pbmih->biClrImportant = 0L; // 表示に必要なカラーインデックス数:通常0 // ** イメージデータの書き込み // ** View2Dクラス内の二次元配列 rr, gg, bb に取得されているイメージデータをイメージファイル // に格納 // ** 画像処理された double 型イメージデータを反転チェックしてから unsigned char 型に変換 short rx, gx, bx; int n = 0; for(j=0; j= 0x1000) { bx = 0x0ff0; // B画素 upper clip } else if(bx <= 0x000f) { bx = 0x0000; // B画素 lower clip } if(gx >= 0x1000) { gx = 0x0ff0; // G画素 upper clip } else if(gx <= 0x000f) { gx = 0x0000; // G画素 lower clip } if(rx >= 0x1000) { rx = 0x0ff0; // R画素 upper clip } else if(rx <= 0x000f) { rx = 0x0000; // R画素 lower clip } // ** 16bit to 8bit 変換 bx = bx >> 4; // LSB側へ 4bit 右シフト(ビット演算) gx = gx >> 4; // (MSB)0000 0000 XXXX XXXX(LSB) rx = rx >> 4; // ** unsigned short(2 byte) → unsigned char(1 byte) 変換 pdata[i*3+0+j*lx*3 +n] = (unsigned char)bx; pdata[i*3+1+j*lx*3 +n] = (unsigned char)gx; pdata[i*3+2+j*lx*3 +n] = (unsigned char)rx; } n = n + dummy; // ラインの最後にダミー追加 } // ** 書き込み用にファイルをオープン CFile file; if(!file.Open( filepath, // 目的とするファイルへのパスを表す文字列を指定 CFile::modeCreate | CFile::modeWrite | CFile::typeBinary )) { // ファイルの共有モードとアクセスモードを指定 // ファイルのパス(filepath)を指定し書き込みモード・バイナリモードでファイルをオープン // fp=_open(filepath, _O_WRONLY|_O_CREAT|_O_BINARY); に相当 return; } // ** イメージファイルの書き込み file.Write(buf, imagefilesize); // CFile オブジェクトに関連付けられたファイル file に // バッファ buf 内のデータを全て(サイズ:imagefilesize) 書き込む // _write(fp, buf, imagefilesize); に相当 // ** ファイルクローズ file.Close(); // このオブジェクトに関連付けられているファイルを閉じ、 // ファイルに対する読み出しや書き込みをできないようにする } // usage : w.SaveBmp(filepath, imagesize); // ** メンバ関数 SaveBmp2 の実装 // ** 引数の double 型二次元配列 RR, GG, BB に取得されている imgsize のイメージデータを // クリップ処理、8bit 変換しイメージファイルにしてから filepath の BMP ファイルへセーブする // 二次元配列 RR, GG, BB は呼び出し側で動的に作成されイメージデータが格納されて引数で渡される void View2D::SaveBmp2(CString filepath, CSize& imgsize, Array RR, Array GG, Array BB) { int i, j; int lx = imgsize.cx; // x方向画素数 int ly = imgsize.cy; // y方向画素数 // ** パディング:ダミー画素の算出(4の倍数問題に対応) int dummy; if(lx % 4 == 0) dummy = 0; else dummy = int(4-(lx*3)%4); // 水平画素数 lx が 4 の倍数になっていない場合は、1 ラインの総バイト数が 4 の倍数になる // ようにダミーデータを各ラインの最後に書き込む // 例えば lx = 430 の場合は dummy = 2 個の空の画素をラインの最後に書き込む int line = lx * 3 + dummy; // ** メモリ上にイメージファイルを作成してファイルに書き込む // ** イメージファイル作成用バッファ int imagefilesize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + line * ly + 2; BYTE *buf = new BYTE[imagefilesize]; // ** イメージファイル用のポインタを設定 // イメージファイルの構成:BITMAPFILEHEADER + BITMAPINFOHEADER + pdata[] BITMAPFILEHEADER *pbmfh = (BITMAPFILEHEADER *)buf; // バッファの1番目に BITMAPFILEHEADER 構造体を格納しそれを参照するために BYTE 型配列の // 先頭アドレス buf を BITMAPFILEHEADER 型にキャストしてポインタ *pbmfh に格納. // これによりポインタ pbmfh を使ってバッファ内の BITMAPFILEHEADER のメンバを参照できる BITMAPINFOHEADER *pbmih = (BITMAPINFOHEADER *)(buf + sizeof(BITMAPFILEHEADER)); // バッファの2番目に BITMAPINFOHEADER 構造体を格納しそれを参照するために、それが // 格納されるアドレスを BITMAPINFOHEADER 型にキャストしてポインタ *pbmih に格納. // これによりポインタ pbmih を使ってバッファ内の BITMAPINFOHEADER のメンバを参照できる BYTE *pdata = buf + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // バッファの3番目に BYTE 型1次元配列 pdata[] を格納しそれを参照するために、それが // 格納されるアドレスをポインタ *pdata に格納. // これによりポインタ pdata を使ってバッファ内の1次元配列 pdata[] を参照できる // ** BITMAPFILEHEADER 型構造体のメンバーを指定してイメージファイルに格納 pbmfh->bfType = 0x4D42; // ファイルタイプ:常に"BM"(0x4D42 or 19778) pbmfh->bfSize = 54L+(long)(line*ly)+2L; // ファイル全体のサイズ(ダミー追加) pbmfh->bfReserved1 = 0; // 予約:常に0 pbmfh->bfReserved2 = 0; // 予約:常に0 pbmfh->bfOffBits = 54L; // BITMAPイメージまでのオフセット値(ヘッダサイズ) // ** BITMAPINFOHEADER型構造体のメンバーを指定してイメージファイルに格納 pbmih->biSize = 40L; // BITMAPINFOHEADERのサイズ(バイト数) pbmih->biWidth = (long)lx; // BITMAPイメージの横幅(画素数) pbmih->biHeight = (long)ly; // BITMAPイメージの縦幅(画素数) pbmih->biPlanes = 1; // 対象デバイスのカラープレーン数:常に1 pbmih->biBitCount = 24; // 画素当たりのビット数(1,4,8,24ビット) pbmih->biCompression = 0L; // BITMAPの圧縮形式:非圧縮0 pbmih->biSizeImage = 0L; // BITMAPイメージサイズ(バイト数) pbmih->biXPelsPerMeter = 0L; // 1m当たりの水平解像度(ピクセル単位) pbmih->biYPelsPerMeter = 0L; // 1m当たりの垂直解像度(ピクセル単位) pbmih->biClrUsed = 0L; // 使用されるカラーインデックス数:通常0 pbmih->biClrImportant = 0L; // 表示に必要なカラーインデックス数:通常0 // ** イメージデータの書き込み // ** 引数の2次元配列 RR, GG, BB のイメージデータをイメージファイルに格納 // ** 画像処理された double 型イメージデータを反転チェックしてから unsigned char 型に変換 short rx, gx, bx; int n = 0; for(j=0; j= 0x1000) { bx = 0x0ff0; // B画素 upper clip } else if(bx <= 0x000f) { bx = 0x0000; // B画素 lower clip } if(gx >= 0x1000) { gx = 0x0ff0; // G画素 upper clip } else if(gx <= 0x000f) { gx = 0x0000; // G画素 lower clip } if(rx >= 0x1000) { rx = 0x0ff0; // R画素 upper clip } else if(rx <= 0x000f) { rx = 0x0000; // R画素 lower clip } // ** 16bit to 8bit 変換 bx = bx >> 4; // LSB側へ 4bit 右シフト(ビット演算) gx = gx >> 4; // (MSB)0000 0000 XXXX XXXX(LSB) rx = rx >> 4; // ** unsigned short(2 byte) → unsigned char(1 byte) 変換 pdata[i*3+0+j*lx*3 +n] = (unsigned char)bx; pdata[i*3+1+j*lx*3 +n] = (unsigned char)gx; pdata[i*3+2+j*lx*3 +n] = (unsigned char)rx; } n = n + dummy; // ラインの最後にダミー追加 } // ** 書き込み用にファイルをオープン CFile file; if(!file.Open( filepath, // 目的とするファイルへのパスを表す文字列を指定 CFile::modeCreate | CFile::modeWrite | CFile::typeBinary )) { // ファイルの共有モードとアクセスモードを指定 // ファイルのパス(filepath)を指定し書き込みモード・バイナリモードでファイルをオープン // fp=_open(filepath, _O_WRONLY|_O_CREAT|_O_BINARY); に相当 return; } // ** イメージファイルの書き込み file.Write(buf, imagefilesize); // CFile オブジェクトに関連付けられたファイル file に // バッファ buf 内のデータを全て(サイズ:imagefilesize) 書き込む // _write(fp, buf, imagefilesize); に相当 // ** ファイルクローズ file.Close(); // このオブジェクトに関連付けられているファイルを閉じ、 // ファイルに対する読み出しや書き込みをできないようにする } // usage : w.SaveBmp2(filepath, imagesize, RR, GG, BB); // ** メンバ関数 SaveDib(#1) の実装 // ** 引数の double 型一次元配列 rr, gg, bb に取得されている imgsize のイメージデータを // クリップ処理、8bit 変換しイメージファイルにしてから // そのビットマップ情報をグローバル変数 HBMP の DIBSECTION にセーブ // 一次元配列 rr, gg, bb は 呼び出し側で動的に作成されイメージデータが格納されて引数で渡される void View2D::SaveDib(CSize& imgsize, double* rr, double* gg, double* bb) { int i, j; int lx = imgsize.cx; // x方向画素数 int ly = imgsize.cy; // y方向画素数 // ** パディング:ダミー画素の算出(4の倍数問題に対応) int dummy; if(lx % 4 == 0) dummy = 0; else dummy = int(4-(lx*3)%4); // 水平画素数 lx が 4 の倍数になっていない場合は、1 ラインの総バイト数が 4 の倍数になる // ようにダミーデータを各ラインの最後に書き込む // 例えば lx = 430 の場合は dummy = 2 個の空の画素をラインの最後に書き込む int line = lx * 3 + dummy; // ** メモリ上にイメージファイルを作成してファイルに書き込む // ** イメージファイル作成用バッファ int imagefilesize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + line * ly + 2; BYTE *buf = new BYTE[imagefilesize]; // ** イメージファイル用のポインタを設定 // イメージファイルの構成:BITMAPFILEHEADER + BITMAPINFOHEADER + pdata[] BITMAPFILEHEADER *pbmfh = (BITMAPFILEHEADER *)buf; // バッファの1番目に BITMAPFILEHEADER 構造体を格納しそれを参照するために BYTE 型配列の // 先頭アドレス buf を BITMAPFILEHEADER 型にキャストしてポインタ *pbmfh に格納. // これによりポインタ pbmfh を使ってバッファ内の BITMAPFILEHEADER のメンバを参照できる BITMAPINFOHEADER *pbmih = (BITMAPINFOHEADER *)(buf + sizeof(BITMAPFILEHEADER)); // バッファの2番目に BITMAPINFOHEADER 構造体を格納しそれを参照するために、それが // 格納されるアドレスを BITMAPINFOHEADER 型にキャストしてポインタ *pbmih に格納. // これによりポインタ pbmih を使ってバッファ内の BITMAPINFOHEADER のメンバを参照できる BYTE *pdata = buf + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // バッファの3番目に BYTE 型1次元配列 pdata[] を格納しそれを参照するために、それが // 格納されるアドレスをポインタ *pdata に格納. // これによりポインタ pdata を使ってバッファ内の1次元配列 pdata[] を参照できる // ** BITMAPFILEHEADER 型構造体のメンバーを指定してイメージファイルに格納 pbmfh->bfType = 0x4D42; // ファイルタイプ:常に"BM"(0x4D42 or 19778) pbmfh->bfSize = 54L+(long)(line*ly)+2L; // ファイル全体のサイズ(ダミー追加) pbmfh->bfReserved1 = 0; // 予約:常に0 pbmfh->bfReserved2 = 0; // 予約:常に0 pbmfh->bfOffBits = 54L; // BITMAPイメージまでのオフセット値(ヘッダサイズ) // ** BITMAPINFOHEADER型構造体のメンバーを指定してイメージファイルに格納 pbmih->biSize = 40L; // BITMAPINFOHEADERのサイズ(バイト数) pbmih->biWidth = (long)lx; // BITMAPイメージの横幅(画素数) pbmih->biHeight = (long)ly; // BITMAPイメージの縦幅(画素数) pbmih->biPlanes = 1; // 対象デバイスのカラープレーン数:常に1 pbmih->biBitCount = 24; // 画素当たりのビット数(1,4,8,24ビット) pbmih->biCompression = 0L; // BITMAPの圧縮形式:非圧縮0 pbmih->biSizeImage = 0L; // BITMAPイメージサイズ(バイト数) pbmih->biXPelsPerMeter = 0L; // 1m当たりの水平解像度(ピクセル単位) pbmih->biYPelsPerMeter = 0L; // 1m当たりの垂直解像度(ピクセル単位) pbmih->biClrUsed = 0L; // 使用されるカラーインデックス数:通常0 pbmih->biClrImportant = 0L; // 表示に必要なカラーインデックス数:通常0 // ** イメージデータの書き込み // ** 引数の一次元配列 rr, gg, bb のイメージデータをイメージファイルに格納 // ** 画像処理された double 型イメージデータを反転チェックしてから unsigned char 型に変換 short rx, gx, bx; int n = 0; for(j=0; j= 0x1000) { bx = 0x0ff0; // B画素 upper clip } else if(bx <= 0x000f) { bx = 0x0000; // B画素 lower clip } if(gx >= 0x1000) { gx = 0x0ff0; // G画素 upper clip } else if(gx <= 0x000f) { gx = 0x0000; // G画素 lower clip } if(rx >= 0x1000) { rx = 0x0ff0; // R画素 upper clip } else if(rx <= 0x000f) { rx = 0x0000; // R画素 lower clip } // ** 16bit to 8bit 変換 bx = bx >> 4; // LSB側へ 4bit 右シフト(ビット演算) gx = gx >> 4; // (MSB)0000 0000 XXXX XXXX(LSB) rx = rx >> 4; // ** unsigned short(2 byte) → unsigned char(1 byte) 変換 pdata[i*3+0+j*lx*3 +n] = (unsigned char)bx; pdata[i*3+1+j*lx*3 +n] = (unsigned char)gx; pdata[i*3+2+j*lx*3 +n] = (unsigned char)rx; } n = n + dummy; // ラインの最後にダミー追加 } // ** ビットマップオブジェクトとして、デバイスコンテキストに依存しない DIBSECTION を作成し // そのハンドルをグローバル変数 HBMP に取得 BYTE *pbits; // イメージデータ格納用の配列を生成 HBMP = ::CreateDIBSection // Win32 API (0, // デバイスコンテキストのハンドル. DIBSECTION は // デバイスコンテキストに依存しないため 0 を指定 (BITMAPINFO *)pbmih, // BITMAPINFO 構造体のポインタを指定 // BITMAPINFO は BITMAPINFOHEADER と RGBQUAD をまとめた構造体につき、 // BITMAPINFOHEADER 構造体のポインタ pbmih を BITMAPINFO にキャスト DIB_RGB_COLORS, // 常に DIB_RGB_COLORS を指定 (void **)&pbits, // イメージデータ格納用配列 pbits の先頭アドレスを指定 // これによりイメージデータの格納に必要なメモリーが確保される 0, // メモリーマップトファイルを使用する場合に指定 0); // 通常は 0 を指定 // CreateDIBSection で割り当てたメモリーのアドレスが DIBSECTION のハンドルとして // HBMP に渡される // この DIBSECTION のハンドルを使ってビューでの描画などが行えるようになる // ** DIBSECTION で確保されたメモリーにイメージデータをコピー long szImage = (pbmih->biWidth * pbmih->biBitCount + 31) / 32 * 4 * pbmih->biHeight; // コピーするバイト数を計算(1ライン分のバイト数が4の倍数になるように調整) // ** バッファ間でデータコピー memcpy(pbits, pdata, szImage); // pdata より szImage のサイズ分を pbits にコピー } // usage : w.SaveDib(imagesize, rr, gg, bb); // ** メンバ関数 SaveDib(#2) の実装 // ** 引数の double 型一次元配列 rr, gg, bb に取得されている imgsize のイメージデータを // クリップ処理、8bit 変換しイメージファイルにしてから // そのビットマップ情報を引数 hBmp の DIBSECTION にセーブ // 一次元配列 rr, gg, bb は 呼び出し側で動的に作成されイメージデータが格納されて引数で渡される void View2D::SaveDib(CSize& imgsize, double* rr, double* gg, double* bb, HBITMAP& hBmp) { int i, j; int lx = imgsize.cx; // x方向画素数 int ly = imgsize.cy; // y方向画素数 // ** パディング:ダミー画素の算出(4の倍数問題に対応) int dummy; if(lx % 4 == 0) dummy = 0; else dummy = int(4-(lx*3)%4); // 水平画素数 lx が 4 の倍数になっていない場合は、1 ラインの総バイト数が 4 の倍数になる // ようにダミーデータを各ラインの最後に書き込む // 例えば lx = 430 の場合は dummy = 2 個の空の画素をラインの最後に書き込む int line = lx * 3 + dummy; // ** メモリ上にイメージファイルを作成してファイルに書き込む // ** イメージファイル作成用バッファ int imagefilesize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + line * ly + 2; BYTE *buf = new BYTE[imagefilesize]; // ** イメージファイル用のポインタを設定 // イメージファイルの構成:BITMAPFILEHEADER + BITMAPINFOHEADER + pdata[] BITMAPFILEHEADER *pbmfh = (BITMAPFILEHEADER *)buf; // バッファの1番目に BITMAPFILEHEADER 構造体を格納しそれを参照するために BYTE 型配列の // 先頭アドレス buf を BITMAPFILEHEADER 型にキャストしてポインタ *pbmfh に格納. // これによりポインタ pbmfh を使ってバッファ内の BITMAPFILEHEADER のメンバを参照できる BITMAPINFOHEADER *pbmih = (BITMAPINFOHEADER *)(buf + sizeof(BITMAPFILEHEADER)); // バッファの2番目に BITMAPINFOHEADER 構造体を格納しそれを参照するために、それが // 格納されるアドレスを BITMAPINFOHEADER 型にキャストしてポインタ *pbmih に格納. // これによりポインタ pbmih を使ってバッファ内の BITMAPINFOHEADER のメンバを参照できる BYTE *pdata = buf + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // バッファの3番目に BYTE 型1次元配列 pdata[] を格納しそれを参照するために、それが // 格納されるアドレスをポインタ *pdata に格納. // これによりポインタ pdata を使ってバッファ内の1次元配列 pdata[] を参照できる // ** BITMAPFILEHEADER 型構造体のメンバーを指定してイメージファイルに格納 pbmfh->bfType = 0x4D42; // ファイルタイプ:常に"BM"(0x4D42 or 19778) pbmfh->bfSize = 54L+(long)(line*ly)+2L; // ファイル全体のサイズ(ダミー追加) pbmfh->bfReserved1 = 0; // 予約:常に0 pbmfh->bfReserved2 = 0; // 予約:常に0 pbmfh->bfOffBits = 54L; // BITMAPイメージまでのオフセット値(ヘッダサイズ) // ** BITMAPINFOHEADER型構造体のメンバーを指定してイメージファイルに格納 pbmih->biSize = 40L; // BITMAPINFOHEADERのサイズ(バイト数) pbmih->biWidth = (long)lx; // BITMAPイメージの横幅(画素数) pbmih->biHeight = (long)ly; // BITMAPイメージの縦幅(画素数) pbmih->biPlanes = 1; // 対象デバイスのカラープレーン数:常に1 pbmih->biBitCount = 24; // 画素当たりのビット数(1,4,8,24ビット) pbmih->biCompression = 0L; // BITMAPの圧縮形式:非圧縮0 pbmih->biSizeImage = 0L; // BITMAPイメージサイズ(バイト数) pbmih->biXPelsPerMeter = 0L; // 1m当たりの水平解像度(ピクセル単位) pbmih->biYPelsPerMeter = 0L; // 1m当たりの垂直解像度(ピクセル単位) pbmih->biClrUsed = 0L; // 使用されるカラーインデックス数:通常0 pbmih->biClrImportant = 0L; // 表示に必要なカラーインデックス数:通常0 // ** イメージデータの書き込み // ** 引数の一次元配列 rr, gg, bb のイメージデータをイメージファイルに格納 // ** 画像処理された double 型イメージデータを反転チェックしてから unsigned char 型に変換 short rx, gx, bx; int n = 0; for(j=0; j= 0x1000) { bx = 0x0ff0; // B画素 upper clip } else if(bx <= 0x000f) { bx = 0x0000; // B画素 lower clip } if(gx >= 0x1000) { gx = 0x0ff0; // G画素 upper clip } else if(gx <= 0x000f) { gx = 0x0000; // G画素 lower clip } if(rx >= 0x1000) { rx = 0x0ff0; // R画素 upper clip } else if(rx <= 0x000f) { rx = 0x0000; // R画素 lower clip } // ** 16bit to 8bit 変換 bx = bx >> 4; // LSB側へ 4bit 右シフト(ビット演算) gx = gx >> 4; // (MSB)0000 0000 XXXX XXXX(LSB) rx = rx >> 4; // ** unsigned short(2 byte) → unsigned char(1 byte) 変換 pdata[i*3+0+j*lx*3 +n] = (unsigned char)bx; pdata[i*3+1+j*lx*3 +n] = (unsigned char)gx; pdata[i*3+2+j*lx*3 +n] = (unsigned char)rx; } n = n + dummy; // ラインの最後にダミー追加 } // ** ビットマップオブジェクトとして、デバイスコンテキストに依存しない DIBSECTION を作成し // そのハンドルを引数 hBmp に取得 BYTE *pbits; // イメージデータ格納用の配列を生成 hBmp = ::CreateDIBSection // Win32 API (0, // デバイスコンテキストのハンドル. DIBSECTION は // デバイスコンテキストに依存しないため 0 を指定 (BITMAPINFO *)pbmih, // BITMAPINFO 構造体のポインタを指定 // BITMAPINFO は BITMAPINFOHEADER と RGBQUAD をまとめた構造体につき、 // BITMAPINFOHEADER 構造体のポインタ pbmih を BITMAPINFO にキャスト DIB_RGB_COLORS, // 常に DIB_RGB_COLORS を指定 (void **)&pbits, // イメージデータ格納用配列 pbits の先頭アドレスを指定 // これによりイメージデータの格納に必要なメモリーが確保される 0, // メモリーマップトファイルを使用する場合に指定 0); // 通常は 0 を指定 // CreateDIBSection で割り当てたメモリーのアドレスが DIBSECTION のハンドルとして // hBmp に渡される // この DIBSECTION のハンドルを使ってビューでの描画などが行えるようになる // ** DIBSECTION で確保されたメモリーにイメージデータをコピー long szImage = (pbmih->biWidth * pbmih->biBitCount + 31) / 32 * 4 * pbmih->biHeight; // コピーするバイト数を計算(1ライン分のバイト数が4の倍数になるように調整) // ** バッファ間でデータコピー memcpy(pbits, pdata, szImage); // pdata より szImage のサイズ分を pbits にコピー } // usage : w.SaveDib(imagesize, rr, gg, bb, hbmp); // ** メンバ関数 WriteBmp(#1) の実装 // ** ReadBmp(#1) により View2D クラスのグローバル変数 HBMP に取得されるビットマップ情報から // イメージファイルを作成して filepath のファイルに書き込む void View2D::WriteBmp(CString filepath) { // ** 書き込みファイルの処理 BITMAPINFOHEADER bmih; // BITMAPINFOHEADER 型変数を宣言 // ** View2D クラスのグローバル変数 HBMPに取得されているビットマップ情報(DIBSECTION のハンドル) // より DIBSECTION 構造体に画像情報を格納 DIBSECTION dib; GetObject(HBMP, sizeof(dib), &dib); // ** DIBSECTION より書き込み用の BITMAPINFOHEADER (dsBmih) を取得 bmih = dib.dsBmih; // ** 24bit FullColor (1677216色 TrueColor) 画像の確認 if(bmih.biBitCount<24) { CString stop; stop = "WriteBmp:24bitフルカラー画像ではありません。処理を中止します!"; AfxMessageBox(stop); AfxThrowArchiveException(CArchiveException::badIndex); // badIndex:「ファイルフォーマットが正しくありません」を意味する } // biBitCount が 24bit 未満の場合は処理を中止 // ** DIBSECTION より BITMAP (dsBm) を取得 BITMAP bmap; bmap = dib.dsBm; // ** BITMAP イメージデータへのポインタ (bmBits) を取得し BYTE 型配列 lpBMP に渡す BYTE *lpBMP = (BYTE*)bmap.bmBits; // これによりポインタ lpBMP を使って BITMAP イメージデータを参照できる // BITMAP イメージデータには 4 の倍数になるようにダミー画素(パディング)が追加されている // ** イメージサイズを取得 int lx = bmih.biWidth; // x方向画素数 int ly = bmih.biHeight; // y方向画素数 // ** パディング:ダミー画素の算出(4の倍数問題に対応) int dummy; if(lx % 4 == 0) dummy = 0; else dummy = int(4-(lx*3)%4); // 水平画素数 lx が 4 の倍数になっていない場合は、1 ラインの総バイト数が 4 の倍数になる // ようにダミーデータを各ラインの最後に書き込む // 例えば lx = 430 の場合は dummy = 2 個の空の画素をラインの最後に書き込む // ** 1ラインのバイト数の算出 int line = lx * 3 + dummy; // ** メモリ上にイメージファイルを作成してファイルに書き込む // ** イメージファイル作成用バッファ int imagefilesize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + line * ly + 2; BYTE *buf = new BYTE[imagefilesize]; // ** イメージファイル用のポインタを設定 // イメージファイルの構成:BITMAPFILEHEADER + BITMAPINFOHEADER + pdata[] BITMAPFILEHEADER *pbmfh = (BITMAPFILEHEADER *)buf; // バッファの1番目に BITMAPFILEHEADER 構造体を格納しそれを参照するために BYTE 型配列の // 先頭アドレス buf を BITMAPFILEHEADER 型にキャストしてポインタ *pbmfh に格納. // これによりポインタ pbmfh を使ってバッファ内の BITMAPFILEHEADER のメンバを参照できる BITMAPINFOHEADER *pbmih = (BITMAPINFOHEADER *)(buf + sizeof(BITMAPFILEHEADER)); // バッファの2番目に BITMAPINFOHEADER 構造体を格納しそれを参照するために、それが // 格納されるアドレスを BITMAPINFOHEADER 型にキャストしてポインタ *pbmih に格納. // これによりポインタ pbmih を使ってバッファ内の BITMAPINFOHEADER のメンバを参照できる BYTE *pdata = buf + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // バッファの3番目に BYTE 型1次元配列 pdata[] を格納しそれを参照するために、それが // 格納されるアドレスをポインタ *pdata に格納. // これによりポインタ pdata を使ってバッファ内の1次元配列 pdata[] を参照できる // ** BITMAPFILEHEADER 型構造体のメンバーを指定してイメージファイルに格納 pbmfh->bfType = 0x4D42; // ファイルタイプ:常に"BM"(0x4D42 or 19778) pbmfh->bfSize = 54L+(long)(line*ly)+2L; // ファイル全体のサイズ(ダミー追加) // pbmfh->bfSize = 54L+(long)(lx*ly*3); では 4 の倍数にならないためエラーになるので要注意 pbmfh->bfReserved1 = 0; // 予約:常に0 pbmfh->bfReserved2 = 0; // 予約:常に0 pbmfh->bfOffBits = 54L; // BITMAPイメージまでのオフセット値(ヘッダサイズ) // ** BITMAPINFOHEADER型構造体のメンバーを指定してイメージファイルに格納 pbmih->biSize = 40L; // BITMAPINFOHEADERのサイズ(バイト数) pbmih->biWidth = (long)lx; // BITMAPイメージの横幅(画素数) pbmih->biHeight = (long)ly; // BITMAPイメージの縦幅(画素数) pbmih->biPlanes = 1; // 対象デバイスのカラープレーン数:常に1 pbmih->biBitCount = 24; // 画素当たりのビット数(1,4,8,24ビット) pbmih->biCompression = 0L; // BITMAPの圧縮形式:非圧縮0 pbmih->biSizeImage = 0L; // BITMAPイメージサイズ(バイト数) pbmih->biXPelsPerMeter = 0L; // 1m当たりの水平解像度(ピクセル単位) pbmih->biYPelsPerMeter = 0L; // 1m当たりの垂直解像度(ピクセル単位) pbmih->biClrUsed = 0L; // 使用されるカラーインデックス数:通常0 pbmih->biClrImportant = 0L; // 表示に必要なカラーインデックス数:通常0 // ** イメージデータの書き込み // ** イメージファイルに確保されたメモリー pdata に lpBMP のイメージデータをコピー long szImage = (pbmih->biWidth * pbmih->biBitCount + 31) / 32 * 4 * pbmih->biHeight; // コピーするバイト数を計算(1ラインのバイト数が4の倍数になるように調整) // ** バッファ間でデータコピー memcpy(pdata, lpBMP, szImage); // lpBMP より szImage のサイズ分を pdata にコピー // ** 書き込み用にファイルをオープン CFile file; if(!file.Open( filepath, // 目的とするファイルへのパスを表す文字列を指定 CFile::modeCreate | CFile::modeWrite | CFile::typeBinary )) { // ファイルの共有モードとアクセスモードを指定 // ファイルのパス(filepath)を指定し書き込みモード・バイナリモードでファイルをオープン // fp=_open(filepath, _O_WRONLY|_O_CREAT|_O_BINARY); に相当 return; } // ** イメージファイルの書き込み file.Write(buf, imagefilesize); // CFile オブジェクトに関連付けられたファイル file に // バッファ buf 内のデータを全て(サイズ:imagefilesize) 書き込む // _write(fp, buf, imagefilesize); に相当 // ** ファイルクローズ file.Close(); // このオブジェクトに関連付けられているファイルを閉じ、 // ファイルに対する読み出しや書き込みをできないようにする } // usage : w.WriteBmp(filepath); // ** メンバ関数 WriteBmp(#2) の実装 // ** ReadBmp(#2) により引数 hBmp に取得されるビットマップ情報から // イメージファイルを作成して filepath のファイルに書き込む void View2D::WriteBmp(CString filepath, HBITMAP& hBmp) { // ** 構造体 HBITMAP の引き渡しには HBITMAP& を指定 // ** 書き込みファイルの処理 BITMAPINFOHEADER bmih; // BITMAPINFOHEADER 型変数を宣言 // ** 引数 hBmp に取得されているビットマップ情報(DIBSECTION のハンドル) // より DIBSECTION 構造体に画像情報を格納 DIBSECTION dib; GetObject(hBmp, sizeof(dib), &dib); // ** DIBSECTION より書き込み用の BITMAPINFOHEADER (dsBmih) を取得 bmih = dib.dsBmih; // ** 24bit FullColor (1677216色 TrueColor) 画像の確認 if(bmih.biBitCount<24) { CString stop; stop = "WriteBmp:24bitフルカラー画像ではありません。処理を中止します!"; AfxMessageBox(stop); AfxThrowArchiveException(CArchiveException::badIndex); // badIndex:「ファイルフォーマットが正しくありません」を意味する } // biBitCount が 24bit 未満の場合は処理を中止 // ** DIBSECTION より BITMAP (dsBm) を取得 BITMAP bmap; bmap = dib.dsBm; // ** BITMAP イメージデータへのポインタ (bmBits) を取得し BYTE 型配列 lpBMP に渡す BYTE *lpBMP = (BYTE*)bmap.bmBits; // これによりポインタ lpBMP を使って BITMAP イメージデータを参照できる // BITMAP イメージデータには 4 の倍数になるようにダミー画素(パディング)が追加されている // ** イメージサイズを取得 int lx = bmih.biWidth; // x方向画素数 int ly = bmih.biHeight; // y方向画素数 // ** パディング:ダミー画素の算出(4の倍数問題に対応) int dummy; if(lx % 4 == 0) dummy = 0; else dummy = int(4-(lx*3)%4); // 水平画素数 lx が 4 の倍数になっていない場合は、1 ラインの総バイト数が 4 の倍数になる // ようにダミーデータを各ラインの最後に書き込む // 例えば lx = 430 の場合は dummy = 2 個の空の画素をラインの最後に書き込む // ** 1ラインのバイト数の算出 int line = lx * 3 + dummy; // ** メモリ上にイメージファイルを作成してファイルに書き込む // ** イメージファイル作成用バッファ int imagefilesize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + line * ly + 2; BYTE *buf = new BYTE[imagefilesize]; // ** イメージファイル用のポインタを設定 // イメージファイルの構成:BITMAPFILEHEADER + BITMAPINFOHEADER + pdata[] BITMAPFILEHEADER *pbmfh = (BITMAPFILEHEADER *)buf; // バッファの1番目に BITMAPFILEHEADER 構造体を格納しそれを参照するために BYTE 型配列の // 先頭アドレス buf を BITMAPFILEHEADER 型にキャストしてポインタ *pbmfh に格納. // これによりポインタ pbmfh を使ってバッファ内の BITMAPFILEHEADER のメンバを参照できる BITMAPINFOHEADER *pbmih = (BITMAPINFOHEADER *)(buf + sizeof(BITMAPFILEHEADER)); // バッファの2番目に BITMAPINFOHEADER 構造体を格納しそれを参照するために、それが // 格納されるアドレスを BITMAPINFOHEADER 型にキャストしてポインタ *pbmih に格納. // これによりポインタ pbmih を使ってバッファ内の BITMAPINFOHEADER のメンバを参照できる BYTE *pdata = buf + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // バッファの3番目に BYTE 型1次元配列 pdata[] を格納しそれを参照するために、それが // 格納されるアドレスをポインタ *pdata に格納. // これによりポインタ pdata を使ってバッファ内の1次元配列 pdata[] を参照できる // ** BITMAPFILEHEADER 型構造体のメンバーを指定してイメージファイルに格納 pbmfh->bfType = 0x4D42; // ファイルタイプ:常に"BM"(0x4D42 or 19778) pbmfh->bfSize = 54L+(long)(line*ly)+2L; // ファイル全体のサイズ(ダミー追加) // pbmfh->bfSize = 54L+(long)(lx*ly*3); では 4 の倍数にならないためエラーになるので要注意 pbmfh->bfReserved1 = 0; // 予約:常に0 pbmfh->bfReserved2 = 0; // 予約:常に0 pbmfh->bfOffBits = 54L; // BITMAPイメージまでのオフセット値(ヘッダサイズ) // ** BITMAPINFOHEADER型構造体のメンバーを指定してイメージファイルに格納 pbmih->biSize = 40L; // BITMAPINFOHEADERのサイズ(バイト数) pbmih->biWidth = (long)lx; // BITMAPイメージの横幅(画素数) pbmih->biHeight = (long)ly; // BITMAPイメージの縦幅(画素数) pbmih->biPlanes = 1; // 対象デバイスのカラープレーン数:常に1 pbmih->biBitCount = 24; // 画素当たりのビット数(1,4,8,24ビット) pbmih->biCompression = 0L; // BITMAPの圧縮形式:非圧縮0 pbmih->biSizeImage = 0L; // BITMAPイメージサイズ(バイト数) pbmih->biXPelsPerMeter = 0L; // 1m当たりの水平解像度(ピクセル単位) pbmih->biYPelsPerMeter = 0L; // 1m当たりの垂直解像度(ピクセル単位) pbmih->biClrUsed = 0L; // 使用されるカラーインデックス数:通常0 pbmih->biClrImportant = 0L; // 表示に必要なカラーインデックス数:通常0 // ** イメージデータの書き込み // ** イメージファイルに確保されたメモリー pdata に lpBMP のイメージデータをコピー long szImage = (pbmih->biWidth * pbmih->biBitCount + 31) / 32 * 4 * pbmih->biHeight; // コピーするバイト数を計算(1ラインのバイト数が4の倍数になるように調整) // ** バッファ間でデータコピー memcpy(pdata, lpBMP, szImage); // lpBMP より szImage のサイズ分を pdata にコピー // ** 書き込み用にファイルをオープン CFile file; if(!file.Open( filepath, // 目的とするファイルへのパスを表す文字列を指定 CFile::modeCreate | CFile::modeWrite | CFile::typeBinary )) { // ファイルの共有モードとアクセスモードを指定 // ファイルのパス(filepath)を指定し書き込みモード・バイナリモードでファイルをオープン // fp=_open(filepath, _O_WRONLY|_O_CREAT|_O_BINARY); に相当 return; } // ** イメージファイルの書き込み file.Write(buf, imagefilesize); // CFile オブジェクトに関連付けられたファイル file に // バッファ buf 内のデータを全て(サイズ:imagefilesize) 書き込む // _write(fp, buf, imagefilesize); に相当 // ** ファイルクローズ file.Close(); // このオブジェクトに関連付けられているファイルを閉じ、 // ファイルに対する読み出しや書き込みをできないようにする } // usage : w.WriteBmp(filepath); // ** メンバ関数 WriteBmpx の実装 // ** ReadBmp(#1) により View2D クラスのグローバル変数 HBMP に取得されるビットマップ情報から // filepath のファイルに書き込む void View2D::WriteBmpx(CString filepath) { // ** 書き込みファイルの処理 BITMAPFILEHEADER bmfh; // BITMAPFILEHEADER 型変数を宣言 BITMAPINFOHEADER bmih; // BITMAPINFOHEADER 型変数を宣言 // ** 引数の hbmp (DIBSECTION のハンドル)より DIBSECTION 構造体に画像情報を格納 DIBSECTION dib; GetObject(HBMP, sizeof(dib), &dib); // ** DIBSECTION より書き込み用の BITMAPINFOHEADER (dsBmih) を取得 bmih = dib.dsBmih; // ** 24bit FullColor (1677216色 TrueColor) 画像の確認 if(bmih.biBitCount<24) { CString stop; stop = "WriteBmp:24bitフルカラー画像ではありません。処理を中止します!"; AfxMessageBox(stop); AfxThrowArchiveException(CArchiveException::badIndex); // badIndex:「ファイルフォーマットが正しくありません」を意味する } // biBitCount が 24bit 未満の場合は処理を中止 // ** DIBSECTION より BITMAP (dsBm) を取得 BITMAP bmap; bmap = dib.dsBm; // ** BITMAP イメージデータへのポインタ (bmBits) を取得し BYTE 型配列 lpBMP に渡す BYTE *lpBMP = (BYTE*)bmap.bmBits; // ** イメージサイズを取得 int lx = bmih.biWidth; // x方向画素数 int ly = bmih.biHeight; // y方向画素数 // ** パディング:ダミー画素の算出(4の倍数問題に対応) int dummy; if(lx % 4 == 0) dummy = 0; else dummy = int(4-(lx*3)%4); // 水平画素数 lx が 4 の倍数になっていない場合は、1 ラインの総バイト数が 4 の倍数になる // ようにダミーデータを各ラインの最後に書き込む // 例えば lx = 430 の場合は dummy = 2 個の空の画素をラインの最後に書き込む // ** 1ラインのバイト数の算出 int line = lx * 3 + dummy; // ** BITMAPFILEHEADER型構造体のメンバーを指定 bmfh.bfType = 0x4D42; // ファイルタイプ:常に"BM"(0x4D42 or 19778) bmfh.bfSize = 54L+(long)(line*ly)+2L; // ファイル全体のサイズ(ダミー追加) // bmfh.bfSize = 54L+(long)(lx*ly*3); では 4 の倍数にならないためエラーになるので要注意 bmfh.bfReserved1 = 0; // 予約:常に0 bmfh.bfReserved2 = 0; // 予約:常に0 bmfh.bfOffBits = 54L; // BITMAPイメージまでのオフセット値(ヘッダサイズ) // ** 書き込み用にファイルをオープン CFile file; if(!file.Open( filepath, // 目的とするファイルへのパスを表す文字列を指定 CFile::modeCreate | CFile::modeWrite | CFile::typeBinary )) { // ファイルの共有モードとアクセスモードを指定 // ファイルのパス(filepath)を指定し、書き込みモード・バイナリモードでファイルをオープン // fp=_open(filepath, _O_WRONLY|_O_CREAT|_O_BINARY); に相当 return; } // ** ファイルヘッダー1(BITMAPFILEHEADER)の書き込み file.Write( (char*)&bmfh, // ファイルに書き込むためのデータを保持する、 // ユーザーが用意したバッファへのポインタを指定 sizeof(BITMAPFILEHEADER)); // バッファから転送されるバイト数を指定 // BITMAPFILEHEADER 型変数 bmfh を CFile オブジェクトに関連付けられたファイルに書き込む // _write(fp,(char*)&bmfh,sizeof(BITMAPFILEHEADER)); に相当 // ** ファイルヘッダー2(BITMAPINFOHEADER)の書き込み file.Write((char*)&bmih,sizeof(BITMAPINFOHEADER)); // BITMAPINFOHEADER 型変数 bmih を CFile オブジェクトに関連付けられたファイルに書き込む // _write(fp,(char*)&bmih,sizeof(BITMAPINFOHEADER)); に相当 // ** イメージデータの書き込み file.Write(lpBMP, bmfh.bfSize - bmfh.bfOffBits); // CFile オブジェクトに関連付けられたファイルにバッファ lpBMP からイメージデータを書き込む // _write(fp, buf, bmfh.bfSize - bmfh.bfOffBits); に相当 // ** ファイルクローズ file.Close(); // このオブジェクトに関連付けられているファイルを閉じ、 // ファイルに対する読み出しや書き込みをできないようにする } // usage : w.WriteBmpx(filepath); // ** メンバ関数 DrawBmp(#1) の実装 // ** ReadBmp(#1) によりグローバル変数 HBMP に取得されるビットマップ情報に基づき // ビュー座標 (x, y) に BMP 画像を描画 void View2D::DrawBmp(int x, int y) { /* if(HBMP != 0) { CString str; str = "DIBSECTION が更新されました。ビットマップ画像を表示します!"; AfxMessageBox(str); } */ // ** グローバル変数の HBMP (DIBSECTION のハンドル)より CBitmap クラスの一時オブジェクトを // ** 作成しそのポインタを pbmp に渡す CBitmap *pbmp = CBitmap::FromHandle(HBMP); // FromHandle は static メンバ関数で定義されているためスコープ解決演算子 :: で呼び出す // ** メモリデバイスコンテキストを作成してビットマップを選択 CDC dcMem; dcMem.CreateCompatibleDC(pdc); // 指定されたデバイスと互換性のあるメモリデバイスコンテキストを作成 CBitmap *pbmpOrig = dcMem.SelectObject(pbmp); // 作成したメモリデバイスコンテキストに、ビットマップオブジェクト pbmp を選択し、 // 元のビットマップは pbmpOrig に保存 // ** HBMP (DIBSECTION のハンドル)よりイメージサイズを取得 CSize ImageSize; ImageSize = GetImageSize(); // ** ビットマップを転送 pdc->BitBlt(x, y, ImageSize.cx, ImageSize.cy, &dcMem, 0, 0, SRCCOPY); // メモリデバイスコンテキスト dcMem にある画像を pDC に転送 // dcMem 上の (0, 0) を基点とするビットマップ画像(すなわち画像全体)をビュー座標 (x, y) // に、横 ImageSize.cx, 縦 ImageSize.cy のサイズでディスプレイ用のメモリ pDC にそのまま // コピー転送(SRCCOPY) // ** 元のビットマップに戻す dcMem.SelectObject(pbmpOrig); // ** 作成したメモリデバイスコンテキスト dcMem を削除 dcMem.DeleteDC(); // ** 作成したビットマップオブジェクト(DIBSECTION)を削除 // ::DeleteObject(HBMP); } // usage : w.DrawBmp(10, 10); // ** メンバ関数 DrawBmp(#2) の実装 // ** ReadBmp(#2) により引数の hBmp に取得されるビットマップ情報に基づき // ビュー座標 (x, y) に BMP 画像を描画 void View2D::DrawBmp(int x, int y, HBITMAP& hBmp) { // ** 引数の hbmp (DIBSECTION のハンドル)より CBitmap クラスの一時オブジェクトを作成し // ** そのポインタを pbmp に渡す CBitmap *pbmp = CBitmap::FromHandle(hBmp); // FromHandle は static メンバ関数で定義されているためスコープ解決演算子 :: で呼び出す // ** メモリデバイスコンテキストを作成してビットマップを選択 CDC dcMem; dcMem.CreateCompatibleDC(pdc); // 指定されたデバイスと互換性のあるメモリデバイスコンテキストを作成 CBitmap *pbmpOrig = dcMem.SelectObject(pbmp); // 作成したメモリデバイスコンテキストに、ビットマップオブジェクト pbmp を選択し、 // 元のビットマップは pbmpOrig に保存 // ** 引数の hbmp (DIBSECTION のハンドル)よりイメージサイズを取得 CSize ImageSize; ImageSize = GetImageSize(hBmp); // ** ビットマップを転送 pdc->BitBlt(x, y, ImageSize.cx, ImageSize.cy, &dcMem, 0, 0, SRCCOPY); // メモリデバイスコンテキスト dcMem にある画像を pDC に転送 // dcMem 上の (0, 0) を基点とするビットマップ画像(すなわち画像全体)をビュー座標 (x, y) // に、横 ImageSize.cx, 縦 ImageSize.cy のサイズでディスプレイ用のメモリ pDC にそのまま // コピー転送(SRCCOPY) // ** 元のビットマップに戻す dcMem.SelectObject(pbmpOrig); // ** 作成したメモリデバイスコンテキスト dcMem を削除 dcMem.DeleteDC(); // ** 作成したビットマップオブジェクト(DIBSECTION)を削除 // ::DeleteObject(hBmp); } // usage : w.DrawBmp(10, 10, hbmp); // ** メンバ関数 GetImageSize(#1) の実装 // ** View2D クラスのグローバル変数 HBMP に取得されたビットマップ情報より // イメージサイズ imgsize を取得し返す CSize View2D::GetImageSize(void) { int lx, ly; // ** 引数の hBmp (DIBSECTION のハンドル)より DIBSECTION 構造体に画像情報を格納 DIBSECTION dib; GetObject(HBMP, sizeof(dib), &dib); // ** DIBSECTION より BITMAPINFOHEADER (dsBmih) を取得 BITMAPINFOHEADER bmih; bmih = dib.dsBmih; // ** BITMAPINFOHEADER よりイメージサイズを取得 (横:imgsize.cx × 縦:imgsize.cy) lx = bmih.biWidth; // x方向画素数取得 ly = bmih.biHeight; // y方向画素数取得 // ** 取得したイメージサイズを CSize クラス imgsize として返す CSize imgsize; imgsize.cx = lx; imgsize.cy = ly; return imgsize; } // usage : CSize imgsize = w.GetImageSize(); // ** メンバ関数 GetImageSize(#2) の実装 // ** 引数のビットマップ情報 hBmp よりイメージサイズ imgsize を取得し返す CSize View2D::GetImageSize(HBITMAP& hBmp) { CSize imgsize; int lx, ly; // ** 引数の hBmp (DIBSECTION のハンドル)より DIBSECTION 構造体に画像情報を格納 DIBSECTION dib; GetObject(hBmp, sizeof(dib), &dib); // ** DIBSECTION より BITMAPINFOHEADER (dsBmih) を取得 BITMAPINFOHEADER bmih; bmih = dib.dsBmih; // ** BITMAPINFOHEADER よりイメージサイズを取得 (横:imgsize.cx × 縦:imgsize.cy) lx = bmih.biWidth; // x方向画素数取得 ly = bmih.biHeight; // y方向画素数取得 // ** 取得したイメージサイズを CSize クラス imgsize として返す imgsize.cx = lx; imgsize.cy = ly; return imgsize; } // usage : CSize imgsize = w.GetImageSize(hbmp); // ** メンバ関数 GetImageSize(#3) の実装 // ** ファイルパス CString filepath の BMP イメージサイズ imgsize を取得し返す CSize View2D::GetImageSize(CString filepath) { // ** 引数のファイルをオープン CFile file; if(!file.Open( filepath, // 目的とするファイルへのパスを表す文字列を指定 CFile::modeRead | CFile::typeBinary // ファイルの共有モードとアクセスモードを指定 )) { // ファイルのパス(filepath)を指定し、読取モード・バイナリモードでファイルをオープン // fp=_open(fname, _O_RDONLY|_O_BINARY); に相当 return NULL; } // ** BMP ファイルの先頭ヘッダー BITMAPFILEHEADER を読み込む BITMAPFILEHEADER bmfh; if(file.Read(&bmfh, sizeof(bmfh)) != sizeof(bmfh)) { AfxThrowArchiveException(CArchiveException::endOfFile); } // ** BITMAPFILEHEADER のファイルタイプ(bfType)をチェック if(bmfh.bfType != 0x4d42){ // "BM" AfxThrowArchiveException(CArchiveException::badIndex); } // ** BMP ファイルの2番目のヘッダー BITMAPINFOHEADER を読み込む BITMAPINFOHEADER bmih; if(file.Read(&bmih, sizeof(bmih)) != sizeof(bmih)) { AfxThrowArchiveException(CArchiveException::endOfFile); } // ** ビットマップイメージサイズの取得 (SIZE 構造体に取得) CSize imgsize; imgsize.cx = bmih.biWidth; // ** x方向画素数取得 imgsize.cy = bmih.biHeight; // ** y方向画素数取得 return imgsize; } // usage : CSize imagesize = w.GetImageSize(filepath); // ** メンバ関数 GetImageSize(#4) の実装 // ** ファイルパス char* filename の BMP イメージサイズ imgsize を取得し返す CSize View2D::GetImageSize(char* filename) { // ** 引数のファイルをオープン CFile file; CString filepath; filepath = filename; if(!file.Open( filepath, // 目的とするファイルへのパスを表す文字列を指定 CFile::modeRead | CFile::typeBinary // ファイルの共有モードとアクセスモードを指定 )) { // ファイルのパス(filepath)を指定し、読取モード・バイナリモードでファイルをオープン // fp=_open(fname, _O_RDONLY|_O_BINARY); に相当 return NULL; } // ** BMP ファイルの先頭ヘッダー BITMAPFILEHEADER を読み込む BITMAPFILEHEADER bmfh; if(file.Read(&bmfh, sizeof(bmfh)) != sizeof(bmfh)) { AfxThrowArchiveException(CArchiveException::endOfFile); } // ** BITMAPFILEHEADER のファイルタイプ(bfType)をチェック if(bmfh.bfType != 0x4d42){ // "BM" AfxThrowArchiveException(CArchiveException::badIndex); } // ** BMP ファイルの2番目のヘッダー BITMAPINFOHEADER を読み込む BITMAPINFOHEADER bmih; if(file.Read(&bmih, sizeof(bmih)) != sizeof(bmih)) { AfxThrowArchiveException(CArchiveException::endOfFile); } // ** ビットマップイメージサイズの取得 (SIZE 構造体に取得) CSize imgsize; imgsize.cx = bmih.biWidth; // ** x方向画素数取得 imgsize.cy = bmih.biHeight; // ** y方向画素数取得 return imgsize; } // usage : CSize imagesize = w.GetImageSize("xxx.bmp"); // ** メンバ関数 CheckBit の実装 // ** 引数のビットマップ情報 hBmp より 24bit フルカラー画像をチェック void View2D::CheckBit(HBITMAP& hBmp) { // 構造体 HBITMAP の引き渡しには HBITMAP& を指定 // ** メンバ変数のビットマップ m_hBmp より DIBSECTION 構造体に画像情報を格納 DIBSECTION dib; GetObject(hBmp, sizeof(dib), &dib); // ** 24bit フルカラー画像(1677216色 TrueColor)の確認:フルカラー画像以外はサポートしない if(dib.dsBmih.biBitCount<16) { CString stop; stop = "CheckBit:24bitフルカラー画像ではありません。処理を中止します!"; AfxMessageBox(stop); AfxThrowUserException(); } // 24bit フルカラー画像でない場合はリターン } // usage : w.CheckBit(hbmp); // ** メンバ関数 GetHBMP の実装 // ** グローバル変数のビットマップ情報 HBMP を取得 HBITMAP View2D::GetHBMP(void) { HBITMAP hbmp = HBMP; return hbmp; } // usage : HBITMAP hbmp = w.GetHBMP(); // ** メンバ関数 PutHBMP の実装 // ** 引数のビットマップ情報 hbmp をグローバル変数 HBMP に渡す void View2D::PutHBMP(HBITMAP& hbmp) { HBMP = hbmp; } // usage : w.PutHBMP(hbmp); // ** メンバ関数 ReadDrawBmp(#1) の実装 // ** filepath のファイルを読み込みビットマップ情報をグローバル HBMP に一時的に取得 // してからビューに表示 void View2D::ReadDrawBmp(CString filepath, int x, int y) { // ** 引数のファイルをオープン CFile file; if(!file.Open( filepath, // 目的とするファイルへのパスを表す文字列を指定 CFile::modeRead | CFile::typeBinary // ファイルの共有モードとアクセスモードを指定 )) { // ファイルのパス(filename)を指定し、読取モード・バイナリモードでファイルをオープン // fp=_open(fname, _O_RDONLY|_O_BINARY); に相当 return; } // ** BMP ファイルの先頭ヘッダー BITMAPFILEHEADER を読み込む BITMAPFILEHEADER bmfh; if(file.Read(&bmfh, sizeof(bmfh)) != sizeof(bmfh)) { AfxThrowArchiveException(CArchiveException::endOfFile); } // ** BITMAPFILEHEADER のファイルタイプ(bfType)をチェック if(bmfh.bfType != 0x4d42){ // "BM" AfxThrowArchiveException(CArchiveException::badIndex); } // ** BYTE 型動的配列 buf を割り当ててファイルの残りを読み込む UINT sz = bmfh.bfSize - sizeof(bmfh); // ファイルの残りサイズを計算 BYTE *buf = new BYTE[sz]; CSize ImageSize; // イメージサイズ取得用 // ** try, catch, throw で例外処理 // ** 例外処理:エラーが発生した場所からそれを処理する場所にエラー情報を通知して、制御を移す try{ // ** try 文でエラー発生の可能性があるコードを記述 if(file.Read(buf, sz) != sz){ // ファイルの長さがおかしい場合 AfxThrowArchiveException(CArchiveException::endOfFile); } // ** buf の最初の部分(BITMAPINFOHEADER 構造体)にポインタ指定 BITMAPINFOHEADER *pbmih = (BITMAPINFOHEADER *)buf; // buf に格納した BYTE 型配列の先頭アドレスを BITMAPINFOHEADER 型に // キャストして pbmih に格納 // これにより pbmih を使って BITMAPINFOHEADER を参照できる // ** 圧縮フォーマット(biCompression)はサポートしない if(pbmih->biCompression != BI_RGB) { // ** 非圧縮の場合 biCompression = BI_RGB AfxThrowArchiveException(CArchiveException::badIndex); } // ** カラーテーブル(RGBQUAD 構造体)の先頭アドレスを取得 RGBQUAD *pcolortbl = NULL; // ** カラーテーブルの初期化 // ** biBitCount が 8bit 以下の場合は BITMAPINFOHEADER の後に RGBQUAD 構造体がくる if(pbmih->biBitCount <= 8) { pcolortbl = (RGBQUAD *)(buf + pbmih->biSize); // BITMAPINFOHEADER の実際のサイズ(biSize)から RGBQUAD の位置を計算 } // ここでは 24bit フルカラー以外はサポートしない // ** イメージデータの先頭アドレスを取得 BYTE *pdata = buf + bmfh.bfOffBits - sizeof(bmfh); // BITMAPFILEHEADER の情報からイメージデータの先頭アドレスを計算 // メモリアクセス速度アップのために、イメージデータの先頭アドレスは、4の倍数に // なるようにダミーデータが挿入されている(詰め物:パディング) // このためイメージデータの先頭アドレスは BITMAPFILEHEADER の bfOffBits から計算 // ** ビットマップオブジェクトとして、デバイスコンテキストに依存しない DIBSECTION を作成し // ** そのハンドルをグローバル変数 HBMP に取得 BYTE *pbits; // ** イメージデータ格納用の配列を生成 HBMP = ::CreateDIBSection // Win32 API (0, // デバイスコンテキストのハンドル. DIBSECTION は // デバイスコンテキストに依存しないため 0 を指定 (BITMAPINFO *)pbmih, // BITMAPINFO 構造体のポインタを指定 // BITMAPINFO は BITMAPINFOHEADER と RGBQUAD をまとめた構造体につき、 // BITMAPINFOHEADER 構造体のポインタ pbmih を BITMAPINFO にキャスト DIB_RGB_COLORS, // 常に DIB_RGB_COLORS を指定 (void **)&pbits, // イメージデータ格納用配列 pbits の先頭アドレスを指定 // ** これによりイメージデータの格納に必要なメモリーが確保される 0, // メモリーマップトファイルを使用する場合に指定 0); // 通常は 0 を指定 // CreateDIBSection で割り当てたメモリーのアドレスが DIBSECTION のハンドルとして // HBMP に渡される // この DIBSECTION のハンドルを使って、ビューでの描画などが行えるようになる if(HBMP == 0 || pbits == NULL) { AfxThrowMemoryException(); } // ** DIBSECTION で確保されたメモリーにイメージデータをコピー long szImage = (pbmih->biWidth * pbmih->biBitCount + 31) / 32 * 4 * pbmih->biHeight; // コピーするバイト数を計算(1ラインのバイト数が4の倍数になるように調整) // ** バッファ間でデータコピー memcpy(pbits, pdata, szImage); // pdata より szImage のサイズ分を pbits にコピー // イメージサイズ取得 ImageSize.cx = pbmih->biWidth; ImageSize.cy = pbmih->biHeight; // ** 動的配列のメモリを解放 delete []buf; } // ** try 文でエラーが発生した場合、そこで実行中断され catch 文以降に制御が移り、 // ** throw 文でエラーを通知 catch(CException *e){ // エラーが起きた場合,確保しているメモリーを解放してから例外を呼び出し // 元へ再 throw する delete []buf; throw e; } // ** HBMP (DIBSECTION のハンドル) より CBitmap クラスの一時オブジェクトを作成し // そのポインタを pbmp に渡す(メモリデバイスコンテキストに HBMP をポインタで選択するため) CBitmap *pbmp = CBitmap::FromHandle(HBMP); // FromHandle は static メンバ関数で定義されているためスコープ解決演算子 :: で呼び出す // ** ウィンドウデバイスコンテキスト(ディスプレイ用メモリ) pdc と互換性のある // メモリデバイスコンテキスト dcMem を作成 CDC dcMem; dcMem.CreateCompatibleDC(pdc); // ** 作成したメモリデバイスコンテキスト dcMem にビットマップオブジェクト(DIBSECTION) pbmp を // 選択し元のビットマップを pbmpOrig に保存 CBitmap *pbmpOrig = dcMem.SelectObject(pbmp); // ** ビットマップを転送 pdc->BitBlt(x, y, ImageSize.cx, ImageSize.cy, &dcMem, 0, 0, SRCCOPY); // メモリデバイスコンテキスト dcMem にある画像を pDC に転送 // dcMem 上の (0, 0) を基点とするビットマップ画像(すなわち画像全体)をビュー座標 (x, y) // に、横 ImageSize.cx, 縦 ImageSize.cy のサイズでディスプレイ用のメモリ pDC にそのまま // コピー転送(SRCCOPY) // ** 元のビットマップに戻す dcMem.SelectObject(pbmpOrig); // ** 作成したメモリデバイスコンテキスト dcMem を削除 dcMem.DeleteDC(); // ** 作成したビットマップオブジェクト(DIBSECTION)を削除 // ::DeleteObject(HBMP); } // usage : w.ReadDrawBmp(filepath, 10, 10); // ** メンバ関数 ReadDrawBmp(#2) の実装 // ** filepath のファイルを読み込みビットマップ情報を引数の hBmp に取得してからビューに表示 void View2D::ReadDrawBmp(CString filepath, int x, int y, HBITMAP& hBmp) { // ** 簡易化のためにファイルチェックは行わない場合を示す // ここでは 24bit フルカラー以外はサポートしない // ** 引数のファイルをオープン CFile file; file.Open(filepath, // 目的とするファイルへのパスを表す文字列を指定 CFile::modeRead | CFile::typeBinary); // ファイルの共有モードとアクセスモードを指定 // ** BMP ファイルの先頭ヘッダー BITMAPFILEHEADER を bmfh に読み込む BITMAPFILEHEADER bmfh; file.Read(&bmfh, sizeof(bmfh)); // ** BYTE 型動的配列 buf を割り当ててファイルの残りを読み込む UINT sz = bmfh.bfSize - sizeof(bmfh); // ファイルの残りサイズを計算 BYTE *buf = new BYTE[sz]; if(file.Read(buf, sz) != sz){ // ファイルの長さがおかしい場合 AfxThrowArchiveException(CArchiveException::endOfFile); } // ** buf の最初の部分(BITMAPINFOHEADER 構造体)にポインタ指定 BITMAPINFOHEADER *pbmih = (BITMAPINFOHEADER *)buf; // buf に格納した BYTE 型配列の先頭アドレスを BITMAPINFOHEADER 型に // キャストして pbmih に格納 // これにより pbmih を使って BITMAPINFOHEADER を参照できる // ** イメージデータの先頭アドレスを取得 BYTE *pdata = buf + bmfh.bfOffBits - sizeof(bmfh); // BITMAPFILEHEADER の情報からイメージデータの先頭アドレスを計算 // メモリアクセス速度アップのために、イメージデータの先頭アドレスは、4の倍数に // なるようにダミーデータが挿入されている(詰め物:パディング) // このためイメージデータの先頭アドレスは BITMAPFILEHEADER の bfOffBits から計算 // ** ビットマップオブジェクトとして、デバイスコンテキストに依存しない DIBSECTION を作成し // そのハンドルを HBITMAP 型の引数 hBmp に渡す BYTE *pbits; // イメージデータ格納用の配列を生成 hBmp = ::CreateDIBSection // Win32 API (0, // デバイスコンテキストのハンドル. DIBSECTION は // デバイスコンテキストに依存しないため 0 を指定 (BITMAPINFO *)pbmih, // BITMAPINFO 構造体のポインタを指定 // BITMAPINFO は BITMAPINFOHEADER と RGBQUAD をまとめた構造体につき、 // BITMAPINFOHEADER 構造体のポインタ pbmih を BITMAPINFO にキャスト DIB_RGB_COLORS, // 常に DIB_RGB_COLORS を指定 (void **)&pbits, // イメージデータ格納用配列 pbits の先頭アドレスを指定 // これによりイメージデータの格納に必要なメモリーが確保される 0, // メモリーマップトファイルを使用する場合に指定 0); // 通常は 0 を指定 // CreateDIBSection で割り当てたメモリーのアドレスが DIBSECTION のハンドルとして // hBmp に渡される // この DIBSECTION のハンドルを使って、ビューでの描画などが行えるようになる // ** DIBSECTION で確保されたメモリーにイメージデータをコピー long szImage = (pbmih->biWidth * pbmih->biBitCount + 31) / 32 * 4 * pbmih->biHeight; // コピーするバイト数を計算(1ライン分のバイト数が4の倍数になるように調整) // ** バッファ間でデータコピー memcpy(pbits, pdata, szImage); // pdata より szImage のサイズ分を pbits にコピー // ** イメージサイズを取得 CSize ImageSize; ImageSize.cx = pbmih->biWidth; ImageSize.cy = pbmih->biHeight; // ** 動的配列のメモリを解放 delete []buf; // ** hBmp (DIBSECTION のハンドル)より CBitmap クラスの一時オブジェクトを作成し // そのポインタを pbmp に渡す(メモリデバイスコンテキストに hBmp をポインタで選択するため) CBitmap *pbmp = CBitmap::FromHandle(hBmp); // FromHandle は static メンバ関数で定義されているためスコープ解決演算子 :: で呼び出す // ** ウィンドウデバイスコンテキスト(ディスプレイ用メモリ) pdc と互換性のある // メモリデバイスコンテキスト dcMem を作成 CDC dcMem; dcMem.CreateCompatibleDC(pdc); // ** 作成したメモリデバイスコンテキスト dcMem にビットマップオブジェクト(DIBSECTION) pbmp を // 選択し元のビットマップを pbmpOrig に保存 CBitmap *pbmpOrig = dcMem.SelectObject(pbmp); // ** ビットマップを転送 pdc->BitBlt(x, y, ImageSize.cx, ImageSize.cy, &dcMem, 0, 0, SRCCOPY); // メモリデバイスコンテキスト dcMem にある画像を pDC に転送 // dcMem 上の (0, 0) を基点とするビットマップ画像(すなわち画像全体)をビュー座標 (x, y) // に、横 ImageSize.cx, 縦 ImageSize.cy のサイズでディスプレイ用のメモリ pDC にそのまま // コピー転送(SRCCOPY) // ** 元のビットマップに戻す dcMem.SelectObject(pbmpOrig); // ** 作成したメモリデバイスコンテキスト dcMem を削除 dcMem.DeleteDC(); // ** 作成したビットマップオブジェクト(DIBSECTION)を削除 // ::DeleteObject(hBmp); } // usage : w.ReadDrawBmp(filepath, 10, 10, hbmp); // ** メンバ関数 ReadLoadBmp の実装 // ** filepath のファイルを内部のバッファ buf に読み込み // 8bit のイメージデータを double 型一次元配列 rr, gg, bb へロード // 一次元配列 rr, gg, bb はこの関数内(View2D クラス)で動的に生成 void View2D::ReadLoadBmp(CString filepath) { // ** 引数のファイルをオープン CFile file; if(!file.Open( filepath, // 目的とするファイルへのパスを表す文字列を指定 CFile::modeRead | CFile::typeBinary // ファイルの共有モードとアクセスモードを指定 )) { // ファイルのパス(filename)を指定し、読取モード・バイナリモードでファイルをオープン // fp=_open(fname, _O_RDONLY|_O_BINARY); に相当 return; } // ** BMP ファイルの先頭ヘッダー BITMAPFILEHEADER を読み込む BITMAPFILEHEADER bmfh; if(file.Read(&bmfh, sizeof(bmfh)) != sizeof(bmfh)) { AfxThrowArchiveException(CArchiveException::endOfFile); } // ** BITMAPFILEHEADER のファイルタイプ(bfType)をチェック if(bmfh.bfType != 0x4d42){ // "BM" AfxThrowArchiveException(CArchiveException::badIndex); } // ** BYTE 型動的配列 buf を割り当ててファイルの残りを読み込む UINT sz = bmfh.bfSize - sizeof(bmfh); // ファイルの残りサイズを計算 BYTE *buf = new BYTE[sz]; // イメージデータ格納用バッファ BITMAPINFOHEADER *pbmih; // BITMAPINFOHEADER 構造体へのポインタ格納用 BYTE *pdata; // イメージデータの先頭アドレス格納用 // ** try, catch, throw で例外処理 // ** 例外処理:エラーが発生した場所からそれを処理する場所にエラー情報を通知して、制御を移す try{ // try 文でエラー発生の可能性があるコードを記述 if(file.Read(buf, sz) != sz){ // ファイルの長さがおかしい場合 AfxThrowArchiveException(CArchiveException::endOfFile); } // ** buf の最初の部分(BITMAPINFOHEADER 構造体)にポインタ指定 pbmih = (BITMAPINFOHEADER *)buf; // buf に格納した BYTE 型配列の先頭アドレスを BITMAPINFOHEADER 型に // キャストして pbmih に格納 // これにより pbmih を使って BITMAPINFOHEADER を参照できる // ** 圧縮フォーマット(biCompression)はサポートしない if(pbmih->biCompression != BI_RGB) { // 非圧縮の場合 biCompression = BI_RGB AfxThrowArchiveException(CArchiveException::badIndex); } // ** カラーテーブル(RGBQUAD 構造体)の先頭アドレスを取得 RGBQUAD *pcolortbl = NULL; // カラーテーブルの初期化 // ** biBitCount が 8bit 以下の場合は BITMAPINFOHEADER の後に RGBQUAD 構造体がくる if(pbmih->biBitCount <= 8) { pcolortbl = (RGBQUAD *)(buf + pbmih->biSize); // BITMAPINFOHEADER の実際のサイズ(biSize)から RGBQUAD の位置を計算 } // ここでは 24bit フルカラー以外はサポートしない // ** イメージデータの先頭アドレスを取得 pdata = buf + bmfh.bfOffBits - sizeof(bmfh); // BITMAPFILEHEADER の情報からイメージデータの先頭アドレスを計算 // メモリアクセス速度アップのために、イメージデータの先頭アドレスは、4の倍数に // なるようにダミーデータが挿入されている(詰め物:パディング) // このためイメージデータの先頭アドレスは BITMAPFILEHEADER の bfOffBits から計算 } // ** try 文でエラーが発生した場合、そこで実行中断され catch 文以降に制御が移り、 // throw 文でエラーを通知 catch(CException *e){ // ** エラーが起きた場合,確保しているメモリーを解放してから例外を呼び出し元へ再 throw する delete []buf; throw e; } int i, j; int lx; // x方向画素数 int ly; // y方向画素数 double r, g, b; // double 型 R,G,B 画素値 // ** BITMAPINFOHEADER よりイメージサイズを取得 (横:imgsize.cx × 縦:imgsize.cy) // ** イメージサイズ取得用 CSize クラスのオブジェクト生成 CSize imgsize; lx = pbmih->biWidth; // x方向画素数取得 ly = pbmih->biHeight; // y方向画素数取得 // ** パディング:ダミー画素の算出(4の倍数問題に対応) int dummy; if(lx % 4 == 0) dummy = 0; else dummy = int(4-(lx*3)%4); // 水平画素数 lx が 4 の倍数になっていない場合は、1 ラインの総バイト数が 4 の倍数になる // ようにダミーデータが各ラインの最後に書き込まれている // 例えば lx = 430 の場合は dummy = 2 個の空の画素がラインの最後に書き込まれている // ** 動的一次元配列の生成 rr = new double[lx*ly]; gg = new double[lx*ly]; bb = new double[lx*ly]; // ** イメージデータの読み込み // ** 配列の先頭 [0] にイメージの左上の画素が来るように読み込む int n = 0; for(j=0; jbiCompression != BI_RGB) { // 非圧縮の場合 biCompression = BI_RGB AfxThrowArchiveException(CArchiveException::badIndex); } // ** カラーテーブル(RGBQUAD 構造体)の先頭アドレスを取得 RGBQUAD *pcolortbl = NULL; // カラーテーブルの初期化 // ** biBitCount が 8bit 以下の場合は BITMAPINFOHEADER の後に RGBQUAD 構造体がくる if(pbmih->biBitCount <= 8) { pcolortbl = (RGBQUAD *)( buf + pbmih->biSize); // BITMAPINFOHEADER の実際のサイズ(biSize)から RGBQUAD の位置を計算 } // ここでは 24bit フルカラー以外はサポートしない // ** イメージデータの先頭アドレスを取得 BYTE *pdata = buf + bmfh.bfOffBits - sizeof(bmfh); // BITMAPFILEHEADER の情報からイメージデータの先頭アドレスを計算 // メモリアクセス速度アップのために、イメージデータの先頭アドレスは、4の倍数に // なるようにダミーデータが挿入されている(詰め物:パディング) // このためイメージデータの先頭アドレスは BITMAPFILEHEADER の bfOffBits から計算 // ** ビットマップオブジェクトとして、デバイスコンテキストに依存しない DIBSECTION を作成し // そのハンドルをこの View2D クラスのグローバル変数 HBMP に取得 BYTE *pbits; // イメージデータ格納用の配列を生成 HBMP = ::CreateDIBSection // Win32 API (0, // デバイスコンテキストのハンドル. DIBSECTION は // デバイスコンテキストに依存しないため 0 を指定 (BITMAPINFO *)pbmih, // BITMAPINFO 構造体のポインタを指定 // BITMAPINFO は BITMAPINFOHEADER と RGBQUAD をまとめた構造体につき、 // BITMAPINFOHEADER 構造体のポインタ pbmih を BITMAPINFO にキャスト DIB_RGB_COLORS, // 常に DIB_RGB_COLORS を指定 (void **)&pbits, // イメージデータ格納用配列 pbits の先頭アドレスを指定 // これによりイメージデータの格納に必要なメモリーが確保される 0, // メモリーマップトファイルを使用する場合に指定 0); // 通常は 0 を指定 // CreateDIBSection で割り当てたメモリーのアドレスが DIBSECTION のハンドルとして // HBMP に渡される // この DIBSECTION のハンドルを使って、ビューでの描画などが行えるようになる if(HBMP == 0 || pbits == NULL) { AfxThrowMemoryException(); } // ** DIBSECTION で確保されたメモリーにイメージデータをコピー long szImage = (pbmih->biWidth * pbmih->biBitCount + 31) / 32 * 4 * pbmih->biHeight; // コピーするバイト数を計算(1ライン分のバイト数が4の倍数になるように調整) // ** バッファ間でデータコピー memcpy(pbits, pdata, szImage); // pdata より szImage のサイズ分を pbits にコピー // ** 動的配列のメモリを解放 delete []buf; } // ** try 文でエラーが発生した場合、そこで実行中断され catch 文以降に制御が移り、 // ** throw 文でエラーを通知 catch(CException *e) { // エラーが起きた場合,確保しているメモリーを解放してから例外を呼び出し元へ再 throw する delete []buf; throw e; } } // usage : w.Reading(ar); // ** メンバ関数 Reading(#2) の実装 // ** ドキュメントクラス C**Doc::Serialize(CArchive& ar) で選択された BMP ファイルから // ビットマップ情報を取得し引数 hbmp に渡す // ビットマップ情報を格納するために DIBSECTION を生成(hbmp はそのハンドル) void View2D::Reading(CArchive& ar, HBITMAP& hbmp) { // ** BMP ファイルの先頭ヘッダー BITMAPFILEHEADER を読み込む BITMAPFILEHEADER bmfh; if(ar.Read(&bmfh, sizeof(bmfh)) != sizeof(bmfh)) { AfxThrowArchiveException(CArchiveException::endOfFile); } // ** BITMAPFILEHEADER のファイルタイプ(bfType)をチェック if(bmfh.bfType != 0x4d42) { // "BM" AfxThrowArchiveException(CArchiveException::badIndex); } // ** BYTE 型動的配列 buf を割り当ててファイルの残りを読み込む UINT sz = bmfh.bfSize - sizeof(bmfh); // ファイルの残りサイズを計算 BYTE *buf = new BYTE[sz]; // ** try, catch, throw で例外処理 // ** 例外処理:エラーが発生した場所からそれを処理する場所にエラー情報を通知して制御を移す try{ // try 文でエラー発生の可能性があるコードを記述 if(ar.Read(buf, sz) != sz) { // ファイルの長さがおかしい場合 AfxThrowArchiveException(CArchiveException::endOfFile); } // ** buf の最初の部分(BITMAPINFOHEADER 構造体)にポインタ指定 BITMAPINFOHEADER *pbmih = (BITMAPINFOHEADER *)buf; // buf に格納した BYTE 型配列の先頭アドレスを BITMAPINFOHEADER 型に // キャストして pbmih に格納 // これにより pbmih を使って BITMAPINFOHEADER を参照できる // 圧縮フォーマット(biCompression)はサポートしない if(pbmih->biCompression != BI_RGB) { // 非圧縮の場合 biCompression = BI_RGB AfxThrowArchiveException(CArchiveException::badIndex); } // ** カラーテーブル(RGBQUAD 構造体)の先頭アドレスを取得 RGBQUAD *pcolortbl = NULL; // カラーテーブルの初期化 // ** biBitCount が 8bit 以下の場合は BITMAPINFOHEADER の後に RGBQUAD 構造体がくる if(pbmih->biBitCount <= 8) { pcolortbl = (RGBQUAD *)( buf + pbmih->biSize); // BITMAPINFOHEADER の実際のサイズ(biSize)から RGBQUAD の位置を計算 } // ここでは 24bit フルカラー以外はサポートしない // ** イメージデータの先頭アドレスを取得 BYTE *pdata = buf + bmfh.bfOffBits - sizeof(bmfh); // BITMAPFILEHEADER の情報からイメージデータの先頭アドレスを計算 // メモリアクセス速度アップのために、イメージデータの先頭アドレスは、4の倍数に // なるようにダミーデータが挿入されている(詰め物:パディング) // このためイメージデータの先頭アドレスは BITMAPFILEHEADER の bfOffBits から計算 // ** ビットマップオブジェクトとして、デバイスコンテキストに依存しない DIBSECTION を作成し // そのハンドルを HBITMAP 型の引数 hbmp に渡す BYTE *pbits; // イメージデータ格納用の配列を生成 hbmp = ::CreateDIBSection // Win32 API (0, // デバイスコンテキストのハンドル. DIBSECTION は // デバイスコンテキストに依存しないため 0 を指定 (BITMAPINFO *)pbmih, // BITMAPINFO 構造体のポインタを指定 // BITMAPINFO は BITMAPINFOHEADER と RGBQUAD をまとめた構造体につき、 // BITMAPINFOHEADER 構造体のポインタ pbmih を BITMAPINFO にキャスト DIB_RGB_COLORS, // 常に DIB_RGB_COLORS を指定 (void **)&pbits, // イメージデータ格納用配列 pbits の先頭アドレスを指定 // これによりイメージデータの格納に必要なメモリーが確保される 0, // メモリーマップトファイルを使用する場合に指定 0); // 通常は 0 を指定 // CreateDIBSection で割り当てたメモリーのアドレスが DIBSECTION のハンドルとして // hbmp に渡される // この DIBSECTION のハンドルを使って、ビューでの描画などが行えるようになる if(hbmp == 0 || pbits == NULL) { AfxThrowMemoryException(); } // ** DIBSECTION で確保されたメモリーにイメージデータをコピー long szImage = (pbmih->biWidth * pbmih->biBitCount + 31) / 32 * 4 * pbmih->biHeight; // コピーするバイト数を計算(1ラインのバイト数が4の倍数になるように調整) // ** バッファ間でデータコピー memcpy(pbits, pdata, szImage); // pdata より szImage のサイズ分を pbits にコピー // ** 動的配列のメモリを解放 delete []buf; } // ** try 文でエラーが発生した場合、そこで実行中断され catch 文以降に制御が移り、 // throw 文でエラーを通知 catch(CException *e) { // エラーが起きた場合,確保しているメモリーを解放してから例外を呼び出し元へ再 throw する delete []buf; throw e; } } // usage : w.Reading(ar, hbmp); // ** メンバ関数 Writing(#1) の実装 // ** ドキュメントクラス C**Doc::Serialize(CArchive& ar) で指定されたファイル名で // Reading(#1) により View2D クラスのグローバル変数 HBMP に取得されるビットマップ情報から // イメージファイルを作成してファイルに書き込む void View2D::Writing(CArchive& ar) { // ** 画像の準備ができていなければリターン if(!HBMP) { CString stop; stop = "Serialize:\n画像の準備ができていません。処理を中止します!"; AfxMessageBox(stop); AfxThrowUserException(); } // ** 書き込みファイルの処理 BITMAPINFOHEADER bmih; // BITMAPINFOHEADER 型変数を宣言 // ** View2D クラスのグローバル変数 HBMPに取得されているビットマップ情報(DIBSECTION のハンドル) // より DIBSECTION 構造体に画像情報を格納 DIBSECTION dib; GetObject(HBMP, sizeof(dib), &dib); // ** DIBSECTION より書き込み用の BITMAPINFOHEADER (dsBmih) を取得 bmih = dib.dsBmih; // ** 24bit FullColor (1677216色 TrueColor) 画像の確認 if(bmih.biBitCount<24) { CString stop; stop = "Writing:24bitフルカラー画像ではありません。処理を中止します!"; AfxMessageBox(stop); AfxThrowArchiveException(CArchiveException::badIndex); // badIndex:「ファイルフォーマットが正しくありません」を意味する } // biBitCount が 24bit 未満の場合は処理を中止 // ** DIBSECTION より BITMAP (dsBm) を取得 BITMAP bmap; bmap = dib.dsBm; // ** BITMAP イメージデータへのポインタ (bmBits) を取得し BYTE 型配列 lpBMP に渡す BYTE *lpBMP = (BYTE*)bmap.bmBits; // これによりポインタ lpBMP を使って BITMAP イメージデータを参照できる // BITMAP イメージデータには 4 の倍数になるようにダミー画素(パディング)が追加されている // ** イメージサイズを取得 int lx = bmih.biWidth; // x方向画素数 int ly = bmih.biHeight; // y方向画素数 // ** パディング:ダミー画素の算出(4の倍数問題に対応) int dummy; if(lx % 4 == 0) dummy = 0; else dummy = int(4-(lx*3)%4); // 水平画素数 lx が 4 の倍数になっていない場合は、1 ラインの総バイト数が 4 の倍数になる // ようにダミーデータを各ラインの最後に書き込む // 例えば lx = 430 の場合は dummy = 2 個の空の画素をラインの最後に書き込む // ** 1ラインのバイト数の算出 int line = lx * 3 + dummy; // ** メモリ上にイメージファイルを作成してファイルに書き込む // ** イメージファイル作成用バッファ int imagefilesize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + line * ly + 2; BYTE *buf = new BYTE[imagefilesize]; // ** イメージファイル用のポインタを設定 // イメージファイルの構成:BITMAPFILEHEADER + BITMAPINFOHEADER + pdata[] BITMAPFILEHEADER *pbmfh = (BITMAPFILEHEADER *)buf; // バッファの1番目に BITMAPFILEHEADER 構造体を格納しそれを参照するために BYTE 型配列の // 先頭アドレス buf を BITMAPFILEHEADER 型にキャストしてポインタ *pbmfh に格納. // これによりポインタ pbmfh を使ってバッファ内の BITMAPFILEHEADER のメンバを参照できる BITMAPINFOHEADER *pbmih = (BITMAPINFOHEADER *)(buf + sizeof(BITMAPFILEHEADER)); // バッファの2番目に BITMAPINFOHEADER 構造体を格納しそれを参照するために、それが // 格納されるアドレスを BITMAPINFOHEADER 型にキャストしてポインタ *pbmih に格納. // これによりポインタ pbmih を使ってバッファ内の BITMAPINFOHEADER のメンバを参照できる BYTE *pdata = buf + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // // バッファの3番目に BYTE 型1次元配列 pdata[] を格納しそれを参照するために、それが // 格納されるアドレスをポインタ *pdata に格納. // これによりポインタ pdata を使ってバッファ内の1次元配列 pdata[] を参照できる // ** BITMAPFILEHEADER 型構造体のメンバーを指定してイメージファイルに格納 pbmfh->bfType = 0x4D42; // ファイルタイプ:常に"BM"(0x4D42 or 19778) pbmfh->bfSize = 54L+(long)(line*ly)+2L; // ファイル全体のサイズ(ダミー追加) // pbmfh->bfSize = 54L+(long)(lx*ly*3); では 4 の倍数にならないためエラーになるので要注意 pbmfh->bfReserved1 = 0; // 予約:常に0 pbmfh->bfReserved2 = 0; // 予約:常に0 pbmfh->bfOffBits = 54L; // BITMAPイメージまでのオフセット値(ヘッダサイズ) // ** BITMAPINFOHEADER型構造体のメンバーを指定してイメージファイルに格納 pbmih->biSize = 40L; // BITMAPINFOHEADERのサイズ(バイト数) pbmih->biWidth = (long)lx; // BITMAPイメージの横幅(画素数) pbmih->biHeight = (long)ly; // BITMAPイメージの縦幅(画素数) pbmih->biPlanes = 1; // 対象デバイスのカラープレーン数:常に1 pbmih->biBitCount = 24; // 画素当たりのビット数(1,4,8,24ビット) pbmih->biCompression = 0L; // BITMAPの圧縮形式:非圧縮0 pbmih->biSizeImage = 0L; // BITMAPイメージサイズ(バイト数) pbmih->biXPelsPerMeter = 0L; // 1m当たりの水平解像度(ピクセル単位) pbmih->biYPelsPerMeter = 0L; // 1m当たりの垂直解像度(ピクセル単位) pbmih->biClrUsed = 0L; // 使用されるカラーインデックス数:通常0 pbmih->biClrImportant = 0L; // 表示に必要なカラーインデックス数:通常0 // ** イメージデータの書き込み // ** イメージファイルに確保されたメモリー pdata に lpBMP のイメージデータをコピー long szImage = (pbmih->biWidth * pbmih->biBitCount + 31) / 32 * 4 * pbmih->biHeight; // コピーするバイト数を計算(1ラインのバイト数が4の倍数になるように調整) // ** バッファ間でデータコピー memcpy(pdata, lpBMP, szImage); // lpBMP より szImage のサイズ分を pdata にコピー // ** イメージファイルの書き込み ar.Write(buf, imagefilesize); // CFile オブジェクトに関連付けられたファイル file に // バッファ buf 内のデータを全て(サイズ:imagefilesize) 書き込む // _write(fp, buf, imagefilesize); に相当 } // usage : w.Writing(ar); // ** メンバ関数 Writing(#2) の実装 // ** ドキュメントクラス C**Doc::Serialize(CArchive& ar) で指定されたファイル名で // Reading(#2) により引数の hbmp に取得されるビットマップ情報から // イメージファイルを作成してファイルに書き込む void View2D::Writing(CArchive& ar, HBITMAP& hbmp) { // ** 画像の準備ができていなければリターン if(!hbmp) { CString stop; stop = "Serialize:\n画像の準備ができていません。処理を中止します!"; AfxMessageBox(stop); AfxThrowUserException(); } // ** 書き込みファイルの処理 BITMAPINFOHEADER bmih; // BITMAPINFOHEADER 型変数を宣言 // ** 引数の hbmp に取得されているビットマップ情報(DIBSECTION のハンドル)より // DIBSECTION 構造体に画像情報を格納 DIBSECTION dib; GetObject(hbmp, sizeof(dib), &dib); // ** DIBSECTION より書き込み用の BITMAPINFOHEADER (dsBmih) を取得 bmih = dib.dsBmih; // ** 24bit FullColor (1677216色 TrueColor) 画像の確認 if(bmih.biBitCount<24) { CString stop; stop = "Writing:24bitフルカラー画像ではありません。処理を中止します!"; AfxMessageBox(stop); AfxThrowArchiveException(CArchiveException::badIndex); // badIndex:「ファイルフォーマットが正しくありません」を意味する } // biBitCount が 24bit 未満の場合は処理を中止 // ** DIBSECTION より BITMAP (dsBm) を取得 BITMAP bmap; bmap = dib.dsBm; // ** BITMAP イメージデータへのポインタ (bmBits) を取得し BYTE 型配列 lpBMP に渡す BYTE *lpBMP = (BYTE*)bmap.bmBits; // これによりポインタ lpBMP を使って BITMAP イメージデータを参照できる // BITMAP イメージデータには 4 の倍数になるようにダミー画素(パディング)が追加されている // ** イメージサイズを取得 int lx = bmih.biWidth; // x方向画素数 int ly = bmih.biHeight; // y方向画素数 // ** パディング:ダミー画素の算出(4の倍数問題に対応) int dummy; if(lx % 4 == 0) dummy = 0; else dummy = int(4-(lx*3)%4); // 水平画素数 lx が 4 の倍数になっていない場合は、1 ラインの総バイト数が 4 の倍数になる // ようにダミーデータを各ラインの最後に書き込む // 例えば lx = 430 の場合は dummy = 2 個の空の画素をラインの最後に書き込む // ** 1ラインのバイト数の算出 int line = lx * 3 + dummy; // ** メモリ上にイメージファイルを作成してファイルに書き込む // ** イメージファイル作成用バッファ int imagefilesize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + line * ly + 2; BYTE *buf = new BYTE[imagefilesize]; // ** イメージファイル用のポインタを設定 // イメージファイルの構成:BITMAPFILEHEADER + BITMAPINFOHEADER + pdata[] BITMAPFILEHEADER *pbmfh = (BITMAPFILEHEADER *)buf; // バッファの1番目に BITMAPFILEHEADER 構造体を格納しそれを参照するために BYTE 型配列の // 先頭アドレス buf を BITMAPFILEHEADER 型にキャストしてポインタ *pbmfh に格納. // これによりポインタ pbmfh を使ってバッファ内の BITMAPFILEHEADER のメンバを参照できる BITMAPINFOHEADER *pbmih = (BITMAPINFOHEADER *)(buf + sizeof(BITMAPFILEHEADER)); // バッファの2番目に BITMAPINFOHEADER 構造体を格納しそれを参照するために、それが // 格納されるアドレスを BITMAPINFOHEADER 型にキャストしてポインタ *pbmih に格納. // これによりポインタ pbmih を使ってバッファ内の BITMAPINFOHEADER のメンバを参照できる BYTE *pdata = buf + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // バッファの3番目に BYTE 型1次元配列 pdata[] を格納しそれを参照するために、それが // 格納されるアドレスをポインタ *pdata に格納. // これによりポインタ pdata を使ってバッファ内の1次元配列 pdata[] を参照できる // ** BITMAPFILEHEADER 型構造体のメンバーを指定してイメージファイルに格納 pbmfh->bfType = 0x4D42; // ファイルタイプ:常に"BM"(0x4D42 or 19778) pbmfh->bfSize = 54L+(long)(line*ly)+2L; // ファイル全体のサイズ(ダミー追加) // pbmfh->bfSize = 54L+(long)(lx*ly*3); では 4 の倍数にならないためエラーになるので要注意 pbmfh->bfReserved1 = 0; // 予約:常に0 pbmfh->bfReserved2 = 0; // 予約:常に0 pbmfh->bfOffBits = 54L; // BITMAPイメージまでのオフセット値(ヘッダサイズ) // ** BITMAPINFOHEADER型構造体のメンバーを指定してイメージファイルに格納 pbmih->biSize = 40L; // BITMAPINFOHEADERのサイズ(バイト数) pbmih->biWidth = (long)lx; // BITMAPイメージの横幅(画素数) pbmih->biHeight = (long)ly; // BITMAPイメージの縦幅(画素数) pbmih->biPlanes = 1; // 対象デバイスのカラープレーン数:常に1 pbmih->biBitCount = 24; // 画素当たりのビット数(1,4,8,24ビット) pbmih->biCompression = 0L; // BITMAPの圧縮形式:非圧縮0 pbmih->biSizeImage = 0L; // BITMAPイメージサイズ(バイト数) pbmih->biXPelsPerMeter = 0L; // 1m当たりの水平解像度(ピクセル単位) pbmih->biYPelsPerMeter = 0L; // 1m当たりの垂直解像度(ピクセル単位) pbmih->biClrUsed = 0L; // 使用されるカラーインデックス数:通常0 pbmih->biClrImportant = 0L; // 表示に必要なカラーインデックス数:通常0 // ** イメージデータの書き込み // ** イメージファイルに確保されたメモリー pdata に lpBMP のイメージデータをコピー long szImage = (pbmih->biWidth * pbmih->biBitCount + 31) / 32 * 4 * pbmih->biHeight; // コピーするバイト数を計算(1ラインのバイト数が4の倍数になるように調整) // ** バッファ間でデータコピー memcpy(pdata, lpBMP, szImage); // lpBMP より szImage のサイズ分を pdata にコピー // ** イメージファイルの書き込み ar.Write(buf, imagefilesize); // CFile オブジェクトに関連付けられたファイル file に // バッファ buf 内のデータを全て(サイズ:imagefilesize) 書き込む // _write(fp, buf, imagefilesize); に相当 } // usage : w.Writing(ar, hbmp); // ** メンバ関数 Writingx の実装 // ** ドキュメントクラス C**Doc::Serialize(CArchive& ar) で指定されたファイル名で // Reading(#1) により View2D クラスのグローバル変数 HBMP に取得されるビットマップ情報から // ファイルに書き込む // イメージファイルは作成せずに直接ファイルに書き込む void View2D::Writingx(CArchive& ar) { // ** 画像の準備ができていなければリターン if(!HBMP) { CString stop; stop = "Serialize:\n画像の準備ができていません。処理を中止します!"; AfxMessageBox(stop); AfxThrowUserException(); } // ** 書き込みファイルの処理 BITMAPFILEHEADER bmfh; // BITMAPFILEHEADER 型変数を宣言 BITMAPINFOHEADER bmih; // BITMAPINFOHEADER 型変数を宣言 // ** 引数の hbmp (DIBSECTION のハンドル)より DIBSECTION 構造体に画像情報を格納 DIBSECTION dib; GetObject(HBMP, sizeof(dib), &dib); // ** DIBSECTION より書き込み用の BITMAPINFOHEADER (dsBmih) を取得 bmih = dib.dsBmih; // ** 24bit FullColor (1677216色 TrueColor) 画像の確認 if(bmih.biBitCount<24) { CString stop; stop = "Writing:24bitフルカラー画像ではありません。処理を中止します!"; AfxMessageBox(stop); AfxThrowArchiveException(CArchiveException::badIndex); // badIndex:「ファイルフォーマットが正しくありません」を意味する } // biBitCount が 24bit 未満の場合は処理を中止 // ** DIBSECTION より BITMAP (dsBm) を取得 BITMAP bmap; bmap = dib.dsBm; // ** BITMAP イメージデータへのポインタ (bmBits) を取得し BYTE 型配列 lpBMP に渡す BYTE *lpBMP = (BYTE*)bmap.bmBits; // ** イメージサイズを取得 int lx = bmih.biWidth; // x方向画素数 int ly = bmih.biHeight; // y方向画素数 // ** パディング:ダミー画素の算出(4の倍数問題に対応) int dummy; if(lx % 4 == 0) dummy = 0; else dummy = int(4-(lx*3)%4); // 水平画素数 lx が 4 の倍数になっていない場合は、1 ラインの総バイト数が 4 の倍数になる // ようにダミーデータを各ラインの最後に書き込む // 例えば lx = 430 の場合は dummy = 2 個の空の画素をラインの最後に書き込む // ** 1ラインのバイト数の算出 int line = lx * 3 + dummy; // ** BITMAPFILEHEADER型構造体のメンバーを指定 bmfh.bfType = 0x4D42; // ファイルタイプ:常に"BM"(0x4D42 or 19778) bmfh.bfSize = 54L+(long)(line*ly)+2L; // ファイル全体のサイズ(ダミー追加) // bmfh.bfSize = 54L+(long)(lx*ly*3); では 4 の倍数にならないためエラーになるので要注意 bmfh.bfReserved1 = 0; // 予約:常に0 bmfh.bfReserved2 = 0; // 予約:常に0 bmfh.bfOffBits = 54L; // BITMAPイメージまでのオフセット値(ヘッダサイズ) // ** ファイルヘッダー1(BITMAPFILEHEADER)の書き込み ar.Write( (char*)&bmfh, // ファイルに書き込むためのデータを保持する、 // ユーザーが用意したバッファへのポインタを指定 sizeof(BITMAPFILEHEADER)); // バッファから転送されるバイト数を指定 // BITMAPFILEHEADER 型変数 bmfh を CFile オブジェクトに関連付けられたファイルに書き込む // _write(fp,(char*)&bmfh,sizeof(BITMAPFILEHEADER)); に相当 // ** ファイルヘッダー2(BITMAPINFOHEADER)の書き込み ar.Write((char*)&bmih,sizeof(BITMAPINFOHEADER)); // BITMAPINFOHEADER 型変数 bmih を CFile オブジェクトに関連付けられたファイルに書き込む // _write(fp,(char*)&bmih,sizeof(BITMAPINFOHEADER)); に相当 // ** イメージデータの書き込み ar.Write(lpBMP, bmfh.bfSize - bmfh.bfOffBits); // CFile オブジェクトに関連付けられたファイルにバッファ lpBMP からイメージデータを書き込む // _write(fp, buf, line); に相当 } // usage : w.Writingx(ar); // ** Message 関数の実装 ** // ** ダイアログボックスに書式付きで数値データを表示 // double, int 型の数値を最大 10 までダイアログボックスに表示(書式付き printf に近似させた関数) void View2D::Message(char* text, double a0, double a1, double a2, double a3, double a4, double a5, double a6, double a7, double a8, double a9) { // int 型は double 型に変換されて表示される CString msg; char str[100]; sprintf(str, text, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); // 文字列に変換 msg = str; AfxMessageBox(msg); // ダイアログボックスを表示 } // usage : w.Message("a = %3.0f", a); // ******** View2D クラスで使用するウィンドウ 2D グラフィックス描画関数 ******** // ** メンバ関数 WriteWin(#1) の実装 // ** ビットマップオブジェクト(DIBSECTION)を介して、表示されているウィンドウの全領域を // イメージファイルを作成して filepath のファイルに書き込む void View2D::WriteWin(CString filepath) { // コンストラクタで初期化されたウィンドウサイズを取得 int lx = Width; // x方向画素数 int ly = Height; // y方向画素数 // ** パディング:ダミー画素の算出(4の倍数問題に対応) int dummy; if(lx % 4 == 0) dummy = 0; else dummy = int(4-(lx*3)%4); // 水平画素数 lx が 4 の倍数になっていない場合は、1 ラインの総バイト数が 4 の倍数になる // ようにダミーデータを各ラインの最後に書き込む // 例えば lx = 430 の場合は dummy = 2 個の空の画素をラインの最後に書き込む // ** 1ラインのバイト数の算出 int line = lx * 3 + dummy; // イメージデータサイズ(総バイト数)の算出 int szimage = line * ly; // ** メモリ上にイメージファイルを作成 // ** イメージファイル作成用バッファ int imagefilesize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + szimage + 2; BYTE *buf = new BYTE[imagefilesize]; // ** イメージファイル用のポインタを設定 // イメージファイルの構成:BITMAPFILEHEADER + BITMAPINFOHEADER + pdata[] BITMAPFILEHEADER *pbmfh = (BITMAPFILEHEADER *)buf; // バッファの1番目に BITMAPFILEHEADER 構造体を格納しそれを参照するために BYTE 型配列の // 先頭アドレス buf を BITMAPFILEHEADER 型にキャストしてポインタ *pbmfh に格納. // これによりポインタ pbmfh を使ってバッファ内の BITMAPFILEHEADER のメンバを参照できる BITMAPINFOHEADER *pbmih = (BITMAPINFOHEADER *)(buf + sizeof(BITMAPFILEHEADER)); // バッファの2番目に BITMAPINFOHEADER 構造体を格納しそれを参照するために、それが // 格納されるアドレスを BITMAPINFOHEADER 型にキャストしてポインタ *pbmih に格納. // これによりポインタ pbmih を使ってバッファ内の BITMAPINFOHEADER のメンバを参照できる BYTE *pdata = buf + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // バッファの3番目に BYTE 型1次元配列 pdata[] を格納しそれを参照するために、それが // 格納されるアドレスをポインタ *pdata に格納. // これによりポインタ pdata を使ってバッファ内の1次元配列 pdata[] を参照できる // ** BITMAPFILEHEADER 型構造体のメンバーを指定してイメージファイルに格納 pbmfh->bfType = 0x4D42; // ファイルタイプ:常に"BM"(0x4D42 or 19778) pbmfh->bfSize = 54L+(long)(szimage)+2L; // ファイル全体のサイズ(ダミー追加) // pbmfh->bfSize = 54L+(long)(lx*ly*3); では 4 の倍数にならないためエラーになるので要注意 pbmfh->bfReserved1 = 0; // 予約:常に0 pbmfh->bfReserved2 = 0; // 予約:常に0 pbmfh->bfOffBits = 54L; // BITMAPイメージまでのオフセット値(ヘッダサイズ) // ** BITMAPINFOHEADER型構造体のメンバーを指定してイメージファイルに格納 pbmih->biSize = 40L; // BITMAPINFOHEADERのサイズ(バイト数) pbmih->biWidth = (long)lx; // BITMAPイメージの横幅(画素数) pbmih->biHeight = (long)ly; // BITMAPイメージの縦幅(画素数) pbmih->biPlanes = 1; // 対象デバイスのカラープレーン数:常に1 pbmih->biBitCount = 24; // 画素当たりのビット数(1,4,8,24ビット) pbmih->biCompression = 0L; // BITMAPの圧縮形式:非圧縮0 pbmih->biSizeImage = 0L; // BITMAPイメージサイズ(バイト数) pbmih->biXPelsPerMeter = 0L; // 1m当たりの水平解像度(ピクセル単位) pbmih->biYPelsPerMeter = 0L; // 1m当たりの垂直解像度(ピクセル単位) pbmih->biClrUsed = 0L; // 使用されるカラーインデックス数:通常0 pbmih->biClrImportant = 0L; // 表示に必要なカラーインデックス数:通常0 // コンストラクタで初期化されたウィンドウハンドル(hWnd = m_hWnd)を取得 HWND hwnd = hWnd; // ウィンドウデバイスコンテキスト(ディスプレイ用メモリ)のハンドル hDC を取得 HDC hDC = ::GetDC(hwnd); // ** ビットマップオブジェクトとして、デバイスコンテキストに依存しない DIBSECTION を作成し // そのハンドルをグローバル変数 HBMP に取得 BYTE *pbits; // イメージデータ格納用の配列を生成 HBMP = ::CreateDIBSection // Win32 API (0, // デバイスコンテキストのハンドル. DIBSECTION は // デバイスコンテキストに依存しないため 0 を指定 (BITMAPINFO *)pbmih, // BITMAPINFO 構造体のポインタを指定 // BITMAPINFO は BITMAPINFOHEADER と RGBQUAD をまとめた構造体につき、 // BITMAPINFOHEADER 構造体のポインタ pbmih を BITMAPINFO にキャスト DIB_RGB_COLORS, // 常に DIB_RGB_COLORS を指定 (void **)&pbits, // イメージデータ格納用配列 pbits の先頭アドレスを指定 // これによりイメージデータの格納に必要なメモリーが確保される 0, // メモリーマップトファイルを使用する場合に指定 0); // 通常は 0 を指定 // CreateDIBSection で割り当てたメモリーのアドレスが DIBSECTION のハンドルとして // HBMP に渡される // ウィンドウデバイスコンテキスト(ディスプレイ用メモリ) hDC と互換性のある // メモリデバイスコンテキスト hdcmem を作成 HDC hdcmem = CreateCompatibleDC(hDC); // 作成したメモリデバイスコンテキスト hdcmem にビットマップオブジェクト(DIBSECTION) を選択し // 元のビットマップは OldDib に保存 HBITMAP OldDib = (HBITMAP)::SelectObject(hdcmem, HBMP); // ** 関数内で描画する場合の例:BitBlt を実行する前に記述したものが有効 // pdc->TextOut(10, 5, "WriteWin_test", 13); // ウィンドウデバイスコンテキスト(ディスプレイ用メモリ) hDC に取得されているイメージデータを // メモリデバイスコンテキスト hdcMem にコピー BitBlt(hdcmem, 0, 0, Width, Height, hDC, 0, 0, SRCCOPY); // ウィンドウ(hDC)上の (0, 0) を基点とするイメージデータ(ビットマップ画像)を // メモリデバイスコンテキスト(hdcmem)上の (0, 0) に、横 Width, 縦 Height のサイズで // コピー転送(SRCCOPY) // これにより、ウィンドウの全領域が切り取られて // メモリデバイスコンテキスト hdcmem のイメージデータ格納用配列 pbits に保存される // ** イメージデータの書き込み // ** イメージファイルに確保されたメモリ pdata に DIBSECTION 内のイメージデータ pbits をコピー memcpy(pdata, pbits, szimage); // バッファ間でデータコピー:pbits よりイメージデータサイズ(szimage)分を pdata にコピー // ** 書き込み用にファイルをオープン CFile file; if(!file.Open( filepath, // 目的とするファイルへのパスを表す文字列を指定 CFile::modeCreate | CFile::modeWrite | CFile::typeBinary )) { // ファイルの共有モードとアクセスモードを指定 // ファイルのパス(filename)を指定し書き込みモード・バイナリモードでファイルをオープン // fp=_open(filepath, _O_WRONLY|_O_CREAT|_O_BINARY); に相当 return; } // ** イメージファイルの書き込み file.Write(buf, imagefilesize); // CFile オブジェクトに関連付けられたファイル file に // バッファ buf 内のデータを全て(サイズ:imagefilesize) 書き込む // _write(fp, buf, imagefilesize); に相当 // ** ファイルクローズ file.Close(); // このオブジェクトに関連付けられているファイルを閉じ、 // ファイルに対する読み出しや書き込みをできないようにする // ** メモリの解放 // メモリデバイスコンテキスト hdcmem に元のビットマップ OldDib を選択 ::SelectObject(hdcmem, OldDib); // 作成したビットマップオブジェクト(DIBSECTION)を削除 ::DeleteObject(HBMP); // 作成したメモリデバイスコンテキスト hdcmem を削除 ::DeleteObject(hdcmem); // ウィンドウデバイスコンテキスト hDC を解放 ::ReleaseDC(hwnd, hDC); } // usage : w.WriteWin(filepath); // ** メンバ関数 WriteWin(#2) の実装 // ** ビットマップオブジェクト(DIBSECTION)を介して、ウィンドウ(m_hWnd)の長方形領域 // (x, y)−(x + width, y + height) よりビットマップ画像を切り出し、イメージファイルを作成して // filepath のファイルに書き込む void View2D::WriteWin(HWND m_hWnd, CString filepath, int x, int y, int width, int height) { int lx = width; // x方向画素数 int ly = height; // y方向画素数 // ** パディング:ダミー画素の算出(4の倍数問題に対応) int dummy; if(lx % 4 == 0) dummy = 0; else dummy = int(4-(lx*3)%4); // 水平画素数 lx が 4 の倍数になっていない場合は、1 ラインの総バイト数が 4 の倍数になる // ようにダミーデータを各ラインの最後に書き込む // 例えば lx = 430 の場合は dummy = 2 個の空の画素をラインの最後に書き込む // ** 1ラインのバイト数の算出 int line = lx * 3 + dummy; // イメージデータサイズ(総バイト数)の算出 int szimage = line * ly; // ** メモリ上にイメージファイルを作成 // ** イメージファイル作成用バッファ int imagefilesize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + szimage + 2; BYTE *buf = new BYTE[imagefilesize]; // ** イメージファイル用のポインタを設定 // イメージファイルの構成:BITMAPFILEHEADER + BITMAPINFOHEADER + pdata[] BITMAPFILEHEADER *pbmfh = (BITMAPFILEHEADER *)buf; // バッファの1番目に BITMAPFILEHEADER 構造体を格納しそれを参照するために BYTE 型配列の // 先頭アドレス buf を BITMAPFILEHEADER 型にキャストしてポインタ *pbmfh に格納. // これによりポインタ pbmfh を使ってバッファ内の BITMAPFILEHEADER のメンバを参照できる BITMAPINFOHEADER *pbmih = (BITMAPINFOHEADER *)(buf + sizeof(BITMAPFILEHEADER)); // バッファの2番目に BITMAPINFOHEADER 構造体を格納しそれを参照するために、それが // 格納されるアドレスを BITMAPINFOHEADER 型にキャストしてポインタ *pbmih に格納. // これによりポインタ pbmih を使ってバッファ内の BITMAPINFOHEADER のメンバを参照できる BYTE *pdata = buf + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // バッファの3番目に BYTE 型1次元配列 pdata[] を格納しそれを参照するために、それが // 格納されるアドレスをポインタ *pdata に格納. // これによりポインタ pdata を使ってバッファ内の1次元配列 pdata[] を参照できる // ** BITMAPFILEHEADER 型構造体のメンバーを指定してイメージファイルに格納 pbmfh->bfType = 0x4D42; // ファイルタイプ:常に"BM"(0x4D42 or 19778) pbmfh->bfSize = 54L+(long)(szimage)+2L; // ファイル全体のサイズ(ダミー追加) // pbmfh->bfSize = 54L+(long)(lx*ly*3); では 4 の倍数にならないためエラーになるので要注意 pbmfh->bfReserved1 = 0; // 予約:常に0 pbmfh->bfReserved2 = 0; // 予約:常に0 pbmfh->bfOffBits = 54L; // BITMAPイメージまでのオフセット値(ヘッダサイズ) // ** BITMAPINFOHEADER型構造体のメンバーを指定してイメージファイルに格納 pbmih->biSize = 40L; // BITMAPINFOHEADERのサイズ(バイト数) pbmih->biWidth = (long)lx; // BITMAPイメージの横幅(画素数) pbmih->biHeight = (long)ly; // BITMAPイメージの縦幅(画素数) pbmih->biPlanes = 1; // 対象デバイスのカラープレーン数:常に1 pbmih->biBitCount = 24; // 画素当たりのビット数(1,4,8,24ビット) pbmih->biCompression = 0L; // BITMAPの圧縮形式:非圧縮0 pbmih->biSizeImage = 0L; // BITMAPイメージサイズ(バイト数) pbmih->biXPelsPerMeter = 0L; // 1m当たりの水平解像度(ピクセル単位) pbmih->biYPelsPerMeter = 0L; // 1m当たりの垂直解像度(ピクセル単位) pbmih->biClrUsed = 0L; // 使用されるカラーインデックス数:通常0 pbmih->biClrImportant = 0L; // 表示に必要なカラーインデックス数:通常0 // ウィンドウデバイスコンテキスト(ディスプレイ用メモリ)のハンドル hDC を取得 HDC hDC = ::GetDC(m_hWnd); // ** ビットマップオブジェクトとして、デバイスコンテキストに依存しない DIBSECTION を作成し // そのハンドルをグローバル変数 HBMP に取得 BYTE *pbits; // イメージデータ格納用の配列を生成 HBMP = ::CreateDIBSection // Win32 API (0, // デバイスコンテキストのハンドル. DIBSECTION は // デバイスコンテキストに依存しないため 0 を指定 (BITMAPINFO *)pbmih, // BITMAPINFO 構造体のポインタを指定 // BITMAPINFO は BITMAPINFOHEADER と RGBQUAD をまとめた構造体につき、 // BITMAPINFOHEADER 構造体のポインタ pbmih を BITMAPINFO にキャスト DIB_RGB_COLORS, // 常に DIB_RGB_COLORS を指定 (void **)&pbits, // イメージデータ格納用配列 pbits の先頭アドレスを指定 // これによりイメージデータの格納に必要なメモリーが確保される 0, // メモリーマップトファイルを使用する場合に指定 0); // 通常は 0 を指定 // CreateDIBSection で割り当てたメモリーのアドレスが DIBSECTION のハンドルとして // HBMP に渡される // ウィンドウデバイスコンテキスト(ディスプレイ用メモリ) hDC と互換性のある // メモリデバイスコンテキスト hdcmem を作成 HDC hdcmem = CreateCompatibleDC(hDC); // 作成したメモリデバイスコンテキスト hdcmem にビットマップオブジェクト(DIBSECTION) を選択し // 元のビットマップは OldDib に保存 HBITMAP OldDib = (HBITMAP)::SelectObject(hdcmem, HBMP); // ** 関数内で描画する場合の例:BitBlt を実行する前に記述したものが有効 // pdc->TextOut(10, 5, "WriteWin_test", 13); // ウィンドウデバイスコンテキスト(ディスプレイ用メモリ) hDC に取得されているイメージデータを // メモリデバイスコンテキスト hdcMem にコピー BitBlt(hdcmem, 0, 0, width, height, hDC, x, y, SRCCOPY); // ウィンドウ(hDC)上の (x, y) を基点とするイメージデータ(ビットマップ画像)を // メモリデバイスコンテキスト(hdcmem)上の (0, 0) に、横 width, 縦 height のサイズで // コピー転送(SRCCOPY) // これにより、ウィンドウの長方形領域 (x, y)-(x + width, y + height) が切り取られて // メモリデバイスコンテキスト hdcmem のイメージデータ格納用配列 pbits に保存される // ** イメージデータの書き込み // ** イメージファイルに確保されたメモリ pdata に DIBSECTION 内のイメージデータ pbits をコピー memcpy(pdata, pbits, szimage); // バッファ間でデータコピー:pbits よりイメージデータサイズ(szimage)分を pdata にコピー // ** 書き込み用にファイルをオープン CFile file; if(!file.Open( filepath, // 目的とするファイルへのパスを表す文字列を指定 CFile::modeCreate | CFile::modeWrite | CFile::typeBinary )) { // ファイルの共有モードとアクセスモードを指定 // ファイルのパス(filename)を指定し書き込みモード・バイナリモードでファイルをオープン // fp=_open(filepath, _O_WRONLY|_O_CREAT|_O_BINARY); に相当 return; } // ** イメージファイルの書き込み file.Write(buf, imagefilesize); // CFile オブジェクトに関連付けられたファイル file に // バッファ buf 内のデータを全て(サイズ:imagefilesize) 書き込む // _write(fp, buf, imagefilesize); に相当 // ** ファイルクローズ file.Close(); // このオブジェクトに関連付けられているファイルを閉じ、 // ファイルに対する読み出しや書き込みをできないようにする // ** メモリの解放 // メモリデバイスコンテキスト hdcmem に元のビットマップ OldDib を選択 ::SelectObject(hdcmem, OldDib); // 作成したビットマップオブジェクト(DIBSECTION)を削除 ::DeleteObject(HBMP); // 作成したメモリデバイスコンテキスト hdcmem を削除 ::DeleteObject(hdcmem); // ウィンドウデバイスコンテキスト hDC を解放 ::ReleaseDC(m_hWnd, hDC); } // usage : w.WriteWin(m_hWnd, filepath, 10, 10, 512, 512); // ** SetWinColor の実装 ** // ** ウィンドウの背景色を設定(default は白色) COLORREF View2D::SetWinColor(Color c) { COLORREF col = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 WinColor = col; // グローバル変数 WinColor を初期化 CRect wrect; // 描画領域(長方形)を宣言 pdc->GetClipBox(&wrect); // ウィンドウの表示領域(長方形)を取得 CBrush *oldbrush, newbrush(col); // 描画用カラーブラシを作成 oldbrush = pdc->SelectObject(&newbrush); // 作成した描画用新ブラシを選択し旧ブラシを保存 pdc->PatBlt(wrect.left, wrect.top, wrect.Width(), wrect.Height(), PATCOPY); // 指定の長方形(ウィンドウ)を現在のブラシでペイント pdc->SelectObject(oldbrush); // 元の旧ブラシに戻しておく newbrush.DeleteObject(); // 作成した新ブラシを削除しておく return col; } // usage : w.SetWinColor(c); or COLORREF WinColor = w.SetWinColor(c); // ** StrColor 関数の実装 ** // ** スクリーン座標に描画する文字列の色を設定 void View2D::StrColor(Color c) { COLORREF col = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 pdc->SetTextColor(col); // 文字色を設定 } // usage : w.StrColor(BLUE); // ** StrFont 関数の実装 ** // ** スクリーン座標に描画する文字列のフォントとサイズを設定 CFont *View2D::StrFont(int size, CString font) { CFont *oldFont, newFont; // フォント操作の CFont クラスオブジェクトを宣言 newFont.CreatePointFont(size * 10, font); // 新しいフォントを設定 // ポイントサイズ size で font の新しいフォントを作成 oldFont = pdc->SelectObject(&newFont); // 描画オブジェクト newFont を DC (デバイスコンテキスト) に設定し // 元のフォント情報を oldFont に取得 newFont.DeleteObject(); // フォント情報を削除 // (新フォントのために)新たに作成されたメモリ領域を解放しフォント情報を削除 return oldFont; // 元のフォント情報 oldFont を返す } // usage : CFont *oldfont = w.StrFont(pDC, 15, font = "MS ゴシック"); // ** ReturnFont 関数の実装 ** // ** StrFont 関数で設定したフォントを元に戻す void View2D::ReturnFont(CFont *oldfont) { pdc->SelectObject(oldfont); // フォントを元の oldfont 戻す // 描画オブジェクト oldfont を DC (デバイスコンテキスト) に設定 } // usage : w.ReturnFont(pDC, oldfont); // ** PutString(#1) 関数の実装 ** // ** スクリーン座標 (x, y) に CString 文字列を Color で描画 void View2D::PutString(int x, int y, CString str, Color c) { COLORREF color = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 pdc->SetBkColor(WinColor); // 文字の背景色をウィンドウの背景色に合わせる COLORREF oldcolor = pdc->SetTextColor(color); // 元の文字色を取得してから文字色を変更 pdc->TextOut(x, y, str); // 文字を出力 pdc->SetTextColor(oldcolor); // 文字色を元に戻す } // usage : w.PutString(10, 10, string, Color(0.5,0.5,0.5)); // ** PutString(#2) 関数の実装 ** // ** スクリーン座標 (x, y) に char* 文字列を Color で描画 void View2D::PutString(int x, int y, char* text, Color c) { COLORREF color = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 pdc->SetBkColor(WinColor); // 文字の背景色をウィンドウの背景色に合わせる COLORREF oldcolor = pdc->SetTextColor(color); // 元の文字色を取得してから文字色を変更 CString str; str = text; pdc->TextOut(x, y, str); // 文字を出力 pdc->SetTextColor(oldcolor); // 文字色を元に戻す } // usage : w.PutString(10, 10, "Test Program", Color(0.5,0.5,0.5)); // ** Wprintf 関数の実装 ** // ** スクリーン座標 (x, y) に書式付きで数値データを表示 // double, int 型の数値を最大 10 までウィンドウに表示(書式付き printf に近似させた関数) void View2D::Wprintf(int x, int y, char* text, double a0, double a1, double a2, double a3, double a4, double a5, double a6, double a7, double a8, double a9) { // int 型は double 型に変換されて表示される char buf[100]; sprintf(buf, text, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); // 文字列に変換 CString str; str = buf; pdc->TextOut(x, y, str, (int)strlen(buf)); // 文字を出力 // pdc->TextOut(x, y, str); // 文字を出力 } // usage : w.Wprintf(10, 10, "a = %3.2f", a); // ** SetPen 関数の実装 ** // ** 描画用ペンの色 c と太さ(ドットサイズ) dot を設定 void View2D::SetPen(CPen& pen, Color c, int dot) { COLORREF col = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 pen.DeleteObject(); // 作成されたペンがあれば削除しておく pen.CreatePen(PS_SOLID, dot, col); // 実線描画用ペンを作成 pdc->SelectObject(&pen); // 作成した描画用ペンを選択 } // usage : w.SetPen(pen, BLACK, 5); // ** Move 関数の実装 ** // ** 描画用ペンをスクリーン座標 (x, y) に移動 void View2D::Move(int x, int y) { pdc->MoveTo(x, y); // 移動 } // usage : w.Move(10, 10); // ** Line(#1) 関数の実装 ** // ** スクリーン座標で現在のペン位置と (x, y) を色 c, ドットサイズ dot の実線で描画 void View2D::Line(int x, int y, Color c, int dot) { COLORREF color = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 CPen *oldpen, newpen; // CPen クラス・オブジェクト宣言 newpen.CreatePen(PS_SOLID, dot, color); // 実線描画用ペンを作成 oldpen = pdc->SelectObject(&newpen); // 作成した描画用ペンを選択 pdc->LineTo(x, y); // 直線描画 pdc->SelectObject(oldpen); // ペンを元に戻しておく newpen.DeleteObject(); // 作成したペンは削除しておく } // usage : w.Line(10, 10, RED, 2); // ** Line(#2) 関数の実装 ** // ** スクリーン座標 (x1, y1) と (x2, y2) を色 c, ドットサイズ dot の実線で描画 void View2D::Line(int x1, int y1, int x2, int y2, Color c, int dot) { COLORREF color = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 CPen *oldpen, newpen; // CPen クラス・オブジェクト宣言 newpen.CreatePen(PS_SOLID, dot, color); // 実線描画用ペンを作成 oldpen = pdc->SelectObject(&newpen); // 作成した描画用ペンを選択 pdc->MoveTo(x1, y1); // 2 点間を直線描画 pdc->LineTo(x2, y2); pdc->SelectObject(oldpen); // ペンを元に戻しておく newpen.DeleteObject(); // 作成したペンは削除しておく } // usage : w.Line(10, 10, 20, 20, RED, 2); // ** Square 関数の実装 ** // ** スクリーン座標 (x1, y1)−(x2, y2) を対角頂点とするの四角形を色 c, ドットサイズ dot で描画 void View2D::Square(int x1, int y1, int x2, int y2, Color c, int dot) { COLORREF color = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 CPen *oldpen, newpen; // CPen クラス・オブジェクト宣言 newpen.CreatePen(PS_SOLID, dot, color); // 実線描画用ペンを作成 oldpen = pdc->SelectObject(&newpen); // 作成した描画用ペンを選択 pdc->MoveTo(x1, y1); // 4 点間を直線描画 pdc->LineTo(x2, y1); pdc->LineTo(x2, y2); pdc->LineTo(x1, y2); pdc->LineTo(x1, y1); pdc->SelectObject(oldpen); // ペンを元に戻しておく newpen.DeleteObject(); // 作成したペンは削除しておく } // usage : w.Square(10, 10, 40, 40, CYAN, 2); // ** Circle 関数の実装 ** // ** スクリーン座標 (x, y) を中心に半径 r の円を色 c、ドットサイズ dot, n 分割で描画 void View2D::Circle(int x, int y, int r, Color c, int dot, int n) { COLORREF color = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 CPen *oldpen, newpen; // CPen クラス・オブジェクト宣言 newpen.CreatePen(PS_SOLID, dot, color); // 実線描画用ペンを作成 oldpen = pdc->SelectObject(&newpen); // 作成した描画用ペンを選択 int i, xx, yy; for ( i = 0; i<=360; i = i + n) { xx = (int)(x + r * cos(i * RAD)); yy = (int)(y - r * sin(i * RAD)); if (i == 0) pdc->MoveTo(xx, yy); // 2 点間を直線描画 else pdc->LineTo(xx, yy); } pdc->SelectObject(oldpen); // ペンを元に戻しておく newpen.DeleteObject(); // 作成したペンは削除しておく } // usage : w.Circle(50, 50, 30, BLUE, 2, 5); // ** PutDot 関数の実装 ** // ** スクリーン座標 (x, y) に色 c 、ドットサイズ dot で点を描画 void View2D::PutDot(int x, int y, Color c, int dot) { COLORREF col = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 CPen *oldpen, newpen; // CPen クラス・オブジェクト宣言 newpen.CreatePen(PS_SOLID, dot, col); // 実線描画用ペンを作成 oldpen = pdc->SelectObject(&newpen); // 作成した描画用ペンを選択 pdc->MoveTo(x, y); // ドットサイズ1以上で点描画するために pdc->LineTo(x, y); // 関数 MoveTo / LineTo を使用 pdc->SelectObject(oldpen); // ペンを元に戻しておく newpen.DeleteObject(); // 作成したペンは削除しておく } // usage : w.PutDot(10, 10, RED, 5); // ** PutPixel 関数の実装 ** // ** スクリーン座標 (x, y) に色 c で画素点を描画 void View2D::PutPixel(int x, int y, Color c) { COLORREF color = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 pdc->SetPixel(x, y, color); // 画素点を描画 } // usage : w.PutPixel(10, 10, BLUE); // ** GetClientSize 関数の実装 ** // ** 描画領域(クライアント領域)のサイズを取得 CSize View2D::GetClientSize(HWND hWnd) { CRect crect; ::GetClientRect(hWnd, crect); // クライアント矩形領域を取得 int width = crect.right - crect.left; int height= crect.bottom - crect.top; CSize clsize; clsize.cx = width; clsize.cy = height; return clsize; } // ******** View2D クラス外で使用するウィンドウ描画関数 ******************************************* // ** SetWinColor の実装 ** // ** ウィンドウの背景色を設定(default は白色) COLORREF SetWinColor(CDC* pdc, Color c) { COLORREF col = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 WinColor = col; // グローバル変数 WinColor を初期化 CRect wrect; // 描画領域(長方形)を宣言 pdc->GetClipBox(&wrect); // ウィンドウの表示領域(長方形)を取得 CBrush *oldbrush, newbrush(col); // 描画用カラーブラシを作成 oldbrush = pdc->SelectObject(&newbrush); // 作成した描画用新ブラシを選択し旧ブラシを保存 pdc->PatBlt(wrect.left, wrect.top, wrect.Width(), wrect.Height(), PATCOPY); // 指定の長方形(ウィンドウ)を現在のブラシでペイント pdc->SelectObject(oldbrush); // 元の旧ブラシに戻しておく newbrush.DeleteObject(); // 作成した新ブラシを削除しておく return col; } // usage : SetWinColor(pDC, c); or COLORREF WinColor = SetWinColor(pDC, c); // ** StrColor 関数の実装 ** // ** スクリーン座標に描画する文字列の色を設定 void StrColor(CDC* pdc, Color c) { COLORREF col = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 pdc->SetTextColor(col); // 文字色を設定 } // usage : StrColor(pDC, BLUE); // ** StrFont 関数の実装 ** // ** スクリーン座標に描画する文字列のフォントとサイズを設定 CFont *StrFont(CDC* pdc, int size, CString font) { CFont *oldFont, newFont; // フォント操作の CFont クラスオブジェクトを宣言 newFont.CreatePointFont(size * 10, font); // 新しいフォントを設定 // ポイントサイズ size で font の新しいフォントを作成 oldFont = pdc->SelectObject(&newFont); // 描画オブジェクト newFont を DC (デバイスコンテキスト) に設定し // 元のフォント情報を oldFont に取得 newFont.DeleteObject(); // フォント情報を削除 // (新フォントのために)新たに作成されたメモリ領域を解放しフォント情報を削除 return oldFont; // 元のフォント情報 oldFont を返す } // usage : CFont *oldfont = StrFont(pDC, 15, font = "MS ゴシック"); // ** ReturnFont 関数の実装 ** // ** StrFont 関数で設定したフォントを元に戻す void ReturnFont(CDC* pdc, CFont *oldfont) { pdc->SelectObject(oldfont); // フォントを元の oldfont 戻す // 描画オブジェクト oldfont を DC (デバイスコンテキスト) に設定 } // usage : ReturnFont(pDC, oldfont); // ** PutString(#1) 関数の実装 ** // ** スクリーン座標 (x, y) に CString 文字列を Color で描画 void PutString(CDC* pdc, int x, int y, CString str, Color c) { COLORREF color = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 pdc->SetBkColor(WinColor); // 文字の背景色をウィンドウの背景色に合わせる COLORREF oldcolor = pdc->SetTextColor(color); // 元の文字色を取得してから文字色を変更 pdc->TextOut(x, y, str); // 文字を出力 pdc->SetTextColor(oldcolor); // 文字色を元に戻す } // usage : PutString(pDC, 10, 10, string, Color(0.5,0.5,0.5)); // ** PutString(#2) 関数の実装 ** // ** スクリーン座標 (x, y) に char* 文字列を Color で描画 void PutString(CDC* pdc, int x, int y, char* text, Color c) { COLORREF color = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 pdc->SetBkColor(WinColor); // 文字の背景色をウィンドウの背景色に合わせる COLORREF oldcolor = pdc->SetTextColor(color); // 元の文字色を取得してから文字色を変更 CString str; str = text; pdc->TextOut(x, y, str); // 文字を出力 pdc->SetTextColor(oldcolor); // 文字色を元に戻す } // usage : w.PutString(10, 10, "Test Program", Color(0.5,0.5,0.5)); // ** Wprintf 関数の実装 ** // ** スクリーン座標 (x, y) に書式付きで数値データを表示 // double, int 型の数値を最大 10 までウィンドウに表示(書式付き printf に近似させた関数) void Wprintf(CDC* pdc, int x, int y, char* text, double a0, double a1, double a2, double a3, double a4, double a5, double a6, double a7, double a8, double a9) { // int 型は double 型に変換されて表示される char buf[100]; sprintf(buf, text, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); // 文字列に変換 CString str; str = buf; pdc->TextOut(x, y, str, (int)strlen(buf)); // 文字を出力 // pdc->TextOut(x, y, str); // 文字を出力 } // usage : Wprintf(pDC, 10, 10, "a = %3.2f", a); // ** SetPen 関数の実装 ** // ** 描画用ペンの色 c と太さ(ドットサイズ) dot を設定 void SetPen(CDC* pdc, CPen& pen, Color c, int dot) { COLORREF col = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 pen.DeleteObject(); // 作成されたペンがあれば削除しておく pen.CreatePen(PS_SOLID, dot, col); // 実線描画用ペンを作成 pdc->SelectObject(&pen); // 作成した描画用ペンを選択 } // usage : SetPen(pDC, pen, BLACK, 5); // ** Move 関数の実装 ** // ** 描画用ペンをスクリーン座標 (x, y) に移動 void Move(CDC* pdc, int x, int y) { pdc->MoveTo(x, y); // 移動 } // usage : Move(pDC, 10, 10); // ** Line(#1) 関数の実装 ** // ** スクリーン座標で現在のペン位置と 点(x, y) を色 c, ドットサイズ dot で実線描画 void Line(CDC* pdc, int x, int y, Color c, int dot) { COLORREF color = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 CPen *oldpen, newpen; // CPen クラス・オブジェクト宣言 newpen.CreatePen(PS_SOLID, dot, color); // 実線描画用ペンを作成 oldpen = pdc->SelectObject(&newpen); // 作成した描画用ペンを選択 pdc->LineTo(x, y); // 直線描画 pdc->SelectObject(oldpen); // ペンを元に戻しておく newpen.DeleteObject(); // 作成したペンは削除しておく } // usage : Line(pDC, 20, 20, BLUE, 5); // ** Line(#2) 関数の実装 ** // ** スクリーン座標 (x1, y1) と (x2, y2) を色 c, ドットサイズ dot で実線描画 void Line(CDC* pdc, int x1, int y1, int x2, int y2, Color c, int dot) { COLORREF color = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 CPen *oldpen, newpen; // CPen クラス・オブジェクト宣言 newpen.CreatePen(PS_SOLID, dot, color); // 実線描画用ペンを作成 oldpen = pdc->SelectObject(&newpen); // 作成した描画用ペンを選択 pdc->MoveTo(x1, y1); // 2 点間を直線描画 pdc->LineTo(x2, y2); pdc->SelectObject(oldpen); // ペンを元に戻しておく newpen.DeleteObject(); // 作成したペンは削除しておく } // usage : Line(pDC, 10, 10, 20, 20, RED, 2); // ** Square 関数の実装 ** // ** スクリーン座標 (x1, y1)−(x2, y2) を対角頂点とする四角形を色 c, ドットサイズ dot で描画 void Square(CDC* pdc, int x1, int y1, int x2, int y2, Color c, int dot) { COLORREF color = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 CPen *oldpen, newpen; // CPen クラス・オブジェクト宣言 newpen.CreatePen(PS_SOLID, dot, color); // 実線描画用ペンを作成 oldpen = pdc->SelectObject(&newpen); // 作成した描画用ペンを選択 pdc->MoveTo(x1, y1); // 4 点間を直線描画 pdc->LineTo(x2, y1); pdc->LineTo(x2, y2); pdc->LineTo(x1, y2); pdc->LineTo(x1, y1); pdc->SelectObject(oldpen); // ペンを元に戻しておく newpen.DeleteObject(); // 作成したペンは削除しておく } // usage : Square(pDC, 10, 10, 40, 40, CYAN, 2); // ** Circle 関数の実装 ** // ** スクリーン座標 (x, y) を中心に半径 r の円を色 c, ドットサイズ dot, n 分割で描画 void Circle(CDC* pdc, int x, int y, int r, Color c, int dot, int n) { COLORREF color = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 CPen *oldpen, newpen; // CPen クラス・オブジェクト宣言 newpen.CreatePen(PS_SOLID, dot, color); // 実線描画用ペンを作成 oldpen = pdc->SelectObject(&newpen); // 作成した描画用ペンを選択 int i, xx, yy; for ( i = 0; i <= 360; i = i + n) { xx = (int)(x + r * cos(i * RAD)); yy = (int)(y - r * sin(i * RAD)); if (i == 0) pdc->MoveTo(xx, yy); // 2 点間を直線描画 else pdc->LineTo(xx, yy); } pdc->SelectObject(oldpen); // ペンを元に戻しておく newpen.DeleteObject(); // 作成したペンは削除しておく } // usage : Circle(pDC, 50, 50, 30, BLUE, 2, 5); // ** PutDot 関数の実装 ** // ** スクリーン座標 (x, y) に色 c 、ドットサイズ dot で点を描画 void PutDot(CDC* pdc, int x, int y, Color c, int dot) { COLORREF col = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 CPen *oldpen, newpen; // CPen クラス・オブジェクト宣言 newpen.CreatePen(PS_SOLID, dot, col); // 実線描画用ペンを作成 oldpen = pdc->SelectObject(&newpen); // 作成した描画用ペンを選択 pdc->MoveTo(x, y); // ドットサイズ1以上で点描画するために pdc->LineTo(x, y); // 関数 MoveTo / LineTo を使用 pdc->SelectObject(oldpen); // ペンを元に戻しておく newpen.DeleteObject(); // 作成したペンは削除しておく } // usage : PutDot(pDC, 10, 10, RED, 5); // ** PutPixel 関数の実装 ** // ** スクリーン座標 (x, y) に色 c で画素点を描画 void PutPixel(CDC* pdc, int x, int y, Color c) { COLORREF color = RGB(255 * c.R, 255 * c.G, 255 * c.B); // Color を COLORREF に変換 pdc->SetPixel(x, y, color); // 画素点を描画 } // usage : PutPixel(pDC, 10, 10, BLUE); // ** GetImageSize(#1) 関数の実装 ** // ファイルパス CString filepath の BMP イメージサイズの取得 CSize GetImageSize(CString filepath) { // ** 引数のファイルをオープン CFile file; if(!file.Open( filepath, // 目的とするファイルへのパスを表す文字列を指定 CFile::modeRead | CFile::typeBinary // ファイルの共有モードとアクセスモードを指定 )) { // ファイルのパス(filename)を指定し、読取モード・バイナリモードでファイルをオープン // fp=_open(fname, _O_RDONLY|_O_BINARY); に相当 return NULL; } // ** BMP ファイルの先頭ヘッダー BITMAPFILEHEADER を読み込む BITMAPFILEHEADER bmfh; if(file.Read(&bmfh, sizeof(bmfh)) != sizeof(bmfh)) { AfxThrowArchiveException(CArchiveException::endOfFile); } // ** BITMAPFILEHEADER のファイルタイプ(bfType)をチェック if(bmfh.bfType != 0x4d42){ // "BM" AfxThrowArchiveException(CArchiveException::badIndex); } // ** BMP ファイルの2番目のヘッダー BITMAPINFOHEADER を読み込む BITMAPINFOHEADER bmih; if(file.Read(&bmih, sizeof(bmih)) != sizeof(bmih)) { AfxThrowArchiveException(CArchiveException::endOfFile); } // ** ビットマップイメージサイズの取得 (SIZE 構造体に取得) CSize imgsize; imgsize.cx = bmih.biWidth; // ** x方向画素数取得 imgsize.cy = bmih.biHeight; // ** y方向画素数取得 return imgsize; } // usage : CSize imagesize = GetImageSize(filepath); // ** メンバ関数 GetImageSize(#2) の実装 // ** ファイルパス char* filename の BMP イメージサイズの取得 CSize GetImageSize(char* filename) { // ** 引数のファイルをオープン CFile file; CString filepath; filepath = filename; if(!file.Open( filepath, // 目的とするファイルへのパスを表す文字列を指定 CFile::modeRead | CFile::typeBinary // ファイルの共有モードとアクセスモードを指定 )) { // ファイルのパス(filepath)を指定し、読取モード・バイナリモードでファイルをオープン // fp=_open(fname, _O_RDONLY|_O_BINARY); に相当 return NULL; } // ** BMP ファイルの先頭ヘッダー BITMAPFILEHEADER を読み込む BITMAPFILEHEADER bmfh; if(file.Read(&bmfh, sizeof(bmfh)) != sizeof(bmfh)) { AfxThrowArchiveException(CArchiveException::endOfFile); } // ** BITMAPFILEHEADER のファイルタイプ(bfType)をチェック if(bmfh.bfType != 0x4d42){ // "BM" AfxThrowArchiveException(CArchiveException::badIndex); } // ** BMP ファイルの2番目のヘッダー BITMAPINFOHEADER を読み込む BITMAPINFOHEADER bmih; if(file.Read(&bmih, sizeof(bmih)) != sizeof(bmih)) { AfxThrowArchiveException(CArchiveException::endOfFile); } // ** ビットマップイメージサイズの取得 (SIZE 構造体に取得) CSize imgsize; imgsize.cx = bmih.biWidth; // ** x方向画素数取得 imgsize.cy = bmih.biHeight; // ** y方向画素数取得 return imgsize; } // usage : CSize imagesize = GetImageSize("xxx.bmp");