Author Topic: Scaling Issue when generating a 'Print Preview' Canvas  (Read 740 times)


  • Full Member
  • ***
  • Posts: 232
Scaling Issue when generating a 'Print Preview' Canvas
« on: December 06, 2019, 04:52:37 pm »
Thanks to the help of this board I've managed to get printing sorted from my application.

Now, though, I am trying to generate a 'Print Preview' to show what the application will print before the user commits to paper or PDF.

To do this I am using a copy of the exact same code as I am using for printing, but instead of drawing elements (boxes and text mainly, but also a bitmap copied from an image on one of my forms) onto the printer canvas I am drawing them to a TBitMap.Canvas that is supposed to be sized the same as the Printer.Canvas.

I then use Canvas.CopyRect to copy the TBitMap.Canvas into a TPaintBox.Canvas that is on my Print Preview form.

For some reason, though, the scaling of everything is completely off.

I have used a couple of showMessage()s to tell me what the dimensions of the printer canvas and the bitmap canvas are, and according to this feedback the two are identical. BUT everything on the bitmap is much much smaller than it is on the printer canvas (except for the image which is copied into the bitmap canvas 0 that is approximately the correct size but the aspect ratio is incorrect), implying that the bitmap canvas is far too big.

What's more, when this bitmap canvas is copied into the PaintBox canvas, it is not all displayed. It overflows the PaintBox and I have to drag the size of the form that contains the PaintBox. It seems that both the bitmap canvas and the PaintBox canvas are taller than they are wide, even though the showMessage returns a landscape aspect canvas.

I'm very confused - I seem to be so close, but the print preview I am generating is useless at teh moment as all text is far too small and the preview doesn;t fit in the preview form!

This is the function I am calling from the PaintBox OnPaint event:

Code: [Select]
procedure TLabelPreviewForm.generatePreview();
  TOPMARGIN = 100;
  PADDING = 20;
  XPos, YPos, LineHeight, LineWidth: Int64;
  LeftSectionLeft, SectionCenter, RightSectionRight, SectionTop, SectionBottom, QRleft, QRtop, QRright, QRbottom: Int64;
  QRcodePosition: TRect;
  stringToAdd: String;
  previewBitmap: TBitmap;


  previewBitmap := TBitMap.Create;
  previewBitmap.Width := Printer.PageWidth;
  previewBitmap.Height := Printer.PageHeight;

showMessage('bitmap.canvas.width='+IntToStr(previewBitmap.Width)+', .height='+IntToStr(previewBitmap.Height));

  RightSectionRight:=Printer.PageWidth - LeftSectionLeft;

  with previewBitmap do

      // Setup the basics
      Canvas.Font.Name := 'Arial';
      Canvas.Font.Color := clBlack;
      Canvas.Brush.Color:= clNone;

      // Draw the boxes
      with Canvas do
         Rectangle (LeftSectionLeft, SectionTop, SectionCenter, SectionBottom);
         Rectangle (SectionCenter, SectionTop, RightSectionRight, SectionBottom);

            // Add some text
            Canvas.Font.Color := clWhite;
            Canvas.Brush.Color := clBlack;
            stringToAdd:='THIS IS SOME TEXT';
            LineWidth := Round(Abs(Canvas.TextWidth(stringToAdd)));
            LineHeight := Round(Abs(Canvas.TextHeight(stringToAdd)));
            XPos:= Round((SectionCenter+((RightSectionRight-SectionCenter)/2)) - (LineWidth/2));
            YPos:= SectionTop+Round(LineHeight*1.5);

            // Add the QR Code
            QRtop:=Round((SectionTop+(RightSectionRight-SectionCenter)*0.1)) + YPos + Round(LineHeight * 1.5);
            QRbottom:=Round((SectionTop+(RightSectionRight-SectionCenter)*0.9)) + YPos + Round(LineHeight * 1.5);


            // Start adding the main text content

            Canvas.Font.Color := clBlack;
            Canvas.Brush.Color:= clNone;
            Canvas.Font.Size := 16;
            LineHeight := Round(1.2 * Abs(Canvas.TextHeight('I')));

            // Add Sender Info First so we know how big the sender box is at the bottom of the page

            // Set XPos and colours for Sender details
            XPos := LeftSectionLeft+PADDING;
            Canvas.Font.Size := 12;
            LineHeight := Round(Abs(Canvas.TextHeight('I')));

           { Add a whole load more text and boxes etc }

            on E: EPrinter do ShowMessage('Printer Error: ' +  E.Message);
            on E: Exception do showMessage('Unexpected error when printing.');
          pbLabelPreview.Canvas.CopyRect(Classes.Rect(0, 0, pbLabelPreview.Canvas.Width, pbLabelPreview.Canvas.Height),
              previewBitMap.Canvas, Classes.Rect(0, 0, previewBitMap.Width, previewBitMap.Height));

Do I need to do some sort of DPI conversion on the sizes?

Why do my preview canvases seem to be portrait when the width and height of the canvases say they are landscape?

As I say, I feel so close with this...


(PS Ultimately, rather than having the same code twice, I'd like to write a function that returns a TCanvas containing the whole layout. That way I can generate the canvas and copy it to the printer canvas or the print prview canvas as required and know that the layout has been generated by the same piece of code.
« Last Edit: December 06, 2019, 05:30:05 pm by fatmonk »


TinyPortal © 2005-2018