WPF 強大的 Image 控制項僅能顯示 GIF 第一幀。雖可用 WebBrowser 或 Frame 載入,但過於笨重且難以抑制右鍵選單。MediaElement 亦不支援 GIF 動畫。
var decoder = new GifBitmapDecoder(
new Uri("OH.gif", UriKind.Relative),
BitmapCreateOptions.PreservePixelFormat,
BitmapCacheOption.Default);
foreach (BitmapFrame frame in decoder.Frames)
{
var img = new Image { Source = frame };
panel.Children.Add(img); // 僅靜態顯示所有幀
}
GIF 格式規範參考:動態 GIF 檔案儲存結構
private int ParseGraphicControlExtension(byte[] gifData, int offset)
{
int length = gifData[offset + 2];
int returnOffset = offset + length + 3;
byte packedField = gifData[offset + 3];
int disposalMethod = (packedField & 0x1C) >> 2;
int delay = BitConverter.ToUInt16(gifData, offset + 4); // 單位:10ms
// 略過應用程式擴展區塊...
return returnOffset;
}
支援多種來源:本地相對/絕對路徑、HTTP/FTP、Pack URI、內嵌資源
if (source.EndsWith(".GIF", StringComparison.OrdinalIgnoreCase) || ForceGifAnim)
{
if (!uri.IsAbsoluteUri) GetGifStreamFromPack(uri);
else if (uri.Scheme == "http" || uri.Scheme == "https") GetGifStreamFromHttp(uri);
else if (uri.Scheme == "file") GetGifStreamFromFile(uri);
else CreateNonGifAnimationImage();
}
else CreateNonGifAnimationImage();
public void CreateGifAnimation(MemoryStream memoryStream)
{
Reset();
byte[] gifData = memoryStream.GetBuffer();
var decoder = new GifBitmapDecoder(memoryStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
numberOfFrames = decoder.Frames.Count;
ParseGif(gifData); // 解析延遲、處置方式
for (int i = 0; i < decoder.Frames.Count; i++)
{
frameList[i].Source = decoder.Frames[i];
frameList[i].Visibility = Visibility.Hidden;
canvas.Children.Add(frameList[i]);
// 設定位置、ZIndex...
}
frameList[0].Visibility = Visibility.Visible;
frameTimer = new DispatcherTimer();
frameTimer.Tick += NextFrame;
frameTimer.Interval = TimeSpan.FromMilliseconds(frameList[0].delayTime * 10);
frameTimer.Start();
}
<local:GifImage Source="pack://application:,,,/Images/loading.gif" />
BitmapCacheOption.OnLoad 釋放檔案鎖定disposalMethod 決定幀切換時是否還原背景或保留前一幀Image 元素,切換 Visibility 而非重建