如题:::public static Region BitmapToRegion(Bitmap bitmap, Color transparencyColor)
        {
            if (bitmap == null)
                throw new ArgumentNullException("Bitmap", "Bitmap cannot be null!");            int height = bitmap.Height;
            int width = bitmap.Width;            GraphicsPath path = new GraphicsPath();            for (int j = 0; j < height; j++)
                for (int i = 0; i < width; i++)
                {
                    if (bitmap.GetPixel(i, j) == transparencyColor)
                        continue;                    int x0 = i;                    while ((i < width) && (bitmap.GetPixel(i, j) != transparencyColor))
                        i++;                    path.AddRectangle(new Rectangle(x0, j, i - x0, 1));
                }            Region region = new Region(path);
            path.Dispose();
            return region;
        }

解决方案 »

  1.   

    时间主要耗费在GetPixel()和AddRectangle()
    如下代码是优化了GetPixel()from
    http://www.codeproject.com/cs/miscctrl/walkingrabbit.asp///<author>Arild Fines</author>
    ///<date>20.04.2002</date>
    using System;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Drawing.Imaging;
    using System.Runtime.InteropServices;namespace BitmapToRegion
    {    /// <summary>
        /// determines the meaning of the transparencyKey argument to the Convert method
        /// </summary>
        public enum TransparencyMode
        {
            /// <summary>
            /// the color key is used to define the transparent region of the bitmap
            /// </summary>
            ColorKeyTransparent,
            /// <summary>
            /// the color key is used to define the area that should _not_ be transparent
            /// </summary>
            ColorKeyOpaque
        } /// <summary>
    /// a class to convert a color-keyed bitmap into a region
    /// </summary>
    public class BitmapToRegion
    {
            /// <summary>
            /// ctor made private to avoid instantiation
            /// </summary>
            private BitmapToRegion()
            {}
            /// <summary>
            /// the meat of this class
            /// converts the bitmap to a region by scanning each line one by one
            /// this method will not affect the original bitmap in any way
            /// </summary>
            /// <param name="bitmap">The bitmap to convert</param>
            /// <param name="transparencyKey">The color which will indicate either transparency or opacity</param>
            /// <param name="mode">Whether the transparency key should indicate the transparent or the opaque region</param>
            public unsafe static Region Convert( Bitmap bitmap, Color transparencyKey, TransparencyMode mode )
            {
                //sanity check
                if ( bitmap == null )
                    throw new ArgumentNullException( "Bitmap", "Bitmap cannot be null!" );            //flag = true means the color key represents the opaque color
                bool modeFlag = ( mode == TransparencyMode.ColorKeyOpaque );
                
                GraphicsUnit unit = GraphicsUnit.Pixel;
                RectangleF boundsF = bitmap.GetBounds( ref unit );
                Rectangle bounds = new Rectangle( (int)boundsF.Left, (int)boundsF.Top, 
                    (int)boundsF.Width, (int)boundsF.Height );            uint key = (uint)((transparencyKey.A << 24) | (transparencyKey.R << 16) | 
                    (transparencyKey.G << 8) | (transparencyKey.B << 0));
                //get access to the raw bits of the image
                BitmapData bitmapData = bitmap.LockBits( bounds, ImageLockMode.ReadOnly, 
                    PixelFormat.Format32bppArgb );
                uint* pixelPtr = (uint*)bitmapData.Scan0.ToPointer();            //avoid property accessors in the for
                int yMax = (int)boundsF.Height;
                int xMax = (int)boundsF.Width;            //to store all the little rectangles in
                GraphicsPath path = new GraphicsPath();            for ( int y = 0; y < yMax; y++ )
                {
                    //store the pointer so we can offset the stride directly from it later
                    //to get to the next line
                    byte* basePos = (byte*)pixelPtr;                for ( int x = 0; x < xMax; x++, pixelPtr++  )
                    {      
                        //is this transparent? if yes, just go on with the loop
                        if ( modeFlag ^ ( *pixelPtr == key ) )
                            continue;                    //store where the scan starts
                        int x0 = x;                    //not transparent - scan until we find the next transparent byte
                        while( x < xMax && !( modeFlag ^ ( *pixelPtr == key ) ) )
                        {
                            ++x;
                            pixelPtr++;
                        }                    //add the rectangle we have found to the path
                        path.AddRectangle( new Rectangle( x0, y, x-x0, 1 ) );
                    }
                    //jump to the next line
                    pixelPtr = (uint*)(basePos + bitmapData.Stride);
                }            //now create the region from all the rectangles
                Region region = new Region( path );            //clean up
                path.Dispose();
                bitmap.UnlockBits( bitmapData );            return region;
            }     }
      
    }
      

  2.   

    如下是Delphi的代码,优化了AddRectangle(),如果上面的效率还不能满足,可以参考修改一个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;    // used to access the rects array of RgnData by index 
      h: HRGN;           // Handles to regions 
      RgnData: PRgnData; // Pointer to structure RGNDATA used to create regions 
      lr, lg, lb, hr, hg, hb: Byte; // values for lowest and hightest trans. colors 
      x,y, x0: Integer;  // coordinates of current rect of visible pixels 
      b: PByteArray;     // used to easy the task of testing the byte pixels (R,G,B) 
      ScanLinePtr: Pointer; // Pointer to current ScanLine being scanned 
      ScanLineInc: Integer; // Offset to next bitmap scanline (can be negative) 
      maxRects: Cardinal;   // Number of rects to realloc memory by chunks of AllocUnit 
    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); 
      { ensures that the pixel format is 32-bits per pixel } 
      bmp.PixelFormat := pf32bit; 
      { alloc initial region data } 
      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; 
        { scan each bitmap row - the orientation doesn't matter (Bottom-up or not) } 
        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 
            { Need to create the region by muliple calls to ExtCreateRegion, 'cause } 
            { it will fail on Windows 98 if the number of rectangles is too large   } 
            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; 
    end;
      

  3.   

    To: zswang(伴水清清)(专家门诊清洁工)太谢谢了,正是我想要的,我Delphi不懂,能不能大体上帮我改成C# (有点过份:-))分加到100了!
      

  4.   

    我试过第一种方法了,效果不明显,而且要是unsafe 模式下,感觉不好
      

  5.   

    翻译起来很耗时间,还是发扬Free的精神C#将图形快速处理成不规则区域
    http://blog.sina.com.cn/u/589d32f5010009nf
      

  6.   

    //实际上从2000开始,Form就开始支持直接半透明和不规则区域
    private void Form1_Load(object sender, EventArgs e)
    {
        TransparencyKey = SystemColors.Control;
    }//如果针对的只是Form(不是子窗体),那么建议用上面的方法合理些