How to print images on TPrinter in real size of image?

12,829

Solution 1

The basic problem here is one of scaling. More or less, figure out how much to expand the resolution of the image and then stretchdraw it to the printer canvas. Something like this gets the image stretched out to the dimension of the printer canvas.

procedure TForm1.Button2Click(Sender: TObject);
  var
    MyRect: TRect;
    scale: Double;
  begin
    if PrintDialog1.Execute then
      begin
        Printer.BeginDoc;
        scale := Printer.PageWidth / Bitmap1.Width;
        ShowMessage(FloatToStr(scale));
       { horizontal pixels, vertical pixels, bit depth 600 x 600 x 24}
        MyRect.Left := 0;
        MyRect.Top := 0;
        MyRect.Right := trunc(Bitmap1.Width * scale);
        MyRect.Bottom := trunc(Bitmap1.Height * scale);
        Printer.Canvas.StretchDraw(MyRect, Bitmap1);
        Printer.EndDoc;
      end;

Of course, you have to check "Right" and "Bottom" to make sure they don't exceed your PageWidth and PageHeight depending on the type of scaling you use (6.25 or 600/96 seems fine for simply making an image the same relative size as the screen, assuming those numbers match your printer and screen), assuming you want to keep the image to one page and not mosaic pieces of it onto multiple pages.

I don't know if this works entirely since I don't have a varied number of devices (i.e. different DPIs) to test both orientations on, but this seems to be what you want to get both DPI numbers dynamically.

if Printer.Orientation = poPortrait then
   scale := GetDeviceCaps(Printer.Handle, LOGPIXELSX) / PixelsPerInch
else
   scale := GetDeviceCaps(Printer.Handle, LOGPIXELSY) / pixelsperinch;

Then of course, you multiply like above.

Solution 2

Delphi Basics link was also helpful : http://www.delphibasics.co.uk/RTL.asp?Name=printer&ExpandCode1=Yes

on form : drag n drop TPrintDialog from your Tool Palette

and manually add this to the uses clause under [Implementation]

uses printers;  // Unit containing the printer command

With that and this post I was able to print directly to any printer at the size I wanted for images or text. There is no need to call the bitmap or assign the TPrinter once you have added the unit above. Just draw directly to the canvas in your PC printer queue.

procedure TForm1.cmdPrintCircleClick(Sender: TObject);
 var
   xx, yy, mySize : integer;
   //printer1 : TPrinter;
 begin
  // create image directly on Printer Canvas and print it
  //Ellipse( X-(Width div 2), Y-(Height div 2), X+(Width div 2), Y+(Height div 2));
  if PrintDialog1.Execute then
   try
    with Printer do
     begin
      if Printer.Orientation = poPortrait then
       begin
         // represents 1/2 US-inch relative to Portrait page size 8.5 x 11
         mySize := Trunc(PageWidth / 8.5 / 2);
      end
      else
       begin
         // represents 1/2 US-inch relative to Landscape page size 11 x 8.5
         mySize := Trunc(PageHeight / 8.5 / 2);
      end;

      xx := Trunc(PageWidth / 2);
      yy := Trunc(PageHeight / 2);

      // Start printing
      BeginDoc;

      // Write out the ellipse  // create one-inch black circle
      Canvas.Brush.Color := clBlack;
      Canvas.Ellipse(xx - mySize, yy - mySize, xx + mySize, yy + mySize);

      // Finish printing
      EndDoc;
    end;
   finally
   end;

end;

Solution 3

The issue you're running into is that there really isn't a "real size" of an image, it's all relative. The printer often has a lot higher resolution then your monitor and that's why pictures look small.

Your monitor has often a resolution of 96 dpi and normal printer has a resolution of 600 dpi which means your image prints in its real size it just looks small because a printer can put a lot more dots in the same space then a monitor can.

Share:
12,829
Alexandr
Author by

Alexandr

please delete me

Updated on June 04, 2022

Comments

  • Alexandr
    Alexandr almost 2 years

    Gretings to all!

    How to print pictures in Delphi on TPrinter, in real sizes of pictures? From canvas of TImage I have good results, but if I paints on TPrinter canvas, I have BAD result, puctures is too small than real size of bitmap.

    Why that happens What I'm need to do for fix bug?

    UPDATE

    Yes, I seen question from the hint in the 1st post. I can't use JCL/JVCL code in my project, but I got idea from it.

    I create temporary TImage, and calculate dimensions of it in accordance with the factor of printer's DPI:

    var
      i, iRow, iCol,        // Counter
      iBorderSize,          // Ident from left/top borders
      iImgDistance,         // Ident between images in grid
      iRows,                // Rows Count
      iColumns,             // Colun count
      iLeft, iTop: Integer; // For calc
      bmp: TBitmap;
      bStop, bRowDone, bColDone: Boolean;
      Img1: TImage;
      scale: Double;
    
      function CalcY: Integer;
      begin
        if (iRow = 1) then
          Result := iBorderSize
        else
          Result := iBorderSize + (iImgDistance * (iRow - 1)) +
            (bmp.Height * (iRow - 1));
      end;
    
      function CalcX: Integer;
      begin
        if (iCol = 1) then
          Result := iBorderSize
        else
          Result := iBorderSize + (iImgDistance * (iCol - 1)) +
            (bmp.Width * (iCol - 1));
      end;
    
    begin
      iBorderSize := StrToInt(BorderSizeEdit.Text);
      iImgDistance := StrToInt(ImgsDistanceEdit.Text);
      iRows := StrToInt(RowsCountEdit.Text);
      iColumns := StrToInt(ColCountEdit.Text);
      iRow := 1;
      iCol := 1;
      iLeft := iBorderSize;
      iTop := iBorderSize;
    
      if Printer.Orientation = poPortrait then
        scale := GetDeviceCaps(Printer.Handle, LOGPIXELSX) /
          Screen.PixelsPerInch
      else
        scale := GetDeviceCaps(Printer.Handle, LOGPIXELSY) /
          Screen.PixelsPerInch;
    
      bmp := TBitmap.Create;
      Img1 := TImage.Create(nil);
      Img1.Height := Trunc(Printer.PageHeight / scale); //Calc canvas size
      Img1.Width := Trunc(Printer.PageWidth / scale); //Calc canvas size
      Img1.Canvas.Brush.Color := clWhite;
      Img1.Canvas.FillRect(Rect(0, 0, Img1.Width, Img1.Height));
      try
        bmp.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'Source.bmp');
        for i := 1 to 18 do
        begin
          if (iRow <= iRows) then
          begin
            iTop := CalcY;
            iLeft := CalcX;
            Img1.Canvas.Draw(iLeft, iTop, bmp);
            if not((iRow = iRows) and (iCol = iColumns)) then
            begin
              if (iCol = iColumns) then
              begin
                Inc(iRow);
                iCol := 1;
              end
              else
                Inc(iCol);
            end
            else
            begin
              PrintImage(Img1, 100);
              iRow := 1;
              iCol := 1;
              Img1.Canvas.Brush.Color := clWhite;
              Img1.Canvas.FillRect(Rect(0, 0, Img1.Width, Img1.Height));
            end;
          end;
        end;
      finally
        FreeAndNil(bmp);
        FreeAndNil(Img1);
      end;
    end;
    

    And draw it on TPrinter.Canvas.

    You can see results below:

    You can see results below:

    Results is good, but not perfect.

    As you can see, in the last column, all images are drawn not to the end, some part misses off the paper and not drawn.

    I think it's happens because I use the Trunc to get integer part of double when I'm calculate dimensions of TImage.Canvas in accordance with the factor of printer's DPI.

    By experiments I know value 0.20. 0.20 is a part of last column images, in pixels, that not drawn. If I change code, that gets scale factor by this:

      if Printer.Orientation = poPortrait then
        scale := GetDeviceCaps(Printer.Handle, LOGPIXELSX) /
          Screen.PixelsPerInch - 0.20
      else
        scale := GetDeviceCaps(Printer.Handle, LOGPIXELSY) /
          Screen.PixelsPerInch - 0.20;
    

    I have that, what I need:

    I have that, what I need:

    I think the value 0.20 isn't a constant and it will change on every PC. How to calculate this value? What need to solve this problem?