理想狀態下,GDI+ 完全取代 GDI;次佳情況僅需單向轉換。但現實專案常面臨「要新特性、要快速開發、又不捨棄舊代碼」的三重壓力,唯有掌握雙向互轉技巧,才能在遷移期平穩過渡。
Graphics g(pDC->GetSafeHdc());
// 任何能構造 CDC 指標的 MFC 物件皆適用:CClientDC、CPaintDC 等
CDC MemDC;
CBitmap MemBitmap;
MemDC.CreateCompatibleDC(pDC);
MemBitmap.CreateCompatibleBitmap(pDC, size.cx, size.cy);
CBitmap* pOldBit = MemDC.SelectObject(&MemBitmap);
Graphics g(MemDC.GetSafeHdc());
// ... 使用 GDI+ 繪圖 ...
MemDC.SelectObject(pOldBit); // 恢復原位圖
替代方案:Bitmap::FromHBITMAP(HBITMAP, HPALETTE) 靜態方法直接建立 GDI+ Bitmap。
Bitmap* pPicture = new Bitmap(L"dotLive.jpg");
HBITMAP hBitmap;
pPicture->GetHBITMAP(Color(0,0,0), &hBitmap); // 背景色設為黑色
CBitmap* pbm = CBitmap::FromHandle(hBitmap);
// ... 使用 pbm 進行 GDI 操作 ...
pbm->DeleteObject(); // 必須釋放 GDI 物件,否則記憶體洩漏
痛點:Bitmap/Image 開啟圖片會鎖定檔案,直接 Save 同名檔案會報「檔案被使用」錯誤。
解法:建立新 Bitmap 複製內容,刪除舊物件釋放鎖定,再儲存新物件。不可用 Clone(),它會連同鎖定資源一起複製。
Bitmap* tPic = new Bitmap(L"dotLive.jpg"); // 鎖定檔案
Bitmap* pPicture = new Bitmap(tPic->GetWidth(), tPic->GetHeight(), tPic->GetPixelFormat());
Graphics g(pPicture);
g.DrawImage(tPic, 0, 0, m_nWidth, m_nHeight); // 複製像素資料
delete tPic; // 釋放鎖定
// ... 對 pPicture 進行操作 ...
CLSID tiffClsid;
GetEncoderClsid(L"image/jpeg", &tiffClsid); // MSDN 有此函數實現
pPicture->Save(L"dotLive.jpg", &tiffClsid); // 成功儲存
場景:GDI+ 載圖方便,但缺異或模式 (橡皮筋)、文字輸出無背景透明控制、字串需轉 WCHAR。需獲取 HDC 使用 GDI 函數。
Bitmap* pPicture = new Bitmap(L"dotLive.jpg");
Graphics tempG(pPicture);
HDC hdc = tempG.GetHDC(); // 獲取 GDI 相容 DC
CDC* tempDC = CDC::FromHandle(hdc);
// ... 瘋狂呼叫 GDI 函數: TextOut, MoveTo, LineTo, SetROP2(R2_NOTXORPEN) ...
tempG.ReleaseHDC(hdc); // 必須 Release,否則資源佔用阻塞後續操作
GetHDC() 必配 ReleaseHDC();SelectObject() 必配還原原物件;new 配置必配 delete。GetPixelFormat() 一致。CLSID (如 image/jpeg、image/png)。歡迎探討 GDI+、影像處理與 .NET 程式設計相關技術。