向所有人致敬!
如何在TPrinter上以真实尺寸的图片在Delphi中打印图片? 从TImage的画布我有很好的效果,但如果我在TPrinter画布上绘画,我有BAD结果,puctures比实际大小的位图小。
为什么会发生这种情况我需要为修复bug做些什么?
更新
是的,我在第一篇文章的提示中看到了一些问题。 我不能在我的项目中使用JCL / JVCL代码,但我从中得到了它的想法。
我创建临时TImage,并根据打印机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;
并在TPrinter.Canvas上绘制。
您可以看到以下结果:
结果很好,但并不完美。
正如您所看到的,在最后一列中,所有图像都是绘制到最后的,有些部分会丢失纸张而不会被绘制。
我认为这是因为当我根据打印机DPI的因素计算TImage.Canvas的尺寸时,我使用Trunc获取double的整数部分。
通过实验,我知道价值0.20。 0.20是最后一列图像的一部分,以像素为单位,未绘制。如果我改变代码,那就得到比例因子:
if Printer.Orientation = poPortrait then
scale := GetDeviceCaps(Printer.Handle, LOGPIXELSX) /
Screen.PixelsPerInch - 0.20
else
scale := GetDeviceCaps(Printer.Handle, LOGPIXELSY) /
Screen.PixelsPerInch - 0.20;
我有,我需要的是:
我认为0.20的值不是常数,它会在每台PC上发生变化。 如何计算这个值?需要解决这个问题的是什么?
答案 0 :(得分:2)
这里的基本问题是缩放问题。或多或少,计算出扩展图像分辨率然后将其拉伸到打印机画布的程度。像这样的东西会使图像延伸到打印机画布的尺寸。
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;
当然,您必须检查“正确”和“底部”,以确保它们不会超过您的PageWidth和PageHeight,具体取决于您使用的缩放类型(6.25或600/96似乎可以简单地制作图像与屏幕相同的相对大小,假设这些数字与您的打印机和屏幕相匹配),假设您想要将图像保留在一个页面而不是将其拼接到多个页面上。
我不知道这是否完全有效,因为我没有不同数量的设备(即不同的DPI)来测试两个方向,但这似乎是你想要动态获得两个DPI数字。 / p>
if Printer.Orientation = poPortrait then
scale := GetDeviceCaps(Printer.Handle, LOGPIXELSX) / PixelsPerInch
else
scale := GetDeviceCaps(Printer.Handle, LOGPIXELSY) / pixelsperinch;
然后,当然,你就像上面那样繁殖。
答案 1 :(得分:1)
您遇到的问题是图像确实没有“实际尺寸”,它们都是相对的。打印机通常具有比显示器高得多的分辨率,这就是图片看起来很小的原因。
您的显示器通常具有96 dpi的分辨率,普通打印机的分辨率为600 dpi,这意味着您的图像以实际尺寸打印,看起来很小,因为打印机可以在相同的空间中放置更多的点然后显示器可以。
答案 2 :(得分:0)
Delphi Basics链接也很有用:http://www.delphibasics.co.uk/RTL.asp?Name=printer&ExpandCode1=Yes
表单上的:从工具选项板中拖放TPrintDialog
并手动将其添加到[Implementation]
下的uses子句中uses printers; // Unit containing the printer command
有了这篇文章,我可以直接打印到我想要的图像或文本大小的任何打印机上。添加完上面的单元后,无需调用位图或指定TPrinter。只需直接绘制到PC打印机队列中的画布。
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;