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

0 件のコメント: