After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 381371 - Print margins not correct in WIN32 - not allowing for unprintable area
Print margins not correct in WIN32 - not allowing for unprintable area
Status: RESOLVED FIXED
Product: gtk+
Classification: Platform
Component: Printing
2.10.x
Other All
: Normal normal
: ---
Assigned To: gtk-bugs
: 582583 (view as bug list)
Depends on:
Blocks:
 
 
Reported: 2006-12-01 18:59 UTC by Ian Puleston
Modified: 2011-02-09 02:16 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Test program to demo the problem (3.51 KB, application/x-compressed-tar)
2009-04-26 07:41 UTC, Ian Puleston
  Details
Patch with a fix for this problem (3.75 KB, patch)
2009-04-26 16:18 UTC, Ian Puleston
none Details | Review
Fix win32 printing offset (3.14 KB, patch)
2009-10-25 02:24 UTC, Adrian Johnson
none Details | Review
Fix win32 printing offset (1.21 KB, patch)
2009-10-25 10:08 UTC, Adrian Johnson
none Details | Review

Description Ian Puleston 2006-12-01 18:59:50 UTC
Please describe the problem:
I have an app which, amongst other things, prints labels on sheets of adhesive labels, and therefore it needs positioning on the paper to be exact. That is not happening in the WIN32 port in that the print margins are bigger than they should be. When I request 1" print margins I get margins of about 1.25". This shows up on different printers and also when printing to a PDF (via PdfFactory Pro).

The mechanism that I'm using to request the margin size is as follows, called either before the call to gtk_message_dialog_new, or in the "begin-print" handler (with topMargin and leftMargin set to 1.0 for 1" margins):

    pageSetup = gtk_page_setup_new();
    gtk_page_setup_set_top_margin(pageSetup, topMargin, GTK_UNIT_INCH);
    gtk_page_setup_set_left_margin(pageSetup, leftMargin, GTK_UNIT_INCH);
    gtk_page_setup_set_bottom_margin(pageSetup, bottomMargin, GTK_UNIT_INCH);
    gtk_print_operation_set_default_page_setup(operation, pageSetup);


Steps to reproduce:
1. Execute the above code with the top and left margin values set to 1.0.
2. Print a page.
3. Grab a rule and measure the top and left margins.



Actual results:
The top and left margins are about 1.25".

Expected results:
The top and left margins should be exactly 1.0".

Does this happen every time?
Yep.

Other information:
I'm pretty sure that it is happening because in Windows you need to allow for the print device's non-printable area and subtract that from the margin sizes, which the GtkPrintOperation is apparently not doing. A work-around is to call the following function from the "begin-print" handler:

/*
 * Sets the print margins.
 *
 * In Windows this needs to be called after the printer has been selected
 *
 * Margins are in inches
 */
void
setPrintMargins(GtkPrintOperation *operation, gdouble topMargin,
                gdouble btmMargin, gdouble leftMargin)
{
    GtkPageSetup        *pageSetup;

#ifdef _WIN32
    /* Should not need to do this - it should be done by GTK! */
    gdouble             offset_x, offset_y;
    POINT               pt;
    HDC                 hDc;
    GtkPrintSettings    *settings;
    const gchar         *printerName;

    settings = gtk_print_operation_get_print_settings(operation);
    printerName = gtk_print_settings_get_printer(settings);

    hDc = CreateDC("WINSPOOL", printerName, NULL, NULL);
    if (hDc)
    {
        pt.x = GetDeviceCaps(hDc, PHYSICALOFFSETX);
        pt.y = GetDeviceCaps(hDc, PHYSICALOFFSETY);
        /* Convert Windows logical units -> pixels and then -> inches */
        LPtoDP(hDc, &pt, 1);
        offset_x = (gdouble)pt.x / (gdouble)GetDeviceCaps(hDc, LOGPIXELSX);
        offset_y = (gdouble)pt.y / (gdouble)GetDeviceCaps(hDc, LOGPIXELSY);

        topMargin -= offset_y;
        leftMargin -= offset_x;
        btmMargin -= offset_y;
    }
#endif

    /* Set the margins */
    pageSetup = gtk_page_setup_new();
    gtk_page_setup_set_top_margin(pageSetup, topMargin, GTK_UNIT_INCH);
    gtk_page_setup_set_left_margin(pageSetup, leftMargin, GTK_UNIT_INCH);
    gtk_page_setup_set_bottom_margin(pageSetup, btmMargin, GTK_UNIT_INCH);
    gtk_print_operation_set_default_page_setup(operation, pageSetup);
}
Comment 1 Ian Puleston 2009-04-26 07:41:55 UTC
Created attachment 133309 [details]
Test program to demo the problem

I've attached a small test program that demonstrates this problem. There are two buttons - both print a page with 0.5" margins requested, but one makes the Win32 API calls to adjust them as above. The adjusted margins print at 0.5" but the unadjusted ones are about 0.75" on my printer and in a print to PDF (using PDF Factory Pro).
Comment 2 Ian Puleston 2009-04-26 16:18:50 UTC
Created attachment 133337 [details] [review]
Patch with a fix for this problem

I've attached a patch to fix this. I've added a "margin_adjust" function pointer into the _GtkPrintOperationPrivate struct, and it is initialized to NULL in the unix version and a new "win32_margin_adjust" function in win32. win32_margin_adjust does basically what I outlined in comment #1 above. The margin_adjust function, if set, is called from _gtk_print_context_translate_into_margin before calling cairo_translate with the left/top margin sizes.

From what I can see in the code, the right/bottom margin settings appear to be ingnored so they are not affected.
Comment 3 Adrian Johnson 2009-05-08 13:23:46 UTC
A simpler fix would be to modify the hDC transform in gtkprintoperation-win32.c before creating the cairo_win32_printing_surface. Something like this:

XFORM xform;
int x_off, y_off;

x_off = GetDeviceCaps (hDC, PHYSICALOFFSETX);
y_off = GetDeviceCaps (hDC, PHYSICALOFFSETY);
SetGraphicsMode (hDC, GM_ADVANCED);
xform.eM11 = 1;
xform.eM12 = 0;
xform.eM21 = 0;
xform.eM22 = 1;
xform.eDx = -x_off;
xform.eDy = -y_off;
SetWorldTransform (hDC, &xform);
op_win32->surface = cairo_win32_printing_surface_create (hDC);

Comment 4 Andreas J. Guelzow 2009-05-15 04:36:02 UTC
*** Bug 582583 has been marked as a duplicate of this bug. ***
Comment 5 Adrian Johnson 2009-10-25 02:24:24 UTC
Created attachment 146193 [details] [review]
Fix win32 printing offset

Here's a simpler patch that uses the device offset feature of cairo to move the origin to the top left of the paper.
Comment 6 Adrian Johnson 2009-10-25 10:08:53 UTC
Created attachment 146196 [details] [review]
Fix win32 printing offset

Updated patch to adjust the device offset at the start of each page. In case different size pages have different size non printable areas, this patch does the offset adjustment at the start of each page.
Comment 7 Tor Lillqvist 2009-10-26 09:08:19 UTC
Thanks Ian for the excellent test program. Thanks Adrian for the patch. 

With Adrian's (latest) patch, the "with no adjustment" printout from the test program does still not exactly match the printout "with adjustment" in a GTK+ without the patch. Should it? Adrian, is the LPtoDP and LOGPIXELSX/Y thing not necessary in your patch?
Comment 8 Adrian Johnson 2009-10-26 14:14:58 UTC
For testing I just used the print demo code from gtk-demo and modified the draw callback to draw a box. I set gtk_print_operation_set_use_full_page() to true and draw a box 20mm from each side then printed it and measure it. With my patch it was exactly 20mm from each side. Without the patch there was an obvious offset.

The adjustment in the test program does not look correct.

     if (topMargin) topMargin -= offset_y;
     if (bottomMargin) bottomMargin -= offset_y;
     if (leftMargin) leftMargin -= offset_x;
     if (rightMargin) rightMargin -= offset_y;

The bottom and right margins should have the offset added. The right margin should be using offset_x, not offset_y.

The LPtoDP is not necessary as the windows CTM is identity. LOGPIXELSX/Y is not used in my patch as cairo device units are the same as the windows logical units. Since the default windows identity CTM is in place the windows logical units are the same as the windows device units. PHYSICALOFFSETX/Y are in device units.
Comment 9 Tor Lillqvist 2009-10-27 10:31:09 UTC
OK, thanks. Adrian's patch committed and pushed to master and gtk-2-18.
Comment 10 Ian Puleston 2011-02-09 02:16:41 UTC
I tested with the original app that showed the problem and GTK 2.22.1. Having removed a hck that I had to put in to work around the problem, it now works fine and the margins are correct without that hack. Thanks for the fix.