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

  • looker from clarisonic venerable

    Posted by iouwanzi on 06/06/2013 09:49pm

    [url=http://www.australiaclarisonic.com/clarisonic-mia]clarisonic mia[/url] Souvent, vous pourriez certainement blâmer la médecine. straightner cheveux babyliss Pour être en mesure de bien déterminer qui sont les premiers hébergeurs sont le soutien cyberespace, vous avez vraiment besoin de prendre du temps, ce qui est malheureusement de vos services, pour explorer avec vous pour la recherche. [url=http://www.miaclarisonicaustralia.org/]clarisonic mia[/url] Avec concernant la saison de Noël, j’ai couru à travers une idée de cadeau vraiment attractif, votre package de Collection de nuit. un nouvel ensemble de boîte très exquis option limitée en place qui comprend également tous les flambant neuf G Platinum intemporelle GHD Styler haute définition, matériel résistant à la chaleur, seulement deux caractéristiques montre les cheveux bouclés, un nouveau miroir de belle main baroque, un séchoir de cheveux bouclés nouvelles d’acquérir voyage autour ultra-compact, ainsi qu’une belle organisation. [url=http://www.miaclarisonicaustralia.org/]clarisonic australia[/url] ghd pas cher peut être une marque japonaise de qui vend le fer à lisser en céramique et même des produits qui comprennent un sèche-cheveux, bonne prise en charge ainsi que des brosses. Que les modèles de plaque de céramique habituellement sont associés à premium et en particulier le lisseur chauffe en quelques minutes. At taper l’ultramoderne sera même petit bip qui vous avertit qu’il peut être tous ensemble.Superb confortable !

    Reply
  • You necessitate some tomato basil and mozzarella. Into indoor power, these slippers are as emerge considering and manueverable as sneakers.

    Posted by Soaceddew on 04/25/2013 12:59am

    Has just released respective new color Democratic Inneva Woven shoes, Nike recently with another way to regurgitate shoes with diverse styling to all [url=http://markwarren.org.uk/goodbuy.cfm]nike free uk[/url] eyes. This brings steadfast print run Let off Inneva Woven is a Creamy Marker of works in the series, represents shoes Italian made the assurance. Latest Free Inneva Woven swart and blue are available in two color schemes, to hand-knit Woven vamp in summing-up to infiltrated Italy's [url=http://northernroofing.co.uk/roofins.cfm]nike free run 3[/url] finest crafts, during the interval gives athletes terminate to the foot of ease, the most consequential thing is the end of Free 5 configuration, barefoot know it will bring cannot be ignored. Nike Empty Inneva Woven SP Pale-complexioned Characterization Compact on March 16 at outlets on all sides the [url=http://northernroofing.co.uk/roofins.cfm]nike free run[/url] trade name on the shelves, and on trade in minimal sort, interested friends should recompense terminate ralame to Nike announced the news.

    Reply
  • 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

  • The latest release of SugarCRM's flagship product gives users new tools to build extraordinary customer relationships. Read an in-depth analysis of SugarCRM's enhanced ability to help companies execute their customer-facing initiatives from Ovum, a leading technology research firm.

  • The impact of a data loss event can be significant. Real-time data is essential to remaining competitive. Many companies can no longer afford to rely on a truck arriving each day to take backup tapes offsite. For most companies, a cloud backup and recovery solution will eliminate, or significantly reduce, IT resources related to the mundane task of backup and allow your resources to be redeployed to more strategic projects. The cloud - can now be comfortable for you – with 100% recovery from anywhere all …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds