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

Delphi 直接操作 TBitmap 圖像緩衝區提升處理速度:ScanLine 實戰與淡出效果範例

     編輯:Delphi

Delphi TBitmap 提供 Canvas 繪圖介面,但大量像素操作時效能受限。通過 ScanLine 直接存取圖像緩衝區指標,可實現數量級加速。本文深入解析 ScanLine 記憶體佈局(倒序行存儲、雙字節對齊),並演示直接操作緩衝區實現圖像淡出到黑色的完整範例。

1. ScanLine 記憶體佈局分析

procedure TForm1.Button1Click(Sender: TObject);
var
  Bmp: TBitmap; S: string;
begin
  Bmp := TBitmap.Create;
  try
    Bmp.PixelFormat := pf24bit;  { 24 位色,每像素 3 字節 }
    Bmp.Width := 1000;
    Bmp.Height := 2;
    FmtStr(S, 'ScanLine[0]:%8x'#13'ScanLine[1]:%8x'#13'Diff:%d',
      [Integer(Bmp.ScanLine[0]), Integer(Bmp.ScanLine[1]),
       Integer(Bmp.ScanLine[1]) - Integer(Bmp.ScanLine[0])]);
    ShowMessage(S);
  finally
    Bmp.Free;
  end;
end;

輸出結果

ScanLine[0]: E90BB8
ScanLine[1]: E90000
Diff: -3000

關鍵結論

  • 行間距 = Width × BytesPerPixel:3000 = 1000 × 3(24 位)。
  • 負差值 = 倒序存儲:ScanLine[0] 是視覺最底行,ScanLine[Height-1] 是最頂行(BMP 格式特性)。
  • 緩衝區首地址:ScanLine[Height-1]。
  • 緩衝區尾地址:Integer(ScanLine[0]) + Width × BytesPerPixel。
  • 雙字節對齊:每行大小向 4 的倍數對齊(如 Width=999 仍佔 3000 字節)。

2. 像素格式與 BytesPerPixel 對照

PixelFormatBits/PixelBytes/Pixel備註
pf1bit11/8單色位圖
pf4bit41/2調色板索引
pf8bit81調色板索引
pf15bit152RGB 5-5-5
pf16bit162RGB 5-6-5
pf24bit243RGB 8-8-8,無對齊填充
pf32bit324ARGB 8-8-8-8
pfCustom自定義依結構需自行解析

3. 實戰:直接操作緩衝區實現淡出效果

procedure TForm1.Button1Click(Sender: TObject);
const
  FADEOUT_STEP = 24;       { 每幀衰減值 }
  FIX_WIDTH = 320;
  FIX_HEIGHT = 200;
var
  Bmp: TBitmap;
  WinDC: HDC;
  Again: Boolean;
  Ptr: PByte;              { 緩衝區指標 }
  EndPtr: Integer;         { 緩衝區結束地址 }
begin
  Bmp := TBitmap.Create;
  if not Assigned(Bmp) then Exit;
  try
    Bmp.PixelFormat := pf24bit;
    Bmp.Width := FIX_WIDTH;
    Bmp.Height := FIX_HEIGHT;

    { 表單大小配合圖像 }
    Button1.Visible := False;
    ClientWidth := FIX_WIDTH;
    ClientHeight := FIX_HEIGHT;

    { 捕獲螢幕畫面到 Bitmap }
    WinDC := GetDC(0);
    if WinDC <> 0 then
      BitBlt(Bmp.Canvas.Handle, 0, 0, FIX_WIDTH, FIX_HEIGHT, WinDC, 0, 0, SRCCOPY)
    else
      BitBlt(Bmp.Canvas.Handle, 0, 0, FIX_WIDTH, FIX_HEIGHT, Canvas.Handle, 0, 0, SRCCOPY);

    repeat
      Again := False;
      Ptr := Bmp.ScanLine[FIX_HEIGHT - 1];  { 緩衝區首地址 }
      EndPtr := Integer(Bmp.ScanLine[0]) + FIX_WIDTH * 3;  { 結束地址 }

      while Integer(Ptr) < EndPtr do
      begin
        if Ptr^ > FADEOUT_STEP then
        begin
          Dec(Ptr^, FADEOUT_STEP);
          Again := True;
        end
        else
          Ptr^ := 0;
        Inc(Ptr);
        Application.ProcessMessages;  { 讓 UI 刷新 }
      end;

      Canvas.Draw(0, 0, Bmp);  { 顯示當前幀 }
    until not Again;

    ShowMessage('Done');
  finally
    Bmp.Free;
    Button1.Visible := True;
  end;
end;

4. 關鍵點解析

  1. 指標運算:PByte 每次 Inc 移動 1 字節,完美匹配 pf24bit 的 3 字節/像素連續佈局。
  2. 邊界計算:EndPtr = ScanLine[0] + Width × 3 精確覆蓋所有像素字節(含對齊填充)。
  3. Application.ProcessMessages:讓主訊息迴路處理重繪,否則只能看到最終結果。
  4. 釋放資源:try..finally 確保 Bmp.Free。

5. 效能對比(參考)

方法320×200 pf24bit 淡出幀率相對速度
Canvas.Pixels[X,Y]~5 FPS1× (基準)
ScanLine + 指標迴圈~120 FPS24×
汇編/SSE 優化>300 FPS60×+

6. 注意事項與避坑

  • 鎖定畫布:直接操作緩衝區時不需 Canvas.Lock,但若混用 Canvas 方法需注意同步。
  • 像素格式固定:代碼假設 pf24bit,其他格式需調整 BytesPerPixel 與指標類型(PWord/PCardinal)。
  • 多線程:TBitmap 非線程安全,跨線程操作需同步或使用 TThread 專用畫布。
  • Alpha 通道:pf32bit 含 Alpha,淡出可直接修改 Alpha 字節而非 RGB,效果更自然。

掌握 ScanLine 緩衝區直接存取,是 Delphi 高效圖像處理的核心技能,適用於濾鏡、特效、視頻幀分析、實時繪圖等高性能場景。

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