原理上没有什么新意,主要就是用CreateRectRgn、CreateRectRgn、CombineRgn和CreatePolygonRgn这 几个API,代码最大的特点就是高速,这个也是最重要的,你甚至可以用来做动画窗体。
代码用CB编写。
//
创建图片形状的窗体,可以是任意颜色
// 速度<30ms
// 作者:cczlp
//
void __fastcall CreateWindowRgn(HWND hwnd, Graphics::TBitmap * SrcBitmap, TColor TransColor)
{
register int x1, x2, y;
register int Left, Right;
int n, m;
int BmpW, BmpH;
int StartY;
int BytePerPix;
BOOL Flag;
BOOL Same;
POINT *pt, *pt1, *pt2;
HRGN WndRgn, tmpRgn;
BYTE *ptr;
Byte R, G, B;
Graphics::TBitmap *Bitmap;
//取图像尺寸
BmpW = SrcBitmap->Width;
BmpH = SrcBitmap->Height;
//只处理24位色和256色, 其它格式转为24位色
if (SrcBitmap->PixelFormat != pf24bit && SrcBitmap->PixelFormat != pf8bit)
{
Bitmap = new Graphics::TBitmap;
Bitmap->Width = BmpW;
Bitmap->Height = BmpH;
Bitmap->PixelFormat = pf24bit;
Bitmap->Canvas->Draw(0, 0, SrcBitmap);
}
else
{
Bitmap = SrcBitmap;
}
pt = new POINT[(BmpH << 1) + 1];
if (Bitmap->PixelFormat == pf24bit)
{
//透明色分量
R = GetRValue(TransColor);
G = GetGValue(TransColor);
B = GetBValue(TransColor);
//每象素所占字节数
BytePerPix = 3;
}
else
{
//取透明色在调色板的索引
PALETTEENTRY pal[256];
GetPaletteEntries(SrcBitmap->Palette, 0, 256, pal);
for (y = 0; y < 256; y++)
{
if (TColor(RGB(pal[y].peRed, pal[y].peGreen, pal[y].peBlue)) == TransColor)
{
break;
}
}
//每象素所占字节数
BytePerPix = 1;
}
//先建整个区域, 然后从中减去透明色的地方
WndRgn = CreateRectRgn(0, 0, BmpW, BmpH);
//使用指针, 加快访问速度
pt1 = pt;
pt2 = pt + (BmpH << 1) - 1;
//从左右扫描图像外部的边界点
//24bit
if (BytePerPix == 3)
{
for (y = 0; y < BmpH; y++)
{
//记录左面不透明色的起点
ptr = (Byte *)Bitmap->ScanLine[y];
for (x1 = 0; x1 < BmpW; x1++)
{
if (*ptr != B || *(ptr + 1) != G || *(ptr + 2) != R)
{
pt1->x = x1;
pt1->y = y;
pt1++;
break;
}
ptr += 3;
}
//记录右面不透明色的起点
ptr = (Byte *)Bitmap->ScanLine[y] + (BmpW - 1) * 3;
for (x2 = BmpW - 1; x2 >= x1; x2--)
{
if (*ptr != B || *(ptr + 1) != G || *(ptr + 2) != R)
{
pt2->x = x2 + 1;
pt2->y = y;
pt2--;
break;
}
ptr -= 3;
}
}
}
else //8bit, 对256色同样处理
{
for (y = 0; y < BmpH; y++)
{
ptr = (Byte *)Bitmap->ScanLine[y];
for (x1 = 0; x1 < BmpW; x1++)
{
if ((*ptr != R)) //
{
pt1->x = x1;
pt1->y = y;
pt1++;
break;
}
ptr++;
}
ptr = (Byte *)Bitmap->ScanLine[y] + (BmpW - 1);
for (x2 = BmpW - 1; x2 >= x1; x2--)
{
if ((*ptr != R)) //
{
pt2->x = x2 + 1;
pt2->y = y;
pt2--;
break;
}
ptr--;
}
}
}
//如果有整行都透明的, 去掉中间的空行
n = pt1 - pt;
m = pt2 - pt;
if (m - n > 0)
{
memmove((char *)pt + n * sizeof(POINT),
(char *)pt + (m + 1) * sizeof(POINT),
n * sizeof(POINT));
}
//去除图像内部的或凹处的剩余的透明点
StartY = pt[0].y;
pt2 = pt + (n << 1) - 1;
for (y = StartY; y < StartY + n; y++)
{
Flag = False;
ptr = (Byte *)Bitmap->ScanLine[y] + pt[y - StartY].x * BytePerPix;
//查找每行透明色的起始和结束点,并去掉透明的区域
for (x1 = pt[y - StartY].x; x1 < pt2->x; x1++)
{
Same = BytePerPix == 3 ?
(*ptr == B) && (*(ptr + 1) == G) && (*(ptr + 2) == R) :
*ptr == R;
if (!Flag && Same)
{
Left = x1;
Flag = TRUE;
}
else if (!Same && Flag)
{
tmpRgn = CreateRectRgn(Left, y, x1, y + 1);
CombineRgn(WndRgn, WndRgn, tmpRgn, RGN_XOR);
DeleteObject(tmpRgn);
Flag = FALSE;
}
ptr += BytePerPix;
}
if (Flag && x1 >= pt2->x)
{
tmpRgn = CreateRectRgn(Left, y, x1, y + 1);
CombineRgn(WndRgn, WndRgn, tmpRgn, RGN_XOR);
DeleteObject(tmpRgn);
}
pt2--;
}
//最后点与起始点相同
pt[n << 1] = pt[0];
//合并区域
tmpRgn = CreatePolygonRgn(pt, (n << 1) + 1, ALTERNATE);
CombineRgn(WndRgn, WndRgn, tmpRgn, RGN_AND);
DeleteObject(tmpRgn);
//设置区域
SetWindowRgn(hwnd, WndRgn, true);
if (Bitmap != SrcBitmap)
{
delete Bitmap;
}
delete []pt;
}
// ----------------------------------------------------------------------------------
// 速度<30ms
// 作者:cczlp
//
void __fastcall CreateWindowRgn(HWND hwnd, Graphics::TBitmap * SrcBitmap, TColor TransColor)
{
register int x1, x2, y;
register int Left, Right;
int n, m;
int BmpW, BmpH;
int StartY;
int BytePerPix;
BOOL Flag;
BOOL Same;
POINT *pt, *pt1, *pt2;
HRGN WndRgn, tmpRgn;
BYTE *ptr;
Byte R, G, B;
Graphics::TBitmap *Bitmap;
//取图像尺寸
BmpW = SrcBitmap->Width;
BmpH = SrcBitmap->Height;
//只处理24位色和256色, 其它格式转为24位色
if (SrcBitmap->PixelFormat != pf24bit && SrcBitmap->PixelFormat != pf8bit)
{
Bitmap = new Graphics::TBitmap;
Bitmap->Width = BmpW;
Bitmap->Height = BmpH;
Bitmap->PixelFormat = pf24bit;
Bitmap->Canvas->Draw(0, 0, SrcBitmap);
}
else
{
Bitmap = SrcBitmap;
}
pt = new POINT[(BmpH << 1) + 1];
if (Bitmap->PixelFormat == pf24bit)
{
//透明色分量
R = GetRValue(TransColor);
G = GetGValue(TransColor);
B = GetBValue(TransColor);
//每象素所占字节数
BytePerPix = 3;
}
else
{
//取透明色在调色板的索引
PALETTEENTRY pal[256];
GetPaletteEntries(SrcBitmap->Palette, 0, 256, pal);
for (y = 0; y < 256; y++)
{
if (TColor(RGB(pal[y].peRed, pal[y].peGreen, pal[y].peBlue)) == TransColor)
{
break;
}
}
//每象素所占字节数
BytePerPix = 1;
}
//先建整个区域, 然后从中减去透明色的地方
WndRgn = CreateRectRgn(0, 0, BmpW, BmpH);
//使用指针, 加快访问速度
pt1 = pt;
pt2 = pt + (BmpH << 1) - 1;
//从左右扫描图像外部的边界点
//24bit
if (BytePerPix == 3)
{
for (y = 0; y < BmpH; y++)
{
//记录左面不透明色的起点
ptr = (Byte *)Bitmap->ScanLine[y];
for (x1 = 0; x1 < BmpW; x1++)
{
if (*ptr != B || *(ptr + 1) != G || *(ptr + 2) != R)
{
pt1->x = x1;
pt1->y = y;
pt1++;
break;
}
ptr += 3;
}
//记录右面不透明色的起点
ptr = (Byte *)Bitmap->ScanLine[y] + (BmpW - 1) * 3;
for (x2 = BmpW - 1; x2 >= x1; x2--)
{
if (*ptr != B || *(ptr + 1) != G || *(ptr + 2) != R)
{
pt2->x = x2 + 1;
pt2->y = y;
pt2--;
break;
}
ptr -= 3;
}
}
}
else //8bit, 对256色同样处理
{
for (y = 0; y < BmpH; y++)
{
ptr = (Byte *)Bitmap->ScanLine[y];
for (x1 = 0; x1 < BmpW; x1++)
{
if ((*ptr != R)) //
{
pt1->x = x1;
pt1->y = y;
pt1++;
break;
}
ptr++;
}
ptr = (Byte *)Bitmap->ScanLine[y] + (BmpW - 1);
for (x2 = BmpW - 1; x2 >= x1; x2--)
{
if ((*ptr != R)) //
{
pt2->x = x2 + 1;
pt2->y = y;
pt2--;
break;
}
ptr--;
}
}
}
//如果有整行都透明的, 去掉中间的空行
n = pt1 - pt;
m = pt2 - pt;
if (m - n > 0)
{
memmove((char *)pt + n * sizeof(POINT),
(char *)pt + (m + 1) * sizeof(POINT),
n * sizeof(POINT));
}
//去除图像内部的或凹处的剩余的透明点
StartY = pt[0].y;
pt2 = pt + (n << 1) - 1;
for (y = StartY; y < StartY + n; y++)
{
Flag = False;
ptr = (Byte *)Bitmap->ScanLine[y] + pt[y - StartY].x * BytePerPix;
//查找每行透明色的起始和结束点,并去掉透明的区域
for (x1 = pt[y - StartY].x; x1 < pt2->x; x1++)
{
Same = BytePerPix == 3 ?
(*ptr == B) && (*(ptr + 1) == G) && (*(ptr + 2) == R) :
*ptr == R;
if (!Flag && Same)
{
Left = x1;
Flag = TRUE;
}
else if (!Same && Flag)
{
tmpRgn = CreateRectRgn(Left, y, x1, y + 1);
CombineRgn(WndRgn, WndRgn, tmpRgn, RGN_XOR);
DeleteObject(tmpRgn);
Flag = FALSE;
}
ptr += BytePerPix;
}
if (Flag && x1 >= pt2->x)
{
tmpRgn = CreateRectRgn(Left, y, x1, y + 1);
CombineRgn(WndRgn, WndRgn, tmpRgn, RGN_XOR);
DeleteObject(tmpRgn);
}
pt2--;
}
//最后点与起始点相同
pt[n << 1] = pt[0];
//合并区域
tmpRgn = CreatePolygonRgn(pt, (n << 1) + 1, ALTERNATE);
CombineRgn(WndRgn, WndRgn, tmpRgn, RGN_AND);
DeleteObject(tmpRgn);
//设置区域
SetWindowRgn(hwnd, WndRgn, true);
if (Bitmap != SrcBitmap)
{
delete Bitmap;
}
delete []pt;
}
// ----------------------------------------------------------------------------------