首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

DelphiX 圖片縮放繪製實戰:StretchDraw 方法完整解析與雙模式對比

     編輯:Delphi

核心功能:StretchDraw 實現任意尺寸縮放繪製

DelphiX 的 TPictureCollectionItem.StretchDraw 方法允許將圖片以任意寬高繪製到目標表面,支援放大、縮小、非等比縮放、鏡像翻轉 (負尺寸)。這是實現 UI 自適應、縮圖預覽、全螢幕背景拉伸、精靈縮放動畫的基礎工具。

函數原型與參數詳解

function StretchDraw(
  Dest: TDirectDrawSurface;  // 目標繪圖表面
  const DestRect: TRect;     // 目標矩形區域 (決定繪製位置與尺寸)
  Pattern: Integer           // 圖樣索引 (動畫幀)
): Boolean;
參數說明特殊用法
Dest通常為 DXDraw1.Surface (後台緩衝區)也可為 DXDraw1.Primary (直接繪製到前台,不建議)
DestRect目標繪製區域 (Left, Top, Right, Bottom)Right-Left = 寬度,Bottom-Top = 高度。負寬/高可鏡像翻轉
Pattern動畫幀索引靜態圖片為 0

完整範例:雙模式縮放對比展示

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DXDraws, StdCtrls, DXClass;

type
  TForm1 = class(TForm)
    DXDraw1: TDXDraw;
    DXImageList1: TDXImageList;
    Button1: TButton;
    Button2: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(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\DelphiX.bmp';
begin
  DXImageList1.DXDraw := DXDraw1;
  
  PicItem := TPictureCollectionItem(DXImageList1.Items.Add);
  PicItem.Picture.LoadFromFile(ImgPath1);
  
  Button1.Caption := 'StretchDraw 全螢幕拉伸 (填滿)';
  Button2.Caption := 'StretchDraw 置中原始比例 (保持比例)';
end;

// 模式 1:全螢幕拉伸填滿 (可能變形)
procedure TForm1.Button1Click(Sender: TObject);
begin
  DXDraw1.Surface.Fill(0);  // 黑色背景
  
  // 直接使用 ClientRect 矩形,圖片會被拉伸填滿整個客戶區
  PicItem.StretchDraw(DXDraw1.Surface, DXDraw1.Surface.ClientRect, 0);
  
  DXDraw1.Flip;
end;

// 模式 2:置中繪製,保持原始寬高比
procedure TForm1.Button2Click(Sender: TObject);
var
  r: TRect;
  Scale: Single;
  DrawW, DrawH: Integer;
begin
  DXDraw1.Surface.Fill(0);
  
  // 計算保持比例的縮放比例
  Scale := Min(DXDraw1.Width / PicItem.Width, DXDraw1.Height / PicItem.Height);
  DrawW := Round(PicItem.Width * Scale);
  DrawH := Round(PicItem.Height * Scale);
  
  // 計算置中矩形
  r.Left := (DXDraw1.Width - DrawW) div 2;
  r.Top := (DXDraw1.Height - DrawH) div 2;
  r.Right := r.Left + DrawW;
  r.Bottom := r.Top + DrawH;
  
  // 繪製
  PicItem.StretchDraw(DXDraw1.Surface, r, 0);
  
  DXDraw1.Flip;
end;

end.

DFM 視窗定義

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'DelphiX StretchDraw 縮放繪製示例'
  ClientHeight = 300
  ClientWidth = 400
  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 = 0
    Width = 400
    Height = 250
    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 = 250
    SurfaceWidth = 400
    TabOrder = 0
    Traces = <>
  end
  object Button1: TButton
    Left = 10
    Top = 260
    Width = 180
    Height = 30
    Caption = 'Button1'
    TabOrder = 1
    OnClick = Button1Click
  end
  object Button2: TButton
    Left = 210
    Top = 260
    Width = 180
    Height = 30
    Caption = 'Button2'
    TabOrder = 2
    OnClick = Button2Click
  end
  object DXImageList1: TDXImageList
    Left = 40
    Top = 40
  end
end

進階縮放技巧

1. 保持比例縮放通用函數

procedure StretchDrawKeepAspect(
  PicItem: TPictureCollectionItem;
  Dest: TDirectDrawSurface;
  const TargetRect: TRect;  // 目標區域 (如 ClientRect)
  Pattern: Integer = 0;
  AlignHorizontal: TAlign = alCenter;  // alLeft, alCenter, alRight
  AlignVertical: TAlign = alCenter     // alTop, alCenter, alBottom
);
var
  Scale: Single;
  DrawW, DrawH, DrawX, DrawY: Integer;
  DestW, DestH: Integer;
  r: TRect;
begin
  DestW := TargetRect.Right - TargetRect.Left;
  DestH := TargetRect.Bottom - TargetRect.Top;
  
  // 計算最大等比縮放
  Scale := Min(DestW / PicItem.Width, DestH / PicItem.Height);
  DrawW := Round(PicItem.Width * Scale);
  DrawH := Round(PicItem.Height * Scale);
  
  // 水平對齊
  case AlignHorizontal of
    alLeft:   DrawX := TargetRect.Left;
    alCenter: DrawX := TargetRect.Left + (DestW - DrawW) div 2;
    alRight:  DrawX := TargetRect.Right - DrawW;
  else DrawX := TargetRect.Left + (DestW - DrawW) div 2;
  end;
  
  // 垂直對齊
  case AlignVertical of
    alTop:    DrawY := TargetRect.Top;
    alCenter: DrawY := TargetRect.Top + (DestH - DrawH) div 2;
    alBottom: DrawY := TargetRect.Bottom - DrawH;
  else DrawY := TargetRect.Top + (DestH - DrawH) div 2;
  end;
  
  r := Rect(DrawX, DrawY, DrawX + DrawW, DrawY + DrawH);
  PicItem.StretchDraw(Dest, r, Pattern);
end;

2. 鏡像翻轉 (負尺寸)

// 水平鏡像 (左右翻轉)
r.Left := CenterX + Width div 2;
r.Right := CenterX - Width div 2;  // Right < Left 產生負寬度
PicItem.StretchDraw(Surface, r, 0);

// 垂直鏡像 (上下翻轉)
r.Top := CenterY + Height div 2;
r.Bottom := CenterY - Height div 2;  // Bottom < Top 產生負高度
PicItem.StretchDraw(Surface, r, 0);

// 同時水平垂直鏡像 = 旋轉 180°

3. 縮放動畫 (縮放彈跳效果)

var
  ScalePhase: Single = 0;
  BaseScale: Single = 1.0;

procedure TForm1.DXTimer1Timer(Sender: TObject; LagCount: Integer);
var
  r: TRect;
  CurrentScale: Single;
  DrawW, DrawH: Integer;
begin
  DXDraw1.Surface.Fill(0);
  
  // 正弦波縮放動畫 0.8x ~ 1.2x
  ScalePhase := ScalePhase + 0.1 * (LagCount + 1);
  CurrentScale := BaseScale + 0.2 * Sin(ScalePhase);
  
  DrawW := Round(PicItem.Width * CurrentScale);
  DrawH := Round(PicItem.Height * CurrentScale);
  
  r := Rect(
    (DXDraw1.Width - DrawW) div 2,
    (DXDraw1.Height - DrawH) div 2,
    (DXDraw1.Width + DrawW) div 2,
    (DXDraw1.Height + DrawH) div 2
  );
  
  PicItem.StretchDraw(DXDraw1.Surface, r, 0);
  DXDraw1.Flip;
end;

4. 九宮格縮放 (Nine-Patch / 九切圖)

DelphiX 無內建九宮格,需手動實現:將圖片分為 9 區 (四角不變、邊緣單向拉伸、中心雙向拉伸),分別 StretchDraw 到對應目標區域。適用於對話框邊框、按鈕背景、進度條等 UI 元件。

StretchDraw vs Draw vs DrawRotate 對比

方法縮放旋轉透明度混合模式效能適用場景
Draw否 (原始尺寸)否透明色普通最快固定尺寸精靈、UI 圖示
StretchDraw是 (任意矩形)否透明色普通快UI 自適應、縮圖、背景拉伸
DrawRotate是 (Width/Height)是 (Angle)透明色普通中等旋轉精靈、指針、車輛
DrawRotateAdd/Sub/Alpha...是是Alpha/混合加色/減色/Alpha較慢特效、粒子、魔法、UI 高亮

效能優化建議

  1. 避免每幀計算 Rect:預先計算常用目標矩形,或使用 Rect() 快速構造
  2. 大圖縮小顯示:若原圖極大 (如 4000x3000) 但顯示很小,建議預先生成縮略圖或使用 TDXTextureImage 的 Mipmap
  3. 批次繪製相同尺寸:相同縮放參數的多張圖片合併繪製
  4. 硬體加速:確保 doHardware 和 doDirectX7Mode 啟用,StretchDraw 會使用顯卡雙線性過濾
  5. 系統記憶體表面:PicItem.SystemMemory := True 可加快 CPU 端像素操作,但 GPU 繪製可能較慢

常見問題排查

問題原因解決
圖片模糊/鋸齒嚴重放大倍數過大或雙線性過濾不佳使用高解析度源圖;檢查 DirectX 設備過濾模式
透明區域出現邊緣/白邊縮放插值導致透明色邊緣混色預乘 Alpha 處理圖片;使用 32位含 Alpha 通道圖片
負尺寸不生效/繪製異常Rect 定義順序錯誤確保 Left > Right 或 Top > Bottom 產生負寬/高
縮放比例計算錯誤整數除法截斷使用 Single/Double 計算,最後 Round 到 Integer
StretchDraw 無視透明色Transparent 屬性未設定PicItem.Transparent := True; PicItem.TransparentColor := clFuchsia (或實際透明色)

總結

StretchDraw 是 DelphiX 實現任意尺寸縮放繪製的核心方法。掌握 TRect 定義目標區域、保持比例計算、負尺寸鏡像翻轉、動畫縮放等技巧,可構建靈活的 UI 自適應系統、精靈縮放動畫、縮圖預覽等功能。關鍵在於理解 DestRect 的幾何含義,配合 Fill 清除背景與 Flip 雙緩衝顯示,即可獲得流暢的縮放視覺效果。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved