2013-11-19 4 views
0

Мой предыдущий вопрос является Why GifBitmapDecoder play incomplete gif , и теперь я хочу, чтобы завершить GIF кадры, прежде чем использовать его, как это:Как объединить два растровых кадра в один?

GifBitmapDecoder _gifDecoder = new GifBitmapDecoder(
     new Uri("pack://application:,,,/Expression/f006.gif"), 
     BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default); 

BitmapFrame preBF = null; 
FrameInfo preFI = null; 
foreach (BitmapFrame bf in gifDecoder.Frames) 
{ 
    FrameInfo fi = GetFrameInfo(bf); 

    if (fi.DisposalMethod == FrameDisposalMethod.Combine && preBF != null) 
    { 
     // TODO Find a way to combine bf and preBF to makeup a complete gif frame 
    } 

    preBF = bf; 
    preFI = fi; 

}

А класс FrameInfo и метод GetFrameInfo являются следующие (спасибо к http://www.thomaslevesque.com/tag/gif/ , но он не работает хорошо в моей работе, так как кадр еще imcomplete и WpfAnimatedGif.dll слишком много памяти):

#region Get the frame information 
private class FrameInfo 
{ 
    public TimeSpan Delay { get; set; } 
    public FrameDisposalMethod DisposalMethod { get; set; } 
    public double Width { get; set; } 
    public double Height { get; set; } 
    public double Left { get; set; } 
    public double Top { get; set; } 

    public Rect Rect 
    { 
    get { return new Rect(Left, Top, Width, Height); } 
    } 
} 

private enum FrameDisposalMethod 
{ 
    Replace = 0, 
    Combine = 1, 
    RestoreBackground = 2, 
    RestorePrevious = 3 
} 

private static FrameInfo GetFrameInfo(BitmapFrame frame) 
{ 
    var frameInfo = new FrameInfo 
    { 
    Delay = TimeSpan.FromMilliseconds(100), 
    DisposalMethod = FrameDisposalMethod.Replace, 
    Width = frame.PixelWidth, 
    Height = frame.PixelHeight, 
    Left = 0, 
    Top = 0 
    }; 

    BitmapMetadata metadata; 
    try 
    { 
    metadata = frame.Metadata as BitmapMetadata; 
    if (metadata != null) 
    { 
     const string delayQuery = "/grctlext/Delay"; 
     const string disposalQuery = "/grctlext/Disposal"; 
     const string widthQuery = "/imgdesc/Width"; 
     const string heightQuery = "/imgdesc/Height"; 
     const string leftQuery = "/imgdesc/Left"; 
     const string topQuery = "/imgdesc/Top"; 

     var delay = GetQueryOrNull<ushort>(metadata, delayQuery); 
     if (delay.HasValue) 
     frameInfo.Delay = TimeSpan.FromMilliseconds(10 * delay.Value); 

     var disposal = GetQueryOrNull<byte>(metadata, disposalQuery); 
     if (disposal.HasValue) 
     frameInfo.DisposalMethod = (FrameDisposalMethod)disposal.Value; 

     var width = GetQueryOrNull<ushort>(metadata, widthQuery); 
     if (width.HasValue) 
     frameInfo.Width = width.Value; 

     var height = GetQueryOrNull<ushort>(metadata, heightQuery); 
     if (height.HasValue) 
     frameInfo.Height = height.Value; 

     var left = GetQueryOrNull<ushort>(metadata, leftQuery); 
     if (left.HasValue) 
     frameInfo.Left = left.Value; 

     var top = GetQueryOrNull<ushort>(metadata, topQuery); 
     if (top.HasValue) 
     frameInfo.Top = top.Value; 
    } 
    } 
    catch (NotSupportedException) 
    { 
    } 

    return frameInfo; 
} 

private static T? GetQueryOrNull<T>(BitmapMetadata metadata, string query) 
    where T : struct 
{ 
    if (metadata.ContainsQuery(query)) 
    { 
    object value = metadata.GetQuery(query); 
    if (value != null) 
     return (T)value; 
    } 
    return null; 
} 
#endregion 

Итак, есть ли способ реализовать TODO?

+0

Возможно, [это] (http://stackoverflow.com/a/20024774/1136211) доставит вас в правильном направлении. – Clemens

+0

Это действительно работает! Но прозрачность источника пропущена ... Как с этим бороться? – Chobits

+0

Вы имеете в виду, что вы копируете растровое изображение с прозрачным фоном поверх другого, которое также имеет прозрачный фон? – Clemens

ответ

0

меня реализовать, но таким образом причина слишком много памяти:

private GifBitmapEncoder MakeupFrames(GifBitmapDecoder gifDecoder) 
{ 
    BitmapFrame preBF = null; 
    FrameInfo preFI = null; 

    GifBitmapEncoder encoder = new GifBitmapEncoder(); 
    for (int i = 0; i < gifDecoder.Frames.Count; i++) 
    { 
    FrameInfo fi = GetFrameInfo(gifDecoder.Frames[i]); 

    if (preBF == null) 
     encoder.Frames.Add(gifDecoder.Frames[i]); 

    else 
    { 
     DrawingVisual visual = new DrawingVisual(); 
     using (var context = visual.RenderOpen()) 
     { 
     if (preBF != null && gifDecoder.Frames[i] != null && 
      fi.DisposalMethod != FrameDisposalMethod.Replace) 
     { 
      var fullRect = new Rect(0, 0, preBF.PixelWidth, preBF.PixelHeight); 
      context.DrawImage(preBF, fullRect); 
     } 

     context.DrawImage(gifDecoder.Frames[i], 
      new Rect(fi.Left, fi.Top, fi.Width, fi.Height)); 
     } 
     var bitmap = new RenderTargetBitmap(
     preBF.PixelWidth, preBF.PixelHeight, 
     preBF.DpiX, preBF.DpiY, 
     PixelFormats.Pbgra32); 
     bitmap.Render(visual); 
     encoder.Frames.Add(BitmapFrame.Create(bitmap)); 
     bitmap = null; 
    } 

    preBF = encoder.Frames[i]; 
    preFI = fi; 
    } 
    return encoder; 
} 
1

Я не уверен, если я вас понял, попробуйте рисует изображения в компонент DrawingVisual и преобразовать его в BitmapSource. затем создайте кодер PngBitmapEncoder, добавьте BitmapSource в кодер. при создании Rect и RenderTargetBitmap задают высоту и ширину изображения. В конце сохранить результат в файл.

int imageWidth = bf.PixelWidth; 
int imageHeight = bf.PixelHeight; 

DrawingVisual drawingVisual = new DrawingVisual(); 
using (DrawingContext drawingContext = drawingVisual.RenderOpen()) 
{ 
    drawingContext.DrawImage(bf, new Rect(...)); 
    drawingContext.DrawImage(preBF , new Rect(...)); 
} 

RenderTargetBitmap bmp = new RenderTargetBitmap(yourSize, yourSize, yourSize, yourSize, PixelFormats.Pbgra32); 
bmp.Render(drawingVisual); 

PngBitmapEncoder encoder = new PngBitmapEncoder(); 
encoder.Frames.Add(BitmapFrame.Create(bmp)); 

using (Stream stream = File.Create(pathTileImage)) 
    encoder.Save(stream); 
Смежные вопросы