-2

I am using a paintbox component to draw various shapes using rect, polygon and other canvas methods. After the user has created the drawing, I want to save a bitmap for use in a listbox. The problem is that the drawing may only use a small portion of the canvas and the resulting image in the listbox would be very small unless I adjust its size by selecting only the used portion of the paintbox's original canvas. So the question is how do I determine what portion of the canvas has been used so I can extract only that part of the canvas to load into a bitmap for display in listbox?

(Note:I edited above to clarify the question a bit)

The actual program has a paintbox (200x200) and an image (32 x 32). The image gets its bitmap from the paintbox using Bitmap1.Canvas.CopyRect(Dest, PaintBox1.Canvas, Source);. If the drawing in the paintbox is only 20x20 in the 200x200 paintbox.canvas, then the resulting bitmap in the Image.canvas will be very small in the 32x32 image.canvas. I need it to be enlarged and that means that I must determine the actual size of the used area in the paintbox and change the source size in 'CopyRec'.

Ashlar
  • 636
  • 1
  • 10
  • 25
  • Er, `TPaintBox` is the wrong component. It doesn't have a persistent drawing surface. – David Heffernan Mar 08 '18 at 18:52
  • @DavidHeffernan Wrong for what? This program generates a code file for constructing the graphic objects for use another program. The paintbox display does not need to be saved. Any future display is generated from the code file this program saved to the file. The canvas also saves a bitmap for use in the listbox. Am I missing something else? – Ashlar Mar 08 '18 at 19:25
  • Probably I don't understand wbat your program does. Common problem when the program is described rather than us having a [MCVE]. – David Heffernan Mar 08 '18 at 19:33
  • You can use TRect.Union to find the resulting union of all the drawing commands. For each drawing command use the surrounding rectangle as input to TRect.Union. – Jan Lauridsen Mar 08 '18 at 21:21
  • Do you keep track of the drawn objects? If so, then it should be easy to calculate their full extent. If not, then you should probably start doing that. – Rudy Velthuis Mar 08 '18 at 22:02
  • A MCVE is worth a thousand words. – Rudy Velthuis Mar 08 '18 at 22:09
  • I have added information to my question, hopefully that helps clarify the question. The actual program is not minimal and I did not realize including it would help. Also, I believe I have worked out one way to solve this and have included the function for doing so in an answer. – Ashlar Mar 09 '18 at 18:21
  • What if the user just wants a small rectangle placed on the bottom right? – Sertac Akyuz Mar 09 '18 at 18:35

1 Answers1

0

One approach I have worked out is based on the assumption that the various items that have been drawn such as circles, rectangles, text, etc are all placed on a neutral background. In that case I can read the bitmap using tbitmap.scanline to compare the color of the drawing vs the background color and calculate the extents of the drawing in each row to determine the extents of the drawing in the overall bitmap.

  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;
Ashlar
  • 636
  • 1
  • 10
  • 25