Hello

Hello,

I use a component that do some nice things on the Printer's Canvas...but I would like to adapt the code to print two A5 on a single A4 paper.

Instead of changing all the logic of the component, I've tried something that work very well but not on all printers :(

I've replaced de Printer.NewPage call by a code that apply a SetWorldTransform() like this

if (PageNo > 1) and (PageNo and 1 = 1) then
Printer.NewPage;
with Printer.Canvas do
begin
// x' = x * eM11 + y * eM21 + eDx
// y' = x * eM12 + y * eM22 + eDy
XFORM.eM11 := 0;
XFORM.em12 := -(210/297); // A4 (210x297) -> A5 (148x210)
XFORM.em21 := +(210/297);
XFORM.em22 := 0;
if Printer.Orientation = poPortrait then
begin
XFORM.eDx := 0;
XFORM.eDy := Printer.PageHeight;
if PageNo and 1 = 0 then
begin
XFORM.eDy := XFORM.eDy / 2;
end;
end else begin
XFORM.eDx := 0;
XFORM.eDy := Printer.PageHeight;
if PageNo and 1 = 0 then
begin
XFORM.eDx := Printer.PageWidth / 2;
end;
end;
SetGraphicsMode(Handle, GM_ADVANCED);
SetWorldTransform(Handle, XFORM);
end;

Is there a known bug or something I've forgot ?

Thanks

Comments

  1. Read the Documentation about WorldTransform etc. again. Your Matrix is wrong. Sorry i have now not enough time. If tomorrow there is no answer, i will comment again

    ReplyDelete
  2. Friedrich Westermann wrong ?! it works fine on the XPS printer at least...

    ReplyDelete
  3. im in the Train now, so from Memory you need to combine three transformations. Translate, rotate and scale. Your Matrix is wrong because em11 and em22 is 0.

    ReplyDelete
  4. well it's a 90° rotation, Cos = 0, sin = 1

    x' = 0 * x - 1 * y
    y' = 1 * x + 0 *y

    :)

    ReplyDelete
  5. You have only the Rotation in your matrix combine it with the default etc... Trust me, Not all drivers are tolerant. Im doing thinks like these a lot.

    ReplyDelete
  6. Attila Kovacs thanks, but in fact, I do know what a Matrix is :)

    http://lookinside.free.fr/delphi.php?FlashPascal+3D

    with your code tr = (0, -0,707070708274841, 0,707070708274841, 0, 0, 296) and 210/297 = 0,70707070707067

    so my code is just fine for the matrix ;) the problem is why the printer driver do not take it into account :/

    ReplyDelete
  7. Paul TOTH i was total wrong yesterday :-( Sorry for that. Your Matrix is ok. After looking in our Sources for printing i have found these comment:
    // Don't use setworldTransform on Printer.
    // Some drivers don't handle it correct
    // We will only use ModifyWorldTransform
    // Let Windows and Driver do the Job

    With these rules there are no problems for us.
    more then 6000 Installations and we use it more or less on all output

    Our flow is
    setidenty
    move to our base point
    Scale
    rotate
    move to position

    ReplyDelete
  8. Friedrich Westermann Thanks Friedrich, that is completely insane

    I've changed this and it works perfectly !

    // SetWorldTransform(Handle, XFORM);
    ModifyWorldTransform(Handle, XFORM, MWT_IDENTITY); // Reset
    ModifyWorldTransform(Handle, XFORM, MWT_LEFTMULTIPLY); // Apply change

    ReplyDelete
  9. So, maybe I'm slow, but I have to write something like
    function MySetWorldTransform(DC: HDC; const XFORM: TXForm): BOOL;
    begin
    Result := ModifyWorldTransform(DC, XFORM, MWT_IDENTITY); // Reset
    if Result then
    Result := ModifyWorldTransform(DC, XFORM, MWT_LEFTMULTIPLY); // Apply change
    end;
    and call that instead of SetWorldTransform and that's it? And MS/the driver manufacturer got that wrong?

    ReplyDelete
  10. Yes don't calculate the transform yourself, use ModifyWorldTransform.
    Some Drivers are a really pain.......

    ReplyDelete
  11. Hi there,

    I can hep to get to the bottom of the issue. I have been writing Windows print drivers since Windows 0.8 beta (1987?).

    Drivers do not get calls for SetWorldTransform". It cannot be the driver's fault for mishandling the call.

    SetWorldTransform, Modify Transform et all), all do the same thing... produce one single transform (way ahead of the driver).

    Done right, the result will always be exactly the same: the coordinates and transform that (may) arrive at the driver.

    Take (0,0) and (Device.PixelWidth, Device.PixelHeight) and transform them in reverse.

    Do you get the expected results?

    Take PointIWantToPrint() and transform it to the printer's device space.

    Did the transformed point end up within the bounds of Device.PixelWidth, Device.PixelHeight?

    If so, OK, blame the driver subsystem and write a nasty letter to someone (hopefully it will end up on my desk, I need some work right now).

    If not, it is a math or order issue with your calls.

    It is worth noting that the vast majority of drivers are Unidrivers, and do not even receive these sort of transforms (they mostly only get pixels to print). Only Monolithic drivers are really affected by needing to interpret (some) transforms, and they are very rare to come by.

    You can easily test the driver subsystem by using a simple, "easy to get right" transform. Print a rotated line. If that works, the driver is fine (be sure to use a line width and color you can see - a one pixel line can be hard to see at 600+ dpi).

    Hope that helps!

    Joe [did I mention I am looking for work? I specialize in Windows GDI, graphic engines, print drivers, PDF, and PostScirpt]

    ReplyDelete
  12. Joe C. Hecht Thanks for the insights!

    ReplyDelete
  13. Uli Gerhardt You are very welcome. I hope it to be helpful.

    ReplyDelete

Post a Comment