BIG Problems when using pdf.CanvasReference := wprefprinter

  • Hello all,

    I need to produce high-resolution graphics. I use WPDF in HDC mode and because I need high resolution and large paper sizes I use pdf.CanvasReference := wprefprinter.

    Unfortunately, this causes problems if the default printer happens to be a certain type of HP color laserjet. Lots of graphic objects are simply missing on the pdf page. It works correctly when the default printer of the PC is of a different type (such as Canon or Epson inkjet printer).
    This is a huge problem for me because all people in our company have a HP laserjet as their default printer. So do many of our customers, I get bug reports all the time.

    I know that HP Laserjets have an issue in their drivers that affects Delphi applications in general. More precisely, they change the floating-point coprocessor control word (see Delphi function set8087cw()) which can cause haphazard crashes and unpredictable behaviour in programs compiled with Delphi and Cbuilder. The bug is known to Codegear/Embarcadero (see Codecentral for a more complete description and a workaround).

    I wonder if WPDF is suffering from this same particular issue?

    Anyway, I desperately need a solution or a workaround.

    • Offizieller Beitrag

    Hi,

    the best approiach would be to create metafiles in hight resolution - but please avoid coordinates>32K.

    Those metafiles could be fed into wPDF and be converted. Internally the "Canvas" does exactly this, but gives you no other control than the "Reference".

    The missing images are probably caused by undocumented clipping. I know this from the screen, but not from printers. The clipping affects bitblt in general (also Fillrects).

    Did you try to select a larger page size for the printer?

    In WPPDFR1.PAS You will find in UpdatePrinterCanvas this code:

    {$IFDEF USELARGEPAGE}
    aPrinter := TPrinter.Create;
    aPrinter.GetPrinter(ADevice, ADriver, APort, ADeviceMode);
    DevMode := GlobalLock(ADeviceMode);
    try
    if DevMode <> nil then
    begin
    // Length/Width in 1/10 of a mm.
    DevMode^.dmPaperWidth := Round(45 * 100);
    DevMode^.dmPaperLength := Round(45 * 100); DevMode^.dmFields := DevMode^.dmFields or DM_PAPERWIDTH or DM_PAPERLENGTH;
    aPrinter.SetPrinter(ADevice, ADriver, APort, ADeviceMode);
    end;
    if ADevice <> '' then
    FReferenceDC := CreateDC(ADriver, ADevice, nil, DevMode)
    else
    FReferenceDC := CreateDC(ADriver, nil, nil, DevMode);
    finally
    if DevMode <> nil then GlobalUnlock(ADeviceMode);
    aPrinter.Free;
    end;
    {$ELSE}
    Printer.GetPrinter(ADevice, ADriver, APort, ADeviceMode);
    if ADevice <> '' then
    FReferenceDC := CreateDC(ADriver, ADevice, nil, nil)
    else
    FReferenceDC := CreateDC(ADriver, nil, nil, nil);
    {$ENDIF}

    Please check if you have same code and activate for a test the $DEFINE USELARGEPAGE.

    Does this help?

    Kind Regards,
    Julian

  • Hi Julian,

    I'll try your test suggestion and report back.
    The missing objects are not just images, they are lines, polylines and fills as well. Not just at the edges of the page but everywhere, randomly. The page size in this particular file was DIN A4 and resolution was 600dpi IIRC. I can send you the file in the "right" and "faulty" versions if you want but you must treat them confidentially.

    Might I suggest, as an improvement to WPDF3, that the user be allowed to specify *which* printer he wants as a reference device and not just the default printer? That way I could check the list of installed printers and avoid any HP's.


    What I would really like most of all is a simple way to simply specify a page size and a resolution (300 or 150 dpi) and not needing to bother with reference devices at all. That way I can lower the DPI if the page size gets too big. I'm more or less stuck with mm_anisotropic because the class library I use relies on that. BTW, both Adobe and CutePDF work fine without needing reference devices and offer me various resolutions. How do those guys do it?


    [/b]

  • I have finally found the solution to this riddle.

    If the reference device of a metafile is a HP Laserjet, SelectClipRgn() appears to behave unreliably. Since WPDF uses metafiles internally, it is affected by this.

    I used to use this code to create a rectangular clipping area:

    hrgn := CreateRectRgn(left, top, left + width, top + height);
    resultcode:=SelectClipRgn(hdc, Hrgn);
    DeleteObject(hrgn);

    ... but it turns out that "resultcode" often indicates that the clip region is a NULL region (even though the coordinates of the region are fine and well within the page rectangle) and subsequent plotting goes into Nirvana.


    But there's a simple workaround. I have found the following to work 100% reliably and it performs the same task as the code above:

    SelectClipRgn(hdc,0);
    IntersectClipRect (hdc,left, top, left + width, top + height);