0

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.

df234987
  • 413
  • 1
  • 9
  • Why don't you go back to basics and just try to print a text string and see if you can get that output to the printer. – Andrew Truckle Feb 22 '20 at 18:53
  • All my print items work. In this one if I don't do anything special for printing (and let the assert break but continue), it prints, it just prints real tiny. – df234987 Feb 22 '20 at 19:02
  • So doesn’t where it asserts indicate the offending line? – Andrew Truckle Feb 22 '20 at 19:19
  • The assert doesn't occur now, it's when I use the OnDraw plain without the adjustments added above for print mode and it was on the `ASSERT(MM_TEXT == pDCView->GetMapMode());` – df234987 Feb 22 '20 at 19:56
  • If I set the `SetWindowExt` to match the `SetViewportExt` it prints to the center of the page but tiny again. I take it I somehow need to adjust SetWindowExt to a value so print the correct size to match the screen. Is there a formula for that? – df234987 Feb 22 '20 at 20:15
  • That makes sense: https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-setmapmode Why not use the metric mapping mode and do an appropriate conversion. And test with a basic rectangle before fiddling with an image. – Andrew Truckle Feb 22 '20 at 22:19
  • added fix to original question. – df234987 Feb 23 '20 at 03:21

1 Answers1

0

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
  }
}
df234987
  • 413
  • 1
  • 9