Wpf 如何将两个位图帧合并为一个?

Wpf 如何将两个位图帧合并为一个?,wpf,gif,Wpf,Gif,我先前的问题是 ,现在我想在使用它之前完成gif帧,如下所示: GifBitmapDecoder _gifDecoder = new GifBitmapDecoder( new Uri("pack://application:,,,/Expression/f006.gif"), BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default); BitmapFrame preBF = nul

我先前的问题是 ,现在我想在使用它之前完成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如下(感谢 ,但在我的工作中效果不佳,因为帧仍然不完整,而且WpfAnimatedGif.dll占用了太多内存):

#区域获取帧信息
私有类框架信息
{
公共时间跨度延迟{get;set;}
public FrameDisposalMethod DisposalMethod{get;set;}
公共双宽度{get;set;}
公共双倍高度{get;set;}
公共双左{get;set;}
公共双顶部{get;set;}
公共矩形
{
获取{返回新矩形(左、上、宽、高);}
}
}
私有枚举FrameDisposalMethod
{
替换=0,
联合=1,
恢复背景=2,
恢复性先前=3
}
私有静态FrameInfo GetFrameInfo(位图帧帧)
{
var frameInfo=新的frameInfo
{
延迟=时间跨度从毫秒(100),
DisposalMethod=FrameDisposalMethod.Replace,
宽度=帧。像素宽度,
高度=帧。像素高度,
左=0,
Top=0
};
位图元数据;
尝试
{
metadata=帧。元数据作为位图元数据;
if(元数据!=null)
{
常量字符串delayQuery=“/grctlext/Delay”;
常量字符串disposalQuery=“/grctlext/Disposal”;
常量字符串宽度查询=“/imgdesc/Width”;
常量字符串heightQuery=“/imgdesc/Height”;
常量字符串leftQuery=“/imgdesc/Left”;
常量字符串topQuery=“/imgdesc/Top”;
var delay=GetQueryOrNull(元数据,delayQuery);
if(delay.HasValue)
frameInfo.Delay=TimeSpan.From毫秒(10*Delay.Value);
var disposition=GetQueryOrNull(元数据,disposalQuery);
if(disposal.HasValue)
frameInfo.DisposalMethod=(FrameDisposalMethod)Disposition.Value;
var width=getQueryNull(元数据,widthQuery);
if(宽度.HasValue)
frameInfo.Width=Width.Value;
var height=GetQueryOrNull(元数据,heightQuery);
if(高度.HasValue)
frameInfo.Height=Height.Value;
var left=GetQueryOrNull(元数据,leftQuery);
if(左.HasValue)
frameInfo.Left=Left.Value;
var top=GetQueryOrNull(元数据,topQuery);
if(top.HasValue)
frameInfo.Top=Top.Value;
}
}
捕获(不支持异常)
{
}
返回frameInfo;
}
私有静态T?GetQueryOrNull(位图元数据、字符串查询)
其中T:struct
{
if(metadata.ContainsQuery(查询))
{
对象值=metadata.GetQuery(查询);
if(值!=null)
返回(T)值;
}
返回null;
}
#端区

那么,有没有实现TODO的方法呢?

我已经实现了,但是这种方法会导致内存过多:

#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
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;
}
专用GifBitmapEncoder生成帧(GifBitmapDecoder gifDecoder)
{
BitmapFrame preBF=null;
FrameInfo preFI=null;
GifBitmapEncoder编码器=新的GifBitmapEncoder();
对于(int i=0;i
我不确定是否理解您的意思,请尝试将图像绘制到DrawingVisual组件中,然后 将其转换为位图源。然后创建编码器PngBitmapEncoder, 将位图源添加到编码器。 创建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);

也许能帮你找到正确的方向。它确实有效!但是缺少了源的透明度…如何处理?你的意思是在另一个位图上复制具有透明背景的位图,而另一个位图也具有透明背景?