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

C# WinForms GIF 動畫繪製完整實戰(一):ImageAnimator 核心機制與 AnimateImage 封裝

     編輯:關於C語言

問題背景

PictureBox 效能與縮放控制不足,採用自繪 OnPaint。發現 Graphics.DrawImage 僅顯示 GIF 第一幀。解決方案:System.Drawing.ImageAnimator。

ImageAnimator 核心 API

方法/屬性用途
CanAnimate(Image)判斷圖片是否為動畫(多幀)
Animate(Image, EventHandler)開始播放,每幀觸發回呼
StopAnimate(Image, EventHandler)停止播放
Image.SelectActiveFrame(FrameDimension, index)切換當前顯示幀
Image.GetFrameCount(FrameDimension)取得總幀數

AnimateImage 完整封裝


using System;
using System.Drawing;
using System.Drawing.Imaging;

namespace GifTest {
    public class AnimateImage {
        private readonly Image _image;
        private readonly FrameDimension _dimension;
        private readonly int _frameCount;
        private int _currentFrame;
        private bool _playing;

        public event EventHandler OnFrameChanged;
        public Image Image => _image;
        public bool CanAnimate { get; }
        public int FrameCount => _frameCount;
        public int CurrentFrame => _currentFrame;
        public bool IsPlaying => _playing;

        public AnimateImage(Image img) {
            _image = img;
            lock (_image) {
                CanAnimate = ImageAnimator.CanAnimate(_image);
                if (CanAnimate) {
                    var guid = _image.FrameDimensionsList[0];
                    _dimension = new FrameDimension(guid);
                    _frameCount = _image.GetFrameCount(_dimension);
                } else {
                    _frameCount = 1;
                }
            }
        }

        public void Play() {
            if (!CanAnimate || _playing) return;
            lock (_image) {
                ImageAnimator.Animate(_image, OnFrameChangedHandler);
                _playing = true;
            }
        }

        public void Stop() {
            if (!CanAnimate || !_playing) return;
            lock (_image) {
                ImageAnimator.StopAnimate(_image, OnFrameChangedHandler);
                _playing = false;
            }
        }

        public void Reset() {
            Stop();
            lock (_image) {
                _image.SelectActiveFrame(_dimension, 0);
                _currentFrame = 0;
            }
        }

        private void OnFrameChangedHandler(object sender, EventArgs e) {
            lock (_image) {
                _currentFrame = (_currentFrame + 1) % _frameCount;
                _image.SelectActiveFrame(_dimension, _currentFrame);
            }
            OnFrameChanged?.Invoke(this, e);
        }
    }
}

關鍵實作細節

  1. 執行緒安全:所有存取 _image 的操作皆在 lock(_image) 內,ImageAnimator 回呼執行緒與 UI 執行緒並發存取
  2. 幀索引環狀:(current + 1) % count 實現循環播放
  3. 事件模式:OnFrameChanged 通知 UI Invalidate() 觸發重繪
  4. 資源管理:外部負責 Image 生命週期,AnimateImage 不擁有

為什麼不直接用 PictureBox?

  • PictureBox 內部使用 ImageAnimator 但不暴露控制介面
  • 縮放模式有限(Normal/Stretch/Zoom/Center),無法自訂插值演算法
  • 效能較差:每次重繪完整複製像素,無雙緩衝優化
  • 無法在自繪場景(遊戲迴圈、圖表、複合圖層)中整合

下一步:整合至 Form 實現播放控制

請參考「C# WinForms GIF 動畫繪製完整實戰(二)」:雙緩衝設定、OnPaint 鎖定繪製、播放/停止/重置按鈕綁定。

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