我之前的问题是 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/ ,但它在我的工作中效果不好,因为框架仍然不完整,而且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 :(得分: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);
答案 1 :(得分: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;
}