How to print images on TPrinter in real size of image?
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.
Comments
-
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:
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 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?