DelphiX 的 TPictureCollectionItem 提供兩層獨立的透明控制機制:
TransparentColor + Transparent := True):將指定顏色的像素視為完全透明 (Alpha=0),實現不規則形狀精靈、去除背景色DrawAlpha 方法的 Alpha 參數 / Transparent 屬性配合 Draw):對整張圖片應用統一透明度係數 (0-255),實現淡入淡出、半透明疊加兩者可疊加:FinalAlpha = PixelAlpha * GlobalAlpha / 255
| 屬性/方法 | 類型 | 說明 | 預設值 |
|---|---|---|---|
| Transparent | Boolean | 啟用/禁用透明色功能 | True |
| TransparentColor | TColor | 指定作為透明色的 RGB 值 | clBlack ($000000) |
| Draw(..., Alpha) | 方法參數 | Draw 方法不直接支援 Alpha,需用 DrawAlpha | - |
| DrawAlpha(Dest, Rect, Pattern, Alpha) | 方法 | 指定全域 Alpha (0-255) 繪製 | - |
| DrawRotateAlpha(..., Alpha) | 方法 | 旋轉 + Alpha 混合 | - |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DXDraws, StdCtrls, DXClass;
type
TForm1 = class(TForm)
DXDraw1: TDXDraw;
DXImageList1: TDXImageList;
CheckBox1: TCheckBox;
TrackBar1: TTrackBar;
lblAlpha: TLabel;
procedure FormCreate(Sender: TObject);
procedure CheckBox1Click(Sender: TObject);
procedure TrackBar1Change(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
var
PicItem: TPictureCollectionItem;
procedure TForm1.FormCreate(Sender: TObject);
const
ImgPath1 = 'C:\Temp\Transparent.bmp'; // 白色背景測試圖
begin
DXImageList1.DXDraw := DXDraw1;
DXDraw1.Align := alClient;
PicItem := TPictureCollectionItem(DXImageList1.Items.Add);
PicItem.Picture.LoadFromFile(ImgPath1);
// 關鍵:指定透明色為白色 (測試圖背景色)
PicItem.TransparentColor := $FFFFFF; // clWhite
PicItem.Transparent := True; // 預設即為 True
// TrackBar 設定 Alpha 0-255
TrackBar1.Min := 0;
TrackBar1.Max := 255;
TrackBar1.Position := 255;
TrackBar1.Align := alBottom;
TrackBar1.Height := 30;
// CheckBox 控制透明色啟用/禁用
CheckBox1.Caption := '啟用透明色 (白色背景透明)';
CheckBox1.Checked := True;
CheckBox1.Align := alTop;
CheckBox1.Height := 30;
lblAlpha.Align := alBottom;
lblAlpha.Height := 25;
lblAlpha.Alignment := taCenter;
lblAlpha.Caption := 'Alpha: 255 (不透明)';
end;
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
// 切換透明色功能
PicItem.Transparent := CheckBox1.Checked;
CheckBox1.Caption := IfThen(CheckBox1.Checked,
'啟用透明色 (白色背景透明)',
'禁用透明色 (白色背景顯示)');
// 立即重繪
TrackBar1Change(nil);
end;
procedure TForm1.TrackBar1Change(Sender: TObject);
var
r: TRect;
begin
// 計算置中矩形
r := Rect(
(DXDraw1.Width - PicItem.Width) div 2,
(DXDraw1.Height - PicItem.Height) div 2,
(DXDraw1.Width + PicItem.Width) div 2,
(DXDraw1.Height + PicItem.Height) div 2
);
// 紅色背景以便觀察透明效果
DXDraw1.Surface.Fill($FF0000); // 紅色
// 核心:DrawAlpha 指定全域透明度
PicItem.DrawAlpha(DXDraw1.Surface, r, 0, TrackBar1.Position);
DXDraw1.Flip;
// 更新標籤
lblAlpha.Caption := Format('Alpha: %d (%s)',
[TrackBar1.Position,
IfThen(TrackBar1.Position = 255, '不透明',
IfThen(TrackBar1.Position = 0, '全透明', '半透明'))]);
end;
end.
object Form1: TForm1
Left = 0
Top = 0
Caption = 'DelphiX 透明色與 Alpha 控制示例'
ClientHeight = 400
ClientWidth = 500
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object DXDraw1: TDXDraw
Left = 0
Top = 30
Width = 500
Height = 315
Align = alClient
AutoInitialize = True
AutoSize = True
Color = clBlack
Display.FixedBitCount = False
Display.FixedRatio = True
Display.FixedSize = True
Options = [doAllowReboot, doWaitVBlank, doCenter, do3D, doDirectX7Mode, doHardware, doSelectDriver]
SurfaceHeight = 315
SurfaceWidth = 500
TabOrder = 0
Traces = <>
end
object CheckBox1: TCheckBox
Left = 0
Top = 0
Width = 500
Height = 30
Align = alTop
Caption = 'CheckBox1'
TabOrder = 1
OnClick = CheckBox1Click
end
object TrackBar1: TTrackBar
Left = 0
Top = 345
Width = 500
Height = 30
Align = alBottom
Max = 255
Min = 0
Position = 255
TabOrder = 2
OnChange = TrackBar1Change
end
object lblAlpha: TLabel
Left = 0
Top = 375
Width = 500
Height = 25
Align = alBottom
Alignment = taCenter
Caption = 'Alpha: 255'
TabOrder = 3
end
object DXImageList1: TDXImageList
Left = 40
Top = 40
end
end
| 背景顏色 | TransparentColor 設定 | 適用格式 | 注意事項 |
|---|---|---|---|
| 純白 | clWhite / $FFFFFF | BMP, JPG | 最常見,但圖片內容若含白色會誤透明 |
| 品紅/洋紅 | clFuchsia / $FF00FF | BMP, PNG | 遊戲開發標準透明色,極少用於圖片內容 |
| 純黑 | clBlack / $000000 | BMP | 預設值,但深色內容易衝突 |
| 自定義 | 任意 RGB | 所有 | 需確保該色不出現在圖片有效內容中 |
function DetectTransparentColor(Pic: TPicture; SampleCorners: Boolean = True): TColor;
var
Bmp: TBitmap;
Colors: array[0..3] of TColor;
i: Integer;
ColorCount: TDictionary;
MostCommon: TColor;
MaxCount: Integer;
begin
Result := clNone;
Bmp := TBitmap.Create;
try
Bmp.Assign(Pic.Graphic);
Bmp.PixelFormat := pf24bit; // 確保 24位
ColorCount := TDictionary.Create;
try
if SampleCorners then
begin
// 採樣四個角落 (各 5x5 區域)
Colors[0] := Bmp.Canvas.Pixels[0, 0];
Colors[1] := Bmp.Canvas.Pixels[Bmp.Width-1, 0];
Colors[2] := Bmp.Canvas.Pixels[0, Bmp.Height-1];
Colors[3] := Bmp.Canvas.Pixels[Bmp.Width-1, Bmp.Height-1];
// 統計最常見顏色
for i := 0 to 3 do
begin
if ColorCount.ContainsKey(Colors[i]) then
ColorCount[Colors[i]] := ColorCount[Colors[i]] + 1
else
ColorCount[Colors[i]] := 1;
end;
MaxCount := 0;
for MostCommon in ColorCount.Keys do
begin
if ColorCount[MostCommon] > MaxCount then
begin
MaxCount := ColorCount[MostCommon];
Result := MostCommon;
end;
end;
end
else
begin
// 全圖掃描 (較慢),取邊緣像素最多的顏色
// ... 省略實現
end;
finally
ColorCount.Free;
end;
finally
Bmp.Free;
end;
end;
// 使用範例
PicItem.TransparentColor := DetectTransparentColor(PicItem.Picture);
PicItem.Transparent := (PicItem.TransparentColor <> clNone);
// 每像素計算 (預乘 Alpha 模式)
Src: (Rs, Gs, Bs, As) // As = 0 (透明色) 或 255 (不透明) 或圖片原始 Alpha
Dst: (Rd, Gd, Bd, Ad) // 目標表面像素
GlobalAlpha: Ga (0-255, 來自 DrawAlpha 參數)
// 有效 Alpha
EffectiveAlpha = (As * Ga) div 255
// 混合公式
R = (Rs * EffectiveAlpha + Rd * (255 - EffectiveAlpha)) div 255
G = (Gs * EffectiveAlpha + Gd * (255 - EffectiveAlpha)) div 255
B = (Bs * EffectiveAlpha + Bd * (255 - EffectiveAlpha)) div 255
// 特例:
// - 透明色像素:As = 0 → EffectiveAlpha = 0 → 完全顯示背景
// - 不透明像素 + Ga=255:EffectiveAlpha = 255 → 完全覆蓋
// - 不透明像素 + Ga=128:EffectiveAlpha = 128 → 50% 混合
type
TFadeMode = (fmFadeIn, fmFadeOut, fmCrossFade);
var
FadeMode: TFadeMode = fmFadeIn;
FadeAlpha: Integer = 0;
FadeSpeed: Integer = 8; // 每幀變化量
procedure TForm1.DXTimer1Timer(Sender: TObject; LagCount: Integer);
var
Delta: Integer;
begin
DXDraw1.Surface.Fill(0);
Delta := FadeSpeed * (LagCount + 1);
case FadeMode of
fmFadeIn:
begin
Inc(FadeAlpha, Delta);
if FadeAlpha >= 255 then
begin
FadeAlpha := 255;
FadeMode := fmFadeOut; // 自動切換淡出
end;
end;
fmFadeOut:
begin
Dec(FadeAlpha, Delta);
if FadeAlpha <= 0 then
begin
FadeAlpha := 0;
FadeMode := fmFadeIn;
end;
end;
fmCrossFade:
begin
// 交叉淡化需兩張圖片,Alpha 互補
// Pic1: Alpha, Pic2: 255-Alpha
end;
end;
PicItem.DrawAlpha(DXDraw1.Surface, CenterRect, 0, FadeAlpha);
DXDraw1.Flip;
end;
| 問題 | 原因 | 解決 |
|---|---|---|
| 透明色不生效,背景仍顯示 | TransparentColor 與圖片實際背景色不匹配 | 用取色器確認確切 RGB 值;注意 JPG 壓縮導致邊緣非純色 |
| 圖片邊緣出現鋸齒/彩邊 | 透明色邊緣像素非純色 (抗鋸齒產生半透明過渡) | 使用 PNG 真 Alpha 通道;或預乘 Alpha 處理;或手動清理邊緣 |
| DrawAlpha 效果與預期不符 | 未考慮透明色與 GlobalAlpha 疊加 | 理解 FinalAlpha = PixelAlpha * GlobalAlpha / 255 |
| Alpha=0 仍可見圖片輪廓 | 背景未清除 (Surface.Fill) | 每幀開始呼叫 DXDraw1.Surface.Fill(背景色) |
| 32位 PNG 載入後透明失效 | DelphiX 載入 PNG 可能不保留 Alpha 通道 | 轉為 32位 BMP (含 Alpha) 或使用 TDXTextureImage 載入 |
Draw 而非 DrawAlpha,省去混合運算DelphiX 的透明控制採用透明色 (像素級二值遮罩)與全域 Alpha (整體透明度係數)雙層機制。透明色解決「不規則形狀/去背景」,Alpha 解決「淡入淡出/半透明疊加」。兩者可疊加使用,最終透明度為乘積關係。掌握 TransparentColor 選擇技巧、DrawAlpha 動畫應用、邊緣抗鋸齒處理,即可實現專業級的精靈透明效果。