locked
How Do I Print a Black Rectangle? RRS feed

  • Question

  • Hi Folks:

    Developing 32 bit app on Win 7 Ultra 64, VS 2010 Pro, C++, Win32, no MFC.

    I have a large app that uses the same function to display the contents of a report on the screen's HDC and the printer's HDC, using GDI. 

    The report consists of a lot of text.  Several rectangles, drawn with FrameRect(), indicate that different text is grouped together. 

    The report also uses several circles, drawn with Arc(). 

    The report displays fine on the screen. 

    The printed report has the text displayed fine, but the rectangles and circles are pail, almost invisible. 

    For this application, printing to an XPS file, and displaying that file, shows everything properly printed, and printing that XPS file prints text, rectangles and circles properly. 

    My client reports the same problem with his printed report. 

    The app is over 100K lines in length, so I've duplicated the problem with a small program. I've included that code, its .rc file and resoruce.h. 

    This sample program uses a function to display a simple collection of a rectangle, an ellipse and two lines. It has a print and a quit button. 

    This function displays on the screen fine, but doesn't display properly for the printer. 

    The XPS file has pail lines  for 3 sides of the rectangle, and no visible line for the bottom of the rectangle.  The lines and ellipse are fine. 

    The printed page has all elements displayed as pail lines and curves. 

    What am I doing wrong? 

    The project uses multi char rather than unicode.

    I hope someone can take a look at this.

    Here is the source:

     



     

    #include <windows.h>
    #include <string>
    #include <commctrl.h>
    #include "resource.h"
    
    INT_PTR CALLBACK brush_printer_problem_dialog_box(HWND hdlg, 
                                                        UINT message, 
                                                        WPARAM wParam, 
                                                        LPARAM lParam);
    
    bool process_print_button(HWND hwnd, std::string *message_string_ptr); 
    bool select_printer(HWND hwnd, PRINTDLGEX *print_dialog_struct_ptr);
    bool print_cover_sheet(HDC printer_hdc, std::string *message_string_ptr);
    bool print_image(HDC printer_hdc, std::string *message_string_ptr);
    void draw_image(HDC hdc, int width, int height);
    
    int WINAPI WinMain (HINSTANCE hinstance, HINSTANCE hPrevInstance,
                                        PSTR szCmdLine, int iCmdShow)
    {
        INT_PTR dialogbox_return = 0;
        DWORD error_code = 0;
        char error_message_buffer[256];
    
        SetLastError(0);
    
        dialogbox_return = 
                    DialogBox(hinstance, 
                            "IDD_PRINTER_BRUSH_PROBLEM",
                            NULL, 
                            (DLGPROC)brush_printer_problem_dialog_box);
    
    }
    
    INT_PTR CALLBACK brush_printer_problem_dialog_box(HWND hdlg, 
                                                        UINT message, 
                                                        WPARAM wParam, 
                                                        LPARAM lParam)
    {
        HDC hdc = NULL;
        std::string local_message_string;
        HBRUSH background_brush_handle = NULL;
        PAINTSTRUCT ps;
        RECT dialog_rect;
    
        switch (message)
        {
        case WM_CTLCOLORDLG:
    
            background_brush_handle = (HBRUSH)GetStockObject(WHITE_BRUSH);
            return INT_PTR(background_brush_handle);
    
        case WM_INITDIALOG:
    
            return FALSE;
    
        case WM_PAINT:
    
            hdc = BeginPaint(hdlg, &ps);
            GetClientRect(hdlg, &dialog_rect);
    
            draw_image(hdc, dialog_rect.right - dialog_rect.left, 
                                                dialog_rect.bottom - dialog_rect.top);
    
            EndPaint(hdlg, &ps);
    
            return 0;
    
        case WM_COMMAND:
    
            switch(LOWORD (wParam))
            {
            case IDOK:
    
                if(HIWORD(wParam) == BN_CLICKED)
                {
                    process_print_button(hdlg, &local_message_string);
                }
    
                break;
    
            case IDCANCEL:
    
                switch(HIWORD(wParam))
                {
                case BN_CLICKED:
    
                    SetLastError(0);
                    EndDialog(hdlg, true);
    
                    break;
                }
    
                return 0;
            }
        }
    
        return 0;
    }
    
    bool process_print_button(HWND hwnd, std::string *message_string_ptr) 
    {
        bool error_found = false;
        HDC printer_hdc = NULL;
        HINSTANCE hinstance = NULL;
        static PRINTDLGEX print_dialog_struct;
        std::string local_message_string;
    
        hinstance = HINSTANCE(GetWindowLongPtr(hwnd, GWLP_HINSTANCE));
    
        if(!select_printer(hwnd, &print_dialog_struct))
        {
            error_found = true;
        }
        else
        {
            printer_hdc = print_dialog_struct.hDC;
    
            if(printer_hdc != NULL)
            {
                print_image(printer_hdc, message_string_ptr);
                DeleteDC(printer_hdc);
            }
        }
    
        return !error_found;
    }
    
    bool select_printer(HWND hwnd, PRINTDLGEX *print_dialog_struct_ptr)
    {
        bool error_found = false;
    
        if(print_dialog_struct_ptr != NULL)
        {
            memset(print_dialog_struct_ptr, 0x00, sizeof (PRINTDLGEX));
    
            print_dialog_struct_ptr->lStructSize         = sizeof (PRINTDLGEX);
            print_dialog_struct_ptr->hwndOwner           = hwnd;
            print_dialog_struct_ptr->Flags               = PD_ALLPAGES | 
                                                            PD_COLLATE | 
                                                            PD_RETURNDC | 
                                                            PD_NOSELECTION |
                                                            PD_HIDEPRINTTOFILE |
                                                            PD_NOPAGENUMS;	// Allows page ranges to be ignored.
            print_dialog_struct_ptr->nCopies             = 1;
            print_dialog_struct_ptr->nStartPage          = START_PAGE_GENERAL;
    
            if(PrintDlgEx(print_dialog_struct_ptr) != S_OK)
            {
                error_found = true;
            }
        }
    
        return !error_found;
    }
    
    bool print_image(HDC printer_hdc, std::string *message_string_ptr)
    {
        bool error_found = false;
        static DOCINFO di = {sizeof (DOCINFO), TEXT ("Print Test")};
        int x_pixels = 0;
        int y_pixels = 0;
    
        if (StartDoc(printer_hdc, &di) > 0)
        {
            x_pixels = GetDeviceCaps(printer_hdc, HORZRES);
            y_pixels = GetDeviceCaps(printer_hdc, VERTRES);
    
            if(StartPage(printer_hdc) > 0)
            {
                draw_image(printer_hdc, x_pixels, y_pixels);
                EndPage(printer_hdc);
            }
    
            EndDoc(printer_hdc);
        }
    
        return !error_found;
    }
    
    void draw_image(HDC hdc, int width, int height)
    {
        RECT test_rect;
        HBRUSH stock_black_brush_handle = (HBRUSH)GetStockObject(BLACK_BRUSH);
        HPEN stock_black_pen_handle = (HPEN)GetStockObject(BLACK_PEN);
        HBRUSH original_brush = (HBRUSH)SelectObject(hdc, stock_black_brush_handle);
        HPEN original_pen = (HPEN)SelectObject(hdc, stock_black_pen_handle);
    
        test_rect.left = width >> 2;
        test_rect.right = width - test_rect.left;
        test_rect.top = height >> 2;
        test_rect.bottom = height - test_rect.top;
    
    
        FrameRect(hdc, &test_rect, stock_black_brush_handle);
    
        Arc(hdc, test_rect.left,
                    test_rect.top,
                        test_rect.right,
                            test_rect.bottom,
                                test_rect.right,
                                    test_rect.bottom,
                                        test_rect.right,
                                            test_rect.bottom);
    
        MoveToEx(hdc, test_rect.left, test_rect.top, NULL);
        LineTo(hdc, test_rect.right, test_rect.bottom);
        MoveToEx(hdc, test_rect.left, test_rect.bottom, NULL);
    
        LineTo(hdc, test_rect.right, test_rect.top);
        SelectObject(hdc, original_brush);
        SelectObject(hdc, original_pen);
    }
    


     




        Here is the .rc file:



    // Microsoft Visual C++ generated resource script.
    //
    #include "resource.h"
    
    #define APSTUDIO_READONLY_SYMBOLS
    /////////////////////////////////////////////////////////////////////////////
    //
    // Generated from the TEXTINCLUDE 2 resource.
    //
    #include "afxres.h"
    
    /////////////////////////////////////////////////////////////////////////////
    #undef APSTUDIO_READONLY_SYMBOLS
    
    /////////////////////////////////////////////////////////////////////////////
    // English (United States) resources
    
    #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
    LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
    
    #ifdef APSTUDIO_INVOKED
    /////////////////////////////////////////////////////////////////////////////
    //
    // TEXTINCLUDE
    //
    
    1 TEXTINCLUDE 
    BEGIN
        "resource.h\0"
    END
    
    2 TEXTINCLUDE 
    BEGIN
        "#include ""afxres.h""\r\n"
        "\0"
    END
    
    3 TEXTINCLUDE 
    BEGIN
        "\r\n"
        "\0"
    END
    
    #endif    // APSTUDIO_INVOKED
    
    
    /////////////////////////////////////////////////////////////////////////////
    //
    // Dialog
    //
    
    IDD_PRINTER_BRUSH_PROBLEM DIALOGEX 0, 0, 316, 183
    STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
    CAPTION "Dialog"
    FONT 8, "MS Shell Dlg", 400, 0, 0x1
    BEGIN
        DEFPUSHBUTTON   "Print",IDOK,106,162,50,14
        PUSHBUTTON      "Cancel",IDCANCEL,160,162,50,14
    END
    
    
    /////////////////////////////////////////////////////////////////////////////
    //
    // DESIGNINFO
    //
    
    #ifdef APSTUDIO_INVOKED
    GUIDELINES DESIGNINFO
    BEGIN
        "IDD_PRINTER_BRUSH_PROBLEM", DIALOG
        BEGIN
            LEFTMARGIN, 7
            RIGHTMARGIN, 309
            TOPMARGIN, 7
            BOTTOMMARGIN, 176
        END
    END
    #endif    // APSTUDIO_INVOKED
    
    #endif    // English (United States) resources
    /////////////////////////////////////////////////////////////////////////////
    
    
    
    #ifndef APSTUDIO_INVOKED
    /////////////////////////////////////////////////////////////////////////////
    //
    // Generated from the TEXTINCLUDE 3 resource.
    //
    
    
    /////////////////////////////////////////////////////////////////////////////
    #endif    // not APSTUDIO_INVOKED
    
    





        Here is the resource.h file:



    //{{NO_DEPENDENCIES}}
    // Microsoft Visual C++ generated include file.
    // Used by printer_brush_problem.rc
    //
    #define IDD_DIALOG1                     101
    
    // Next default values for new objects
    // 
    #ifdef APSTUDIO_INVOKED
    #ifndef APSTUDIO_READONLY_SYMBOLS
    #define _APS_NEXT_RESOURCE_VALUE        102
    #define _APS_NEXT_COMMAND_VALUE         40001
    #define _APS_NEXT_CONTROL_VALUE         1001
    #define _APS_NEXT_SYMED_VALUE           101
    #endif
    #endif
    




    Wednesday, November 9, 2011 4:24 PM

Answers

  • Try using Rectangle (with white or null brush) instead of FrameRect.

     

    You can also create wider pens with CreatePen and maybe use different drawing modes with SetMapMode etc.

    Wednesday, November 9, 2011 7:43 PM

All replies

  • Try using Rectangle (with white or null brush) instead of FrameRect.

     

    You can also create wider pens with CreatePen and maybe use different drawing modes with SetMapMode etc.

    Wednesday, November 9, 2011 7:43 PM
  • Thanks Viorel:

       I've never needed to do that before. This is a new printer/fax/copier combo. 

       I'm now passing draw_image() the line width in pixels, which is calculated from the ratio of the display's line width (1) to the dialog's pixel width. The printer's line width is this ratio times the printer's pixel width. 

       This seems to work, but I'm not totally satisfied with it. 

       How would you handle this?

        It's odd that my clients and I have never run into this problem before.  I'm glad I know this as I put together my first product that will be sold to a wider audience. 

      Is there some method to know the narrowest line line a printer can draw that will be fully black? 

       I appreciate your assistance. 

                  Thanks
                  Larry

     

    Thursday, November 10, 2011 6:37 AM