4

向所有人问好!

如何在TPrinter上以真实大小的图片打印Delphi中的图片?从 TImage 的画布我有很好的结果,但如果我在 TPrinter 画布上绘画,我的结果很糟糕,puctures 比位图的实际大小太小。

为什么会发生这种情况我需要做什么来修复错误?

更新

是的,我从第 1 篇文章的提示中看到了问题。我不能在我的项目中使用 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 上发生变化。如何计算这个值?这个问题需要解决什么?

4

3 回答 3

4

这里的基本问题是缩放问题之一。或多或少,弄清楚图像的分辨率扩大多少,然后将其拉伸到打印机画布上。像这样的东西可以将图像拉伸到打印机画布的尺寸。

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 数字的原因。

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

然后当然,你像上面那样乘法。

于 2013-08-02T03:29:57.377 回答
1

您遇到的问题是图像确实没有“真实大小”,这都是相对的。打印机的分辨率通常比显示器高很多,这就是图片看起来很小的原因。

您的显示器的分辨率通常为 96 dpi,而普通打印机的分辨率为 600 dpi,这意味着您的图像以实际尺寸打印,它看起来很小,因为打印机可以在同一空间内放置比显示器更多的点。

于 2013-08-02T07:03:42.200 回答
1

Delphi Basics 链接也很有帮助:http ://www.delphibasics.co.uk/RTL.asp?Name=printer&ExpandCode1=Yes

在表单上:从工具面板中拖放 TPrintDialog

并手动将其添加到 [实施] 下的使用子句中

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;
于 2016-06-01T20:24:19.043 回答