快速创建图片窗体

原理上没有什么新意,主要就是用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(00, 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, 0256, 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(00, 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
->= x1;
                    pt1
->= 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
->= x2 + 1;
                    pt2
->= 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
->= x1;
                    pt1
->= y;
                    pt1
++;
                    
break;
                }

                ptr
++;
            }


            ptr 
= (Byte *)Bitmap->ScanLine[y] + (BmpW - 1);
            
for (x2 = BmpW - 1; x2 >= x1; x2--)
            
{
                
if ((*ptr != R))     //
                {
                    pt2
->= x2 + 1;
                    pt2
->= 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;
}

// ----------------------------------------------------------------------------------

感谢 ydlchina 提出修正建议。

你可能感兴趣的:(快速创建图片窗体)