Manipulating Draw Mode Settings and Using GDI+ to Save



Click here for a larger image.

Environment: Tested on Windows 2000

A simple demonstration of draw mode settings as well as a demonstration using GDI+ to save to a file.

This is my first column. I'll show you how to set the drawing mode with SetROP2. Parameters R2_NOTXORPEN Pixel are the inverse of the R2_XORPEN color (final pixel = NOT(pen XOR screen pixel)).

LRESULT CMiniProjectView::WindowProc
        (UINT message, WPARAM wParam, LPARAM lParam)
{
  CDC *pDC = NULL;
  CMiniProjectDoc *pDoc = NULL;
  CMainFrame *pMainFrame = (CMainFrame *)AfxGetMainWnd();

  CPen *pOldPen = NULL;
  CDrawObj *pDwObj = NULL;
  CRect rcClient, rcRT, rcSave;
  CPoint ptClientUL, ptClientLR;
  static POINTS ptsBegin;
  static POINTS ptsEnd;
  static POINTS ptsPrevEnd;
  static BOOL bPrevLine = FALSE;
  INT_PTR nNewFH = 0;

  switch (message)
  {
    case WM_SAVE_TO_FILE:
      SaveToFile((BOOL)wParam);

      break;
    case WM_RECT_TRACK:
      pDoc = GetDocument();
      ASSERT(pDoc);

      GetClientRect(&rcClient);
      m_bSelArea = (BOOL)wParam;

      if((INT)lParam == 1)
        rcRT.CopyRect(DEF_RECT1);
      else
        rcRT.CopyRect(DEF_RECT2);

      rcRT.SetRect(0, 0, rcRT.Width() * MULTI,
                         rcRT.Height() * MULTI);
      rcRT.OffsetRect((rcClient.Width() 
                       -rcRT.Width()) >> 1, (rcClient.Height()
                       -rcRT.Height()) >> 1);

      pDoc->m_rtSelArea.m_rect.CopyRect(rcRT);
      InvalidateRect(&rcClient, TRUE);

      break;
      case WM_LBUTTONDOWN:
      ptsBegin = MAKEPOINTS(lParam);
      pDoc = GetDocument();
      ASSERT(pDoc);

      if(m_bSelArea)
      {
        pDoc->m_rtSelArea.GetTrueRect(&rcSave);
        if(pDoc->m_rtSelArea.HitTest
          (CPoint(ptsBegin.x, ptsBegin.y)) !=
                  CRectTracker::hitNothing)
        {
          pDoc->m_rtSelArea.Track(this, CPoint
                                 (ptsBegin.x, ptsBegin.y));
          Invalidate(TRUE);
          return 0;
        }
      }

      SetCapture();
      GetClientRect(&rcClient);
      ptClientUL.x = rcClient.left;
      ptClientUL.y = rcClient.top;

      ptClientLR.x = rcClient.right + 1;
      ptClientLR.y = rcClient.bottom + 1;
      ClientToScreen(&ptClientUL);
      ClientToScreen(&ptClientLR);

      SetRect(&rcClient, ptClientUL.x, ptClientUL.y,
                         ptClientLR.x, ptClientLR.y);
      ClipCursor(&rcClient);

      if(pMainFrame->m_eActiveStyle == eFreehandStyle)
      {
        ASSERT(pDoc->m_parrObj);

        pDoc->m_parrObj->Add(new CDrawObj
                         (CRect(ptsBegin.x, ptsBegin.y,
                                ptsEnd.x, ptsEnd.y),
                                pMainFrame->m_eActiveStyle));
      }

      return 0;
      case WM_MOUSEMOVE:
      pDoc = GetDocument();

      if (wParam & MK_LBUTTON)
      {
        pDC = GetDC();
        pDC->SetROP2(R2_NOTXORPEN);
        CPen pen(PS_SOLID, PEN_WIDTH, RGB(0, 0, 0));
        pOldPen = pDC->SelectObject(&pen);

        switch(pMainFrame->m_eActiveStyle)
        {
          case eLineStyle:
            if (bPrevLine)
            {
              pDC->MoveTo(ptsBegin.x, ptsBegin.y);
              pDC->LineTo(ptsPrevEnd.x, ptsPrevEnd.y);
          }

            ptsEnd = MAKEPOINTS(lParam);
            pDC->MoveTo(ptsBegin.x, ptsBegin.y);
            pDC->LineTo(ptsEnd.x, ptsEnd.y);

            bPrevLine = TRUE;
            ptsPrevEnd = ptsEnd;

            break;
          case eSquareStyle:
            if (bPrevLine)
              pDC->Rectangle(ptsBegin.x, ptsBegin.y,
                             ptsPrevEnd.x, ptsPrevEnd.y);

          ptsEnd = MAKEPOINTS(lParam);
          pDC->Rectangle(ptsBegin.x,  ptsBegin.y,
                            ptsEnd.x, ptsEnd.y);

            bPrevLine = TRUE;
            ptsPrevEnd = ptsEnd;

            break;
          case eFreehandStyle:
            ptsEnd = MAKEPOINTS(lParam);
            pDC->MoveTo(ptsBegin.x, ptsBegin.y);
            pDC->LineTo(ptsEnd.x, ptsEnd.y);

            bPrevLine = TRUE;
            ptsPrevEnd = ptsEnd;
            ptsBegin = ptsEnd;

            //save point
            nNewFH = pDoc->m_parrObj->GetCount() - 1;
            if(nNewFH >= 0)
            {
              pDwObj = (CDrawObj *)pDoc->m_parrObj->GetAt(nNewFH);
              if(pDwObj == NULL)
              {TRACE0("Get NULL of Freehand object\n");
                break;
              }

              if(pDwObj->m_eStyle == eFreehandStyle)
                pDwObj->m_parrPoint->Add(new CPoint
                                        (ptsEnd.x, ptsEnd.y));
            }
            break;
          case eCircleStyle:
            if (bPrevLine)
              pDC->Ellipse(ptsBegin.x, ptsBegin.y,
                           ptsPrevEnd.x, ptsPrevEnd.y);

            ptsEnd = MAKEPOINTS(lParam);
            if((ptsEnd.x - ptsBegin.x > 0) &&
                          (ptsEnd.x - ptsBegin.x < MIN_SIZE))
              break;
            else if((ptsEnd.x - ptsBegin.x < 0) &&
                    (ptsBegin.x - ptsEnd.x < MIN_SIZE))
              break;
            else
            {
              pDC->Ellipse(ptsBegin.x, ptsBegin.y,
                           ptsEnd.x, ptsEnd.y);
              bPrevLine = TRUE;
              ptsPrevEnd = ptsEnd;
            }

            break;
          default:
            break;
        } //end style
        pDC->SelectObject(pOldPen);
        pDC->ReleaseOutputDC();
      }

            break;
         case WM_LBUTTONUP:
      pDoc = GetDocument();
      bPrevLine = FALSE;
      ClipCursor(NULL);
      ReleaseCapture();

      ASSERT(pDoc->m_parrObj);
      if(pMainFrame->m_eActiveStyle != eFreehandStyle)
      {
        pDoc->m_parrObj->Add(new CDrawObj( CRect
                            (ptsBegin.x, ptsBegin.y,
                             ptsEnd.x, ptsEnd.y),
                             pMainFrame->m_eActiveStyle));
      }

      return 0;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
  }

  return CView::WindowProc(message, wParam, lParam);
}

For saving to a file, I showed you how to use GDI+. Before using GDI+, you must initialize GDI+ with GdiplusStartup(...) and override GetEncoderClsid(...) to get the encode class identified for the target image type.

int CMiniProjectView::GetEncoderClsid
                      (const WCHAR* format, CLSID* pClsid)
{
  UINT  num = 0;          // number of image encoders
  UINT  size = 0;         // size of the image encoder array
                          // in bytes

  ImageCodecInfo* pImageCodecInfo = NULL;

  GetImageEncodersSize(&num, &size);
  if(size == 0)
    return -1;

  pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
  if(pImageCodecInfo == NULL)
    return -1;

  GetImageEncoders(num, size, pImageCodecInfo);

  for(UINT j = 0; j < num; ++j)
  {
    if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
    {
      *pClsid = pImageCodecInfo[j].Clsid;
      free(pImageCodecInfo);
      return j;  // Success
    }
  }

  free(pImageCodecInfo);
  return -1;
}


  GdiplusStartupInput gdiplusStartupInput;
  ULONG_PTR gdiplusToken;
  GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

  Bitmap *pBitmap = Bitmap::FromHBITMAP(
                    (HBITMAP)bmp.GetSafeHandle(),
                    (HPALETTE)pPalette->GetSafeHandle());

  //get encoder CLSID
  CLSID Clsid;
  if(fileDlg.GetFileExt().MakeUpper() == _T("BMP"))
    GetEncoderClsid(L"image/bmp", &Clsid);
  else if(fileDlg.GetFileExt().MakeUpper() == _T("GIF"))
    GetEncoderClsid(L"image/gif", &Clsid);
  else if(fileDlg.GetFileExt().MakeUpper() == _T("JPG"))
    GetEncoderClsid(L"image/jpeg", &Clsid);

  //save to file with current color
  BSTR bstrFileName = fileDlg.GetPathName().AllocSysString();
  pBitmap->Save(bstrFileName, &Clsid, NULL);

  //clear and shutdown GDI+
  SysFreeString(bstrFileName);
  GdiplusShutdown(gdiplusToken);

You must initialize an array of EncoderParameters if you want to set parameters for encoding.

  long nCompress = 0;
  EncoderParameters encoderParameters[2];
  encoderParameters[0].Count = 2;
  encoderParameters[0].Parameter[0].Guid = EncoderQuality;
  encoderParameters[0].Parameter[0].NumberOfValues = 1;
  encoderParameters[0].Parameter[0].Type = 
                       EncoderParameterValueTypeLong;
  encoderParameters[0].Parameter[0].Value = &nCompress;

  int nDep = 1;
  encoderParameters[1].Parameter[0].Guid = EncoderColorDepth;
  encoderParameters[1].Parameter[0].NumberOfValues = 1;
  encoderParameters[1].Parameter[0].Type = 
                       EncoderParameterValueTypeLong;
  encoderParameters[1].Parameter[0].Value = &nDep;

  //save to file with current color
  BSTR bstrFileName =  fileDlg.GetPathName().AllocSysString();
  pBitmap->Save(bstrFileName, &Clsid, encoderParameters);

Downloads

Download demo project - 44 Kb
Download source - 202 Kb