ホーム > カテゴリ > C/C++ >

ビットマップを保存する(RLE圧縮対応)(C/C++版)

ビットマップを保存する(RLE圧縮対応)サンプルです。

サンプルの実行画面

ソースコード

[Sample79.c]

//--------------------------------------------------------------------------------------
//  ■ビットマップを保存する(RLE圧縮対応)■ Sample NO.79
//
//--------------------------------------------------------------------------------------

#include <windows.h>

HBITMAP hBitmap=NULL;

#define IDM_MENU 100
 #define IDM_SUBMENU1 101
 #define IDM_SUBMENU2 102

int  OpenDiaog(HWND hwnd,LPCSTR Filter,char *FileName,DWORD Flags);
int  SaveDiaog(HWND hwnd,LPCSTR Filter,char *FileName,DWORD Flags);
void SaveBMP(const char *FileName,HBITMAP hBMP);

//ウインドウを中央にする為にX座標(LEFT)とY座標(TOP)算出するマクロ
#define ScreenCenterX(Width) ((0)<((int)((GetSystemMetrics(SM_CXSCREEN)- Width) / 2)) ? ((int)((GetSystemMetrics(SM_CXSCREEN)- Width) / 2)) :(0))
#define ScreenCenterY(Height) ((0)<((int)((GetSystemMetrics(SM_CYSCREEN)- Height) / 2)) ? ((int)((GetSystemMetrics(SM_CYSCREEN)- Height) / 2)) :(0))

//いつものプロシージャ
HWND CreateMainWindow(int Width,int Height,LPCTSTR Caption,HINSTANCE hInstance,int nCmdShow,WNDPROC lpfnWndProc, DWORD dwstyle,DWORD dwExstyle,LPCTSTR MenuID,HICON hIcon);
int  WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow);
LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);

//----------------------------------------------------------
//■関数 SaveBMP
//■用途 ビットマップオブジェクトをファイルに保存する
//■引数
//        FileName       ...親ウインドウのハンドル
//        hBMP           ...ビットマップオブジェクト
//■備考
//      ビットマップオブジェクトはCreateDIBSection()の呼び出し
//      で作成されたビットマップでないとエラーになります。
//----------------------------------------------------------
void SaveBMP(const char *FileName,HBITMAP hBMP)
{
  BITMAPFILEHEADER BMPFileHeader;
  DIBSECTION       DIB;
  HANDLE           hFile=NULL;
  DWORD            Work;
  int              Colors=0; 
  RGBQUAD          *RGBQuad;
  HDC              hMem,hDC;

  //ファイル作成
  hFile = CreateFile(FileName, GENERIC_WRITE, 0,NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, NULL);
  if (hFile!=NULL)
  {
    //初期化
    ZeroMemory(&BMPFileHeader,sizeof(BITMAPFILEHEADER));
    //BITMAPINFO構造体の取得
    GetObject(hBMP, sizeof(DIBSECTION), &DIB);
    
//BITMAPFILEHEADER構造体の設定----->

    BMPFileHeader.bfType=0x4D42;
    //カラーパレットのサイズを計算
    if (DIB.dsBmih.biClrUsed==0)
    {
      switch (DIB.dsBmih.biBitCount)
      {
         case 1:  Colors=2;   break;
         case 4:  Colors=16;  break;
         case 8:  Colors=256; break;
      }
    }
   else
   {
     switch (DIB.dsBmih.biBitCount)
     {
        case 1:  Colors=DIB.dsBmih.biClrUsed;  break;
        case 4:  Colors=DIB.dsBmih.biClrUsed;  break;
        case 8:  Colors=DIB.dsBmih.biClrUsed;  break;
     }        
   }
    //LoadImageで読込んだ画像はbiSizeImageが0の場合は絶対にない。だから、イメージデータサイズを計算しなくてもOK。
    BMPFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+Colors*sizeof(RGBQUAD);
    BMPFileHeader.bfSize=BMPFileHeader.bfOffBits+DIB.dsBmih.biSizeImage;

  //ファイルに書き込み----->

    //BITMAPFILEHEADERの書き込み
    WriteFile(hFile,&BMPFileHeader,sizeof(BITMAPFILEHEADER),&Work,NULL);
    //BITMAPINFOHEADERの書き込み
    WriteFile(hFile,&(DIB.dsBmih),sizeof(BITMAPINFOHEADER),&Work,NULL);
    //カラーパレットの書き込み
    if (Colors!=0)
    {
     hDC=GetDC(0);
     hMem = CreateCompatibleDC(hDC);
     SelectObject(hMem, hBMP);
     RGBQuad=(RGBQUAD *)malloc(Colors*sizeof(RGBQUAD));
     GetDIBColorTable(hMem,0,Colors,RGBQuad);
     WriteFile(hFile,RGBQuad,Colors*sizeof(RGBQUAD),&Work,NULL);
     free(RGBQuad);
     DeleteDC(hMem);    
     ReleaseDC(0,hDC);    
    }
    //イメージデータの書き込み
    WriteFile(hFile,DIB.dsBm.bmBits,DIB.dsBmih.biSizeImage,&Work,NULL);

    CloseHandle(hFile);
  }
}

//------------------------------------------------------
//■関数 OpenDiaog
//■用途 「ファイルを開く」ダイアログを表示する
//■引数
//        hwnd       ...親ウインドウのハンドル
//        Filter     ...フィルター
//        FileName   ...ファイルのフルパス名(戻り値)
//        Flags      ...ダイアログのフラグ
//■戻り値
//      ファイルを選択  true   
//------------------------------------------------------
int OpenDiaog(HWND hwnd,LPCSTR Filter,char *FileName,DWORD Flags)
{
   OPENFILENAME OFN; 

   ZeroMemory(&OFN,sizeof(OPENFILENAME));
   OFN.lStructSize = sizeof(OPENFILENAME); 
   OFN.hwndOwner = hwnd;
   OFN.lpstrFilter =Filter;
   OFN.lpstrFile =FileName;  
   OFN.nMaxFile = MAX_PATH*2;
   OFN.Flags = Flags;    
   OFN.lpstrTitle = "ファイルを開く";
   return (GetOpenFileName(&OFN));
}

//------------------------------------------------------
//■関数 SaveDiaog
//■用途 「名前を付けて保存」ダイアログを表示する
//■引数
//        hwnd       ...親ウインドウのハンドル
//        Filter     ...フィルター
//        FileName   ...ファイルのフルパス名(戻り値)
//        Flags      ...ダイアログのフラグ
//■戻り値
//      ファイルを選択 true   
//------------------------------------------------------
int SaveDiaog(HWND hwnd,LPCSTR Filter,char *FileName,DWORD Flags)
{
   OPENFILENAME OFN; 

   ZeroMemory(&OFN,sizeof(OPENFILENAME));
   OFN.lStructSize = sizeof(OPENFILENAME); 
   OFN.hwndOwner = hwnd;
   OFN.lpstrFilter =Filter;
   OFN.lpstrFile =FileName;  
   OFN.nMaxFile = MAX_PATH*2;
   OFN.Flags = Flags;    
   OFN.lpstrTitle = "名前を付けて保存";
   return (GetSaveFileName(&OFN));
}

//------------------------------------------------------
//■関数 CreateMainWindow
//■用途 メインウインドウを作成する
//■引数
//  Width       ...ウインドウの横幅
//  Height      ...ウインドウの縦幅
//  Caption     ...タイトル名
//  hInstance   ...インスタンスハンドル
//  nCmdShow    ...ウインドウの表示形態
//  lpfnWndProc ...コールバックプロシージャ
//  dwstyle     ...ウインドウスタイル
//  dwExstyle   ...拡張ウインドウスタイル
//  MenuID      ...メニューのID
//  hIcon       ...アイコン
//■戻り値
//  ウインドウのハンドル
//------------------------------------------------------
HWND CreateMainWindow(int Width,int Height,LPCTSTR Caption,HINSTANCE hInstance,int nCmdShow,WNDPROC lpfnWndProc, DWORD dwstyle,DWORD dwExstyle,LPCTSTR MenuID,HICON hIcon)
{
    HWND hWnd;         //メインウインドウのハンドル
    WNDCLASS myClass;  //WNDCLASS構造体
    
    //WNDCLASS構造体を0で初期化
    ZeroMemory(&myClass,sizeof(WNDCLASS));
 
//--->WNDCLASS構造体の設定&ウインドウクラスの登録

    myClass.style =CS_HREDRAW | CS_VREDRAW;       //ウインドウスタイルを設定 
    myClass.lpfnWndProc   = lpfnWndProc;          //コールバックプロシージャへのポインタ
    myClass.hInstance=hInstance;                  //インスタンスハンドルを設定
    myClass.hCursor=LoadCursor(NULL, IDC_ARROW);  //カーソルの設定(Windows標準リソースを使用)  
    myClass.hbrBackground=(HBRUSH)COLOR_WINDOW;   //ウインドウの背景を設定(デフォルトカラー)
    myClass.lpszClassName="TForm";                //クラス名の設定(Borland Delphi風)  
    myClass.hIcon =hIcon;                         //アイコンの指定
    myClass.lpszMenuName=MenuID;                  //メニューの設定

    //ウィンドウ クラスを登録
    RegisterClass(&myClass); 
    
//--->ウインドウの作成&表示
   
  //メインウインドウの生成
  hWnd = CreateWindowEx(
           dwExstyle,            //拡張ウインドウスタイル
           "TForm",              //登録されたクラス名のアドレス 
           Caption,              //ウインドウ名
           dwstyle,              //ウインドウスタイルを設定
           ScreenCenterX(Width), //X座標の位置設定
           ScreenCenterY(Height),//Y座標の位置設定
           Width,                //横幅を設定
           Height,               //縦幅を設定
           NULL,                 //親ウインドウを設定
           NULL,                 //メニューを設定
           hInstance,            //インスタンスを識別
           NULL);                //作成したウインドウに渡すデータへのポインタ
 
  //ウインドウの表示(表示方法はnCmdShowに従う)
  ShowWindow(hWnd, nCmdShow);
  return(hWnd);
}

//--------------------------------------------------------
//■関数 WinMain
//■用途 メインの関数 
//■引数
// hInstance    ...現在のインスタンスのハンドル
// hPrevInstance...以前のインスタンスのハンドル
// pszCmdLine   ...コマンド ラインのアドレス
// nCmdShow     ...ウィンドウの表示状態
//--------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
   MSG msg;

  //メインウインドウを作成
  CreateMainWindow(400,400,"ビットマップを保存する(RLE圧縮対応)",hInstance,nCmdShow,(WNDPROC)WindowProc,
       WS_OVERLAPPEDWINDOW|WS_TABSTOP,WS_EX_CONTROLPARENT,MAKEINTRESOURCE(IDM_MENU),LoadIcon(NULL,MAKEINTRESOURCE(IDI_APPLICATION)));

  //送られてくるメッセージを翻訳してプロシージャに渡す  
  while (GetMessage(&msg, NULL, 0, 0)) 
  {
    TranslateMessage(&msg); 
    DispatchMessage(&msg);   
  } 
 return (msg.wParam);
}

//------------------------------------------------------
// ■関数 WindowProc
// ■用途 メインウインドウに送られるメッセージを処理
// ■引数
//   hwnd    ...ウインドウのハンドル
//   uMsg    ...メッセージID
//   wParam  ...第1メッセージ パラメータ    
//   lParam  ...第2メッセージ パラメータ
//------------------------------------------------------
LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{  
  char   FileName[MAX_PATH*2]; 
  BITMAP  BMPINFO;
  HDC     hMem,hDC;
  RECT    Rect;
  HBRUSH  hBrush; 

 switch (uMsg)
 {
  case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        
        case IDM_SUBMENU1 :
             //初期化(これをしないとごみが入る)
             ZeroMemory(FileName,MAX_PATH*2);
             //「ファイルを開く」ダイアログを表示
             if (OpenDiaog(hwnd,"BMP Files(*.bmp)\0*.bmp\0",
                         FileName,OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY))
             {
               //ビットマップのロード
               DeleteObject(hBitmap);
               //LR_CREATEDIBSECTIONフラグを使用しているに注目
               //(これを指定しないとSaveBMP()がうまく動作致しません。)
                hBitmap =(HBITMAP)LoadImage((HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),FileName,IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);             
               //強制再描画
               hDC=GetDC(hwnd);
               hBrush=CreateSolidBrush(RGB(192,192,192)); 
               GetWindowRect(hwnd,&Rect);  
               FillRect (hDC,&Rect,hBrush);
               DeleteObject(hBrush);
               ReleaseDC(hwnd,hDC);
               SendMessage(hwnd,WM_PAINT,0,0);
             }
             break;
        case IDM_SUBMENU2 :
             if (hBitmap!=NULL)
             {
               //初期化(これをしないとごみが入る)
               ZeroMemory(FileName,MAX_PATH*2);
               //「名前を付けて保存」ダイアログを表示
               if (SaveDiaog(hwnd,"BMP Files(*.bmp)\0*.bmp\0",
                    FileName,OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT))
               {
                     SaveBMP(FileName,hBitmap);
               }
             }
             break;
        }
  case WM_PAINT:
        //ビットマップの描画
        if (hBitmap!=NULL)
        {                   
            hDC=GetDC(hwnd);
            GetObject(hBitmap, sizeof(BITMAP), &BMPINFO);
            hMem = CreateCompatibleDC(hDC);
            SelectObject(hMem, hBitmap);
            BitBlt(hDC,0,0, BMPINFO.bmWidth,BMPINFO.bmHeight, hMem, 0, 0, SRCCOPY);
            DeleteDC(hMem);    
            ReleaseDC(hwnd,hDC);
        }    
        return(DefWindowProc(hwnd, uMsg, wParam, lParam)); 
        break;
 case WM_DESTROY:
         DeleteObject(hBitmap);
        PostQuitMessage(0);
        break;
 default: return(DefWindowProc(hwnd, uMsg, wParam, lParam)); 
 }
 
 return (0);

}


ソースコード一式のダウンロード

capi_sample79.zip 4,083 バイト

動作環境

このサンプルは 「Windows98」及び「Microsoft Visual C++5.0」「Borland C++ Compiler 5.5」で確認しております。環境が異なる場合は正常に動作しない場合もございますのでご了承下さい。

Visual C++5.0でのコンパイル

VC5.0でサンプルをコンパイルする場合は新規プロジェクト(Win32Application)を作成後、各ファイルを追加してビルドしてください。

Borland C++ Compiler 5.5でのコンパイル

BCC5.5でサンプルをコンパイルする場合は「bcc32.exe」で*.c又は*.cppファイルをコンパイルします。リソースがある場合は「brc32.exe」で*resファイルを付与してください。

サンプルについて

このWindows APIサンプル集(C/C++版)は2000年頃にC/C++言語の学習の為に作成したものです。コードはエレガントではなく「初心者レベルのコーディング」です。仕事などの業務で利用する際にはエラー処理やメモリ解放などの再確認を必ずして下さい。





関連記事



公開日:2015年03月19日
記事NO:00535