从BMP到Region(100分)

  • 主题发起人 主题发起人 歪就歪
  • 开始时间 开始时间

歪就歪

Unregistered / Unconfirmed
GUEST, unregistred user!
有求一个算法:输入是BMP文件,左上角的色彩被视为背景色,
要读取该BMP,找出BMP内图形边缘各点,并输出为ARRAY,且
ARRAY中各点的顺序是建立REGION的顺序。
说明白了吧,就是想把BMP中的图形抠出来,用CreatePolyRng。
CODE PLEASE,它值300分。
(抱歉,最近生病了,不能及时回贴)
 
见鬼,分数贴错了,如果有代码,300分。
 
我倒是经常使用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 - 1do
begin
b := ARect.Left;
e := b - 1;
p := Pointer(Integer(ABmp.ScanLine) + ARect.Left * 3);
// scanline中起始位置
for j := ARect.Left to ARect.Right - 1do
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;
 
从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 TempBitmapdo
begin
for Row := 0 to TempBitmap.height-1do
begin
Line:= scanLine[row];
Col := 0;
while Col < TempBitmap.Widthdo
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;
 
www.csdn.net的Delphi专题上有。
 
Another_eYes:谢谢了,虽然没有得到数组,但目的达到了。其实,我在卡到
这个问题的时候,就想起了你。:〕,没想到,你还真来回答了。我做了个蝴
蝶,现在它飞起来了。谢谢。
xWolf:谢谢了,我会了。都是大同小异的方式。
原来打算出三百分的,但输入错误,输入了100分。如果哪位嫌这分少了,烦
请告诉我一声,我再开题。
谢谢各位。
 

Similar threads

后退
顶部