傳統逐像素建立區域 (方法一) 速度極慢。本文提出混合演算法:先雙向掃描建立外框多邊形區域 (方法二),再掃描內部移除凹陷透明區塊,最後取交集,大幅提升建立速度。
| 方法 | 原理 | 速度 | 缺點 |
|---|---|---|---|
| 一、逐像素 XOR | 白色像素建 1x1 矩形區域 XOR 合併 | 極慢 (4-5 秒) | 大圖無法接受 |
| 二、多邊形外框 | 每列掃描左右邊界建立多邊形 | 快 | 內凹區域無法呈現 |
| 三、混合法 (推薦) | 方法二建外框 + 方法一除內凹 + 取交集 | 快且完整 | 程式較複雜 |
void __fastcall TForm1::FormCreate(TObject *Sender)
{
register int x, y;
int l, r;
POINT *a;
bool lb, rb;
HRGN WndRgn, TempRgn, tepRgn;
Width = 800; Height = 600; // 初始大小
if ((a = (POINT*)malloc(800*4*sizeof(POINT))) == NULL) {
ShowMessage("記憶體配置失敗!"); exit(0);
}
Image1->Picture->LoadFromFile(".\\face.bmp");
Width = Image1->Width; Height = Image1->Height;
Repaint();
l = 0; r = Image1->Height * 2 - 1;
WndRgn = CreateRectRgn(0, 0, Image1->Width, Image1->Height);
// 步驟 1: 雙向掃描建立外框座標陣列
for (y = 0; y < Image1->Height; y++) {
lb = true;
for (x = 0; x < Image1->Width; x++)
if (Image1->Canvas->Pixels[x][y] != clWhite) {
a[l].x = x+1; a[l].y = y; lb = false; break;
}
if (lb) a[l] = a[l-1]; l++;
rb = true;
for (x = Image1->Width-1; x >= 0; x--)
if (Image1->Canvas->Pixels[x][y] != clWhite) {
a[r].x = x; a[r].y = y; rb = false; break;
}
if (rb) a[r] = a[r+1]; r--;
}
// 步驟 2: 掃描內部白色像素建立小矩形 XOR 移除內凹
r = Image1->Height * 2 - 1;
for (y = 0; y < Image1->Height; y++) {
for (x = a[y].x; x < a[r].x; x++)
if (Image1->Canvas->Pixels[x][y] == clWhite) {
tepRgn = CreateRectRgn(x, y, x+1, y+1);
CombineRgn(WndRgn, WndRgn, tepRgn, RGN_XOR);
DeleteObject(tepRgn);
}
r--;
}
// 步驟 3: 外框多邊形區域與現有區域取交集
TempRgn = CreatePolygonRgn(a, Image1->Height * 2, ALTERNATE);
CombineRgn(WndRgn, WndRgn, TempRgn, RGN_AND);
DeleteObject(TempRgn);
free(a);
SetWindowRgn(Handle, WndRgn, true);
SetWindowPos(Handle, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
face.bmp)。TImage、TPopupMenu (含關閉項目)。Celeron 466, Win98SE/Win2000, C++ Builder 5.0 通過測試。