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


Comments

  • Must have VC++ 7.0 to run and complie

    Posted by Legacy on 12/30/2002 12:00am

    Originally posted by: Anonymous

    ...

    Reply
  • Complier Err, Why not use MFC4.2 lib, it is enough

    Posted by Legacy on 10/28/2002 12:00am

    Originally posted by: Too many compile error

    Pls note to the readers it is compiled in Visual .Net
    You know there is no GetCount() in CPrtArray class, so how u conpile these codes.
    At last pls limk staticly to facilate the readers, thank u.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date