需要一种方法来计算 tcanvas 中实际绘图项的范围

Posted

技术标签:

【中文标题】需要一种方法来计算 tcanvas 中实际绘图项的范围【英文标题】:Need a method to calculate the extents of the actual drawing items in a tcanvas 【发布时间】:2018-03-08 18:43:52 【问题描述】:

我正在使用一个paintbox 组件,使用矩形、多边形和其他画布方法绘制各种形状。用户创建绘图后,我想保存位图以在列表框中使用。问题是绘图可能只使用画布的一小部分,并且列表框中的结果图像会非常小,除非我通过仅选择油漆框原始画布的已使用部分来调整其大小。所以问题是如何确定画布的哪一部分已被使用,以便仅提取画布的那部分以加载到位图中以在列表框中显示?

(注意:我在上面进行了编辑以澄清问题)

实际的程序有一个画框 (200x200) 和一个图像 (32 x 32)。图像使用Bitmap1.Canvas.CopyRect(Dest, PaintBox1.Canvas, Source); 从paintbox 中获取其位图。如果在 200x200 的paintbox.canvas 中,paintbox 中的绘图只有 20x20,那么在 Image.canvas 中生成的位图在 32x32 的 image.canvas 中将非常小。我需要将其放大,这意味着我必须确定颜料盒中使用区域的实际大小并更改“CopyRec”中的源大小。

【问题讨论】:

呃,TPaintBox 是错误的组件。它没有持久的绘图表面。 @DavidHeffernan 错了什么?该程序生成一个代码文件,用于构建图形对象以供其他程序使用。不需要保存画框显示。任何未来的显示都是从这个程序保存到文件中的代码文件生成的。画布还保存了一个位图以供在列表框中使用。我还缺少其他东西吗? 可能我不明白你的程序是做什么的。描述程序而不是我们拥有minimal reproducible example 时的常见问题。 您可以使用 TRect.Union 来查找所有绘图命令的结果并集。对于每个绘图命令,使用周围的矩形作为 TRect.Union 的输入。 你跟踪绘制的对象吗?如果是这样,那么应该很容易计算它们的全部范围。如果没有,那么您可能应该开始这样做。 【参考方案1】:

我制定的一种方法是基于以下假设:已绘制的各种项目(例如圆形、矩形、文本等)都放置在中性背景上。在这种情况下,我可以使用tbitmap.scanline 读取位图以比较绘图的颜色与背景颜色,并计算每行中的绘图范围以确定整个位图中的绘图范围。

  TRGBTriple = packed record
    rgbtBlue: Byte;
    rgbtGreen: Byte;
    rgbtRed: Byte;
  end;
  TRGBTripleArray = ARRAY[Word] of TRGBTriple;
  pRGBTripleArray = ^TRGBTripleArray; // use a PByteArray for pf8bit color

function findBMPExtents (Bmp : tbitmap; BkgdClr : longint):trect;
// finds the extents of an image in a background or BkgdClr color
//works on 24 bit colors
var
  P : pRGBTripleArray;
  x,y : integer;
  tfound, bfound, done : boolean;
  WorkTrpl : TRGBTriple;
  WorkRect : trect;
begin
  result.top := 0;
  result.bottom := Bmp.height;
  result.left := Bmp.Width;
  result.right := 0;
  tfound := false;
  bfound := false;
  WorkTrpl := getRGB (BkgdClr);

  //find left and top
  y := 0;
  done := false;
  Repeat
    P := Bmp.ScanLine[y];
    x := 0;
    Repeat
      if (p[x].rgbtBlue <> WorkTrpl.rgbtBlue) or
         (p[x].rgbtGreen <> WorkTrpl.rgbtGreen) or
         (p[x].rgbtRed <> WorkTrpl.rgbtRed) then
        begin
          tfound := true;
          if x <= result.left then begin
            result.left := x;
            done := true;
          end;
        end;
      inc (x);
    until (x = bmp.width) or done;
    done := false;
    inc (y);
    if not tfound then
      inc(result.top);
  until (y = bmp.height);

  //find right and bottom
  y := bmp.height - 1;
  done := false;
  Repeat
    P := Bmp.ScanLine[y];
    x := bmp.width-1;
    Repeat
      if (p[x].rgbtBlue <> WorkTrpl.rgbtBlue) or
         (p[x].rgbtGreen <> WorkTrpl.rgbtGreen) or
         (p[x].rgbtRed <> WorkTrpl.rgbtRed) then
        begin
          bfound := true;
          if x >= result.right then begin
            result.right := x;
            done := true;
          end;
        end;
      dec (x);
    Until (x = 0) or done;
    if not bfound then
      dec(result.bottom);
    done := false;
    dec (y);
  Until (y = -1);
  dec(result.bottom);
end;

【讨论】:

以上是关于需要一种方法来计算 tcanvas 中实际绘图项的范围的主要内容,如果未能解决你的问题,请参考以下文章

Delphi 绘图TCanvas类[3] TPen类参数及介绍

Delphi 绘图[1] TCanvas(画布)的类成员 及参数介绍

Delphi 绘图[2] 无Canvas属性,获取 Canvas 对象

TCanvas.CopyRect方法中参数CopyMode的意义

20200116(绘图和可视化——pandas)

如何将计算机绘图旋转 90 度