【问题标题】:How to print image that is larger than one page如何打印大于一页的图像
【发布时间】:2021-05-26 05:59:48
【问题描述】:

我需要打印从扫描仪获取的图像。
当扫描适合一张 A4 页面时,没有问题,我的代码打印完美。

但是,当扫描不适合,但需要 2 页时,只打印一页。第一个。

这是我目前的代码

procedure TFormMain.PrintPicture;
var
  MyRect: TRect;
  Scale: Double;
begin
  try
    Printer.BeginDoc;

    Scale := Printer.PageWidth / ImgHolder.Picture.Bitmap.Width;
    MyRect.Left := 0;
    MyRect.Top := 0;
    MyRect.Right := trunc(ImgHolder.Picture.Bitmap.Width * Scale);
    MyRect.Bottom := trunc(ImgHolder.Picture.Bitmap.Height * Scale);
    Printer.Canvas.StretchDraw(MyRect, ImgHolder.Picture.Bitmap);

    Printer.EndDoc;
  except
    on E:Exception do
    begin
      MessageBox(Handle, PChar('Printing failed' + chr(13) + E.Message), PChar(Caption), MB_OK or MB_ICONWARNING);
    end;
  end;
end;

图片占一页时,MyRect的高度=13092
当图像包含 2 页时,高度为 26185

这对我来说似乎是正确的,但仍然只打印了第一页。 所以我一定是做错了,有人可以指出我如何打印高于一页高度的图像的正确方向

编辑
如果图像较大,我想打印多页。
我不想将图像缩小到一页。
我的代码中比例尺的原因是因为我一开始无法正确打印,我在另一个问题中找到了这段代码,为我解决了这个问题。
但现在看来这种做法是错误的。
因此,如果我能在正确设置打印方面获得帮助,我将不胜感激。

如果用户扫描 2 或 3 次,图像将变大,新的扫描将添加到底部的图像中。
这就是图片长度超过一页的原因。
现在我需要完整地打印这张图片,如果需要的话,打印不止一页

【问题讨论】:

  • 您应该根据高度和宽度计算两个比例因子,并使用两者中最严格的一个。
  • @fpiette 这需要更多解释
  • @GuidoG:ScaleX := Printer.PageWidth / ImgHolder.Picture.Bitmap.Width; ScaleY := Printer.PageHeight / ImgHolder.Picture.Bitmap.Height; Scale := Min(ScaleX, ScaleY) (uses Math)。或者,换句话说:ScaleX 是使图像适合纸张宽度所需的缩小因子。例如,如果纸张为 1000×1000,图像为 2000×1000,您显然需要将其缩小到 50% 以使其水平适合。但如果图像是 1000×5000,问题不是宽度而是高度,显然需要将其缩小到 20% 以使其垂直适合。所以一般来说,你需要这些中最小的。
  • 所以如果图像是 2000×5000,你需要比例因子为 50% 或更小才能使它水平适合,你需要比例因子为 20% 或更小才能使它适合垂直。因此,比例因子必须
  • @AndreasRejbrand(和.at. fpiette)他问的是如何在两页上打印,而不是如何让输出适合一页。我已经有十年或更长时间没有做过任何打印代码(而且从来没有在 Delphi 中做过),所以我似乎不适合尝试答案......

标签: delphi canvas printing delphi-10.3-rio


【解决方案1】:

有很多方法可以打印图像。

首先,请记住您的屏幕和打印机具有不同的分辨率(例如,以每英寸像素为单位)。通常,打印机的分辨率比 PC 显示器高得多,因此如果您在 A4 页面上打印全屏 1920×1080 图像,除非您将其放大,否则页面上的图像会非常小。

现在,话虽如此,让我们考虑两种常见情况(您需要第二种情况)。

缩放图像使其完美地适合单个页面

“完美贴合”是指图像按比例缩放,保留其纵横比,使其在页面上尽可能大而不会被剪裁。

让 (uses Math)

ScaleX := Printer.PageWidth / Bitmap.Width;
ScaleY := Printer.PageHeight / Bitmap.Height;
Scale := Min(ScaleX, ScaleY).

那么Scale就是你的比例因子。

确实,ScaleX 是允许图像水平适应页面的最大缩放因子。例如,如果纸张为 1000×1000,图像为 2000×1000,您显然需要将其缩小到至少 ScaleX = 50% 以使其水平适合。另一方面,如果图像是 1000×5000,问题不是宽度而是高度,显然需要将其缩小到至少ScaleY = 20% 以使其垂直适合。

因此,如果图像为 2000×5000,则需要将比例因子设为 50% 或更低才能使其水平适合,并且需要比例因子小于或等于 20% 才能使其垂直适合。满足这两个限制的最大比例因子为 20%,最小为 50% 和 20%。

procedure PrintBitmap(ABitmap: TBitmap);
begin
  Printer.BeginDoc;
  var ScaleX := Printer.PageWidth / ABitmap.Width;
  var ScaleY := Printer.PageHeight / ABitmap.Height;
  var Scale := Min(ScaleX, ScaleY);
  var W := Round(ABitmap.Width  * Scale);   // Note: scaling proportionally,
  var H := Round(ABitmap.Height * Scale);   //       same factor
  Printer.Canvas.Brush.Color := clRed;
  Printer.Canvas.StretchDraw(
    TRect.Create(                           // Centre on page
      Point((Printer.PageWidth - W) div 2, (Printer.PageHeight - H) div 2),
      W, H
    ),
    ABitmap
  );
  Printer.EndDoc;
end;

例如,

procedure TForm1.FormCreate(Sender: TObject);
begin

  var bm := TBitmap.Create;
  try
    bm.LoadFromFile('K:\Sally.bmp');
    PrintBitmap(bm);
  finally
    bm.Free;
  end;

end;

具有固定的图像大小,可能跨越多个页面

现在,假设您有一个固定的图像尺寸(W, H),并且您想根据需要在尽可能多的页面上打印它。然后需要循环遍历 2D 纸网格,分别绘制每一页:

procedure PrintBitmap(ABitmap: TBitmap);

var
  W, H: Integer;
  ImgPageWidth, ImgPageHeight: Integer;

  function GetSourceRect(Row, Col: Integer): TRect;
  begin
    Result := TRect.Create(
      Point(Col * ImgPageWidth, Row * ImgPageHeight),
      ImgPageWidth, ImgPageHeight
    );
  end;

  function GetDestRect(Row, Col: Integer): TRect;
  begin
    Result := Rect(0, 0, Printer.PageWidth, Printer.PageHeight);
  end;

begin
  Printer.BeginDoc;
  W := ABitmap.Width * 4;    // Hardcoding these in this example
  H := ABitmap.Height * 4;
  ImgPageWidth := Round(ABitmap.Width * (Printer.PageWidth / W));
  ImgPageHeight := Round(ABitmap.Height * (Printer.PageHeight / H));
  var PageCountX := Ceil(W / Printer.PageWidth);   // Image width in pages
  var PageCountY := Ceil(H / Printer.PageHeight);  // Image height in pages
  // Notice that the total page count is PageCountX * PageCountY.
  for var y := 0 to PageCountY - 1 do
    for var x := 0 to PageCountX - 1 do
    begin
      if x + y > 0 then
        Printer.NewPage;
      Printer.Canvas.CopyRect(
        GetDestRect(y, x),
        ABitmap.Canvas,
        GetSourceRect(y, x)
      );
    end;
  Printer.EndDoc;
end;

【讨论】:

  • 感谢您的精彩解释。感谢 fpiette 的回答,我已经弄清楚了,所以接受答案的学分属于他。但是您的回答对于遇到此问题的每个人都会有很大帮助
【解决方案2】:

要在多页上打印大图像,您必须循环宽度和高度(两个循环)以创建包含部分图像的页面。要打印一张局部图像,您可以使用TCanvas.CopyRect

【讨论】:

  • 经过一些尝试和错误,但我让它循环工作。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-05-08
  • 2015-05-11
  • 2016-11-10
  • 2022-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多