Solved

Printing 256 colors images drawn in a memory DC

Posted on 1997-04-21
24
454 Views
Last Modified: 2013-11-20
Hi !
I am currently trying to transfer a memory DC (m_dcMem) toward a printer DC by overriding CView::OnPrint(), but whereas everything is OK in Print-Preview Mode, the resulting hardcopy is black and white (without the expected grey-levels). I must precise that m_dcMem is one of my class view members and is initialized with :
      CClientDC ClientDC(AfxGetMainWnd());
      m_dcMem.CreateCompatibleDC(&ClientDC);
Thus, m_dcMem is compatible with a display context, and then I draw a 256 colors image in it (and I visualize the result by transferring m_dcMem to the screen in CView::OnDraw) : the transfer to a Display Context is successfull but the transfer to a Printer DC fails partially (this printer can print grey levels).
Here is the extract of the source code that produce a black and white hard-copy instead of a grey level one :
void CPolytraceView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{ ...

        // pPal is the logical palette associated with the
        // image drawn in m_dcMem.
      m_dcMem.SelectPalette(pPal, TRUE);
      pOldPal = pDC->SelectPalette(pPal, TRUE);
      pDC->SetStretchBltMode(STRETCH_DELETESCANS);
      pDC->StretchBlt(x, y,
                  dx, dy,
                  &m_dcMem,
                  0, 0,
                  dxSrc, dySrc,
                  SRCCOPY);

      if (pOldPal)
      {
            m_dcMem.SelectPalette(pOldPal, FALSE);
            pDC->SelectPalette(pOldPal, FALSE);
            pDC->RealizePalette();
      }
}
Moreover, I tried to use an intermediate memory DC (dcPrinter) between m_dcMem and the printer. dcPrinter was made compatible with the printer DC, and I tried to transfer m_dcMem to dcPrinter with BitBlt, but to do so, I had to create a bitmap and select it into dcPrinter : SelectObject fails if this bitmap is not a monochrome bitmap ! Furthermore, I tried to do m_dcMem local in OnPrint (initialized with "CClientDC ClientDC(this);
dcMem.CreateCompatibleDC(&ClientDC);"), but the result didn't change at all...

Now, I have no more ideas and feel very disappointed not to be able to solve such a classical problem : I need your help and I thank you in advance.
drouaud@jouve.fr
0
Comment
Question by:drouaud
  • 13
  • 6
  • 2
  • +2
24 Comments
 
LVL 4

Expert Comment

by:AVaulin
ID: 1301101
Try to do m_dcMem local in OnPrint method and initialize it
with "this" instead of "AfxGetMianWnd()". I hope it will help.
0
 

Author Comment

by:drouaud
ID: 1301102
Edited text of question
0
 

Author Comment

by:drouaud
ID: 1301103
I am sorry that AVaulin's answer doesn't work, but I sincerely want to thank him(her) because he(she) tried to help me. To proove that I have applied his(her) answer, here is the code I used :
void CPolytraceView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{ ...
   // Initialization and drawing in the memory DC
   CDC dcMem;
   CClientDC ClientDC(this);
   dcMem.CreateCompatibleDC(&ClientDC);
   CPalette* pPal;
   pPal = pDoc->m_pdibFond->GetPalette();
   dcMem.SelectPalette(pPal, TRUE);
   dcMem.RealizePalette();
   PrepareDCMem(TRUE, TRUE, &dcMem); // my drawing function

   // Transfer to the destination DC
   CPalette* pOldPal;
   pOldPal = pDC->SelectPalette(pPal, TRUE);
   pDC->RealizePalette();
   pDC->SetStretchBltMode(STRETCH_DELETESCANS);
   pDC->StretchBlt(x, y,
                   dx, dy,
                   &dcMem,
                   0, 0,
                   dxfond, dyfond,
                   SRCCOPY);

   // Restoration
   if (pOldPal)
   {
      dcMem.SelectPalette(pOldPal, FALSE);

      pDC->SelectPalette(pOldPal, FALSE);
      pDC->RealizePalette();
   }
}
The resulting hardcopy is still black and white (without the expected grey levels)...So as you can guess, I am looking forward for another suggestion.

Thanks a lot and have a nice day.
Damien (drouaud@jouve.fr)

0
 
LVL 1

Expert Comment

by:jmmougeolle
ID: 1301104
What you got to do is to create your compatible DC on the PRINT DC!!!

So you just got to change the dcMem.CreateCompatibleDC(&ClientDC);
into
dcMem.CreateCompatibleDC(pDC);

I think it could help a lot, cause the Palette will be then computed into the Printer options!



0
 

Author Comment

by:drouaud
ID: 1301105
Thanks for your answer, but the resulting hardcopy is completely black ! It is probably due to the fact that in order to draw in this memory DC, I have to create and then to select a bitmap in it. As you can see below (extract of my PrepareDCMem function), I am calling for that purpose CreateBitmap to which I am passing
pDC->GetDeviceCaps(BITSPIXEL) as the bytes per pixel argument :
for a printer DC, the resulting value is 1 byte per pixel, but if I replace pDC->GetDeviceCaps(BITSPIXEL) with the number 8 (for instance), the SelectObject function fails (and the resulting hardcopy is a completely white piece of paper) !
void CPolytraceView::PrepareDCMem(BOOL bRedrawAll, BOOL bFirstTime, CDC* pDC)
{ ...
   if (bRedrawAll)
   {
      if (bFirstTime)
      {
         HBITMAP hbmpFond =
            (HBITMAP)::CreateBitmap(dxfond, dyfond, 1,
                                  pDC->GetDeviceCaps(BITSPIXEL),
                                  NULL);
         m_hbmpOld = (HBITMAP)::SelectObject(pDC->m_hDC,
                                             hbmpFond);
      }

      // Drawing by the means of a special function
      pDoc->m_pdibFond->Draw(pDC, 0, 0, 0, 0, dxfond, dyfond,
                             CDIB_NORMAL);
...
}

Sorry !
Damien (droaud@jouve.fr)
0
 
LVL 4

Expert Comment

by:AVaulin
ID: 1301106
Try follow experiment: use LoadBitmap for existing 256-color
bitmap instead CreateBitmap in CPolytraceView::PrepareDCMem().
0
 
LVL 1

Expert Comment

by:xbwen
ID: 1301107
 I am not known your printer, you said it can print gray-level, is it mean the printer print 256 color picture as a gray-level automaticly?
  As I known, normally, you must create a gray-level palette then
realize it with prnDC, I used this way and print 256 color to gray-level successful.
  If you think my way has some helpful, I can give the detail.
0
 
LVL 1

Expert Comment

by:jmmougeolle
ID: 1301108
To be sure that you could print colored things onto that printer, you just have to test it with text, using different RGB TextColor.... it could help to kow if the problem come from your printer or from your Bitmap preparation...

Anyway, i still inisit on the fact that you don't need a client DC there as you already have on constructed and mapped to the Printer, given by the MFC, and managed correctly!
0
 

Author Comment

by:drouaud
ID: 1301109
First, I want to thank AVaulin, xbwen and jmmougeolle for their respective comment. Second, I want to precise that I am sure that my printer can print gray levels automatically (I have done the tests with CDC::SetTextColor and CDC::TextOut), but I decided to test xbwen's very interesting suggestion using the following code :
void CPolytraceView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{ ...
   CPalette pal;
   CPalette* pOldPal = NULL;

   if (CreateBlackAndWhitePalette(&pal) < 0) ::MessageBeep(-1);
   else
   {
      m_dcMem.SelectPalette(&pal, TRUE);
      m_dcMem.RealizePalette();
      pOldPal = pDC->SelectPalette(&pal, TRUE);
      pDC->RealizePalette();
   }

   pDC->SetStretchBltMode(STRETCH_DELETESCANS);
   pDC->StretchBlt(x, y, dx, dy, &m_dcMem, 0, 0, dxfond, dyfond,
                   SRCCOPY);

   if (pOldPal)
   {
      m_dcMem.SelectPalette(pOldPal, FALSE);
      m_dcMem.RealizePalette();
      pDC->SelectPalette(pOldPal, FALSE);
      pDC->RealizePalette();
   }
}

int CPolytraceView::CreateBlackAndWhitePalette(CPalette* pPal)
{
   LOGPALETTE* pLogPal;
   int i;

   if ((pLogPal = (LOGPALETTE*)LocalAlloc(LMEM_FIXED,
                        sizeof(LOGPALETTE) +
                        256*sizeof(PALETTEENTRY))) != NULL)
   {      
      pLogPal->palVersion = 0x0300;
      pLogPal->palNumEntries = 256;
            
      for (i=0; i<256; i++)
      {
         pLogPal->palPalEntry[i].peRed   = i;
         pLogPal->palPalEntry[i].peGreen = i;
         pLogPal->palPalEntry[i].peBlue  = i;
         pLogPal->palPalEntry[i].peFlags = 0;
      }

      if (!(pPal->CreatePalette(pLogPal)))
      {
         LocalFree((HLOCAL)pLogPal);
         return (-1);
      }

      LocalFree((HLOCAL)pLogPal);
      return (0);
   }
   else return (-1);
}

Unfortunately, the resulting hardcopy remains black and white !
(I have done the test with m_dcMem, a memory DC compatible with the screen (-> black and white hardcopy), and after, I use a local dcMem in OnPrint that I first try to initialize with
   CClientDC ClientDC(this);
   dcMem.CreateCompatibleDC(ClientDC);
(-> black and white hardcopy), and second with
   dcMem.CreateCompatibleDC(ClientDC);
(-> completely black copy).

I begin to think that my problem is not so easy to solve !
Damien (drouaud@jouve.fr)
0
 
LVL 1

Expert Comment

by:xbwen
ID: 1301110
 My way is create a memDC and draw 256 color bitmap in memDC, than create Graylevel palette and realize it with prnDC, use BitBlt from memDC to prnDC.
  I give you my function of create gray-level palette

CPalette * WINAPI CreateGrayPalette(CPalette* srcPal,CPalette* pPal)
{  
    if (pPal != NULL)
        delete pPal;
   
   
    PALETTEENTRY FAR *ppe;
    LPLOGPALETTE lpPal;    // pointer to a logical palette
   
    int Number;
    srcPal->GetObject(sizeof(int),&Number);
   
    lpPal = (LPLOGPALETTE)GlobalAllocPtr(GHND, sizeof(LOGPALETTE)
                                                + sizeof(PALETTEENTRY)
                                                * Number);

            /* if not enough memory, clean up and return NULL */
      if (lpPal == NULL)
            return NULL;


            /* set version and number of palette entries */
      lpPal->palVersion = PALVERSION;
      lpPal->palNumEntries = (WORD)Number;

            /* is this a Win 3.0 DIB? */
    ppe =(PALETTEENTRY FAR*) GlobalAllocPtr(GHND,(DWORD)(Number * 2 * sizeof(PALETTEENTRY)));
   
    if (ppe == NULL)
    {
        GlobalFreePtr(lpPal);
        return NULL;
    }
   
    GetPaletteEntries((HPALETTE)srcPal->m_hObject, 0, Number, ppe);

    for (int i=0; i<Number; i++){
         DWORD rgb=GetLevel(RGB(ppe[i].peRed,ppe[i].peBlue,ppe[i].peGreen));
             lpPal->palPalEntry[i].peRed=GetRValue(rgb);
             lpPal->palPalEntry[i].peGreen=GetGValue(rgb);
             lpPal->palPalEntry[i].peBlue=GetBValue(rgb);
             lpPal->palPalEntry[i].peFlags = 0;            
    }
   
    pPal=new CPalette;    
    pPal->CreatePalette(lpPal);
   
    GlobalFreePtr(lpPal);
    GlobalFreePtr(ppe);
   
    return pPal;
}
//==================================================================
DWORD WINAPI GetLevel(DWORD rgbValue)
{
     DWORD rgb1=RGB(0,0,0);
    DWORD rgb2=RGB(16,16,16);
    DWORD rgb3=RGB(32,32,32);
    DWORD rgb4=RGB(48,48,48);
    DWORD rgb5=RGB(64,64,64);
    DWORD rgb6=RGB(80,80,80);
    DWORD rgb7=RGB(96,96,96);
    DWORD rgb8=RGB(112,112,112);
    DWORD rgb9=RGB(128,128,128);
    DWORD rgb10=RGB(144,144,144);      
    DWORD rgb11=RGB(160,160,160);
    DWORD rgb12=RGB(176,176,176);
    DWORD rgb13=RGB(192,192,192);
    DWORD rgb14=RGB(208,208,208);
    DWORD rgb15=RGB(224,224,224);
    DWORD rgb16=RGB(240,240,240);
    DWORD rgb17=RGB(255,255,255);
   
    if (rgbValue>=0 && rgbValue<rgb2)
        return rgb1;
    else
      if (rgbValue>=rgb2 && rgbValue<rgb3)
          return rgb2;    
      else
        if (rgbValue>=rgb3 && rgbValue<rgb4)
            return rgb3;  
        else
          if (rgbValue>=rgb4 && rgbValue<rgb5)
              return rgb4;  
          else
            if (rgbValue>=rgb5 && rgbValue<rgb6)
                return rgb5;    
            else
              if (rgbValue>=rgb6 && rgbValue<rgb7)
                  return rgb6;      
              else
                if (rgbValue>=rgb7 && rgbValue<rgb8)
                    return rgb7;        
                else
                  if (rgbValue>=rgb8 && rgbValue<rgb9)
                      return rgb8;    
                  else
                    if (rgbValue>=rgb9 && rgbValue<rgb10)
                        return rgb9;
                    else
                      if (rgbValue>=rgb10 && rgbValue<rgb11)
                          return rgb10;
                      else
                        if (rgbValue>=rgb11 && rgbValue<rgb12)
                            return rgb11;  
                        else
                          if (rgbValue>=rgb12 && rgbValue<rgb13)
                              return rgb12;      
                          else
                            if (rgbValue>=rgb13 && rgbValue<rgb14)
                                return rgb13;      
                            else
                              if (rgbValue>=rgb14 && rgbValue<rgb15)
                                  return rgb14;    
                              else
                                if (rgbValue>=rgb15 && rgbValue<rgb16)
                                    return rgb15;        
                                else
                                  if (rgbValue>=rgb16 && rgbValue<rgb17)
                                      return rgb16;
                                  else
                                      return rgb17;                                                      
}


 
0
 

Author Comment

by:drouaud
ID: 1301111
Thanks a lot for your suggestion and your function, but unfortunately, no change was observed when I used it ...
(Remark : I used a memDC compatible with the screen because otherwise, I couldn't select a color bitmap in it).
0
 
LVL 1

Expert Comment

by:xbwen
ID: 1301112
 If you display the memDC on screen without any problem but fail
to print, I start to guess your prnDC.
 
int MyAppWin::Print(HWND hWnd)
{
    HDC                  hPrn;
    DOCINFO            myData;
    this->BeginWaitCursor();
    hPrn = ::GetPrinterDC();
    if(hPrn)
    {
          ::SetPrinterDC(hPrn);
          myData.cbSize = sizeof(DOCINFO);
          myData.lpszDocName = (LPCSTR)"My AppData";
          myData.lpszOutput = (LPCSTR)NULL;
          if(::StartDoc(hPrn, (DOCINFO FAR*)&myData) > 0)
          {  
              this->BeginWaitCursor();
          ::StartPage(hPrn);
          MyPrintFun(hWnd, hPrn);//print what you want                                                
          ::EndPage(hPrn);
          ::EndDoc(hPrn);
            ::DeleteDC(hPrn);
            this->EndWaitCursor();
              return 1;
          }
          else
          {  
          ::MessageBeep(MB_ICONHAND);
          ::AfxMessageBox((LPCSTR)"Fail to print...");    
          }      
          ::DeleteDC(hPrn);
    }
    else
    {
      ::MessageBeep(MB_ICONEXCLAMATION);
      ::AfxMessageBox( (LPCSTR)"Printer driver not found...");
    }
    this->EndWaitCursor();
    return 0;//unsuccessful
}//Print





HDC      GetPrinterDC()
{
      char      cPrinter[77];
      LPCSTR      szDevice, szDriver, szOutput;
      HDC            hPrn      = NULL;
      
      GetProfileString((LPCSTR)"windows", (LPCSTR)"device", (LPCSTR)",,,", (LPSTR)cPrinter, sizeof(cPrinter));
      if(((szDevice      = (LPCSTR)strtok(cPrinter, ",")) != NULL) && ((szDriver      = (LPCSTR)strtok(NULL, ",")) != NULL) && ((szOutput      = (LPCSTR)strtok(NULL, ",")) != NULL))
      {
            hPrn      = CreateDC(szDriver, szDevice, szOutput, (const void FAR*)NULL);
      }
    return hPrn;
}//end of GetPrinterDC

int      SetPrinterDC(HDC hPrn)
{  
   
    HDC SrnDC=CreateIC("DISPLAY",NULL,NULL,(const void FAR*)NULL);
   
      SetMapMode(hPrn, MM_ANISOTROPIC);
      SetWindowExt(hPrn,GetDeviceCaps(SrnDC,LOGPIXELSX),GetDeviceCaps(SrnDC,LOGPIXELSY));
      SetViewportExt(hPrn,GetDeviceCaps(hPrn,LOGPIXELSX),GetDeviceCaps(hPrn,LOGPIXELSY));
      SetWindowOrg(hPrn, 0, 0);
      SetViewportOrg(hPrn, 0, 0);
      DeleteDC(SrnDC);  
      return 1;
}//end of SetPrinterDC

hope this can help you.
0
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 

Author Comment

by:drouaud
ID: 1301113
I am sorry, but one time again, it doesn't work. However, I want to thank xbwen for his so detailed answer, and I think it is time for me to summarize my problem :

- I am using Visual C++ 4.0 and I have a laser printer that can automatically convert colors into gray levels (to determine it, I have called CDC::SetTextColor() and CDC::TextOut() for different colors in my CView::OnPrint function).

- The application I am creating has a Single Document Interface.

- In this application, I am drawing on color memory DC compatible with the Display Context. This memory DC is named m_dcMem and I use it in CView::OnDraw and in CView::OnPrint :
I got the following results :
Transfer toward the screen (in "classical" mode with BitBlt and preview mode, with StrechBlt) -> OK (a color image is displayed);
Transfer toward the printer (with StretchBlt) -> PROBLEM (a black and white hardcopy is produced instead of a gray-level one : that's the problem I would like to solve).

- The initialization of m_dcMem (only one time per document) is done with :
HBITMAP hbmpFond = (HBITMAP)::CreateBitmap(dxfond, dyfond, 1,                           m_dcMem.GetDeviceCaps(BITSPIXEL),
                       NULL);
m_hbmpOld = (HBITMAP)::SelectObject(m_dcMem, hbmpFond);

- A test :
I tried to use an intermediate memory DC (local in OnPrint and compatible with the Printer DC) toward which I tried to transfer m_dcMem, but in this DC compatible with the printer I could just select a MONOCHROME bitmap...

- About palette :
I can retrieve anywhere in my application a pointer pPal toward a CPalette object. This palette is a color one (but I have also tested a gray levels one). Before any transfer toward the screen or a printer (identified by a pointer pDC), I select and realize this palette in it :
   pOldPal = pDC->SelectPalette(pPal, TRUE);
   pDC->RealizePalette();
And after the transfer (that is to say a call to BitBlt or StretchBlt to transfer m_dcMem to *pDC), I restore the original palette :
   pDC->SelectPalette(pOldPal, TRUE);
   pDC->RealizePalette();


I hope that my question is now more precise. Thank you for your patience.
0
 

Author Comment

by:drouaud
ID: 1301114
I am sorry, but one time again, it doesn't work. However, I want to thank xbwen for his so detailed answer, and I think it is time for me to summarize my problem :

- I am using Visual C++ 4.0 and I have a laser printer that can automatically convert colors into gray levels (to determine it, I have called CDC::SetTextColor() and CDC::TextOut() for different colors in my CView::OnPrint function).

- The application I am creating has a Single Document Interface.

- In this application, I am drawing on color memory DC compatible with the Display Context. This memory DC is named m_dcMem and I use it in CView::OnDraw and in CView::OnPrint :
I got the following results :
Transfer toward the screen (in "classical" mode with BitBlt and preview mode, with StrechBlt) -> OK (a color image is displayed);
Transfer toward the printer (with StretchBlt) -> PROBLEM (a black and white hardcopy is produced instead of a gray-level one : that's the problem I would like to solve).

- The initialization of m_dcMem (only one time per document) is done with :
HBITMAP hbmpFond = (HBITMAP)::CreateBitmap(dxfond, dyfond, 1,                           m_dcMem.GetDeviceCaps(BITSPIXEL),
                       NULL);
m_hbmpOld = (HBITMAP)::SelectObject(m_dcMem, hbmpFond);

- A test :
I tried to use an intermediate memory DC (local in OnPrint and compatible with the Printer DC) toward which I tried to transfer m_dcMem, but in this DC compatible with the printer I could just select a MONOCHROME bitmap...

- About palette :
I can retrieve anywhere in my application a pointer pPal toward a CPalette object. This palette is a color one (but I have also tested a gray levels one). Before any transfer toward the screen or a printer (identified by a pointer pDC), I select and realize this palette in it :
   pOldPal = pDC->SelectPalette(pPal, TRUE);
   pDC->RealizePalette();
And after the transfer (that is to say a call to BitBlt or StretchBlt to transfer m_dcMem to *pDC), I restore the original palette :
   pDC->SelectPalette(pOldPal, TRUE);
   pDC->RealizePalette();


I hope that my question is now more precise. Thank you for your patience.
0
 
LVL 1

Expert Comment

by:xbwen
ID: 1301115
when you use StretchBlt(), both DC you use MUST realize the palette. and you prnDC can't create with MONOCHROME bitmap!
0
 

Author Comment

by:drouaud
ID: 1301116
Adjusted points to 80
0
 

Author Comment

by:drouaud
ID: 1301117
I understand your comment xbwen but as you can guess, I have already tried to realize the palette only in the final DC, then only in the memory DC, then in both (before or/and after the transfer has been done)...
0
 
LVL 1

Expert Comment

by:xbwen
ID: 1301118
if you just createCompatibleBitmap with MONOCHROME, you can only
get the black/white printout instead of gray-level one. right?
0
 

Author Comment

by:drouaud
ID: 1301119
OK, but I have written in my previous comment that I am using a memory DC (m_dcMem) compatible with the Display context, so the bitmap I am creating with :
HBITMAP hbmpFond = (HBITMAP)::CreateBitmap(dxfond, dyfond, 1,
                 m_dcMem.GetDeviceCaps(BITSPIXEL), NULL);
is a COLOR bitmap.
Moreover, I have indicated that IF I use another memory DC (named memDC2)(this time compatible with the printer DC) intermediate between m_dcMem and the printer DC, I must apparently select a MONOCHROME bitmap in memDC2, because I have seen experimentaly that the selection of a color bitmap in such a memory DC always fails.
Thanks a lot for your comments and suggestions.
Damien (drouaud@jouve.fr)
0
 

Author Comment

by:drouaud
ID: 1301120
Adjusted points to 201
0
 

Author Comment

by:drouaud
ID: 1301121
I think that using CreateDIBSection instead of CreateBitmap and then selecting the resulting Device Independant Bitmap into m_dcMem may solve my problem : if you agree with me, could you explain me how to define the 4th parameter of CreateDIBSection ?
0
 
LVL 1

Expert Comment

by:xbwen
ID: 1301122
I  f you use CreateCompatibleBitmap() instead of CreateBitmap(), I think there will be more safe.
   Or you can check with the samples\mfc\general\diblook to get some help.
   Maybe I can sent a .exe to you to test my way that I listed above on your printer, I used it under win3.1 one year before.

0
 

Author Comment

by:drouaud
ID: 1301123
Here is an extract of

Visual C++ books Online 4.1
Win32 SDK
Printing Monochrome and Color Bitmaps from Windows

"DIBs and DIB functions should be used for printing color bitmaps [...] When the display bitmap is a color DDB (Device Dependant Bitmap), printing is more difficult because the display DDB may not match the printer DDB format. Because Windows supports a wide variety of devices, this situation is quite common. When the formats DDB differ, the application must convert the display DDB into a print DDB or a DIB.
DIBs are designed to ease the process of transferring images between devices. When an application uses a DIB, the GDI or the output driver performs any conversions required for the device."

Applying it to the question we are interested in, the transfer of a color memory DC (named m_dcMem) compatible with the display context toward a printer DC can be done with :

void CYourClassView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{...
   CPalette* pPal;
   pPal = pDoc->m_pdibFond->GetPalette();
   CPalette* pOldPal = NULL;
   if (!pPal) ::MessageBeep(MB_ICONEXCLAMATION);
   else
   {
      pOldPal = pDC->SelectPalette(pPal, TRUE);
      pDC->RealizePalette();
   }

   CDC* pScreenDC;
   pScreenDC = GetDC();
   CDC InterDCMem;
   InterDCMem.CreateCompatibleDC(pScreenDC);
   ReleaseDC(pScreenDC);

   // HERE IS THE KEY POINT : the use of CreateDIBSection instead
   // of CreateBitmap or CreateCompatibleBitmap
   HBITMAP hbmpOld;
   HBITMAP hbmpFond =
      (HBITMAP)::CreateDIBSection(InterDCMem.GetSafeHdc(),
                                  lpbi, DIB_RGB_COLORS,
                                  &lpBits, NULL, 0);
   hbmpOld = HBITMAP)::SelectObject(InterDCMem.GetSafeHdc(),
                                    hbmpFond);

   InterDCMem.BitBlt(0, 0, dxfond, dyfond,
                     &m_dcMem,
                     0, 0,
                     SRCCOPY);

   pDC->SetStretchBltMode(COLORONCOLOR);
   pDC->StretchBlt(x, y, dx, dy,
                   &InterDCMem,
                   0, 0,
                   dxfond, dyfond,
                   SRCCOPY);

   if (hbmpOld) ::SelectObject(InterDCMem.GetSafeHdc(), hbmpOld);
   if (hbmpFond) ::DeleteObject(hbmpFond);

   if (pOldPal)
   {
      pDC->SelectPalette(pOldPal, FALSE);
      pDC->RealizePalette();
   }
}

Remark : you don't need to use a gray-level palette even if your printer is not a color printer, and as you can see, there is no problem to transfer an intermediate memory DC compatible with the screen toward a printer DC !

I use this method and it perfectly works, but if you disagree with it or if you think that your solution is better, you can contact me by e-mail (till august 97) : drouaud@jouve.fr
0
 
LVL 7

Accepted Solution

by:
linda101698 earned 200 total points
ID: 1301124
I'm posting drouaud's solution as an answer so the question can be graded.

Here is an extract of

                     Visual C++ books Online 4.1
                     Win32 SDK
                     Printing Monochrome and Color Bitmaps from Windows

                     "DIBs and DIB functions should be used for printing color bitmaps [...] When the display bitmap is a color
                     DDB (Device Dependant Bitmap), printing is more difficult because the display DDB may not match the
                     printer DDB format. Because Windows supports a wide variety of devices, this situation is quite common.
                     When the formats DDB differ, the application must convert the display DDB into a print DDB or a DIB.
                     DIBs are designed to ease the process of transferring images between devices. When an application uses a
                     DIB, the GDI or the output driver performs any conversions required for the device."

                     Applying it to the question we are interested in, the transfer of a color memory DC (named m_dcMem)
                     compatible with the display context toward a printer DC can be done with :

                     void CYourClassView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
                     {...
                        CPalette* pPal;
                        pPal = pDoc->m_pdibFond->GetPalette();
                        CPalette* pOldPal = NULL;
                        if (!pPal) ::MessageBeep(MB_ICONEXCLAMATION);
                        else
                        {
                         pOldPal = pDC->SelectPalette(pPal, TRUE);
                         pDC->RealizePalette();
                        }

                        CDC* pScreenDC;
                        pScreenDC = GetDC();
                        CDC InterDCMem;
                        InterDCMem.CreateCompatibleDC(pScreenDC);
                        ReleaseDC(pScreenDC);

                        // HERE IS THE KEY POINT : the use of CreateDIBSection instead
                        // of CreateBitmap or CreateCompatibleBitmap
                        HBITMAP hbmpOld;
                        HBITMAP hbmpFond =
                         (HBITMAP)::CreateDIBSection(InterDCMem.GetSafeHdc(),
                         lpbi, DIB_RGB_COLORS,
                         &lpBits, NULL, 0);
                        hbmpOld = HBITMAP)::SelectObject(InterDCMem.GetSafeHdc(),
                         hbmpFond);

                        InterDCMem.BitBlt(0, 0, dxfond, dyfond,
                         &m_dcMem,
                         0, 0,
                         SRCCOPY);

                        pDC->SetStretchBltMode(COLORONCOLOR);
                        pDC->StretchBlt(x, y, dx, dy,
                         &InterDCMem,
                         0, 0,
                         dxfond, dyfond,
                         SRCCOPY);

                        if (hbmpOld) ::SelectObject(InterDCMem.GetSafeHdc(), hbmpOld);
                        if (hbmpFond) ::DeleteObject(hbmpFond);

                        if (pOldPal)
                        {
                         pDC->SelectPalette(pOldPal, FALSE);
                         pDC->RealizePalette();
                        }
                     }

                     Remark : you don't need to use a gray-level palette even if your printer is not a color printer, and as you can
                     see, there is no problem to transfer an intermediate memory DC compatible with the screen toward a printer
                     DC !

                     I use this method and it perfectly works.
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

Introduction: Load and Save to file, Document-View interaction inside the SDI. Continuing from the second article about sudoku.   Open the project in visual studio. From the class view select CSudokuDoc and double click to open the header …
Introduction: Finishing the grid – keyboard support for arrow keys to manoeuvre, entering the numbers.  The PreTranslateMessage function is to be used to intercept and respond to keyboard events. Continuing from the fourth article about sudoku. …
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now