1. 전형적인 이미지 출력
    1. 윈도우 프로그래밍에서 비트맵 이미지를 출력하는 전형적인 방법
      - 리소스로 등록된 비트맵 이미지를 메모리 DC에 로드하여 화면 DC로 출력(BitBlt())
      - 이미지의 크기를 변경(StretchBlt())
      - 일부 영역을 투명하게 처리(TransparentBlt())
      - 반투명하게 처리(AlphaBlend())
    2. 비트맵(Bitmap)에 대한 이론
      1. 장치 의존적인 비트맵(DDB, Device Dependent Bitmap) & 장치 독립적인 비트맵(DIB, Device Independent Bitmap)으로 나뉨
      2. 우리가 아는 비트맵 파일은 모두 DIB라고 보아도 무방...
      3. 비트맵을 우리 눈으로 보려면 DDB로 변환이 필요
        - 변환 작업은 운영체제가 한다
    3. 비트맵 리소스 출력
    4. void CBmpDisplayDemoView::OnPaint()

      {

      CPaintDC dc(this);

       

      CDC MemDC;

      BITMAP bmpInfo;

       

      //화면 DC와 호환되는 메모리 DC를 생성

      MemDC.CreateCompatibleDC(&dc);

       

      //비트맵 리소스를 로딩

      CBitmap bmp;

      CBitmap* pOldBmp = NULL;

      bmp.LoadBitmap(IDB_Test_Image);//IDB_Test_Image 비트맵 리소스를 미리 등록해야 함.

       

      //로딩된 비트맵의 정보를 알아본다.

      bmp.GetBitmap(&bmpInfo);

       

      //메모리 DC에 선택한다.

      pOldBmp = MemDC.SelectObject(&bmp);

       

      //메모리 DC에 들어 있는 비트맵을 화면 DC로 복사하여 출력

      dc.BitBlt(0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, &MemDC, 0, 0, SRCCOPY);

       

      //두 배 확대하여 출력

      //dc.StrectchBlt(200, 200, 250 * 2, 300 * 2, &MemDC, 350, 200, 250, 300, SRCCOPY);

       

      MemDC.SelectObject(pOldBmp);

      }

      • 화면 DC와 호환되는 메모리 DC
        • 가령 현재 모니터가 32비트 트루 컬러라면 메모리 DC도 같게 32비트 트루 컬러로 설정
      • BitBlt()
        • 메모리 DC에 로드된 비트맵 이미지를 화면 DC로 전송하면 내부적으로 DIB가 DDB로 변환되어 모니터 화면에 출력
        • 마지막 인자 : 래스터 연산(Raster Operation)을 어떻게 할지 명시
          • SRCCOPY - 원본 그대로 화면 DC에 복사
          • SRCAND - 원본과 대상을 AND 연산
          • NOTSRCCOPY - 원본 이미지의 색상을 반전
          • DSTINVERT - 원본 이미지와는 상관없이 대상 이미지를 반전
  2. 고급 이미지 출력 함수
    1. TransparentBlt()
    2. void CBmpDisplayDemoView::OnPaint()

      {

      CPaintDC dc(this);

       

      CDC MemDC;

      BITMAP bmpInfo;

      MemDC.CreateCompatibleDC(&dc);

       

      CBitmap bmp;

      CBitmap* pOldBmp = NULL;

      bmp.LoadBitmap(IDB_Test_Image);

       

      bmp.GetBitmap(&bmpInfo);

      pOldBmp = MemDC.SelectObject(&bmp);

       

      dc.StrectchBlt(20, 20, bmpInfo.bmWidth * 2, bmInfo.bmHeight * 2, &MemDC, 0, 0, bmpInfo.bmWidth, bmInfo.bmHeight, SRCCOPY);

       

      dc.TransparentBlt(20, 100,

      bmpInfo.bmWidth * 2, bmInfo.bmHeight * 2,

      &MemDC,

      0, 0,

      bmpInfo.bmWidth, bmInfo.bmHeight,

      RGB(0, 0, 0));    //투명 처리될 색상의 RGB 값

       

      MemDC.SelectObject(pOldBmp);

      }

      TransprentBlt의 마지막 인자 값이 RGB(0, 0, 0) 이므로 검정색이 투명하게 출력
    3. AlphaBlend()
    4. void CBmpDisplayDemoView::OnPaint()

      {

      CPaintDC dc(this);

       

      CDC MemDC;

      BITMAP bmpInfo;

      MemDC.CreateCompatibleDC(&dc);

       

      CBitmap bmp;

      CBitmap* pOldBmp = NULL;

      bmp.LoadBitmap(IDB_Test_Image);

       

      bmp.GetBitmap(&bmpInfo);

      pOldBmp = MemDC.SelectObject(&bmp);

       

      dc.StrectchBlt(20, 20, bmpInfo.bmWidth * 2, bmInfo.bmHeight * 2, &MemDC, 0, 0, bmpInfo.bmWidth, bmInfo.bmHeight, SRCCOPY);

       

      BLENDFUNCTION bf;

      bf.BlendOp = AC_SRC_OVER;

      bf.BlendFlags = 0;

      bf.SourceConstantAlpha = 50;

      bf.AlphaFormat = 0;

       

      dc.AlphaBlend(20, 100,

      bmpInfo.bmWidth * 2, bmInfo.bmHeight * 2,

      &MemDC,

      0, 0,

      bmpInfo.bmWidth, bmInfo.bmHeight,

      bf);

       

      MemDC.SelectObject(pOldBmp);

      }

      BLENDFUNCTION 구조체 

      BlendOp 멤버 : 원본/대상 이미지를 서로 섞음

      BlendFlags : 사용 안 함(반드시 0)

      SourceConstantAlpha : 투명도(0~255), 0에 가까울수록 투명

      AlphaFormat : 0 or AC_SRC_ALPHA, AC_SRC_ALPHA인 경우는 진정한 32비트 비트맵인 경우

  3. CImage 클래스의 활용
    1. Visual C++ 6.0에선 외부 이미지 파일을 로드하는게 번거로웠다. 비트맵 파일을 제외한 JPEG, PNG, GIF 와 같은 이미지 파일을 로드하려면 별도의 외부 라이브러리를 사용해야 했다.
    2. CImage는 다양한 형식의 파일을 지원한다.
    3. CImage 클래스를 사용하려면 반드시 atlimage.h 파일을 인클루드해야 한다.
    4. void CImgOutDemoView::OnPaint()

      {

      CPaintDC dc(this);

       

      //로드할 이미지 파일 경로

      CString strImagePath = _T("IMG_0076.jpg");

       

      //이미지 파일 로드

      CImage Image;

      HRESULT hResult = Image.Load(strImagePath);

       

      if(FAILED(hResult))

      {

      CString strtmp = _T("ERROR: Failed to load");

      strtmp += strImagePath + _T("\n");

      TRACE(strtmp);

      return;

      }

       

      //화면 DC에 출력

      Image.BitBlt(dc.m_hDC, 0, 0);

      }

      • CImage 클래스는 MFC가 제공하는 ATL(ActiveX Template Library) 클래스 중 하나이다. 그래서 내부적으로 COM(Component Object Model) 객체로 구현되어 있다.
      • C++의 클래스가 논리적인 코드를 객체화한 개념이라면 COM은 실행 바이너리 파일 단위(모듈 단위)로 객체화한 것이라 할 수 있다. 그래서 메서드가 반환하는 값은 HRESULT형이며, FAILED() 매크로나 SUCCEEDED() 매크로를 이용해 오류를 확인한다. 

      void CImgOutDemoView::OnPaint()

      {

      CPaintDC dc(this);

       

      CImage Image;

       

      //비트맵 리소스를 로드하여 DIB 생성

      Image.LoadFromResource(AfxGetInstanceHandle(), IDB_Image_Test);

       

      //비트맵 이미지에 대한 DC 생성

      CDC* pDC = CDC::FromHandle(Image.GetDC());

       

      //이 이미지 DC에 문자열 출력

      pDC->SetBkMode(TRANSPARENT);

      pDC->TextOut(200, 30, ,TEXT("CImage sample!"));

       

      Image.ReleaseDC();

       

      //이미지를 화면 DC에 출력

      Image.BitBlt(dc.m_hDC, 0, 0);

       

      //문자열을 화면 DC에 출력

      //dc.SetBkMode(TRANSPARENT);

      //dc.TextOut(200, 30, ,TEXT("CImage sample!"));

      }

      • LoadFromResource() 메서드는 비트맵 리소스를 로드하여 비트맵 이미지를 생성한다.
  4. 색상(Color)의 변환
    1. RGB 컬러를 흑백으로 변환
    2. #endif //_DEBUG

      inline void RGBtoGray(COLORREF& rgb)
      {
       BYTE byGray = (GetRValue(rgb) * 30
          + GetGValue(rgb) * 59
          + GetBValue(rgb) * 11) / 100
      ;

       rgb = RGB(byGray, byGray, byGray);
      }


      // CSaveGrayDemoView 메시지 처리기 

    3. 바탕화면의 일부를 변환하여 출력
    4. void CSaveGrayDemoView::OnLButtonDown(UINT nFlags, CPoint point)
      {

      // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.

      //바탕화면 윈도우 객체에 대한 포인터를 얻음
      CWnd* pWndDesktop = GetDesktopWindow();
      CWindowDC SrcDC(pWndDesktop);
      CClientDC dc(this);

       

      //바탕화면 크기 및 색상수와 동일한 비트맵 이미지를 만든다.
      CImage Image;
      Image.Create(300, 300, SrcDC.GetDeviceCaps(BITSPIXEL));

       

      //이미지 DC와 화면 DC에 바탕화면 윈도우 DC를 출력한다.
      CDC* pDC = CDC::FromHandle(Image.GetDC());
      pDC->BitBlt(0, 0, 300, 300, &SrcDC, 0, 0, SRCCOPY);
      Image.ReleaseDC();

       

      //일부(200 * 200)를 흑백 이미지로 변환
      COLORREF rgb;
      for(int x = 0; x < 200; x++)
      {
          for(int y = 0; y < 200; y++)
         {
             rgb = Image.GetPixel(x, y);
             //Gray RGB 값으로 변환
             RGBtoGray(rgb);
             Image.SetPixel(x, y, rgb);
         }
      }

       

      //흑백으로 변환된 이미지를 화면 DC에 출력

      Image.BitBlt(dc.m_hDC, 0, 0);

      CView::OnLButtonDown(nFlags, point);

      • GetDesktopWindow() 메서드는 바탕화면 윈도우 객체의 포인터 반환
      • CWindowDC 클래스는 비클라이언트 영역을 포함한 윈도우 전체에 대한 DC
      • CDC 클래스의 GetDeviceCaps() 메서드는 인자로 전달받은 인덱스(BITPIXEL, HORZSIZE, VERTSIZE 등)에 해당하는 DC 정보를 반환
    5. 바탕화면을 별도의 이미지 파일로 저장
    6. void CSaveGrayDemoView::OnRButtonDown(UINT nFlags, CPoint point)
      {

      // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.

      //바탕화면 윈도우 객체에 대한 포인터를 얻음
      CWnd* pWndDesktop = GetDesktopWindow();
      CWindowDC SrcDC(pWndDesktop);
      CClientDC dc(this);

       

      //바탕화면 윈도우의 크기를 알아낸다.
      CRect Rect;
      pWndDesktop->GetWindowRect(&Rect);

       

      //바탕화면 크기 및 색상수와 동일한 비트맵 이미지를 만든다.
      CImage Image;
      int cx = Rect.Width();
      int cy = Rect.Height();
      Image.Create(cx, cy, SrcDC.GetDeviceCaps(BITSPIXEL));

       

      //이미지 DC와 화면 DC에 바탕화면 윈도우 DC를 출력한다.
      CDC* pDC = CDC::FromHandle(Image.GetDC());
      pDC->BitBlt(0, 0, cx, cy, &SrcDC, 0, 0, SRCCOPY);
      dc.BitBlt(0, 0, cx, cy, pDC, 0, 0, SRCCOPY);
      Image.ReleaseDC();

       

      //JPEG 형식으로 바탕 화면 이미지를 저장한다.
      Image.Save(TEXT("desktop.jpg"), Gdiplus::ImageFormatJPEG);

       

      //저장된 이미지를 뷰어를 실행하여 보여준다.
      ::ShellExecute(NULL, TEXT("open"), TEXT("desktop.jpg"), NULL, NULL, SW_SHOW);
       
      CView::OnRButtonDown(nFlags, point);

      }   

      • GetWindowRect()로 바탕화면 윈도우 크기 얻어옴
      • CImage 클래스의 Save() 함수는 현재 선택한 비트맵 이미지를 주어진 파일 형식으로 변환하여 저장 
      • ::ShellExecute() API 함수를 이용하여 이미지 파일 실행


+ Recent posts