Wpf 如何将两个位图帧合并为一个?
我先前的问题是 ,现在我想在使用它之前完成gif帧,如下所示:Wpf 如何将两个位图帧合并为一个?,wpf,gif,Wpf,Gif,我先前的问题是 ,现在我想在使用它之前完成gif帧,如下所示: GifBitmapDecoder _gifDecoder = new GifBitmapDecoder( new Uri("pack://application:,,,/Expression/f006.gif"), BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default); BitmapFrame preBF = nul
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);
也许能帮你找到正确的方向。它确实有效!但是缺少了源的透明度…如何处理?你的意思是在另一个位图上复制具有透明背景的位图,而另一个位图也具有透明背景?