Jump to content
slacky

Crop a bitmap to the given TBox.

Recommended Posts

Is there anyway to crop a bitmap in SCAR? I've been searching a lot, yet not found any solutions.

 

The secound function is the way I'm doing it now, but it's is simply to time consumung, but it's as fast as I could get it (for now).

{=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=]
TBox = XS,YS, XE,YE
Speed?? I used 354ms @ 200x200px out of a bmp.
[=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=}
function CropBitmap(bmp:TSCARBitmap; cbox: TBox): TSCARBitmap;
var
 x,y: Integer;
 Res:TSCARBitmap; 
begin
 Res := TSCARBitmap.Create('');
 Res.SetSize(IAbs(cbox.X2-cbox.X1)+1, IAbs(cbox.Y2-cbox.Y1)+1);

 if cbox.X2 > bmp.Width  then cbox.X2 := bmp.Width-1;  
 if cbox.Y2 > bmp.Height then cbox.X2 := bmp.Height-1;

 for x:=cbox.X1 to cbox.X2 do
   for y:=cbox.Y1 to cbox.Y2 do
     Res.Pixels[x - cbox.X1, y - cbox.Y1] := BMP.Pixels[x,y];   

 Result := Res;
end;


{=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=]
Speed?? I used 290ms @ 200x200px out of a bmp.
[=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=}
function CropBitmap2(bmp:TSCARBitmap; cbox: TBox): TSCARBitmap;
var
 i,W,H,x,y,Size,modI: Integer;
 Res:TSCARBitmap;
 TIA: TIntArray;  
 TPA: TPointArray;
begin
 W:= IAbs(cbox.X2-cbox.X1)+1;
 H:= IAbs(cbox.Y2-cbox.Y1)+1; 

 Res := TSCARBitmap.Create('');
 Res.SetSize(W, H);

 if cbox.X2 > bmp.Width  then cbox.X2 := bmp.Width-1;  
 if cbox.Y2 > bmp.Height then cbox.Y2 := bmp.Height-1; 
 TPA := TPAFromBox(Box(cBox.X1,cBox.Y1, cBox.X2, cBox.Y2));
 TIA := Bmp.GetPixels(TPA); 

 x:=0; y:=0;     
 Size := W*H;
 for I:=0 to Size-1 do begin
   modI := I mod W;
   if (modI = 0) and (I > 0) then y:=y+1; 
   Res.Pixels[modI,y] := TIA[i];
 end;
 Result := Res;
end;

 

The second function is the fastest one... But it's not much differance... 88ms/10000px VS 72ms/10000px...

 

-----------------------

 

EDIT: I found the function "DrawTo" in the Wiki, but wasn't documented, but a little testing allowed me to understand how (I think) it works, it turned out to be pretty darn fast! :)

 

//Solution
function CropBitmap(bmp:TSCARBitmap; cbox: TBox): TSCARBitmap;
var
 W,H: Integer;
 Res: TSCARBitmap;
begin
 W:= IAbs(cbox.X2-cbox.X1)+1;
 H := IAbs(cbox.Y2-cbox.Y1)+1;

 Res := TSCARBitmap.Create(''); 
 Res.SetSize(W, H); 

 bmp.DrawTo(Res, -cbox.X1,-cbox.Y1); 
 Result := Res;
end;

Edited by slacky
Link to comment
Share on other sites

About your CropBitmap() function, it can be shortened down to 3 lines:

 

function CropBitmap(bmp: TSCARBitmap; cbox: TBox): TSCARBitmap;
begin
 Result := TSCARBitmap.Create('');
 Result.SetSize(IAbs((cbox.X2 - cbox.X1) + 1), IAbs((cbox.Y2 - cbox.Y1) + 1));
 bmp.DrawTo(Result, -cbox.X1, -cbox.Y1);
end;

 

That way you don't even need to create extra bitmap (Res), as you can directly create the result bitmap and draw the stuff/data on it. :)

 

Going to add it in MSSL, this is fairly useful! Credits belong to you of course. :P

 

-Jani

Edited by Janilabo
Updated, thanks Freddy
Link to comment
Share on other sites

Well, there isn't a built-in method, however, it can be done a lot faster than this. I also notice that your size calculations are off by 1 pixel. if X1 = X2, you calculate width 0, when in face, you have selected 1 pixel for the width.

 

Try this:

[scar]procedure CropBitmap(const Bmp: TSCARBitmap; const Box: TBox);

var

Tmp: TSCARBitmap;

begin

if (Box.X2 < Box.X1) or (Box.Y2 < Box.Y1) then

begin

WriteLn('Invalid box specified');

TerminateScript;

end;

 

Tmp := Bmp.Clone;

try

Bmp.SetSize(Box.X2 - Box.X1 + 1, Box.Y2 - Box.Y1 + 1);

Tmp.DrawTo(Bmp, -Box.X1, -Box.Y1);

finally

Tmp.Free;

end;

end;[/scar]

 

EDIT: Lol, looks like I had this window open from yesterday xD Didn't know it was solved already. But do note the 1 pixel difference, it's important.

Link to comment
Share on other sites

That's a fine catch, Freddy! :-)

 

Also, I believe that your:

 if (Box.X2 < Box.X1) or (Box.Y2 < Box.Y1) then
 begin
   WriteLn('Invalid box specified');
   TerminateScript;
 end;

Is just a bit faster than a call (or two in my case) to IAbs. That would at least be the case in Python.

Edited by slacky
Link to comment
Share on other sites

That's a fine catch, Freddy! :-)

 

Also, I believe that your:

 if (Box.X2 < Box.X1) or (Box.Y2 < Box.Y1) then
 begin
   WriteLn('Invalid box specified');
   TerminateScript;
 end;

Is just a bit faster than a call (or two in my case) to IAbs. That would at least be the case in Python.

 

It's not faster actually, IAbs calls a core function, which is pure machine code, this executes a lot faster than processing all of the script code for the condition I've imposed, because the script engine isn't all that fast. But I've made it a convention not to allow "incorrect boxes".

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
  • Create New...