怎样生成任意形状的控件?比如根据一幅黑白的掩膜图片。(50分)

  • 主题发起人 主题发起人 BaKuBaKu
  • 开始时间 开始时间
B

BaKuBaKu

Unregistered / Unconfirmed
GUEST, unregistred user!
API 的 SetWindowRgn 函数可以根据一个 Region 生成不规则的
窗口,但是 Region 只能是简单的形状(如圆,框等),或简单的形状
的运算合成。
我需要的是真正的不规则形状,而不是不停的截取背景,然后与掩
膜图片运算,再往画布上画。
能不能根据黑白的掩膜图片生成一个 Region ?

From: BaKuBaku.
 
有求一个算法:输入是BMP文件,左上角的色彩被视为背景色,
要读取该BMP,找出BMP内图形边缘各点,并输出为ARRAY,且
ARRAY中各点的顺序是建立REGION的顺序。

说明白了吧,就是想把BMP中的图形抠出来,用CreatePolyRng。



来自:Another_eYes 时间:00-3-21 11:47:45 ID:203293
我倒是经常使用bmp->rgn, 不过您的要求我不知道答案.

我是直接将bmp转成rgn的. 我也一直想知道如何取得边界点的坐标. 可
想不出算法. 呵呵

如果您只是需要bmp->rgn(也就是说那个array纯粹只是作为中间步骤, 别无
他用), 那我这里有个完整的例子(我写的一个图象工具库中的一个函数):

思路:
扫描图象的scanline, 取不是背景色的连续坐标, 认为是一个height=1的rect,
用CreateRectRgn生成region, 再用CombineRgn(.....RGN_OR)与先前生成
的region合并生成新的region.
重复扫描完所有扫描线后就得到一个region了.

function CreateRgnFromBmp(ABmp: TBitmap; ARect: TRect; TransColor: TColor): HRGN;
var
b, e: Integer;
i, j: Integer;
p: PChar;
rg: HRGN;
rgbcolor: longint;
begin
result := 0;
if not assigned(ABmp) or ABmp.Empty then exit; // 返回空region
rgbcolor := ColorToRGB(transcolor);
rgbcolor := (
rgbcolor and $0000ff00
or (rgbcolor shr 16)
or (rgbcolor shl 16)
) and $00ffffff; // 交换RGB颜色值中的R与B, 使之与scanline中顺序相同
if IsRectEmpty(ARect) then
ARect := bounds(0, 0, abmp.width, abmp.height)
else
IntersectRect(arect, arect, bounds(0, 0, abmp.width, abmp.height));
if IsRectEmpty(arect) then exit;
ABmp.PixelFormat := pf24Bit; // 转换图象成24bit
for i := ARect.Top to ARect.Bottom - 1 do
begin
b := ARect.Left;
e := b - 1;
p := Pointer(Integer(ABmp.ScanLine) + ARect.Left * 3); // scanline中起始位置
for j := ARect.Left to ARect.Right - 1 do
begin
if CompareMem(p, @rgbcolor, 3) then // 透明色
if b >= e then Inc(b)
else
begin
if result = 0 then
result := CreateRectRgn(b, i, e, i+1)
else begin
rg := CreateRectRgn(b, i, e, i+1);
CombineRgn(result, result, rg, RGN_OR);
DeleteObject(rg);
end;
b := e;
end
else if b >=e then e := b + 1
else Inc(e);
p := p + 3;
end;
if b < e then
if result = 0 then
result := CreateRectRgn(b, i, e, i+1)
else begin
rg := CreateRectRgn(b, i, e, i+1);
CombineRgn(result, result, rg, RGN_OR);
DeleteObject(rg);
end;
end;
if result <> 0 then // 将region定到(0,0)坐标
OffsetRgn(result, -arect.left, -arect.top);
end;




--------------------------------------------------------------------------------
来自:xWolf 时间:00-3-21 13:16:04 ID:203354
从1stClass源码中Copy而来,看来与Another_eYes的相差无几:

const
BitMask: array[0..7] of byte = (128, 64, 32, 16, 8, 4, 2, 1);

function fcThisThat(const Clause: Boolean; TrueVal, FalseVal: Integer): Integer;
begin
if Clause then result := TrueVal else Result := FalseVal;
end;

function fcIsTrueColorBitmap(Bitmap: TBitmap): boolean;
begin
result:= Bitmap.PixelFormat = Graphics.pf24bit;
end;

function fcCreateRegionFromBitmap(ABitmap: TBitmap; TransColor: TColor): HRgn;
var
TempBitmap: TBitmap;
Rgn1, Rgn2: HRgn;
Col, StartCol, Row: integer;
Line: PByteArray;

function ColToColor(Col: integer): TColor;
begin
if fcIsTrueColorBitmap(TempBitmap) then
result:= Line[Col * 3] * 256 * 256 + Line[Col * 3 + 1] * 256 + Line[Col * 3 + 2]
else result := TColor(fcThisThat((Line[Col div 8] and BitMask[Col mod 8]) <> 0, clBlack, clWhite));
end;
begin
result := 0;
if (ABitmap <> nil) and (ABitmap.Width = 0) or (ABitmap.Height = 0) then Exit;
Rgn1 := 0;

TempBitmap := TBitmap.Create;

TempBitmap.Assign(ABitmap);
if not fcIsTrueColorBitmap(TempBitmap) then
begin
TempBitmap.Mask(TransColor);
TransColor := clBlack;
end;

with TempBitmap do
begin
for Row := 0 to TempBitmap.height-1 do
begin
Line:= scanLine[row];

Col := 0;
while Col < TempBitmap.Width do
begin
while (Col < TempBitmap.Width) and (ColToColor(Col) = TransColor) do inc(Col);
if Col >= TempBitmap.Width then Continue;

StartCol := Col;
while (Col < TempBitmap.Width) and (ColToColor(Col) <> TransColor) do inc(Col);
if Col >= TempBitmap.Width then Col := TempBitmap.Width;

if Rgn1 = 0 then Rgn1 := CreateRectRgn(StartCol, Row, Col, Row + 1)
else begin
Rgn2 := CreateRectRgn(StartCol, Row, Col, Row + 1);
if (Rgn2 <> 0) then CombineRgn(Rgn1,Rgn1,Rgn2,RGN_OR);
Deleteobject(Rgn2);
end;
end;
end;
end;
result := Rgn1;
TempBitmap.Free;
end;



 
瘪瘪嘴:跟我的程序段一样。
用它还可以派生出实时的Panel:我搞过
 
接受答案了.
 
其实在深度历险中有一个Skinform的控件也能实现此问题。
 
后退
顶部