2010年1月31日日曜日

「いめーじぺたぺた」 ver 1.02


 
http://cid-8cd7cf5ea9fbca55.skydrive.live.com/self.aspx/Public/program/imgPt102.zip
いめーじぺたぺた ver 1.02
size: 1.00MB
 
 
■概要
ゲーム用画像を作成するとき、一定サイズの画像を一定間隔に並べることがよくあります。
「いめーじぺたぺた」は決まった大きさの画像を貼り付けていく作業をサポートするツールです。
 
 
■更新履歴
2010-01-28 ver1.02
  「サイズを自動拡張する」の拡張サイズ計算が間違っていたのを修正
  グリッド位置の動作仕様を変更
    ファイルリストの「選択範囲を動かす」の動作を仕様変更にあわせて修正
2010-01-27 ver1.01
  色数カウント機能を追加
  バックバッファが終了時にメモリリークしていたのを修正
2010-01-03 ver1.0
 
 
 
 画像は使いまわし。
ぼちぼち自分で使い始める状況になったので使っていたら、意図した動作にならなかったので修正。



Vector:いめーじぺたぺた (WindowsNT/2000/XP/Vista / 画像&サウンド) - ソフトの詳細
http://www.vector.co.jp/soft/winnt/art/se481479.html

 公開されたようですが、1.01→1.02にしたらステータスが公開停止に。ぎりぎりで差し替えられるものかと思っていたがそうではないらしい。

351号

http://cid-8cd7cf5ea9fbca55.skydrive.live.com/self.aspx/Public/music/no%20name351.ogg
351号
size: 2.14MB
音源:オルガーニャ + どこだかで拾ったドラムセット
SoundEngineFreeで少しリバーブをかけたあと、oggdropXPdで出力
 
 星間飛行的な曲に。最初はノリのいい感じを目指していたが見当違いな方向に向いてしまい、そのままごまかしたらこうなった。
 しばらくガルーダの曲を耳コピして遊んでたりしたのだけど、そこから得たのはコストの削減方法であった。
8和音万歳!
耳コピ歴が足りないと得られるものも少ないらしく、もっと修行がいるね! がんばれ→俺←がんばれ。
 
 バージョンアップ報告の記事が二つ並ぶのはまずいと筆休め的な記事ではさむ作戦。

2010年1月27日水曜日

「いめーじぺたぺた」v1.01


「いめーじぺたぺた」 ver 1.01

http://cid-8cd7cf5ea9fbca55.skydrive.live.com/self.aspx/Public/program/imgPt.zip

http://cid-8cd7cf5ea9fbca55.skydrive.live.com/self.aspx/Public/program/imgPt101.zip

Size: 1.0MB
 
 
■更新履歴
2010-01-27 ver1.01
 色数カウント機能を追加
 バックバッファが終了時にメモリリークしていたのを修正
2010-01-03 ver1.0
 
 
 ついでにvectorに登録してみました。
怖い怖い怖い!
 色カウント機能はググッたらすぐ出てきた、ビットで使用色フラグを保存するタイプをそのまま使用。
ためしにバブリーなプログラムを組んで800x800ぐらいで実験したら数えるのに5分ぐらいかかった。
さすがに使い物にならないので、フラグを保存するタイプにしたら1秒程度で完了して笑った。
アルゴリズムは偉大だ。
 
 早速バグを発見、readmeの修正忘れと踏んだりけったりだが、まあ良くあることだ。

2010年1月23日土曜日

日記ちゃん


 届いたー。



 4bitDIBの実験。
160x144の画面に、8x8の弾を2万6千個レンダリングして55FPS前後。
画面サイズはゲームボーイサイズで、4bitDIBって選択もGBは4色だからという理由なんだけど時代を逆行しすぎて誰も付いてきてくれない気がする。
 8x8とか16x16のドット絵が大変楽しい。
4bitは16色しか使えないので工夫がいるんだろうけど、逆に言えば色選択が少ないので最適化しやすく美味。
この画面サイズだと16x16はちょっと大きく感じる、ベースは8x8になるのかな?
 一度に16色しか使えないけど、表画面をフルカラーにしてパレット変えながら複数回レンダリングすれば何色でもいけそうで夢一杯! 背景16色、敵弾16色とか分ければやりたい放題。パレットをグラデーションにすれば半透明も加算合成もいけちゃうという、楽して大もうけみたいな。
 8ピクセル一気に転送するから速度も高速かと思いきや、計算式が複雑になるんでむしろ遅いという。

2010年1月22日金曜日

日記ちゃん



 ちょっとおもしろかったので転載。
こんだけデンジャー君がたまってるのを見ると真似したくなるよね。わくわく。
稼ぐとバンバン画面上にオブジェクトが増えていくのはちょっとした技術革新な気がする。
永パ防止というかマンネリ防止用なんだろうけど、稼ぎに利用されるあたりが生々しい。

 ニコニコの貼り付け実験もかねてるが、意外に重いな。次からは普通のリンクにしとくか。

2010年1月21日木曜日

32bitDIB(7) DIBSection

■DIBSection
 DIBとDIBSectionではメモリの確保が違うくらいなので、あれこれ使い回しが聞きます。
そんなわけでDIB32クラスのcreateとrelease周りをオーバーライドするだけ。デストラクタも忘れずに。
 バックバッファをDIBSectionにすると文字表示が楽に出来るのでデバッグしやすかったりします、まあお好みで。

class DIB32
{
public:
  virtual ~DIB32() { release(); }
  virtual bool create( LONG width, LONG height );
  virtual void release();
 
protected:
  LPDWORD m_pixel;
  BITMAPINFO m_bmi;
};
 
 
class DIBSection32 : public DIB32
{
public:
  DIBSection32()
    : m_hdc( NULL )
    , m_hBitmap( NULL )
    , m_hOldBitmap( NULL )
  {}
  virtual ~DIBSection32() { release(); }
 
  virtual bool create( LONG width, LONG height )
  {
    if ( width <= 0 || height <= 0 ) return false;
 
    release();
 
    m_bmi.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
    m_bmi.bmiHeader.biWidth = width;
    m_bmi.bmiHeader.biHeight = height;
    m_bmi.bmiHeader.biPlanes = 1;
    m_bmi.bmiHeader.biBitCount = 32;
    m_bmi.bmiHeader.biCompression = BI_RGB;
 
    m_hdc = CreateCompatibleDC( NULL );
    if ( m_hdc == NULL ) return false;
 
    m_hBitmap = CreateDIBSection( m_hdc, &m_bmi,
      DIB_RGB_COLORS, reinterpret_cast<void**>(&m_pixel), NULL, 0 );
    if ( m_hBitmap == NULL )
    {
      DeleteDC( m_hdc );
      m_hdc = NULL;
      return false;
    }
 
    m_hOldBitmap =
      reinterpret_cast<HBITMAP>( SelectObject(m_hdc, m_hBitmap) );
 
    return true;
  }
 
 
  virtual void release()
  {
    if ( m_hBitmap )
    {
      DeleteObject( SelectObject(m_hdc, m_hOldBitmap) );
      DeleteObject( m_hBitmap );
      m_hBitmap = NULL;
      m_hOldBitmap = NULL;
    }
 
    if ( m_hdc )
    {
      DeleteObject( m_hdc );
      m_hdc = NULL;
    }
    
    m_pixel = NULL;
    ZeroMemory( &m_bmi, sizeof(m_bmi) );
  }
 
  HDC getDC() { return m_hdc; }
 
protected:
  HDC m_hdc;
  HBITMAP m_hBitmap, m_hOldBitmap;
};




■サンプル

#include <windows.h>
 
 
 
class DIB32
{
public:
  DIB32()
    : m_pixel( NULL )
  {
    ZeroMemory( &m_bmi, sizeof(m_bmi) );
  }
 
  virtual ~DIB32()
  {
    release();
  }
 
  virtual bool create( LONG width, LONG height )
  {
    if ( width <= 0 || height <= 0 ) return false;
    release();
 
    m_pixel = new DWORD[ width * height ];
    if ( !m_pixel ) return false;
 
    m_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    m_bmi.bmiHeader.biWidth = width;
    m_bmi.bmiHeader.biHeight = height;
    m_bmi.bmiHeader.biPlanes = 1;
    //32bit固定にする
    m_bmi.bmiHeader.biBitCount = 32;
    m_bmi.bmiHeader.biCompression = BI_RGB;
    //96dpiだと3780らしい。0の場合もあるとのこと
    m_bmi.bmiHeader.biXPelsPerMeter = 3780;
    m_bmi.bmiHeader.biYPelsPerMeter = 3780;
 
    return true;
  }
 
  bool create( LPCTSTR bitmapFile )
  {
    if ( !bitmapFile ) return false;
 
    HBITMAP hBmp = static_cast<HBITMAP>(
      LoadImage(NULL, bitmapFile, IMAGE_BITMAP,
      0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE) );
    if ( !hBmp ) return false;
 
    BITMAP bm = {0};
    GetObject( hBmp, sizeof(BITMAP), &bm );
 
    // create DC
    HDC hdc = CreateCompatibleDC( NULL );
    if ( !hdc )
    {
      DeleteDC( hdc );
      DeleteObject( hBmp );
      return false;
    }
 
    // create buf
    if ( !create( bm.bmWidth, bm.bmHeight ) )
    {
      DeleteDC( hdc );
      DeleteObject( hBmp );
      return false;
    }
 
    // copy
    GetDIBits( hdc, hBmp, 0, bm.bmHeight,m_pixel, &m_bmi,
      DIB_RGB_COLORS );
 
    DeleteDC( hdc );
    DeleteObject( hBmp );
 
    return true;
  }
 
  virtual void release()
  {
    if ( m_pixel )
    {
      delete [] m_pixel;
      m_pixel = NULL;
    }
    ZeroMemory( &m_bmi, sizeof(m_bmi) );
  }
 
  bool render(
    HDC hdc,
    LONG destX, LONG destY,
    LONG destWidth, LONG destHeight,
    LONG srcX, LONG srcY,
    LONG srcWidth, LONG srcHeight ) const
  {
    return GDI_ERROR != StretchDIBits(
      hdc, destX, destY, destWidth, destHeight,
      srcX, srcY, srcWidth, srcHeight,
      m_pixel, &m_bmi, DIB_RGB_COLORS, SRCCOPY );
  }
 
 
 
  bool render(
    DIB32& dest,
    LONG destX, LONG destY, LONG destWidth, LONG destHeight,
    LONG srcX, LONG srcY, LONG srcWidth, LONG srcHeight ) const
  {
    if ( !m_pixel || !dest.m_pixel ) return false;
 
    const float magniX = static_cast<float>(destWidth) / static_cast<float>(srcWidth);
    const float magniY = static_cast<float>(destHeight) / static_cast<float>(srcHeight);
    const LONG sw = static_cast<LONG>( static_cast<float>(getWidth()) * magniX );
    const LONG sh = static_cast<LONG>( static_cast<float>(getHeight()) * magniY );
    LONG sx = static_cast<LONG>( static_cast<float>(srcX) * magniX );
    LONG sy = static_cast<LONG>( static_cast<float>(srcY) * magniY );
 
    if ( cliping( destX, destY, destWidth, destHeight,
      sx, sy, dest.getWidth(), dest.getHeight(), sw, sh ) )
    {
      const float addX = 1.f / magniX;
      const float addY = 1.f / magniY;
      float fsy = static_cast<float>( sy ) / magniY;
      LPDWORD destLine = dest.m_pixel
        + ((dest.getHeight()-1)-destY) * dest.getWidth()
        + destX;
 
      for (LONG y=0; y<destHeight; ++y)
      {
        LPDWORD destPixel = destLine;
        LPDWORD srcLine = m_pixel
          + ((getHeight()-1)-static_cast<LONG>(fsy)) * getWidth();
        float fsx = static_cast<float>( sx ) / magniY;
        for (LONG x=0; x<destWidth; ++x)
        {
          *destPixel++ = srcLine[ static_cast<LONG>(fsx) ];
          fsx += addX;
        }
 
        fsy += addY;
        destLine -= dest.getWidth();
      }
 
      return true;
    }
 
    return false;
  }
 
 
  LONG getWidth() const { return m_bmi.bmiHeader.biWidth; }
  LONG getHeight() const { return m_bmi.bmiHeader.biHeight; }
 
  static bool cliping(
    LONG& destX, LONG& destY,
    LONG& width, LONG& height,
    LONG& srcX, LONG& srcY,
    const LONG destWidth, const LONG destHeight,
    const LONG srcWidth, const LONG srcHeight )
  {
    // 左端クリッピング
    if ( destX < 0 ) { width += destX; srcX -= destX; destX = 0; }
    if ( srcX < 0 ) { width += srcX; destX -= srcX; srcX = 0; }
 
    // 右端
    if ( destX + width > destWidth ) { width -= ((destX+width)-destWidth); }
    if ( srcX + width > srcWidth ) { width -= ((srcX+width)-srcWidth); }
 
    // 上
    if ( destY < 0 ) { height += destY; srcY -= destY; destY = 0; }
    if ( srcY < 0 ) { height += srcY; destY -= srcY; srcY = 0; }
 
    // 下
    if ( destY + height > destHeight ) { height -= ((destY+height)-destHeight); }
    if ( srcY + height > srcHeight ) { height -= ((srcY+height)-srcHeight); }
 
    return ((width > 0) & (height > 0));
  }
 
protected:
  LPDWORD m_pixel;
  BITMAPINFO m_bmi;
};
 
 
class DIBSection32 : public DIB32
{
public:
  DIBSection32()
    : m_hdc( NULL )
    , m_hBitmap( NULL )
    , m_hOldBitmap( NULL )
  {}
  virtual ~DIBSection32() { release(); }
 
  virtual bool create( LONG width, LONG height )
  {
    if ( width <= 0 || height <= 0 ) return false;
 
    release();
 
    m_bmi.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
    m_bmi.bmiHeader.biWidth = width;
    m_bmi.bmiHeader.biHeight = height;
    m_bmi.bmiHeader.biPlanes = 1;
    m_bmi.bmiHeader.biBitCount = 32;
    m_bmi.bmiHeader.biCompression = BI_RGB;
 
    m_hdc = CreateCompatibleDC( NULL );
    if ( m_hdc == NULL ) return false;
 
    m_hBitmap = CreateDIBSection( m_hdc, &m_bmi,
      DIB_RGB_COLORS, reinterpret_cast<void**>(&m_pixel), NULL, 0 );
    if ( m_hBitmap == NULL )
    {
      DeleteDC( m_hdc );
      m_hdc = NULL;
      return false;
    }
 
    m_hOldBitmap =
      reinterpret_cast<HBITMAP>( SelectObject(m_hdc, m_hBitmap) );
 
    return true;
  }
 
 
  virtual void release()
  {
    if ( m_hBitmap )
    {
      DeleteObject( SelectObject(m_hdc, m_hOldBitmap) );
      DeleteObject( m_hBitmap );
      m_hBitmap = NULL;
      m_hOldBitmap = NULL;
    }
 
    if ( m_hdc )
    {
      DeleteObject( m_hdc );
      m_hdc = NULL;
    }
    
    m_pixel = NULL;
    ZeroMemory( &m_bmi, sizeof(m_bmi) );
  }
 
  HDC getDC() { return m_hdc; }
 
protected:
  HDC m_hdc;
  HBITMAP m_hBitmap, m_hOldBitmap;
};
 
 
 
 
LRESULT CALLBACK wndProc(
  HWND hWnd,
  UINT msg,
  WPARAM wParam,
  LPARAM lParam )
{
  static DIBSection32 image;
  static DIB32 image2;
  switch (msg)
  {
  case WM_DESTROY:
    ShowWindow( hWnd, SW_HIDE );
    PostQuitMessage(0);
    break;
  case WM_CREATE:
    image.DIB32::create( TEXT("image.bmp") );
    image2.create( TEXT("image2.bmp") );
    break;
  case WM_PAINT:
    {
      PAINTSTRUCT ps = {0};
      HDC hdc = BeginPaint( hWnd, &ps );
      image2.render( image,
        -100, -50, image2.getWidth()*2, image2.getHeight()*2,
        0, 0, image2.getWidth(), image2.getHeight() );
 
      Rectangle( image.getDC(),
        10, 10, image.getWidth()-10, image.getHeight()-10 );
 
      image.render( hdc,
        10, 10, image.getWidth(), image.getHeight(),
        0, 0, image.getWidth(), image.getHeight() );
      EndPaint( hWnd, &ps );
    }
    break;
  default:
    return DefWindowProc( hWnd, msg, wParam, lParam );
  }
 
  return 0;
}
 
 
 
 
int WINAPI WinMain(
  HINSTANCE hInstance,
  HINSTANCE hPrevInstance,
  PSTR lpCmdLine,
  int nCmdShow )
{
  LPCTSTR WINDOW_NAME = TEXT("sample");
 
  WNDCLASSEX wc;
  wc.style    = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc  = reinterpret_cast<WNDPROC>( wndProc );
  wc.cbClsExtra  = 0;
  wc.cbWndExtra  = 0;
  wc.cbSize    = sizeof( WNDCLASSEX );
  wc.hInstance  = hInstance;
  wc.hIcon    = NULL;
  wc.hIconSm    = NULL;
  wc.hCursor    = LoadCursor( NULL, IDC_ARROW );
  wc.hbrBackground= reinterpret_cast<HBRUSH>( GetStockObject(WHITE_BRUSH) );
  wc.lpszMenuName  = NULL;
  wc.lpszClassName= WINDOW_NAME;
  if ( !RegisterClassEx(&wc) ) return 0;
 
  LONG winWidth = 640
    + GetSystemMetrics(SM_CXEDGE)
    + GetSystemMetrics(SM_CXBORDER)
    + GetSystemMetrics(SM_CXDLGFRAME);
  LONG winHeight = 480
    + GetSystemMetrics(SM_CYEDGE)
    + GetSystemMetrics(SM_CYBORDER)
    + GetSystemMetrics(SM_CYDLGFRAME)
    + GetSystemMetrics(SM_CYCAPTION);
  HWND hWnd = CreateWindowEx(
    0, WINDOW_NAME, NULL, WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME,
    CW_USEDEFAULT, CW_USEDEFAULT, winWidth, winHeight,
    NULL, NULL, hInstance, NULL);
  if ( !hWnd ) return -1;
 
  ShowWindow( hWnd, SW_SHOWNORMAL );
  UpdateWindow( hWnd );
 
  MSG msg;
  for (;;)
  {
    if ( !GetMessage(&msg, NULL, 0, 0) ) break;
    TranslateMessage( &msg );
    DispatchMessage( &msg );
  }
 
  
  UnregisterClass( WINDOW_NAME, hInstance );
  return msg.wParam;
}

 
 
 

 今までどおりDIB->DIBのレンダリングをしつつも、HDCも使用可能。
image->DIB::create(~)が異常にキモイが、どうにもならん。

bool DIBSection32::create(LPCTSTR fileName )
{
  return DIB32::create( fileName );
}

とかやってオーバーロードするととりあえず回避は可能だけど、美しくない気もする。

■関連記事:
生産がす: 32bitDIB(1) 作成と破棄
生産がす: 32bitDIB(2) 画像読み込み
生産がす: 32bitDIB(3) 塗りつぶし
生産がす: 32bitDIB(4) DIBに描画
生産がす: 32bitDIB(5) ファイルに出力
生産がす: 32bitDIB(6) 拡大縮小描画
生産がす: 32bitDIB(7) DIBSection
生産がす: DIB(8) - 直線描画
生産がす: DIB(9) - 回転描画
生産がす: DIB(10) - 三角形描画
生産がす: 日記ちゃん半透明合成
生産がす: 32bitDIBから無圧縮AVI2.0

2010年1月19日火曜日

日記ちゃん

 携帯解約してきた。
使っていたのはauのW43SAで、解約にかかった時間は約10分ぐらい。
必要なのは身分証明できるものだけで、携帯と印鑑は自分は使わなかった。
 携帯の番号と誕生日を聞かれた後、書類を書くだけ。印鑑の変わりにサインでOKだった。
実際に携帯が使えなくなるまで1分もかからないみたいで、あっという間だったよ。
携帯の電池裏にあるカードを使うのかと思ったが別にいらんらしい。

 これで、有料のゴミから無料のゴミに様変わり。あれ?
手続きは10分だったが人が多く、待つのに1時間ぐらいかかった。

 携帯起動時にサーバーにチェックしに行くらしく、携帯を再起動したら「auIC(UIM)エラー。このカードではご利用になれません」とか表示が出てそのまま待ち受け画面に移行する。
EZWebもこのエラーがでて使用不可。EZテレビ、EZ・FM、アプリもエラーで使用できない。
 新着メール問い合わせの選択欄が黒ずんで選択不能状態になってるなど、結構細かい。au Music Playerもこの状態。
 なぜかPCサイトビューアーは起動できるが、接続できませんのメッセージ。

 使えるのはカメラ、カレンダー、アドレス帳、メールボックス関係、赤外線、そのほかこまごましたツールぐらい。個人的に時計とアラームがあればほかはどうでもいいな。
 累積通話時間が57分だった、4年で57分ってお前……。



 プログラムのソースコードを乗せるときに今までは


<blockquote><pre>
</pre></blockquote>


を使っていたのだけど、コピペすると改行がなくなって一行になる問題がでていたので、


<blockquote><code>
</code></blockquote>


に変更した。<code>を使うとタブ文字やスペースが表示されなくなるので、スペースは&nbsp;で表現する。
 あれこれ1,2時間ほど検索かけたりしたのだけど、うまい方法が見つからなかった。そのまま表示できれば一番いいのになあ。

2010年1月18日月曜日

32bitDIB(6) 拡大縮小描画

■拡大縮小レンダリング
 いままでは*destPixel++ = *srcPixel++;でしたが、

float addX = srcWidth / destWidth;
float sx = srcX;
for (LONG x=0; x<width; ++x)
{
  *destPixel++ = srcPixel[ static_cast<int>(sx) ];
  sx += addX;
}

 みたいに不動小数点数を使うと手軽に実装できます。
固定小数点数でもブレゼンハムでもいけますが速度はどっこいどっこい、心持ち浮動小数点のほうが遅いです。やむなし。


 クリッピングが面倒ですが、参照位置や参照画像サイズを描画倍率にあわせることでいままでのクリッピング関数を使いまわすことが出来ます。
クリッピング後に元に直せば、必要な部分だけクリッピングされた領域が計算されている状態になります。

 うまくクリッピングされていればループ中にif文がいらないのでそこそこ高速に処理できます。

bool render(
  DIB32& dest,
  LONG destX, LONG destY, LONG destWidth, LONG destHeight,
  LONG srcX, LONG srcY, LONG srcWidth, LONG srcHeight ) const
{
  if ( !m_pixel || !dest.m_pixel ) return false;
 
  const float magniX = static_cast<float>(destWidth) / static_cast<float>(srcWidth);
  const float magniY = static_cast<float>(destHeight) / static_cast<float>(srcHeight);
  const LONG sw = static_cast<LONG>( static_cast<float>(getWidth()) * magniX );
  const LONG sh = static_cast<LONG>( static_cast<float>(getHeight()) * magniY );
  LONG sx = static_cast<LONG>( static_cast<float>(srcX) * magniX );
  LONG sy = static_cast<LONG>( static_cast<float>(srcY) * magniY );
 
  if ( cliping( destX, destY, destWidth, destHeight, sx, sy, dest.getWidth(), dest.getHeight(), sw, sh ) )
  {
    const float addX = 1.f / magniX;
    const float addY = 1.f / magniY;
    float fsy = static_cast<float>( sy ) / magniY;
    LPDWORD destLine = dest.m_pixel
      + ((dest.getHeight()-1)-destY) * dest.getWidth()
      + destX;
 
    for (LONG y=0; y<destHeight; ++y)
    {
      LPDWORD destPixel = destLine;
      LPDWORD srcLine = m_pixel
        + ((getHeight()-1)-static_cast<LONG>(fsy)) * getWidth();
      float fsx = static_cast<float>( sx ) / magniY;
      for (LONG x=0; x<destWidth; ++x)
      {
        *destPixel++ = srcLine[ static_cast<LONG>(fsx) ];
        fsx += addX;
      }
 
      fsy += addY;
      destLine -= dest.getWidth();
    }
 
    return true;
  }
 
  return false;
}





●サンプル
http://cid-8cd7cf5ea9fbca55.skydrive.live.com/self.aspx/Public/program/Sample6.cpp


#include <windows.h>
 
class DIB32
{
public:
 DIB32()
  : m_pixel( NULL )
 {
  ZeroMemory( &m_bmi, sizeof(m_bmi) );
 }
 
 ~DIB32()
 {
  release();
 }
 
 bool create( LONG width, LONG height )
 {
  if ( width <= 0 || height <= 0 ) return false;
  release();
 
  m_pixel = new DWORD[ width * height ];
  if ( !m_pixel ) return false;
 
  m_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  m_bmi.bmiHeader.biWidth = width;
  m_bmi.bmiHeader.biHeight = height;
  m_bmi.bmiHeader.biPlanes = 1;
  //32bit固定にする
  m_bmi.bmiHeader.biBitCount = 32;
  m_bmi.bmiHeader.biCompression = BI_RGB;
  //96dpiだと3780らしい。0の場合もあるとのこと
  m_bmi.bmiHeader.biXPelsPerMeter = 3780;
  m_bmi.bmiHeader.biYPelsPerMeter = 3780;
 
  return true;
 }
 
 bool create( LPCTSTR bitmapFile )
 {
  if ( !bitmapFile ) return false;
 
  HBITMAP hBmp = static_cast<HBITMAP>(
   LoadImage(NULL, bitmapFile, IMAGE_BITMAP,
   0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE) );
  if ( !hBmp ) return false;
 
  BITMAP bm = {0};
  GetObject( hBmp, sizeof(BITMAP), &bm );
 
  // create DC
  HDC hdc = CreateCompatibleDC( NULL );
  if ( !hdc )
  {
   DeleteDC( hdc );
   DeleteObject( hBmp );
   return false;
  }
 
  // create buf
  if ( !create( bm.bmWidth, bm.bmHeight ) )
  {
   DeleteDC( hdc );
   DeleteObject( hBmp );
   return false;
  }
 
  // copy
  GetDIBits( hdc, hBmp, 0, bm.bmHeight,m_pixel, &m_bmi,
   DIB_RGB_COLORS );
 
  DeleteDC( hdc );
  DeleteObject( hBmp );
 
  return true;
 }
 
 void release()
 {
  if ( m_pixel )
  {
   delete [] m_pixel;
   m_pixel = NULL;
  }
  ZeroMemory( &m_bmi, sizeof(m_bmi) );
 }
 
 bool render(
  HDC hdc,
  LONG destX, LONG destY,
  LONG destWidth, LONG destHeight,
  LONG srcX, LONG srcY,
  LONG srcWidth, LONG srcHeight ) const
 {
  return GDI_ERROR != StretchDIBits(
   hdc, destX, destY, destWidth, destHeight,
   srcX, srcY, srcWidth, srcHeight,
   m_pixel, &m_bmi, DIB_RGB_COLORS, SRCCOPY );
 }
 
 
 
 bool render(
  DIB32& dest,
  LONG destX, LONG destY, LONG destWidth, LONG destHeight,
  LONG srcX, LONG srcY, LONG srcWidth, LONG srcHeight ) const
 {
  if ( !m_pixel || !dest.m_pixel ) return false;
 
  const float magniX = static_cast<float>(destWidth) / static_cast<float>(srcWidth);
  const float magniY = static_cast<float>(destHeight) / static_cast<float>(srcHeight);
  const LONG sw = static_cast<LONG>( static_cast<float>(getWidth()) * magniX );
  const LONG sh = static_cast<LONG>( static_cast<float>(getHeight()) * magniY );
  LONG sx = static_cast<LONG>( static_cast<float>(srcX) * magniX );
  LONG sy = static_cast<LONG>( static_cast<float>(srcY) * magniY );
 
  if ( cliping( destX, destY, destWidth, destHeight, sx, sy, dest.getWidth(), dest.getHeight(), sw, sh ) )
  {
   const float addX = 1.f / magniX;
   const float addY = 1.f / magniY;
   float fsy = static_cast<float>( sy ) / magniY;
   LPDWORD destLine = dest.m_pixel
    + ((dest.getHeight()-1)-destY) * dest.getWidth()
    + destX;
 
   for (LONG y=0; y<destHeight; ++y)
   {
    LPDWORD destPixel = destLine;
    LPDWORD srcLine = m_pixel
     + ((getHeight()-1)-static_cast<LONG>(fsy)) * getWidth();
    float fsx = static_cast<float>( sx ) / magniY;
    for (LONG x=0; x<destWidth; ++x)
    {
     *destPixel++ = srcLine[ static_cast<LONG>(fsx) ];
     fsx += addX;
    }
 
    fsy += addY;
    destLine -= dest.getWidth();
   }
 
   return true;
  }
 
  return false;
 }
 
 
 LONG getWidth() const { return m_bmi.bmiHeader.biWidth; }
 LONG getHeight() const { return m_bmi.bmiHeader.biHeight; }
 
 static bool cliping(
  LONG& destX, LONG& destY,
  LONG& width, LONG& height,
  LONG& srcX, LONG& srcY,
  const LONG destWidth, const LONG destHeight,
  const LONG srcWidth, const LONG srcHeight )
 {
  // 左端クリッピング
  if ( destX < 0 ) { width += destX; srcX -= destX; destX = 0; }
  if ( srcX < 0 ) { width += srcX; destX -= srcX; srcX = 0; }
 
  // 右端
  if ( destX + width > destWidth ) { width -= ((destX+width)-destWidth); }
  if ( srcX + width > srcWidth ) { width -= ((srcX+width)-srcWidth); }
 
  // 上
  if ( destY < 0 ) { height += destY; srcY -= destY; destY = 0; }
  if ( srcY < 0 ) { height += srcY; destY -= srcY; srcY = 0; }
 
  // 下
  if ( destY + height > destHeight ) { height -= ((destY+height)-destHeight); }
  if ( srcY + height > srcHeight ) { height -= ((srcY+height)-srcHeight); }
 
  return ((width > 0) & (height > 0));
 }
 
private:
 LPDWORD m_pixel;
 BITMAPINFO m_bmi;
};
 
 
 
 
LRESULT CALLBACK wndProc(
 HWND hWnd,
 UINT msg,
 WPARAM wParam,
 LPARAM lParam )
{
 static DIB32 image;
 static DIB32 image2;
 switch (msg)
 {
 case WM_DESTROY:
  ShowWindow( hWnd, SW_HIDE );
  PostQuitMessage(0);
  break;
 case WM_CREATE:
  image.create( TEXT("image.bmp") );
  image2.create( TEXT("image2.bmp") );
  break;
 case WM_PAINT:
  {
   PAINTSTRUCT ps = {0};
   HDC hdc = BeginPaint( hWnd, &ps );
   image2.render( image, -100, -50, image2.getWidth()*2, image2.getHeight()*2, 0, 0, image2.getWidth(), image2.getHeight() );
   image.render(
    hdc, 10, 10, image.getWidth(), image.getHeight(),
    0, 0, image.getWidth(), image.getHeight() );
   EndPaint( hWnd, &ps );
  }
  break;
 default:
  return DefWindowProc( hWnd, msg, wParam, lParam );
 }
 
 return 0;
}
 
 
 
 
int WINAPI WinMain(
 HINSTANCE hInstance,
 HINSTANCE hPrevInstance,
 PSTR lpCmdLine,
 int nCmdShow )
{
 LPCTSTR WINDOW_NAME = TEXT("sample");
 
 WNDCLASSEX wc;
 wc.style  = CS_HREDRAW | CS_VREDRAW;
 wc.lpfnWndProc = reinterpret_cast<WNDPROC>( wndProc );
 wc.cbClsExtra = 0;
 wc.cbWndExtra = 0;
 wc.cbSize  = sizeof( WNDCLASSEX );
 wc.hInstance = hInstance;
 wc.hIcon  = NULL;
 wc.hIconSm  = NULL;
 wc.hCursor  = LoadCursor( NULL, IDC_ARROW );
 wc.hbrBackground= reinterpret_cast<HBRUSH>( GetStockObject(WHITE_BRUSH) );
 wc.lpszMenuName = NULL;
 wc.lpszClassName= WINDOW_NAME;
 if ( !RegisterClassEx(&wc) ) return 0;
 
 LONG winWidth = 640
  + GetSystemMetrics(SM_CXEDGE)
  + GetSystemMetrics(SM_CXBORDER)
  + GetSystemMetrics(SM_CXDLGFRAME);
 LONG winHeight = 480
  + GetSystemMetrics(SM_CYEDGE)
  + GetSystemMetrics(SM_CYBORDER)
  + GetSystemMetrics(SM_CYDLGFRAME)
  + GetSystemMetrics(SM_CYCAPTION);
 HWND hWnd = CreateWindowEx(
  0, WINDOW_NAME, NULL, WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME,
  CW_USEDEFAULT, CW_USEDEFAULT, winWidth, winHeight,
  NULL, NULL, hInstance, NULL);
 if ( !hWnd ) return -1;
 
 ShowWindow( hWnd, SW_SHOWNORMAL );
 UpdateWindow( hWnd );
 
 MSG msg;
 for (;;)
 {
  if ( !GetMessage(&msg, NULL, 0, 0) ) break;
  TranslateMessage( &msg );
  DispatchMessage( &msg );
 }
 
 
 UnregisterClass( WINDOW_NAME, hInstance );
 return msg.wParam;
}

 
 
 


■関連記事:
生産がす: 32bitDIB(1) 作成と破棄
生産がす: 32bitDIB(2) 画像読み込み
生産がす: 32bitDIB(3) 塗りつぶし
生産がす: 32bitDIB(4) DIBに描画
生産がす: 32bitDIB(5) ファイルに出力
生産がす: 32bitDIB(6) 拡大縮小描画
生産がす: 32bitDIB(7) DIBSection
生産がす: DIB(8) - 直線描画
生産がす: DIB(9) - 回転描画
生産がす: DIB(10) - 三角形描画
生産がす: 日記ちゃん半透明合成
生産がす: 32bitDIBから無圧縮AVI2.0

32bitDIB(5) ファイルに出力

■ファイルに出力
 そのまま出力する場合は簡単で、BITMAPFILEHEADER→BITMAPINFO→ピクセルデータと順番にファイルに書き込むだけです。
 32bitのビットマップを読み込めないアプリケーションがちょいちょいあるので使い勝手は微妙ですが。

bool saveBitmap( LPCTSTR fileName ) const
{
  //FileHeader用意
  BITMAPFILEHEADER bmpfh;
  bmpfh.bfOffBits = sizeof(bmpfh) + sizeof(m_bmi);
  bmpfh.bfSize = bmpfh.bfOffBits + getWidth()*getHeight()*sizeof(*m_pixel);
  bmpfh.bfType = ('M'<<8)+'B';
  bmpfh.bfReserved1 = bmpfh.bfReserved2 = 0;
 
  //ファイル作成
  HANDLE fh = CreateFile( fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
  if ( fh == INVALID_HANDLE_VALUE )
  {
    return false;
  }
 
  DWORD dwSize;
  WriteFile( fh, &bmpfh, sizeof(BITMAPFILEHEADER), &dwSize, NULL );
  WriteFile( fh, &m_bmi, sizeof(m_bmi), &dwSize, NULL );
  WriteFile( fh, m_pixel, getWidth()*getHeight()*sizeof(*m_pixel), &dwSize, NULL );
  CloseHandle( fh );
 
  return true;
}




●サンプル

http://cid-8cd7cf5ea9fbca55.skydrive.live.com/self.aspx/Public/program/Sample5.cpp



#include <windows.h>
 
class DIB32
{
public:
  DIB32()
    : m_pixel( NULL )
  {
    ZeroMemory( &m_bmi, sizeof(m_bmi) );
  }
 
  ~DIB32()
  {
    release();
  }
 
  bool create( LONG width, LONG height )
  {
    if ( width <= 0 || height <= 0 ) return false;
    release();
 
    m_pixel = new DWORD[ width * height ];
    if ( !m_pixel ) return false;
 
    m_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    m_bmi.bmiHeader.biWidth = width;
    m_bmi.bmiHeader.biHeight = height;
    m_bmi.bmiHeader.biPlanes = 1;
    //32bit固定にする
    m_bmi.bmiHeader.biBitCount = 32;
    m_bmi.bmiHeader.biCompression = BI_RGB;
    //96dpiだと3780らしい。0の場合もあるとのこと
    m_bmi.bmiHeader.biXPelsPerMeter = 3780;
    m_bmi.bmiHeader.biYPelsPerMeter = 3780;
 
    return true;
  }
 
  bool create( LPCTSTR bitmapFile )
  {
    if ( !bitmapFile ) return false;
 
    HBITMAP hBmp = static_cast<HBITMAP>(
      LoadImage(NULL, bitmapFile, IMAGE_BITMAP,
      0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE) );
    if ( !hBmp ) return false;
 
    BITMAP bm = {0};
    GetObject( hBmp, sizeof(BITMAP), &bm );
 
    // create DC
    HDC hdc = CreateCompatibleDC( NULL );
    if ( !hdc )
    {
      DeleteDC( hdc );
      DeleteObject( hBmp );
      return false;
    }
 
    // create buf
    if ( !create( bm.bmWidth, bm.bmHeight ) )
    {
      DeleteDC( hdc );
      DeleteObject( hBmp );
      return false;
    }
 
    // copy
    GetDIBits( hdc, hBmp, 0, bm.bmHeight,m_pixel, &m_bmi,
      DIB_RGB_COLORS );
 
    DeleteDC( hdc );
    DeleteObject( hBmp );
 
    return true;
  }
 
  void release()
  {
    if ( m_pixel )
    {
      delete [] m_pixel;
      m_pixel = NULL;
    }
    ZeroMemory( &m_bmi, sizeof(m_bmi) );
  }
 
  bool render(
    HDC hdc,
    LONG destX, LONG destY,
    LONG destWidth, LONG destHeight,
    LONG srcX, LONG srcY,
    LONG srcWidth, LONG srcHeight ) const
  {
    return GDI_ERROR != StretchDIBits(
      hdc, destX, destY, destWidth, destHeight,
      srcX, srcY, srcWidth, srcHeight,
      m_pixel, &m_bmi, DIB_RGB_COLORS, SRCCOPY );
  }
 
 
  bool render(
    DIB32& dest,
    LONG destX, LONG destY,
    LONG width, LONG height,
    LONG srcX, LONG srcY ) const
  {
    if ( !m_pixel || !dest.m_pixel ) return false;
    if ( cliping(destX, destY, width, height, srcX, srcY, dest.getWidth(), dest.getHeight(), getWidth(), getHeight() ) )
    {
      DWORD transColor = *m_pixel;
      LPDWORD destLine = dest.m_pixel
        + ((dest.getHeight()-1)-destY)*dest.getWidth()
        + destX;
      LPDWORD srcLine = m_pixel
        + ((getHeight()-1)-srcY)*getWidth()
        + srcX;
      for (LONG y=0; y<height; ++y)
      {
        LPDWORD destPixel = destLine;
        LPDWORD srcPixel = srcLine;
        for (LONG x=0; x<width; ++x)
        {
          if ( (*srcPixel & 0xFFFFFF) != transColor )
          {
            *destPixel = *srcPixel;
          }
          destPixel++;
          srcPixel++;
        }
 
        destLine -= dest.getWidth();
        srcLine -= getWidth();
      }
 
      return true;
    }
 
    return false;
  }
 
  bool saveBitmap( LPCTSTR fileName ) const
  {
    //FileHeader用意
    BITMAPFILEHEADER bmpfh;
    bmpfh.bfOffBits = sizeof(bmpfh) + sizeof(m_bmi);
    bmpfh.bfSize = bmpfh.bfOffBits + getWidth()*getHeight()*sizeof(*m_pixel);
    bmpfh.bfType = ('M'<<8)+'B';
    bmpfh.bfReserved1 = bmpfh.bfReserved2 = 0;
 
    //ファイル作成
    HANDLE fh = CreateFile( fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
    if ( fh == INVALID_HANDLE_VALUE )
    {
      return false;
    }
 
    DWORD dwSize;
    WriteFile( fh, &bmpfh, sizeof(BITMAPFILEHEADER), &dwSize, NULL );
    WriteFile( fh, &m_bmi, sizeof(m_bmi), &dwSize, NULL );
    WriteFile( fh, m_pixel, getWidth()*getHeight()*sizeof(*m_pixel), &dwSize, NULL );
    CloseHandle( fh );
 
    return true;
  }
 
  LONG getWidth() const { return m_bmi.bmiHeader.biWidth; }
  LONG getHeight() const { return m_bmi.bmiHeader.biHeight; }
 
  static bool cliping(
    LONG& destX, LONG& destY,
    LONG& width, LONG& height,
    LONG& srcX, LONG& srcY,
    const LONG destWidth, const LONG destHeight,
    const LONG srcWidth, const LONG srcHeight )
  {
    // 左端クリッピング
    if ( destX < 0 ) { width += destX; srcX -= destX; destX = 0; }
    if ( srcX < 0 ) { width += srcX; destX -= srcX; srcX = 0; }
 
    // 右端
    if ( destX + width > destWidth ) { width -= ((destX+width)-destWidth); }
    if ( srcX + width > srcWidth ) { width -= ((srcX+width)-srcWidth); }
 
    // 上
    if ( destY < 0 ) { height += destY; srcY -= destY; destY = 0; }
    if ( srcY < 0 ) { height += srcY; destY -= srcY; srcY = 0; }
 
    // 下
    if ( destY + height > destHeight ) { height -= ((destY+height)-destHeight); }
    if ( srcY + height > srcHeight ) { height -= ((srcY+height)-srcHeight); }
 
    return ((width > 0) & (height > 0));
  }
 
private:
  LPDWORD m_pixel;
  BITMAPINFO m_bmi;
};
 
 
 
 
LRESULT CALLBACK wndProc(
  HWND hWnd,
  UINT msg,
  WPARAM wParam,
  LPARAM lParam )
{
  static DIB32 image;
  static DIB32 image2;
  switch (msg)
  {
  case WM_DESTROY:
    ShowWindow( hWnd, SW_HIDE );
    PostQuitMessage(0);
    break;
  case WM_CREATE:
    image.create( TEXT("image.bmp") );
    image2.create( TEXT("image2.bmp") );
    break;
  case WM_PAINT:
    {
      PAINTSTRUCT ps = {0};
      HDC hdc = BeginPaint( hWnd, &ps );
      image2.render( image, -50, -50, image2.getWidth(), image2.getHeight(), 0, 0 );
      image.render(
        hdc, 10, 10, image.getWidth(), image.getHeight(),
        0, 0, image.getWidth(), image.getHeight() );
      EndPaint( hWnd, &ps );
    }
    break;
  case WM_KEYDOWN:
    if ( wParam == VK_SPACE )
    {
      image.saveBitmap( TEXT("output.bmp") );
    }
    break;
  default:
    return DefWindowProc( hWnd, msg, wParam, lParam );
  }
 
  return 0;
}
 
 
 
 
int WINAPI WinMain(
  HINSTANCE hInstance,
  HINSTANCE hPrevInstance,
  PSTR lpCmdLine,
  int nCmdShow )
{
  LPCTSTR WINDOW_NAME = TEXT("sample");
 
  WNDCLASSEX wc;
  wc.style    = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc  = reinterpret_cast<WNDPROC>( wndProc );
  wc.cbClsExtra  = 0;
  wc.cbWndExtra  = 0;
  wc.cbSize    = sizeof( WNDCLASSEX );
  wc.hInstance  = hInstance;
  wc.hIcon    = NULL;
  wc.hIconSm    = NULL;
  wc.hCursor    = LoadCursor( NULL, IDC_ARROW );
  wc.hbrBackground= reinterpret_cast<HBRUSH>( GetStockObject(WHITE_BRUSH) );
  wc.lpszMenuName  = NULL;
  wc.lpszClassName= WINDOW_NAME;
  if ( !RegisterClassEx(&wc) ) return 0;
 
  LONG winWidth = 640
    + GetSystemMetrics(SM_CXEDGE)
    + GetSystemMetrics(SM_CXBORDER)
    + GetSystemMetrics(SM_CXDLGFRAME);
  LONG winHeight = 480
    + GetSystemMetrics(SM_CYEDGE)
    + GetSystemMetrics(SM_CYBORDER)
    + GetSystemMetrics(SM_CYDLGFRAME)
    + GetSystemMetrics(SM_CYCAPTION);
  HWND hWnd = CreateWindowEx(
    0, WINDOW_NAME, NULL, WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME,
    CW_USEDEFAULT, CW_USEDEFAULT, winWidth, winHeight,
    NULL, NULL, hInstance, NULL);
  if ( !hWnd ) return -1;
 
  ShowWindow( hWnd, SW_SHOWNORMAL );
  UpdateWindow( hWnd );
 
  MSG msg;
  for (;;)
  {
    if ( !GetMessage(&msg, NULL, 0, 0) ) break;
    TranslateMessage( &msg );
    DispatchMessage( &msg );
  }
 
  
  UnregisterClass( WINDOW_NAME, hInstance );
  return msg.wParam;
}

 スペースキーを押すと、output.bmpをファイル出力します。

■関連記事:
生産がす: 32bitDIB(1) 作成と破棄
生産がす: 32bitDIB(2) 画像読み込み
生産がす: 32bitDIB(3) 塗りつぶし
生産がす: 32bitDIB(4) DIBに描画
生産がす: 32bitDIB(5) ファイルに出力
生産がす: 32bitDIB(6) 拡大縮小描画
生産がす: 32bitDIB(7) DIBSection
生産がす: DIB(8) - 直線描画
生産がす: DIB(9) - 回転描画
生産がす: DIB(10) - 三角形描画
生産がす: 日記ちゃん半透明合成
生産がす: 32bitDIBから無圧縮AVI2.0

2010年1月17日日曜日

32bitDIB(4) DIBに描画

■ DIB→DIB

 クリッピングがややこしい以外は、塗りつぶしと同じく1ピクセルずつ書き換えるだけです。
画像の赤い部分が実際に転送される領域ですが、範囲外が含まれていると参照位置や描画サイズを計算しなおす必要があります。


static bool cliping(
  LONG& destX, LONG& destY,
  LONG& width, LONG& height,
  LONG& srcX, LONG& srcY,
  const LONG destWidth, const LONG destHeight,
  const LONG srcWidth, const LONG srcHeight )
{
  // 左端クリッピング
  if ( destX < 0 ) { width += destX; srcX -= destX; destX = 0; }
  if ( srcX < 0 ) { width += srcX; destX -= srcX; srcX = 0; }
 
  // 右端
  if ( destX + width > destWidth ) { width -= ((destX+width)-destWidth); }
  if ( srcX + width > srcWidth ) { width -= ((srcX+width)-srcWidth); }
 
  // 上
  if ( destY < 0 ) { height += destY; srcY -= destY; destY = 0; }
  if ( srcY < 0 ) { height += srcY; destY -= srcY; srcY = 0; }
 
  // 下
  if ( destY + height > destHeight ) { height -= ((destY+height)-destHeight); }
  if ( srcY + height > srcHeight ) { height -= ((srcY+height)-srcHeight); }
 
  return ((width > 0) & (height > 0));
}

 もっといい方法があるのかもしれませんが、まあそこそこ動けばいいんじゃないでしょうか。だめか。
描画する領域がある場合はTrueが返り、引数に指定した変数に変更後のパラメータが各種代入されます。


bool render(
  DIB32& dest,
  LONG destX, LONG destY,
  LONG width, LONG height,
  LONG srcX, LONG srcY ) const
{
  if ( !m_pixel || !dest.m_pixel ) return false;
  if ( cliping(destX, destY, width, height, srcX, srcY, dest.getWidth(), dest.getHeight(), getWidth(), getHeight() ) )
  {
    LPDWORD destLine = dest.m_pixel
      + ((dest.getHeight()-1)-destY)*dest.getWidth()
      + destX;
    LPDWORD srcLine = m_pixel
      + ((getHeight()-1)-srcY)*getWidth()
      + srcX;
    for (LONG y=0; y<height; ++y)
    {
      LPDWORD destPixel = destLine;
      LPDWORD srcPixel = srcLine;
      for (LONG x=0; x<width; ++x)
      {
        *destPixel++ = *srcPixel++;
      }
 
      destLine -= dest.getWidth();
      srcLine -= getWidth();
    }
 
    return true;
  }
 
  return false;
}


 特に変更なくそのまま転送するのであれば、CopyMemoryで一気に転送してもいいのかもしれません。

for (LONG y=0; y<height; ++y)
{
  /*
  LPDWORD destPixel = destLine;
  LPDWORD srcPixel = srcLine;
  for (LONG x=0; x<width; ++x)
  {
    *destPixel++ = *srcPixel++;
  }
  */
  CopyMemory( destLine, srcLine, sizeof(DWORD)*width );
 
  destLine -= dest.getWidth();
  srcLine -= getWidth();
}


 抜き色を考慮するのであればif文で分岐するのがシンプルです。
ビット演算でごにょごにょしても可能ですが経験上ifのほうが高速です。

for (LONG y=0; y<height; ++y)
{
  LPDWORD destPixel = destLine;
  LPDWORD srcPixel = srcLine;
  for (LONG x=0; x<width; ++x)
  {
    if ( (*srcPixel & 0xFFFFFF) != transColor )
    {
      *destPixel = *srcPixel;
    }
    destPixel++;
    srcPixel++;
  }
 
  destLine -= dest.getWidth();
  srcLine -= getWidth();
}



 自分が普段使うときはtemplateで以下みたいにして描画モードを制御してるんですが、これは行儀がいいのか悪いのか。switchで分岐するよりは記述が楽だし、inline展開されれば速度も問題なし。されなければ地獄。

template < class T >
bool render( ... )
{
  ...
  for (LONG y=0; y<height; ++y)
  {
    LPDWORD destPixel = destLine;
    LPDWORD srcPixel = srcLine;
    for (LONG x=0; x<width; ++x)
    {
      T::update( *destPixel++, *srcPixel++ );
    }
 
    destLine -= dest.getWidth();
    srcLine -= getWidth();
  }
}
 
 
 
 
class PutColorCopy
{
public:
  static inline void update( DWORD& dest, DWORD src ) { dest = src; }
};



●サンプル

#include <windows.h>
 
class DIB32
{
public:
  DIB32()
    : m_pixel( NULL )
  {
    ZeroMemory( &m_bmi, sizeof(m_bmi) );
  }
 
  ~DIB32()
  {
    release();
  }
 
  bool create( LONG width, LONG height )
  {
    if ( width <= 0 || height <= 0 ) return false;
    release();
 
    m_pixel = new DWORD[ width * height ];
    if ( !m_pixel ) return false;
 
    m_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    m_bmi.bmiHeader.biWidth = width;
    m_bmi.bmiHeader.biHeight = height;
    m_bmi.bmiHeader.biPlanes = 1;
    //32bit固定にする
    m_bmi.bmiHeader.biBitCount = 32;
    m_bmi.bmiHeader.biCompression = BI_RGB;
    //96dpiだと3780らしい。0の場合もあるとのこと
    m_bmi.bmiHeader.biXPelsPerMeter = 3780;
    m_bmi.bmiHeader.biYPelsPerMeter = 3780;
 
    return true;
  }
 
  bool create( LPCTSTR bitmapFile )
  {
    if ( !bitmapFile ) return false;
 
    HBITMAP hBmp = static_cast<HBITMAP>(
      LoadImage(NULL, bitmapFile, IMAGE_BITMAP,
      0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE) );
    if ( !hBmp ) return false;
 
    BITMAP bm = {0};
    GetObject( hBmp, sizeof(BITMAP), &bm );
 
    // create DC
    HDC hdc = CreateCompatibleDC( NULL );
    if ( !hdc )
    {
      DeleteDC( hdc );
      DeleteObject( hBmp );
      return false;
    }
 
    // create buf
    if ( !create( bm.bmWidth, bm.bmHeight ) )
    {
      DeleteDC( hdc );
      DeleteObject( hBmp );
      return false;
    }
 
    // copy
    GetDIBits( hdc, hBmp, 0, bm.bmHeight,m_pixel, &m_bmi,
      DIB_RGB_COLORS );
 
    DeleteDC( hdc );
    DeleteObject( hBmp );
 
    return true;
  }
 
  void release()
  {
    if ( m_pixel )
    {
      delete [] m_pixel;
      m_pixel = NULL;
    }
    ZeroMemory( &m_bmi, sizeof(m_bmi) );
  }
 
  bool render(
    HDC hdc,
    LONG destX, LONG destY,
    LONG destWidth, LONG destHeight,
    LONG srcX, LONG srcY,
    LONG srcWidth, LONG srcHeight ) const
  {
    return GDI_ERROR != StretchDIBits(
      hdc, destX, destY, destWidth, destHeight,
      srcX, srcY, srcWidth, srcHeight,
      m_pixel, &m_bmi, DIB_RGB_COLORS, SRCCOPY );
  }
 
 
  bool render(
    DIB32& dest,
    LONG destX, LONG destY,
    LONG width, LONG height,
    LONG srcX, LONG srcY ) const
  {
    if ( !m_pixel || !dest.m_pixel ) return false;
    if ( cliping(destX, destY, width, height, srcX, srcY, dest.getWidth(), dest.getHeight(), getWidth(), getHeight() ) )
    {
      LPDWORD destLine = dest.m_pixel
        + ((dest.getHeight()-1)-destY)*dest.getWidth()
        + destX;
      LPDWORD srcLine = m_pixel
        + ((getHeight()-1)-srcY)*getWidth()
        + srcX;
      for (LONG y=0; y<height; ++y)
      {
        /*
        LPDWORD destPixel = destLine;
        LPDWORD srcPixel = srcLine;
        for (LONG x=0; x<width; ++x)
        {
          *destPixel++ = *srcPixel++;
        }
        */
        CopyMemory( destLine, srcLine, sizeof(DWORD)*width );
 
        destLine -= dest.getWidth();
        srcLine -= getWidth();
      }
 
      return true;
    }
 
    return false;
  }
 
  LONG getWidth() const { return m_bmi.bmiHeader.biWidth; }
  LONG getHeight() const { return m_bmi.bmiHeader.biHeight; }
 
  static bool cliping(
    LONG& destX, LONG& destY,
    LONG& width, LONG& height,
    LONG& srcX, LONG& srcY,
    const LONG destWidth, const LONG destHeight,
    const LONG srcWidth, const LONG srcHeight )
  {
    // 左端クリッピング
    if ( destX < 0 ) { width += destX; srcX -= destX; destX = 0; }
    if ( srcX < 0 ) { width += srcX; destX -= srcX; srcX = 0; }
 
    // 右端
    if ( destX + width > destWidth ) { width -= ((destX+width)-destWidth); }
    if ( srcX + width > srcWidth ) { width -= ((srcX+width)-srcWidth); }
 
    // 上
    if ( destY < 0 ) { height += destY; srcY -= destY; destY = 0; }
    if ( srcY < 0 ) { height += srcY; destY -= srcY; srcY = 0; }
 
    // 下
    if ( destY + height > destHeight ) { height -= ((destY+height)-destHeight); }
    if ( srcY + height > srcHeight ) { height -= ((srcY+height)-srcHeight); }
 
    return ((width > 0) & (height > 0));
  }
 
private:
  LPDWORD m_pixel;
  BITMAPINFO m_bmi;
};
 
 
 
 
LRESULT CALLBACK wndProc(
  HWND hWnd,
  UINT msg,
  WPARAM wParam,
  LPARAM lParam )
{
  static DIB32 image;
  static DIB32 image2;
  switch (msg)
  {
  case WM_DESTROY:
    ShowWindow( hWnd, SW_HIDE );
    PostQuitMessage(0);
    break;
  case WM_CREATE:
    image.create( TEXT("image.bmp") );
    image2.create( TEXT("image2.bmp") );
    break;
  case WM_PAINT:
    {
      PAINTSTRUCT ps = {0};
      HDC hdc = BeginPaint( hWnd, &ps );
      image2.render( image, 10, 10, image2.getWidth(), image2.getHeight(), 0, 0 );
      image.render(
        hdc, 10, 10, image.getWidth(), image.getHeight(),
        0, 0, image.getWidth(), image.getHeight() );
      EndPaint( hWnd, &ps );
    }
    break;
  default:
    return DefWindowProc( hWnd, msg, wParam, lParam );
  }
 
  return 0;
}
 
 
 
 
int WINAPI WinMain(
  HINSTANCE hInstance,
  HINSTANCE hPrevInstance,
  PSTR lpCmdLine,
  int nCmdShow )
{
  LPCTSTR WINDOW_NAME = TEXT("sample");
 
  WNDCLASSEX wc;
  wc.style    = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc  = reinterpret_cast<WNDPROC>( wndProc );
  wc.cbClsExtra  = 0;
  wc.cbWndExtra  = 0;
  wc.cbSize    = sizeof( WNDCLASSEX );
  wc.hInstance  = hInstance;
  wc.hIcon    = NULL;
  wc.hIconSm    = NULL;
  wc.hCursor    = LoadCursor( NULL, IDC_ARROW );
  wc.hbrBackground= reinterpret_cast<HBRUSH>( GetStockObject(WHITE_BRUSH) );
  wc.lpszMenuName  = NULL;
  wc.lpszClassName= WINDOW_NAME;
  if ( !RegisterClassEx(&wc) ) return 0;
 
  LONG winWidth = 640
    + GetSystemMetrics(SM_CXEDGE)
    + GetSystemMetrics(SM_CXBORDER)
    + GetSystemMetrics(SM_CXDLGFRAME);
  LONG winHeight = 480
    + GetSystemMetrics(SM_CYEDGE)
    + GetSystemMetrics(SM_CYBORDER)
    + GetSystemMetrics(SM_CYDLGFRAME)
    + GetSystemMetrics(SM_CYCAPTION);
  HWND hWnd = CreateWindowEx(
    0, WINDOW_NAME, NULL, WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME,
    CW_USEDEFAULT, CW_USEDEFAULT, winWidth, winHeight,
    NULL, NULL, hInstance, NULL);
  if ( !hWnd ) return -1;
 
  ShowWindow( hWnd, SW_SHOWNORMAL );
  UpdateWindow( hWnd );
 
  MSG msg;
  for (;;)
  {
    if ( !GetMessage(&msg, NULL, 0, 0) ) break;
    TranslateMessage( &msg );
    DispatchMessage( &msg );
  }
 
  
  UnregisterClass( WINDOW_NAME, hInstance );
  return msg.wParam;
}



 上下反転や左右反転を実装する場合、
*destPixel++destPixel += addなどとしaddに1か-1を入れる、あとはポインタの初期位置を変更すれば実装できます。
もっともクリッピングを考え直す必要があり、頭が痛いのでここまでにしたい。私には無理だ……ドコサヘキサエンさんが足りない。
■関連記事:
生産がす: 32bitDIB(1) 作成と破棄
生産がす: 32bitDIB(2) 画像読み込み
生産がす: 32bitDIB(3) 塗りつぶし
生産がす: 32bitDIB(4) DIBに描画
生産がす: 32bitDIB(5) ファイルに出力
生産がす: 32bitDIB(6) 拡大縮小描画
生産がす: 32bitDIB(7) DIBSection
生産がす: DIB(8) - 直線描画
生産がす: DIB(9) - 回転描画
生産がす: DIB(10) - 三角形描画
生産がす: 日記ちゃん半透明合成
生産がす: 32bitDIBから無圧縮AVI2.0

32bitDIB(3) 塗りつぶし

■塗りつぶし
 Bitmapデータは画面下から上へ向かってデータが格納されるのでポインタ計算に注意しなければなりません。
たとえば座標(10, 10)であれば((height-1)-10)*width + 10の位置に、
座標(50, 24)であれば((height-1)-24)*width + 50の位置にデータがあります。


bool boxf( LONG x, LONG y, LONG width, LONG height, DWORD color )
{
   if ( !m_pixel ) return false;
 
   width = abs( width );
   height = abs( height );
 
   RECT rect;
   rect.left = max( 0, x );
   rect.top = max( 0, y );
   rect.right = min( x+width, getWidth() );
   rect.bottom = min( y+height, getHeight() );
 
   LPDWORD line = m_pixel
     + ((getHeight()-1)-rect.top) * getWidth()
     + rect.left;
   for (LONG py=rect.top; py<rect.bottom; ++py)
   {
     LPDWORD destPixel = line;
     for (LONG px=rect.left; px<rect.right; ++px)
     {
       *destPixel++ = color;
     }
 
     line -= getWidth();
   }
 
   return true;
}

 クリッピングして、あとは1ピクセルごと書き換えていくだけです。
正しくクリッピングできれば範囲外にアクセスしなくなるので、比較的高速に処理することができます。


■サンプル

#include <windows.h>
 
class DIB32
{
public:
  DIB32()
    : m_pixel( NULL )
  {
    ZeroMemory( &m_bmi, sizeof(m_bmi) );
  }
 
  ~DIB32()
  {
    release();
  }
 
  bool create( LONG width, LONG height )
  {
    if ( width <= 0 || height <= 0 ) return false;
    release();
 
    m_pixel = new DWORD[ width * height ];
    if ( !m_pixel ) return false;
 
    m_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    m_bmi.bmiHeader.biWidth = width;
    m_bmi.bmiHeader.biHeight = height;
    m_bmi.bmiHeader.biPlanes = 1;
    //32bit固定にする
    m_bmi.bmiHeader.biBitCount = 32;
    m_bmi.bmiHeader.biCompression = BI_RGB;
    //96dpiだと3780らしい。0の場合もあるとのこと
    m_bmi.bmiHeader.biXPelsPerMeter = 3780;
    m_bmi.bmiHeader.biYPelsPerMeter = 3780;
 
    return true;
  }
 
  bool create( LPCTSTR bitmapFile )
  {
    if ( !bitmapFile ) return false;
 
    HBITMAP hBmp = static_cast<HBITMAP>(
      LoadImage(NULL, bitmapFile, IMAGE_BITMAP,
      0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE) );
    if ( !hBmp ) return false;
 
    BITMAP bm = {0};
    GetObject( hBmp, sizeof(BITMAP), &bm );
 
    // create DC
    HDC hdc = CreateCompatibleDC( NULL );
    if ( !hdc )
    {
      DeleteDC( hdc );
      DeleteObject( hBmp );
      return false;
    }
 
    // create buf
    if ( !create( bm.bmWidth, bm.bmHeight ) )
    {
      DeleteDC( hdc );
      DeleteObject( hBmp );
      return false;
    }
 
    // copy
    GetDIBits( hdc, hBmp, 0, bm.bmHeight,m_pixel, &m_bmi,
      DIB_RGB_COLORS );
 
    DeleteDC( hdc );
    DeleteObject( hBmp );
 
    return true;
  }
 
  void release()
  {
    if ( m_pixel )
    {
      delete [] m_pixel;
      m_pixel = NULL;
    }
    ZeroMemory( &m_bmi, sizeof(m_bmi) );
  }
 
  bool render(
    HDC hdc,
    LONG destX, LONG destY,
    LONG destWidth, LONG destHeight,
    LONG srcX, LONG srcY,
    LONG srcWidth, LONG srcHeight ) const
  {
    return GDI_ERROR != StretchDIBits(
      hdc, destX, destY, destWidth, destHeight,
      srcX, srcY, srcWidth, srcHeight,
      m_pixel, &m_bmi, DIB_RGB_COLORS, SRCCOPY );
  }
 
  bool render( HWND hWnd, HDC hdc )
  {
    RECT rect;
    if ( GetClientRect( hWnd, &rect ) )
    {
      return render(
        hdc, 0, 0, rect.right, rect.bottom,
        0, 0, getWidth(), getHeight() );
    }
 
    return false;
  }
 
  bool boxf( LONG x, LONG y, LONG width, LONG height, DWORD color )
  {
    if ( !m_pixel ) return false;
 
    width = abs( width );
    height = abs( height );
 
    RECT rect;
    rect.left = max( 0, x );
    rect.top = max( 0, y );
    rect.right = min( x+width, getWidth() );
    rect.bottom = min( y+height, getHeight() );
 
    LPDWORD line = m_pixel + ((getHeight()-1)-rect.top) * getWidth() + rect.left;
    for (LONG py=rect.top; py<rect.bottom; ++py)
    {
      LPDWORD destPixel = line;
      for (LONG px=rect.left; px<rect.right; ++px)
      {
        *destPixel++ = color;
      }
 
      line -= getWidth();
    }
 
    return true;
  }
 
  LONG getWidth() const { return m_bmi.bmiHeader.biWidth; }
  LONG getHeight() const { return m_bmi.bmiHeader.biHeight; }
 
private:
  LPDWORD m_pixel;
  BITMAPINFO m_bmi;
};
  
  
LRESULT CALLBACK wndProc(
  HWND hWnd,
  UINT msg,
  WPARAM wParam,
  LPARAM lParam )
{
  static DIB32 image;
  switch (msg)
  {
  case WM_DESTROY:
    ShowWindow( hWnd, SW_HIDE );
    PostQuitMessage(0);
    break;
  case WM_CREATE:
    image.create( TEXT("image.bmp") );
    break;
  case WM_PAINT:
    {
      PAINTSTRUCT ps = {0};
      HDC hdc = BeginPaint( hWnd, &ps );
      image.boxf( 100, 100, 50, 1050, 0xFF00FF );
      image.render(
        hdc, 10, 10, image.getWidth(), image.getHeight(),
        0, 0, image.getWidth(), image.getHeight() );
      EndPaint( hWnd, &ps );
    }
    break;
  default:
    return DefWindowProc( hWnd, msg, wParam, lParam );
  }
 
  return 0;
}
 
 
int WINAPI WinMain(
  HINSTANCE hInstance,
  HINSTANCE hPrevInstance,
  PSTR lpCmdLine,
  int nCmdShow )
{
  LPCTSTR WINDOW_NAME = TEXT("sample");
 
  WNDCLASSEX wc;
  wc.style    = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc  = reinterpret_cast<WNDPROC>( wndProc );
  wc.cbClsExtra  = 0;
  wc.cbWndExtra  = 0;
  wc.cbSize    = sizeof( WNDCLASSEX );
  wc.hInstance  = hInstance;
  wc.hIcon    = NULL;
  wc.hIconSm    = NULL;
  wc.hCursor    = LoadCursor( NULL, IDC_ARROW );
  wc.hbrBackground= reinterpret_cast<HBRUSH>( GetStockObject(WHITE_BRUSH) );
  wc.lpszMenuName  = NULL;
  wc.lpszClassName= WINDOW_NAME;
  if ( !RegisterClassEx(&wc) ) return 0;
 
  LONG winWidth = 640
    + GetSystemMetrics(SM_CXEDGE)
    + GetSystemMetrics(SM_CXBORDER)
    + GetSystemMetrics(SM_CXDLGFRAME);
  LONG winHeight = 480
    + GetSystemMetrics(SM_CYEDGE)
    + GetSystemMetrics(SM_CYBORDER)
    + GetSystemMetrics(SM_CYDLGFRAME)
    + GetSystemMetrics(SM_CYCAPTION);
  HWND hWnd = CreateWindowEx(
    0, WINDOW_NAME, NULL, WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME,
    CW_USEDEFAULT, CW_USEDEFAULT, winWidth, winHeight,
    NULL, NULL, hInstance, NULL);
  if ( !hWnd ) return -1;
 
  ShowWindow( hWnd, SW_SHOWNORMAL );
  UpdateWindow( hWnd );
 
  MSG msg;
  for (;;)
  {
    if ( !GetMessage(&msg, NULL, 0, 0) ) break;
    TranslateMessage( &msg );
    DispatchMessage( &msg );
  }
 
  
  UnregisterClass( WINDOW_NAME, hInstance );
  return msg.wParam;
}



 boxf使用時に高さを1050と異常値にしていますが、クリッピングでカットされています。



 boxf()の*dest++ = colorの部分を変えれば、塗りつぶす以外にもあれこれできますね。そうですか。
■関連記事:
生産がす: 32bitDIB(1) 作成と破棄
生産がす: 32bitDIB(2) 画像読み込み
生産がす: 32bitDIB(3) 塗りつぶし
生産がす: 32bitDIB(4) DIBに描画
生産がす: 32bitDIB(5) ファイルに出力
生産がす: 32bitDIB(6) 拡大縮小描画
生産がす: 32bitDIB(7) DIBSection
生産がす: DIB(8) - 直線描画
生産がす: DIB(9) - 回転描画
生産がす: DIB(10) - 三角形描画
生産がす: 日記ちゃん半透明合成
生産がす: 32bitDIBから無圧縮AVI2.0

32bitDIB(2) 画像読み込み

■画像読み込み


bool create( LPCTSTR bitmapFile )
{
  if ( !bitmapFile ) return false;
 
  HBITMAP hBmp = static_cast(
    LoadImage(NULL, bitmapFile, IMAGE_BITMAP,
    0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE) );
  if ( !hBmp ) return false;
 
  BITMAP bm = {0};
  GetObject( hBmp, sizeof(BITMAP), &bm );
 
  // create DC
  HDC hdc = CreateCompatibleDC( NULL );
  if ( !hdc )
  {
    DeleteDC( hdc );
    DeleteObject( hBmp );
    return false;
  }
 
  // create buf
  if ( !create( bm.bmWidth, bm.bmHeight ) )
  {
    DeleteDC( hdc );
    DeleteObject( hBmp );
    return false;
  }
 
  // copy
  GetDIBits(
    hdc, hBmp, 0, bm.bmHeight, m_pixel, &m_bmi,
    DIB_RGB_COLORS );
 
  DeleteDC( hdc );
  DeleteObject( hBmp );
 
  return true;
}

・LoadImageでHBITMAPを作成。
・GetObjectで横幅と高さを取得。
・取得した横幅、高さでメモリ確保(メンバ関数で)。
・GetDIBitsするためにCreateCompatibleDCでHDCをでっち上げ、
 その後GetDIBitsでHBITMAPのピクセルデータを取得。
・いらなくなったデータを処分。
 といった流れ。

 LoadImageでは各種BITMAPが読み込めるようで、
RLE圧縮されたBITMAPも平然と読んでくれるので便利です。

 
■サンプル

#include <windows.h>
 
class DIB32
{
public:
  DIB32()
    : m_pixel( NULL )
  {
    ZeroMemory( &m_bmi, sizeof(m_bmi) );
  }
 
  ~DIB32()
  {
    release();
  }
 
  bool create( LONG width, LONG height )
  {
    if ( width <= 0 || height <= 0 ) return false;
    release();
 
    m_pixel = new DWORD[ width * height ];
    if ( !m_pixel ) return false;
 
    m_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    m_bmi.bmiHeader.biWidth = width;
    m_bmi.bmiHeader.biHeight = height;
    m_bmi.bmiHeader.biPlanes = 1;
    //32bit固定にする
    m_bmi.bmiHeader.biBitCount = 32;
    m_bmi.bmiHeader.biCompression = BI_RGB;
    //96dpiだと3780らしい。0の場合もあるとのこと
    m_bmi.bmiHeader.biXPelsPerMeter = 3780;
    m_bmi.bmiHeader.biYPelsPerMeter = 3780;
 
    return true;
  }
 
  bool create( LPCTSTR bitmapFile )
  {
    if ( !bitmapFile ) return false;
 
    HBITMAP hBmp = static_cast<HBITMAP>(
      LoadImage(NULL, bitmapFile, IMAGE_BITMAP,
      0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE) );
    if ( !hBmp ) return false;
 
    BITMAP bm = {0};
    GetObject( hBmp, sizeof(BITMAP), &bm );
 
    // create DC
    HDC hdc = CreateCompatibleDC( NULL );
    if ( !hdc )
    {
      DeleteDC( hdc );
      DeleteObject( hBmp );
      return false;
    }
 
    // create buf
    if ( !create( bm.bmWidth, bm.bmHeight ) )
    {
      DeleteDC( hdc );
      DeleteObject( hBmp );
      return false;
    }
 
    // copy
    GetDIBits( hdc, hBmp, 0, bm.bmHeight,m_pixel, &m_bmi,
      DIB_RGB_COLORS );
 
    DeleteDC( hdc );
    DeleteObject( hBmp );
 
    return true;
  }
 
  void release()
  {
    if ( m_pixel )
    {
      delete [] m_pixel;
      m_pixel = NULL;
    }
    ZeroMemory( &m_bmi, sizeof(m_bmi) );
  }
 
  bool render(
    HDC hdc,
    LONG destX, LONG destY,
    LONG destWidth, LONG destHeight,
    LONG srcX, LONG srcY,
    LONG srcWidth, LONG srcHeight ) const
  {
    return GDI_ERROR != StretchDIBits(
      hdc, destX, destY, destWidth, destHeight,
      srcX, srcY, srcWidth, srcHeight,
      m_pixel, &m_bmi, DIB_RGB_COLORS, SRCCOPY );
  }
 
  bool render( HWND hWnd, HDC hdc )
  {
    RECT rect;
    if ( GetClientRect( hWnd, &rect ) )
    {
      return render(
        hdc, 0, 0, rect.right, rect.bottom,
        0, 0, getWidth(), getHeight() );
    }
 
    return false;
  }
 
  LONG getWidth() const { return m_bmi.bmiHeader.biWidth; }
  LONG getHeight() const { return m_bmi.bmiHeader.biHeight; }
 
private:
  LPDWORD m_pixel;
  BITMAPINFO m_bmi;
};
  
  
LRESULT CALLBACK wndProc(
  HWND hWnd,
  UINT msg,
  WPARAM wParam,
  LPARAM lParam )
{
  static DIB32 image;
  switch (msg)
  {
  case WM_DESTROY:
    ShowWindow( hWnd, SW_HIDE );
    PostQuitMessage(0);
    break;
  case WM_CREATE:
    image.create( TEXT("image.bmp") );
    break;
  case WM_PAINT:
    {
      PAINTSTRUCT ps = {0};
      HDC hdc = BeginPaint( hWnd, &ps );
      image.render(
        hdc, 10, 10, image.getWidth(), image.getHeight(),
        0, 0, image.getWidth(), image.getHeight() );
      EndPaint( hWnd, &ps );
    }
    break;
  default:
    return DefWindowProc( hWnd, msg, wParam, lParam );
  }
 
  return 0;
}
 
 
int WINAPI WinMain(
  HINSTANCE hInstance,
  HINSTANCE hPrevInstance,
  PSTR lpCmdLine,
  int nCmdShow )
{
  LPCTSTR WINDOW_NAME = TEXT("sample");
 
  WNDCLASSEX wc;
  wc.style    = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc  = reinterpret_cast<WNDPROC>( wndProc );
  wc.cbClsExtra  = 0;
  wc.cbWndExtra  = 0;
  wc.cbSize    = sizeof( WNDCLASSEX );
  wc.hInstance  = hInstance;
  wc.hIcon    = NULL;
  wc.hIconSm    = NULL;
  wc.hCursor    = LoadCursor( NULL, IDC_ARROW );
  wc.hbrBackground= reinterpret_cast<HBRUSH>( GetStockObject(WHITE_BRUSH) );
  wc.lpszMenuName  = NULL;
  wc.lpszClassName= WINDOW_NAME;
  if ( !RegisterClassEx(&wc) ) return 0;

  LONG winWidth = 640
    + GetSystemMetrics(SM_CXEDGE)
    + GetSystemMetrics(SM_CXBORDER)
    + GetSystemMetrics(SM_CXDLGFRAME);
  LONG winHeight = 480
    + GetSystemMetrics(SM_CYEDGE)
    + GetSystemMetrics(SM_CYBORDER)
    + GetSystemMetrics(SM_CYDLGFRAME)
    + GetSystemMetrics(SM_CYCAPTION);
  HWND hWnd = CreateWindowEx(
    0, WINDOW_NAME, NULL, WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME,
    CW_USEDEFAULT, CW_USEDEFAULT, winWidth, winHeight,
    NULL, NULL, hInstance, NULL);
  if ( !hWnd ) return -1;
 
  ShowWindow( hWnd, SW_SHOWNORMAL );
  UpdateWindow( hWnd );
 
  MSG msg;
  for (;;)
  {
    if ( !GetMessage(&msg, NULL, 0, 0) ) break;
    TranslateMessage( &msg );
    DispatchMessage( &msg );
  }
 
  
  UnregisterClass( WINDOW_NAME, hInstance );
  return msg.wParam;
}




 他にはOleLoadPictureを使えば、JPGやGIFも読み込むことが出来ますが、OleLoadPictureではRLE圧縮のBITMAPを読めないので使い分けが必要なようです。
■関連記事:
生産がす: 32bitDIB(1) 作成と破棄
生産がす: 32bitDIB(2) 画像読み込み
生産がす: 32bitDIB(3) 塗りつぶし
生産がす: 32bitDIB(4) DIBに描画
生産がす: 32bitDIB(5) ファイルに出力
生産がす: 32bitDIB(6) 拡大縮小描画
生産がす: 32bitDIB(7) DIBSection
生産がす: DIB(8) - 直線描画
生産がす: DIB(9) - 回転描画
生産がす: DIB(10) - 三角形描画
生産がす: 日記ちゃん半透明合成
生産がす: 32bitDIBから無圧縮AVI2.0