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

C++Builder 位圖 90 度旋轉演算法 (像素級複製 + 緩衝區)

     編輯:關於C++

演算法原理

將來源位圖 (x, y) 像素映射到目標位圖 (y, H-1-x) (順時針 90°) 或 (W-1-y, x) (逆時針 90°)。使用記憶體位圖緩衝區 避免重疊複製錯誤,最後一次性繪回目標。

順時針 90° 完整實作 (VCL)


void __fastcall RotateBitmap90CW(Graphics::TBitmap* Src, Graphics::TBitmap* Dest)
{
    if (!Src || !Dest || Src->Empty) return;

    int srcW = Src->Width;
    int srcH = Src->Height;

    // 1. 建立目標緩衝區 (寬高互換)
    Graphics::TBitmap* Buffer = new Graphics::TBitmap();
    try {
        Buffer->Width  = srcH;
        Buffer->Height = srcW;
        Buffer->PixelFormat = Src->PixelFormat; // 保持像素格式

        // 2. 像素級複製 (順時針 90°: (x,y) -> (y, srcH-1-x))
        for (int y = 0; y < srcH; ++y) {
            for (int x = 0; x < srcW; ++x) {
                TColor color = Src->Canvas->Pixels[x][y]; // 取得像素顏色
                Buffer->Canvas->Pixels[y][srcH - 1 - x] = color; // 寫入緩衝區
            }
        }

        // 3. 指派給目標位圖
        Dest->Assign(Buffer); // 複製像素、調色盤、格式
    }
    __finally {
        delete Buffer;
    }
}

// 使用範例:旋轉 Image1 的位圖並顯示回 Image1
void __fastcall TForm1::ButtonRotateClick(TObject *Sender)
{
    Graphics::TBitmap* Rotated = new Graphics::TBitmap();
    try {
        RotateBitmap90CW(Image1->Picture->Bitmap, Rotated);
        Image1->Picture->Assign(Rotated); // 更新顯示
    }
    __finally {
        delete Rotated;
    }
}

高效能版本:掃描線存取 (避免 Pixels[][] 陣列邊界檢查開銷)


void __fastcall RotateBitmap90CW_Fast(Graphics::TBitmap* Src, Graphics::TBitmap* Dest)
{
    if (!Src || !Dest || Src->Empty) return;

    int srcW = Src->Width;
    int srcH = Src->Height;

    Graphics::TBitmap* Buffer = new Graphics::TBitmap();
    try {
        Buffer->Width  = srcH;
        Buffer->Height = srcW;
        Buffer->PixelFormat = Src->PixelFormat;

        // 針對 24/32-bit 格式優化
        if (Src->PixelFormat == pf24bit || Src->PixelFormat == pf32bit) {
            int bytesPerPixel = (Src->PixelFormat == pf24bit) ? 3 : 4;

            for (int y = 0; y < srcH; ++y) {
                // 來源掃描線
                BYTE* srcLine = (BYTE*)Src->ScanLine[y];
                // 目標掃描線 (順時針: 目標行 = y, 目標列 = srcH-1-x)
                for (int x = 0; x < srcW; ++x) {
                    BYTE* srcPixel = srcLine + x * bytesPerPixel;
                    BYTE* dstLine = (BYTE*)Buffer->ScanLine[y];
                    BYTE* dstPixel = dstLine + (srcH - 1 - x) * bytesPerPixel;
                    // 複製像素 (含 Alpha)
                    memcpy(dstPixel, srcPixel, bytesPerPixel);
                }
            }
        } else {
            // 其他格式退回 Pixels[][]
            for (int y = 0; y < srcH; ++y)
                for (int x = 0; x < srcW; ++x)
                    Buffer->Canvas->Pixels[y][srcH - 1 - x] = Src->Canvas->Pixels[x][y];
        }

        Dest->Assign(Buffer);
    }
    __finally {
        delete Buffer;
    }
}

逆時針 90° / 180° / 水鏡/垂直鏡像 映射公式

轉換目標座標 (x', y')目標尺寸
順時針 90°(y, H-1-x)(H, W)
逆時針 90°(W-1-y, x)(H, W)
180°(W-1-x, H-1-y)(W, H)
水平鏡像(W-1-x, y)(W, H)
垂直鏡像(x, H-1-y)(W, H)

GDI+ 替代方案 (支援插值、抗鋸齒、任意角度)


#include 
#pragma comment(lib, "gdiplus.lib")

void RotateGdiplus(Gdiplus::Bitmap* src, Gdiplus::Bitmap** dst, float angle)
{
    int w = src->GetWidth();
    int h = src->GetHeight();
    *dst = new Gdiplus::Bitmap(h, w, src->GetPixelFormat()); // 90° 交換寬高

    Gdiplus::Graphics g(*dst);
    g.TranslateTransform(h/2.0f, w/2.0f); // 移至中心
    g.RotateTransform(angle);               // 旋轉
    g.TranslateTransform(-w/2.0f, -h/2.0f); // 移回
    g.SetInterpolationMode(Gdiplus::InterpolationModeHighQualityBicubic);
    g.DrawImage(src, 0, 0, w, h);
}

常見問題

  • 顏色失真:確認 PixelFormat 一致 (pf24bit/pf32bit),Assign 會自動轉換,手動 ScanLine 複製需自行處理格式。
  • 透明度遺失:pf32bit 含 Alpha,Pixels[][] 存取會捨棄 Alpha,必須用 ScanLine 複製 4 位元組。
  • 大圖效能:Pixels[][] 極慢 (每次存取觸發 GDI 鎖定/解鎖),>1000x1000 必須用 ScanLine 或 GDI+。
  • 記憶體不足:緩衝區需額外 W*H*4 bytes,大圖分塊處理或使用檔案映射。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved