Search code examples
printingbitmapmfcstretchdibits

MFC: How do you print a DI Bitmap to the printer?


I'm using MFC and trying to use OnPrint() to print the contents of a DI Bitmap. I know how to get my bitmap, I know of ::StretchDIBit to get to to a DC, but to do it, I need to know the paper size and want to say if normal bitmap size fits, just use that, if too big, make it smaller. But Where do I get the page size? How do I relate my DI bitmap width / height to the output to the printer page?

Sending the ::StretchDIBit to some random values for testing:

pDC->SetMapMode(MM_ISOTROPIC);
pDC->SetWindowExt(500, 500);
pDC->SetViewportExt(4500, 6500);

Printed but it was stretched out of proportion. If I just simply send it down to __super::OnPrint() it prints but very tiny. I'd rather let it just use the OnDraw() which outputs to the screen fine and that's what __super::OnPrint() does, but how do I set it up to print the correct size and proportion?

TIA!!

EDIT:

Based on answer below, it didn't work. Nothing printed. If I used MM_ISOTROPIC when showing on the CView (not printing) nothing was showing so I mad the map mode conditional. Here's the complete code including scaling supported in the CView window. What is missing/wrong?

TIA!!

void CMyImageView::OnDraw(CDC* pDCView)
{
  if (m_DIBData != NULL) {
    #define PALSIZE(x) ((x) > 8? 0: 1 << (x))

    // move different versions of bitmap header to bitmap structure
    BITMAP bm;
    if (m_DIBData->biSize == sizeof(BITMAPCOREHEADER)) {
      bm.bmWidth=((BITMAPCOREHEADER*)m_DIBData)->bcWidth;
      bm.bmHeight=((BITMAPCOREHEADER*)m_DIBData)->bcHeight;
      bm.bmBitsPixel=((BITMAPCOREHEADER*)m_DIBData)->bcBitCount;
      bm.bmType=BI_RGB;
      bm.bmBits=PBYTE(m_DIBData) + m_DIBData->biSize + PALSIZE(bm.bmBitsPixel) * 3;
    }
    else {
      bm.bmWidth=m_DIBData->biWidth;
      bm.bmHeight=m_DIBData->biHeight;
      bm.bmBitsPixel=m_DIBData->biBitCount;
      bm.bmType=m_DIBData->biCompression;
      long color=m_DIBData->biClrUsed ? m_DIBData->biClrUsed : PALSIZE(bm.bmBitsPixel);
      bm.bmBits=PBYTE(m_DIBData) + m_DIBData->biSize + color * 4;
    }

    CPoint point=GetScrollPosition();

    CRect rcClient(0, 0, 0, 0);

    if(pDCView->IsPrinting())
    {
      pDCView->SetMapMode(MM_ISOTROPIC);
      pDCView->SetWindowExt(bm.bmWidth, bm.bmHeight);

      rcClient.right=pDCView->GetDeviceCaps(HORZRES);
      rcClient.bottom=pDCView->GetDeviceCaps(VERTRES);

      // setup view
      pDCView->SetViewportExt(rcClient.right, rcClient.bottom);
    }
    else {
      ASSERT(MM_TEXT == pDCView->GetMapMode());
      ASSERT(CPoint(0, 0) == pDCView->GetViewportOrg());
      GetClientRect(rcClient);
    }

    const int cx=rcClient.right;      // view client area width
    const int cy=rcClient.bottom;     // view client area height
    const int bx=bm.bmWidth;          // source bitmap width
    const int by=bm.bmHeight;         // source bitmap height
    const int vx=(int)(bx * m_fZoom); // virtual document width
    const int vy=(int)(by * m_fZoom); // virtual document height
    const int xPos=point.x;           // horizontal scroll position
    const int yPos=point.y;           // vertical scroll position

    // source and destination coordinates and sizes
    int xSrc, ySrc, nSrcWidth, nSrcHeight, xDst, yDst, nDstWidth, nDstHeight;

    if (vx > cx) {
      xSrc=(int)(xPos / m_fZoom);
      nSrcWidth=bx - xSrc;
      xDst=0;
      nDstWidth=vx - xPos;
    }
    else {
      xSrc=0;
      nSrcWidth=bx;
      xDst=cx / 2 - vx / 2;
      nDstWidth=vx;
    }

    if (vy > cy) {
      ySrc=0;
      nSrcHeight=by;
      yDst=-yPos;
      nDstHeight=vy;
    }
    else {
      ySrc=0;
      nSrcHeight=by;
      yDst=cy / 2 - vy / 2;
      nDstHeight=vy;
    }

    ::StretchDIBits(pDCView->m_hDC,
                    xDst, yDst,                 // xy-coordinates of upper-left corner of dest. rect.
                    nDstWidth, nDstHeight,      // width & height of destination rectangle
                    xSrc, ySrc,                 // xy-coordinates of lower-left corner of source rect.
                    nSrcWidth, nSrcHeight,      // width & height of source rectangle
                    bm.bmBits,                  // address of array with DIB bits
                    (BITMAPINFO*)m_DIBData,     // address of structure with bitmap info
                    DIB_RGB_COLORS,             // usage flags
                    SRCCOPY);                   // raster operation code
  }
}

Edit:

So I modified the IsPrinting section above to be:

    if(pDCView->IsPrinting())
    {
      pDCView->SetMapMode(MM_ISOTROPIC);
      // setup base size of item
      pDCView->SetWindowExt(bm.bmWidth, bm.bmHeight);
      rcClient.right=bm.bmWidth;
      rcClient.bottom=bm.bmHeight;

      // setup view output to full page
      int horzres=pDCView->GetDeviceCaps(HORZRES);
      int vertres=pDCView->GetDeviceCaps(VERTRES);
      pDCView->SetViewportExt(horzres, vertres);
    }

It worked! But now I have to ask about bitmaps and precision output in a different question.


Solution

  • The answer is:

    void CMyImageView::OnDraw(CDC* pDCView)
    {
      if (m_DIBData != NULL) {
        #define PALSIZE(x) ((x) > 8? 0: 1 << (x))
    
        // move different versions of bitmap header to bitmap structure
        BITMAP bm;
        if (m_DIBData->biSize == sizeof(BITMAPCOREHEADER)) {
          bm.bmWidth=((BITMAPCOREHEADER*)m_DIBData)->bcWidth;
          bm.bmHeight=((BITMAPCOREHEADER*)m_DIBData)->bcHeight;
          bm.bmBitsPixel=((BITMAPCOREHEADER*)m_DIBData)->bcBitCount;
          bm.bmType=BI_RGB;
          bm.bmBits=PBYTE(m_DIBData) + m_DIBData->biSize + PALSIZE(bm.bmBitsPixel) * 3;
        }
        else {
          bm.bmWidth=m_DIBData->biWidth;
          bm.bmHeight=m_DIBData->biHeight;
          bm.bmBitsPixel=m_DIBData->biBitCount;
          bm.bmType=m_DIBData->biCompression;
          long color=m_DIBData->biClrUsed ? m_DIBData->biClrUsed : PALSIZE(bm.bmBitsPixel);
          bm.bmBits=PBYTE(m_DIBData) + m_DIBData->biSize + color * 4;
        }
    
        CPoint point=GetScrollPosition();
    
        CRect rcClient(0, 0, 0, 0);
    
        if(pDCView->IsPrinting())
        {
          pDCView->SetMapMode(MM_ISOTROPIC);
          // setup base size of item
          pDCView->SetWindowExt(bm.bmWidth, bm.bmHeight);
          rcClient.right=bm.bmWidth;
          rcClient.bottom=bm.bmHeight;
    
          // setup view output to full page
          int horzres=pDCView->GetDeviceCaps(HORZRES);
          int vertres=pDCView->GetDeviceCaps(VERTRES);
          pDCView->SetViewportExt(horzres, vertres);
        }
        else {
          ASSERT(MM_TEXT == pDCView->GetMapMode());
          ASSERT(CPoint(0, 0) == pDCView->GetViewportOrg());
          GetClientRect(rcClient);
        }
    
        const int cx=rcClient.right;      // view client area width
        const int cy=rcClient.bottom;     // view client area height
        const int bx=bm.bmWidth;          // source bitmap width
        const int by=bm.bmHeight;         // source bitmap height
        const int vx=(int)(bx * m_fZoom); // virtual document width
        const int vy=(int)(by * m_fZoom); // virtual document height
        const int xPos=point.x;           // horizontal scroll position
        const int yPos=point.y;           // vertical scroll position
    
        // source and destination coordinates and sizes
        int xSrc, ySrc, nSrcWidth, nSrcHeight, xDst, yDst, nDstWidth, nDstHeight;
    
        if (vx > cx) {
          xSrc=(int)(xPos / m_fZoom);
          nSrcWidth=bx - xSrc;
          xDst=0;
          nDstWidth=vx - xPos;
        }
        else {
          xSrc=0;
          nSrcWidth=bx;
          xDst=cx / 2 - vx / 2;
          nDstWidth=vx;
        }
    
        if (vy > cy) {
          ySrc=0;
          nSrcHeight=by;
          yDst=-yPos;
          nDstHeight=vy;
        }
        else {
          ySrc=0;
          nSrcHeight=by;
          yDst=cy / 2 - vy / 2;
          nDstHeight=vy;
        }
    
        ::StretchDIBits(pDCView->m_hDC,
                        xDst, yDst,                 // xy-coordinates of upper-left corner of dest. rect.
                        nDstWidth, nDstHeight,      // width & height of destination rectangle
                        xSrc, ySrc,                 // xy-coordinates of lower-left corner of source rect.
                        nSrcWidth, nSrcHeight,      // width & height of source rectangle
                        bm.bmBits,                  // address of array with DIB bits
                        (BITMAPINFO*)m_DIBData,     // address of structure with bitmap info
                        DIB_RGB_COLORS,             // usage flags
                        SRCCOPY);                   // raster operation code
      }
    }