如何在TPrinter上以实际尺寸的图像打印图像?

时间:2013-08-01 19:18:06

标签: delphi printing

向所有人致敬!

如何在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上绘制。

您可以看到以下结果:

You can see results below:

结果很好,但并不完美。

正如您所看到的,在最后一列中,所有图像都是绘制到最后的,有些部分会丢失纸张而不会被绘制。

我认为这是因为当我根据打印机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;

我有,我需要的是:

I have that, what I need:

我认为0.20的值不是常数,它会在每台PC上发生变化。 如何计算这个值?需要解决这个问题的是什么?

3 个答案:

答案 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;