利用 GDI+ (System.Drawing) 可實作豐富的圖片動畫展示效果,類似 PowerPoint 簡報切換動畫。本文提供 14 種經典動畫的完整 C# 實作代碼,所有效果均在 PictureBox 或 Panel 上繪製,可直接整合至 WinForms 專案。
private Bitmap _sourceBitmap;
private Bitmap _displayBitmap;
private void BtnLoadImage_Click(object sender, EventArgs e)
{
using (OpenFileDialog dlg = new OpenFileDialog())
{
dlg.Filter = "圖片檔|*.jpg;*.jpeg;*.gif;*.bmp;*.png;*.tif|所有檔案|*.*";
if (dlg.ShowDialog() == DialogResult.OK)
{
_sourceBitmap = new Bitmap(dlg.FileName);
_displayBitmap = new Bitmap(_sourceBitmap, pictureBox1.Width, pictureBox1.Height);
pictureBox1.Image = _displayBitmap;
}
}
}
private void AnimateFlipVertical()
{
int w = _displayBitmap.Width, h = _displayBitmap.Height;
using (Graphics g = panel1.CreateGraphics())
{
for (int i = -w/2; i <= w/2; i++)
{
g.Clear(Color.Gray);
int j = (int)(i * (float)h / w);
Rectangle dest = new Rectangle(0, h/2 - j, w, 2*j);
Rectangle src = new Rectangle(0, 0, w, h);
g.DrawImage(_displayBitmap, dest, src, GraphicsUnit.Pixel);
Thread.Sleep(10);
}
}
}
private void AnimateMeetVertical()
{
int w = _displayBitmap.Width, h = _displayBitmap.Height;
using (Graphics g = panel1.CreateGraphics())
using (Bitmap bmp = new Bitmap(w, h))
{
for (int y = 0; y <= h/2; y++)
{
for (int x = 0; x < w; x++)
{
bmp.SetPixel(x, y, _displayBitmap.GetPixel(x, y));
bmp.SetPixel(x, h - y - 1, _displayBitmap.GetPixel(x, h - y - 1));
}
g.DrawImage(bmp, 0, 0);
Thread.Sleep(10);
}
}
}
private void AnimateExpandFromCenter()
{
int w = _displayBitmap.Width, h = _displayBitmap.Height;
using (Graphics g = panel1.CreateGraphics())
{
for (int i = 0; i <= w/2; i++)
{
g.Clear(Color.Gray);
int j = (int)(i * (float)h / w);
Rectangle dest = new Rectangle(w/2 - i, h/2 - j, 2*i, 2*j);
Rectangle src = new Rectangle(0, 0, w, h);
g.DrawImage(_displayBitmap, dest, src, GraphicsUnit.Pixel);
Thread.Sleep(10);
}
}
}
private void AnimateBlockReveal()
{
int w = _displayBitmap.Width, h = _displayBitmap.Height;
using (Graphics g = panel1.CreateGraphics())
{
g.Clear(Color.White);
RectangleF[] blocks = {
new RectangleF(0, 0, w/2, h/2),
new RectangleF(w/2, 0, w/2, h/2),
new RectangleF(0, h/2, w/2, h/2),
new RectangleF(w/2, h/2, w/2, h/2)
};
Bitmap[] pieces = new Bitmap[4];
for (int i = 0; i < 4; i++)
pieces[i] = _displayBitmap.Clone(blocks[i], _displayBitmap.PixelFormat);
g.DrawImage(pieces[0], 0, 0); Thread.Sleep(1000);
g.DrawImage(pieces[1], w/2, 0); Thread.Sleep(1000);
g.DrawImage(pieces[3], w/2, h/2); Thread.Sleep(1000);
g.DrawImage(pieces[2], 0, h/2);
}
}
private void AnimateFadeIn()
{
int w = _displayBitmap.Width, h = _displayBitmap.Height;
using (Graphics g = panel1.CreateGraphics())
using (ImageAttributes attr = new ImageAttributes())
{
ColorMatrix cm = new ColorMatrix();
cm.Matrix33 = 1; cm.Matrix44 = 1; // Alpha 與 W 分量
for (float a = 0f; a <= 1f; a += 0.02f)
{
cm.Matrix00 = cm.Matrix11 = cm.Matrix22 = a;
attr.SetColorMatrix(cm);
g.DrawImage(_displayBitmap, new Rectangle(0,0,w,h), 0,0,w,h, GraphicsUnit.Pixel, attr);
Thread.Sleep(20);
}
}
}
private void AnimateFadeOut()
{
// 類似 FadeIn,但 a 從 1f 遞減至 0f
}
邏輯同上下對接/翻轉,交換 X/Y 座標計算即可。
private void AnimateStretchTopToBottom()
{
int w = _displayBitmap.Width, h = _displayBitmap.Height;
using (Graphics g = panel1.CreateGraphics())
{
for (int y = 1; y <= h; y++)
{
using (Bitmap frame = _displayBitmap.Clone(new Rectangle(0,0,w,y), _displayBitmap.PixelFormat))
{
g.DrawImage(frame, 0, 0);
Thread.Sleep(10);
}
}
}
}
private void AnimateRotate()
{
using (Graphics g = panel1.CreateGraphics())
{
for (float angle = 0; angle < 360; angle += 0.5f)
{
using (TextureBrush brush = new TextureBrush(_displayBitmap))
{
brush.RotateTransform(angle);
g.FillRectangle(brush, ClientRectangle);
Thread.Sleep(50);
}
}
}
}
private void AnimateEllipseClip()
{
using (Graphics g = panel1.CreateGraphics())
using (TextureBrush brush = new TextureBrush(_displayBitmap))
{
g.FillEllipse(brush, panel1.ClientRectangle);
}
}
private void AnimateAlphaBlend()
{
using (Graphics g = panel1.CreateGraphics())
using (TextureBrush brush = new TextureBrush(_displayBitmap))
{
g.FillRectangle(brush, panel1.ClientRectangle);
for (int a = 0; a < 255; a++)
{
using (SolidBrush mask = new SolidBrush(Color.FromArgb(a, Color.DarkSlateGray)))
{
g.FillRectangle(mask, panel1.ClientRectangle);
Thread.Sleep(10);
}
}
}
}
分別使用 Bitmap.SetResolution 與 Bitmap.RotateFlip 遍歷 RotateFlipType 列舉值。
Timer、async/await 或 BackgroundWorker 避免凍結 UI。Graphics、Bitmap 物件會產生大量 Gen 0 垃圾,建議複用物件或採用 BufferedGraphics 雙緩衝。