由图片得异形窗体太费时怎么办??

BWZY 2007-05-25 08:39:36
如题:::

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;
}
...全文
338 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
王集鹄 2007-05-25
  • 打赏
  • 举报
回复
//实际上从2000开始,Form就开始支持直接半透明和不规则区域
private void Form1_Load(object sender, EventArgs e)
{
TransparencyKey = SystemColors.Control;
}

//如果针对的只是Form(不是子窗体),那么建议用上面的方法合理些
王集鹄 2007-05-25
  • 打赏
  • 举报
回复
翻译起来很耗时间,还是发扬Free的精神

C#将图形快速处理成不规则区域
http://blog.sina.com.cn/u/589d32f5010009nf
BWZY 2007-05-25
  • 打赏
  • 举报
回复
我试过第一种方法了,效果不明显,而且要是unsafe 模式下,感觉不好
BWZY 2007-05-25
  • 打赏
  • 举报
回复
To: zswang(伴水清清)(专家门诊清洁工)

太谢谢了,正是我想要的,我Delphi不懂,能不能大体上帮我改成C# (有点过份:-))

分加到100了!
王集鹄 2007-05-25
  • 打赏
  • 举报
回复
如下是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;
王集鹄 2007-05-25
  • 打赏
  • 举报
回复
时间主要耗费在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;
}

}

}
YUAN168 2007-05-25
  • 打赏
  • 举报
回复
每次只读一条记录就可以了。
我的图片是放在数据库中的,每次都是只读一条记录,感觉不到慢...

110,571

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧