首页  编辑  

用位图生成一个区域

Tags: /超级猛料/Picture.图形图像编程/图片处理/   Date Created:

贴一个能精确裁减的算法(NiceCrop),还有一个能满足动画要求的算法(FastCrop)。想要的朋友联系wwwsheng@sian.com

function NiceCropRgn(bitmap: TBitmap; clMask: TColor): HRGN;

var

 hrgn, hrgn1 : integer;

 x, y : integer;

begin

 hrgn := CreateRectRgn(0, 0, bitmap.Width, bitmap.Height);

 for x := 1 to bitmap.Width do

   for y := 1 to bitmap.Height do

     if bitmap.Canvas.Pixels[x - 1, y - 1] = clMask then begin

       hrgn1 := CreateRectRgn(x - 1, y - 1, x, y);

       CombineRgn(hrgn, hrgn, hrgn1, RGN_DIFF);

       DeleteObject(hrgn1);

     end;

 Result := hrgn;

end;

***************

TBitmaps to Windows Regions

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

function BitmapToRegion(bmp: TBitmap; TransparentColor: TColor=clBlack;

 RedTol: Byte=1; GreenTol: Byte=1; BlueTol: Byte=1): HRGN;

const

 AllocUnit = 100;

type

 PRectArray = ^TRectArray;

 TRectArray = Array[0..(MaxInt div SizeOf(TRect))-1] of TRect;

var

 pr: PRectArray;    

 h: HRGN;          

 RgnData: PRgnData;

 lr, lg, lb, hr, hg, hb: Byte;

 x,y, x0: Integer;  

 b: PByteArray;    

 ScanLinePtr: Pointer;

 ScanLineInc: Integer;

 maxRects: Cardinal;  

begin

 Result := 0;

 { Keep on hand lowest and highest values for the "transparent" pixels }

 lr := GetRValue(TransparentColor);

 lg := GetGValue(TransparentColor);

 lb := GetBValue(TransparentColor);

 hr := Min($ff, lr + RedTol);

 hg := Min($ff, lg + GreenTol);

 hb := Min($ff, lb + BlueTol);

 bmp.PixelFormat := pf32bit;

 

 maxRects := AllocUnit;

 GetMem(RgnData,SizeOf(RGNDATAHEADER) + (SizeOf(TRect) * maxRects));

 try

   with RgnData^.rdh do

   begin

     dwSize := SizeOf(RGNDATAHEADER);

     iType := RDH_RECTANGLES;

     nCount := 0;

     nRgnSize := 0;

     SetRect(rcBound, MAXLONG, MAXLONG, 0, 0);

   end;

 

   ScanLinePtr := bmp.ScanLine[0];

   ScanLineInc := Integer(bmp.ScanLine[1]) - Integer(ScanLinePtr);

   for y := 0 to bmp.Height - 1 do

   begin

     x := 0;

     while x < bmp.Width do

     begin

       x0 := x;

       while x < bmp.Width do

       begin

         b := @PByteArray(ScanLinePtr)[x*SizeOf(TRGBQuad)];

         // BGR-RGB: Windows 32bpp BMPs are made of BGRa quads (not RGBa)

         if (b[2] >= lr) and (b[2] <= hr) and

            (b[1] >= lg) and (b[1] <= hg) and

            (b[0] >= lb) and (b[0] <= hb) then

           Break; // pixel is transparent

         Inc(x);

       end;

       { test to see if we have a non-transparent area in the image }

       if x > x0 then

       begin

         { increase RgnData by AllocUnit rects if we exceeds maxRects }

         if RgnData^.rdh.nCount >= maxRects then

         begin

           Inc(maxRects,AllocUnit);

           ReallocMem(RgnData,SizeOf(RGNDATAHEADER) + (SizeOf(TRect) * MaxRects));

         end;

         { Add the rect (x0, y)-(x, y+1) as a new visible area in the region }

         pr := @RgnData^.Buffer; // Buffer is an array of rects

         with RgnData^.rdh do

         begin

           SetRect(pr[nCount], x0, y, x, y+1);

           { adjust the bound rectangle of the region if we are "out-of-bounds" }

           if x0 < rcBound.Left then rcBound.Left := x0;

           if y < rcBound.Top then rcBound.Top := y;

           if x > rcBound.Right then rcBound.Right := x;

           if y+1 > rcBound.Bottom then rcBound.Bottom := y+1;

           Inc(nCount);

         end;

       end; // if x > x0

     

       

       if RgnData^.rdh.nCount = 2000 then

       begin

         h := ExtCreateRegion(nil, SizeOf(RGNDATAHEADER) + (SizeOf(TRect) * maxRects), RgnData^);

         if Result > 0 then

         begin // Expand the current region

           CombineRgn(Result, Result, h, RGN_OR);

           DeleteObject(h);

         end

         else  // First region, assign it to Result

           Result := h;

         RgnData^.rdh.nCount := 0;

         SetRect(RgnData^.rdh.rcBound, MAXLONG, MAXLONG, 0, 0);

       end;

       Inc(x);

     end; // scan every sample byte of the image

     Inc(Integer(ScanLinePtr), ScanLineInc);

   end;

   { need to call ExCreateRegion one more time because we could have left    }

   { a RgnData with less than 2000 rects, so it wasn't yet created/combined  }

   h := ExtCreateRegion(nil, SizeOf(RGNDATAHEADER) + (SizeOf(TRect) * MaxRects), RgnData^);

   if Result > 0 then

   begin

     CombineRgn(Result, Result, h, RGN_OR);

     DeleteObject(h);

   end

   else

     Result := h;

 finally

   FreeMem(RgnData,SizeOf(RGNDATAHEADER) + (SizeOf(TRect) * MaxRects));

 end;