問題現象
使用 Graphics.DrawRectangle 繪製白色背景矩形時,將 Bitmap 尺寸從 400×200 改為 1000×500 後,出現巨大黑色邊框遮蓋畫布。
錯誤程式碼
// 錯誤:用 400 像素寬的畫筆畫邊框
g.DrawRectangle(new Pen(Color.White, 400), 0, 0, img.Width, img.Height);
根因分析
Pen 的第二個參數是**畫筆寬度**,單位為像素
new Pen(Color.White, 400) 創建了一支**寬度 400 像素**的畫筆
DrawRectangle 以矩形**中心線**為基準,向內外各延伸 200 像素
- 畫布 400×200 時:畫筆剛好覆蓋整個畫布,視覺上變白
- 畫布 1000×500 時:畫筆只覆蓋中心 400×400 區域,外圍露出預設黑色背景
正確做法:用填充而非描邊
// ✅ 正確:填充整個矩形區域
g.FillRectangle(new SolidBrush(Color.White), 0, 0, img.Width, img.Height);
// 或清空畫布
g.Clear(Color.White); // 最簡單、效能最好
GDI+ 繪圖核心概念對照
| 操作 | 方法 | 用途 | 參數含義 |
| 描邊 | DrawRectangle | 畫邊框 | Pen 寬度 = 邊框粗細 |
| 填充 | FillRectangle | 填滿區域 | Brush = 填充樣式 |
| 清空 | Clear | 整圖填色 | Color = 背景色 |
完整修正範例
public MemoryStream DrawChart() {
using (Bitmap img = new Bitmap(1000, 500))
using (Graphics g = Graphics.FromImage(img)) {
// 1. 高品質設定
g.SmoothingMode = SmoothingMode.AntiAlias;
g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
// 2. 正確清空背景
g.Clear(Color.White); // 替代錯誤的 DrawRectangle
// 3. 繪製座標軸、曲線...
using (Pen axisPen = new Pen(Color.Black, 2))
using (Pen curvePen = new Pen(Color.Blue, 1.5f))
using (SolidBrush pointBrush = new SolidBrush(Color.Red)) {
// 座標軸
g.DrawLine(axisPen, 100, 450, 900, 450); // X軸
g.DrawLine(axisPen, 100, 450, 100, 50); // Y軸
// 曲線繪製邏輯...
}
// 4. 輸出
MemoryStream ms = new MemoryStream();
img.Save(ms, ImageFormat.Png); // PNG 無損,比 JPEG 適合圖表
return ms;
}
}
資源管理最佳實踐
- ✅ 所有
IDisposable (Pen, Brush, Font, Graphics, Bitmap, MemoryStream) 用 using 包裹
- ✅ 避免在循環中創建筆刷,提取到循環外復用
- ✅ 大圖片考慮
Bitmap(..., PixelFormat.Format32bppPArgb) 效能更好
延伸:座標系轉換輔助類
public class ChartTransform {
public RectangleF DataRect { get; set; } // 數據範圍
public RectangleF DrawRect { get; set; } // 繪圖區域 (留白邊距)
public PointF Transform(float x, float y) {
float scaleX = DrawRect.Width / DataRect.Width;
float scaleY = DrawRect.Height / DataRect.Height;
return new PointF(
DrawRect.Left + (x - DataRect.Left) * scaleX,
DrawRect.Bottom - (y - DataRect.Bottom) * scaleY // Y軸翻轉
);
}
}
- 上一篇文章: C 語言棧記憶體佈局揭秘:為什麼 k[10] 會覆蓋變數 i
- 下一篇文章: C++ 判斷整數位數:log10 數學法 vs 循環除法 vs 字串轉換
Copyright ©
程式碼之家 All Rights Reserved