Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. The mismatch between Print preview and the real printing

The mismatch between Print preview and the real printing

Scheduled Pinned Locked Moved C / C++ / MFC
c++graphicshostingcloudhelp
8 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • U Offline
    U Offline
    User 13855067
    wrote on last edited by
    #1

    I want to print a bitmap. To avoid printing small bitmap I set CScrollView mode as MM_LOMETRIC with sizes 3830x1995. I have created the bitmap and made the bitblt to the screen. There were everythig just like I want on the screen and on the print preview but when I printed the document I`ve got very bad result. It seems to me that printer does not see a bitmap the same way as print preview does. Pay attantion that the first ractangle puts directly on the DC and memDC puts into it. Are there any ideas how to fix this mismatch between print previw and the real printing? MFC_T_Print_1.zip[^]

    void OnDraw()
    {
    CPen pen;
    pen.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
    CPen* OldPen = pDC->SelectObject(&pen);

    CRect rcView;
    GetClientRect(rcView);
    int iClientWidth = rcView.right;
    int iClientHeight = rcView.bottom;
    int iMemWidth = 1900;
    int iMemHeight = 950;
    CDC memDC;
    CBitmap memBitmap;
    memDC.CreateCompatibleDC(pDC);
    memBitmap.CreateCompatibleBitmap(pDC, iMemWidth, iMemHeight);
    memDC.SelectObject(&memBitmap);
    memDC.SetMapMode(MM\_LOMETRIC);
    CPen pen1;
    pen1.CreatePen(PS\_SOLID, 3, RGB(0, 0, 0));
    memDC.SelectObject(&pen1);
    CBrush brBK;
    brBK.CreateSolidBrush(RGB(255, 255, 255));
    memDC.SelectObject(&brBK);
    RECT rc;
    rc.left = 0;
    rc.top = 0;
    rc.right = iMemWidth;
    rc.bottom = iMemHeight;
    memDC.FillRect(&rc, &brBK);
    memDC.Rectangle(rc.left, rc.top, rc.right, -rc.bottom);
    memDC.MoveTo(0, 0);
    memDC.LineTo(1900, -950);
    
    memDC.MoveTo(0, -950);
    memDC.LineTo(200, -750);
    
    CFont font;
    font.CreateFont(
        50,                        // nHeight
        0,                         // nWidth
        0,                         // nEscapement
        0,                         // nOrientation
        FW\_NORMAL,                 // nWeight
        FALSE,                     // bItalic
        FALSE,                     // bUnderline
        0,                         // cStrikeOut
        ANSI\_CHARSET,              // nCharSet
        OUT\_DEFAULT\_PRECIS,        // nOutPrecision
        CLIP\_DEFAULT\_PRECIS,       // nClipPrecision
        DEFAULT\_QUALITY,           // nQuality
        DEFAULT\_PITCH | FF\_SWISS,  // nPitchAndFamily
        \_T("Arial"));
    memDC.SelectObject(&font);
    memDC.TextOut(100, -
    
    L 1 Reply Last reply
    0
    • U User 13855067

      I want to print a bitmap. To avoid printing small bitmap I set CScrollView mode as MM_LOMETRIC with sizes 3830x1995. I have created the bitmap and made the bitblt to the screen. There were everythig just like I want on the screen and on the print preview but when I printed the document I`ve got very bad result. It seems to me that printer does not see a bitmap the same way as print preview does. Pay attantion that the first ractangle puts directly on the DC and memDC puts into it. Are there any ideas how to fix this mismatch between print previw and the real printing? MFC_T_Print_1.zip[^]

      void OnDraw()
      {
      CPen pen;
      pen.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
      CPen* OldPen = pDC->SelectObject(&pen);

      CRect rcView;
      GetClientRect(rcView);
      int iClientWidth = rcView.right;
      int iClientHeight = rcView.bottom;
      int iMemWidth = 1900;
      int iMemHeight = 950;
      CDC memDC;
      CBitmap memBitmap;
      memDC.CreateCompatibleDC(pDC);
      memBitmap.CreateCompatibleBitmap(pDC, iMemWidth, iMemHeight);
      memDC.SelectObject(&memBitmap);
      memDC.SetMapMode(MM\_LOMETRIC);
      CPen pen1;
      pen1.CreatePen(PS\_SOLID, 3, RGB(0, 0, 0));
      memDC.SelectObject(&pen1);
      CBrush brBK;
      brBK.CreateSolidBrush(RGB(255, 255, 255));
      memDC.SelectObject(&brBK);
      RECT rc;
      rc.left = 0;
      rc.top = 0;
      rc.right = iMemWidth;
      rc.bottom = iMemHeight;
      memDC.FillRect(&rc, &brBK);
      memDC.Rectangle(rc.left, rc.top, rc.right, -rc.bottom);
      memDC.MoveTo(0, 0);
      memDC.LineTo(1900, -950);
      
      memDC.MoveTo(0, -950);
      memDC.LineTo(200, -750);
      
      CFont font;
      font.CreateFont(
          50,                        // nHeight
          0,                         // nWidth
          0,                         // nEscapement
          0,                         // nOrientation
          FW\_NORMAL,                 // nWeight
          FALSE,                     // bItalic
          FALSE,                     // bUnderline
          0,                         // cStrikeOut
          ANSI\_CHARSET,              // nCharSet
          OUT\_DEFAULT\_PRECIS,        // nOutPrecision
          CLIP\_DEFAULT\_PRECIS,       // nClipPrecision
          DEFAULT\_QUALITY,           // nQuality
          DEFAULT\_PITCH | FF\_SWISS,  // nPitchAndFamily
          \_T("Arial"));
      memDC.SelectObject(&font);
      memDC.TextOut(100, -
      
      L Offline
      L Offline
      Lost User
      wrote on last edited by
      #2

      You need to set the mapping mode in the actual device context where you are writing the data. In this case you need to set it into the PrinterDC to make it consistent with the screen settings, and the actual image. See Mapping Modes and Translations | Microsoft Docs[^].

      U 1 Reply Last reply
      0
      • L Lost User

        You need to set the mapping mode in the actual device context where you are writing the data. In this case you need to set it into the PrinterDC to make it consistent with the screen settings, and the actual image. See Mapping Modes and Translations | Microsoft Docs[^].

        U Offline
        U Offline
        User 13855067
        wrote on last edited by
        #3

        Mapping mode (MM_LOMETRICETRIC) has been set both in OnPrepareDC() and in OnPrint(). The result is the same - we still have mismatch between print preview and the real printing.

        L 1 Reply Last reply
        0
        • U User 13855067

          Mapping mode (MM_LOMETRICETRIC) has been set both in OnPrepareDC() and in OnPrint(). The result is the same - we still have mismatch between print preview and the real printing.

          L Offline
          L Offline
          leon de boer
          wrote on last edited by
          #4

          The screen works on 96DPI unless you are in a DPI aware app which if you want to confirm

          HDC screen = GetDC(0);
          long hPixelsPerInch = GetDeviceCaps(screen,LOGPIXELSX);
          long vPixelsPerInch = GetDeviceCaps(screen,LOGPIXELSY);

          So it's setup that 96 pixels = 1 inch, not in the real world but that is what 96 pixel represents on screen When you map it to 0.1mm per device space 25.4mm = 1 inch so 254 pixels now = 1 inch Now the same works for the resolution of your printer depending on it's resolution So lets say you are printing at 150dpi on the printer so when you set it to 0.1mm per device unit 1500 pixels = 1 inch on the printer Normallly the printer select dialog goes close because it knows the screen is 96DPI and it knows what the printer DPI is but you have messed about with the modes and thrown it out by a fair bit. It's usually pretty close all by itself :-) Anyhow the scaling is easy .... correct size = size * effective Printer DPI / effective Screen DPI; When you select the printer you can get it's DC and pass it into the code above and get it's hPixelsPerInch and vPixelsPerInch just as you did the screen. Hence you can work out the scale.

          In vino veritas

          U 1 Reply Last reply
          0
          • L leon de boer

            The screen works on 96DPI unless you are in a DPI aware app which if you want to confirm

            HDC screen = GetDC(0);
            long hPixelsPerInch = GetDeviceCaps(screen,LOGPIXELSX);
            long vPixelsPerInch = GetDeviceCaps(screen,LOGPIXELSY);

            So it's setup that 96 pixels = 1 inch, not in the real world but that is what 96 pixel represents on screen When you map it to 0.1mm per device space 25.4mm = 1 inch so 254 pixels now = 1 inch Now the same works for the resolution of your printer depending on it's resolution So lets say you are printing at 150dpi on the printer so when you set it to 0.1mm per device unit 1500 pixels = 1 inch on the printer Normallly the printer select dialog goes close because it knows the screen is 96DPI and it knows what the printer DPI is but you have messed about with the modes and thrown it out by a fair bit. It's usually pretty close all by itself :-) Anyhow the scaling is easy .... correct size = size * effective Printer DPI / effective Screen DPI; When you select the printer you can get it's DC and pass it into the code above and get it's hPixelsPerInch and vPixelsPerInch just as you did the screen. Hence you can work out the scale.

            In vino veritas

            U Offline
            U Offline
            User 13855067
            wrote on last edited by
            #5

            Thak you for the answer but there is a problem with the bitmap that is inscribed in the ractangle. If you look at the print preview - you will see this bitmap well. But if you print the real page you will see that ractangle is printed perfectly but the bitmap (inscribed into ractangle) was cut from the right side and the bottom. If there was a problem with dpi we would have problems both with the ractangle and with the bitmap. Print preview: Preview[^] Real print: Printed page[^]

            L 1 Reply Last reply
            0
            • U User 13855067

              Thak you for the answer but there is a problem with the bitmap that is inscribed in the ractangle. If you look at the print preview - you will see this bitmap well. But if you print the real page you will see that ractangle is printed perfectly but the bitmap (inscribed into ractangle) was cut from the right side and the bottom. If there was a problem with dpi we would have problems both with the ractangle and with the bitmap. Print preview: Preview[^] Real print: Printed page[^]

              L Offline
              L Offline
              leon de boer
              wrote on last edited by
              #6

              And there is nothing surprising about that you only made your DC a fixed size based on screen, Rough guess your printer is running at 300 DPI, confirm what resolution you have on printer? let me jog your memory with your memory bitmap/DC (which matches the screen) ===> memBitmap.CreateCompatibleBitmap(pDC, iMemWidth, iMemHeight); then you only transfer that screen size ====> pDC->BitBlt(10, -10, iMemWidth, -iMemHeight, &memDC, 0, 0, SRCCOPY); Those sizes are in screen pixels the printer DC is different to iMemWidth, iMemHeight pixels, It is hardly surprising you only get the top left corner, it is telling you the same thing :-) Remember the sizes on the transfer are in the DC pixels of the DC you use for the function. You have pDC vs memDC and those are not the same DPI. You would either need to StretchBlt or get the printer DC and work out the size to make the memory bitmap that size because it has a different DPI. If you can set the printer to 100 DPI which is as close to 96 DPI you will get close to what you want :-).

              In vino veritas

              U 1 Reply Last reply
              0
              • L leon de boer

                And there is nothing surprising about that you only made your DC a fixed size based on screen, Rough guess your printer is running at 300 DPI, confirm what resolution you have on printer? let me jog your memory with your memory bitmap/DC (which matches the screen) ===> memBitmap.CreateCompatibleBitmap(pDC, iMemWidth, iMemHeight); then you only transfer that screen size ====> pDC->BitBlt(10, -10, iMemWidth, -iMemHeight, &memDC, 0, 0, SRCCOPY); Those sizes are in screen pixels the printer DC is different to iMemWidth, iMemHeight pixels, It is hardly surprising you only get the top left corner, it is telling you the same thing :-) Remember the sizes on the transfer are in the DC pixels of the DC you use for the function. You have pDC vs memDC and those are not the same DPI. You would either need to StretchBlt or get the printer DC and work out the size to make the memory bitmap that size because it has a different DPI. If you can set the printer to 100 DPI which is as close to 96 DPI you will get close to what you want :-).

                In vino veritas

                U Offline
                U Offline
                User 13855067
                wrote on last edited by
                #7

                Nice idea but :-( I tried to make different Width and Height for display and printer. It broke Print Preview[^]. But when I`ve printed document the result was the same[^] .

                int iMemWidth = 1900; // 1900
                int iMemHeight = 950; // 950
                ...
                if (pDC->GetDeviceCaps(TECHNOLOGY) == DT\_RASDISPLAY)
                {
                	pDC->BitBlt(10, -10, iMemWidth, -iMemHeight, &memDC, 0, 0, SRCCOPY);
                }
                else if (pDC->GetDeviceCaps(TECHNOLOGY) == DT\_RASPRINTER)
                {
                	pDC->BitBlt(10, -10, 3830, -1950, &memDC, 0, 0, SRCCOPY);
                }
                

                Here is the source code: MFC_T_Print_LOMETRIC.zip[^]

                L 1 Reply Last reply
                0
                • U User 13855067

                  Nice idea but :-( I tried to make different Width and Height for display and printer. It broke Print Preview[^]. But when I`ve printed document the result was the same[^] .

                  int iMemWidth = 1900; // 1900
                  int iMemHeight = 950; // 950
                  ...
                  if (pDC->GetDeviceCaps(TECHNOLOGY) == DT\_RASDISPLAY)
                  {
                  	pDC->BitBlt(10, -10, iMemWidth, -iMemHeight, &memDC, 0, 0, SRCCOPY);
                  }
                  else if (pDC->GetDeviceCaps(TECHNOLOGY) == DT\_RASPRINTER)
                  {
                  	pDC->BitBlt(10, -10, 3830, -1950, &memDC, 0, 0, SRCCOPY);
                  }
                  

                  Here is the source code: MFC_T_Print_LOMETRIC.zip[^]

                  L Offline
                  L Offline
                  leon de boer
                  wrote on last edited by
                  #8

                  You aren't getting that memory DC's are basically free you aren't limited to just one and why they exist :-) Lets see if I can make you understand. This stuff is only important for bitmaps you can print text all day and never need to know this stuff 1.) When you print bitmaps you make a new memory DC to match the printer not the screen!!!! HDC SecondDC = CreateCompatibleDC( >>> PrinterDC <<<); 2.) Put your image on the memory DC and you use it to print .. just like you did the screen DC 3.) Now print it. 4.) Now you destroy the memory DC that matches the printer you are done with it. At no point in that did I change or alter your screen bitmap/DC What you aren't grasping is why you need a memory DC .. so lets deal with that because it is important. So a true device DC may have a different planes and colour layout to your image and if that was done at a driver level, every driver would have to know how to deal with every colour format. So they don't do that the driver generally knows exactly one colour format usually RGB. The memory context is the thing that knows all the different formats and is essentially device independent. So when you want to print what a bitmap what you want is a memory context that matches the PRINTER DC not the screen. That is all covered here .. I want you to carefully read the paragraph that starts with "The original bitmap in a memory DC is simply a placeholder" Memory Device Contexts | Microsoft Docs[^] Now here is a tutorial on bitmap printing I want you to go to Part 9 https://www.dreamincode.net/forums/topic/261009-bitmap-printing-tutorial-in-c-win32/ I want you to take particular note of lines 9 to 13 which does this

                  prn = GetPrinterDC(hwnd);
                  cxpage = GetDeviceCaps (prn, HORZRES);
                  cypage = GetDeviceCaps (prn, VERTRES);
                  hdcMem = CreateCompatibleDC(prn);
                  HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hBitmap);

                  If you understood the above you will understand what they are doing but lets walk thru it 1.) They got the printer DC because that is our device NOT the screen 2.) They got the width and height of the printer from that DC. 3.) They made a memory DC to the printer DC to transfer the image onto (printer D

                  1 Reply Last reply
                  0
                  Reply
                  • Reply as topic
                  Log in to reply
                  • Oldest to Newest
                  • Newest to Oldest
                  • Most Votes


                  • Login

                  • Don't have an account? Register

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • World
                  • Users
                  • Groups