WPF 中Image切换ImageSource做动画
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WPF 中Image切换ImageSource做动画相关的知识,希望对你有一定的参考价值。
在WPF中,我想通过连续改变Image的值来做动画效果,可是当实现后发现CPU占用出去的高,经测试发是imgsourceconverter的问题。所以
请问各位人兄,是否有提高性能的方法,或者其它用C#实现高效动画播放的方法。数据源是一堆连续的图片。
感谢兄弟的回答,不过我这儿的情况可能说得不是很清楚。我下面再说说
我这儿有一堆连续的图片从网络上发过来,我每接受一张就显示,因为图片是连续的,所以会产生动画视频效果。
这个是确的。现在的问题是,我采用改变Image的属性ImageSource的方法来加载图片,CPU性能会很底。除此之外,我想用C#在WPF上直接绘图(不知道WPF里可以不)或许是一种方法,但是我不知道该怎么做,网上也没有找到适合的资料。烦请有这方面经验的朋友些能提供一些实质性的解决方案。代码或者可以实现的思路。
把一张张连续的显示在WPF用户界面上以便形成动画效果。
这就等于在一帧一帧放视频啊 性能肯定高不到哪里去的
最好是应该用矢量path来animation啊,这才是WPF原生支持的动画效果
不过考虑到你手上已经是一堆连续图片了,如果一定要一张一张播放的话,那可能就需要注意加载图片的大小和时机了。
如果所需要的大小没有那么大,就不要把原本很大的图都加载了,加载一个小的copy,还有就是事先把要用的图都加载好,不要到要播放的时候再在XAML改变Image的Source属性
XAML里Source属性是用string的,当然要用converter转换再加载对应的图片。提前加载好,后台代码直接更改Source属性…… 参考技术A 在播放动画前用一个泛型的集合先把所以图片都储存起来,这样就不用转换了
public class myImage
public ImageSource AnimationImage get; private set;
public myImage(ImageSource image)
AnimationImage = image;
public class myImageCollection : List<myImage>
public void addImage(ImageSource image)
Add(new myImage(image));
在一个循环语句里每隔一个间隔就读集合,设置前台的ImageSource就可以播动画了
WPF - 将位图转换为 ImageSource
【中文标题】WPF - 将位图转换为 ImageSource【英文标题】:WPF - converting Bitmap to ImageSource 【发布时间】:2014-12-03 08:02:23 【问题描述】:我需要将 System.Drawing.Bitmap
转换为 System.Windows.Media.ImageSource
类,以便将其绑定到 WizardPage(扩展 WPF 工具包)的 HeaderImage 控件中。
位图被设置为我编写的程序集的资源。
它被这样引用:
public Bitmap GetBitmap
get
Bitmap bitmap = new Bitmap(Resources.my_banner);
return bitmap;
public ImageSource HeaderBitmap
get
ImageSourceConverter c = new ImageSourceConverter();
return (ImageSource)c.ConvertFrom(GetBitmap);
转换器是我here找到的。我在
得到一个 NullReferenceExceptionreturn (ImageSource) c.ConvertFrom(Resources.my_banner);
如何初始化 ImageSource 以避免此异常?还是有其他方法? 之后我想使用它:
<xctk:WizardPage x:Name="StartPage" Height="500" Width="700"
HeaderImage="Binding HeaderBitmap"
Enter="StartPage_OnEnter"
提前感谢您的任何回答。
【问题讨论】:
见这里:What is a NullReferenceException and how do I fix it? 【参考方案1】:void Draw()
System.Drawing.Bitmap bmp = new Bitmap();
...
Image img = new Image();
img.Source = BitmapToImageSource(bmp)
private BitmapImage BitmapToImageSource(System.Drawing.Bitmap bitmap)
using (MemoryStream memory = new MemoryStream())
bitmap.Save(memory, System.Drawing.Imaging.ImageFormat.Bmp);
memory.Position = 0;
BitmapImage bitmapimage = new BitmapImage();
bitmapimage.BeginInit();
bitmapimage.StreamSource = memory;
bitmapimage.CacheOption = BitmapCacheOption.OnLoad;
bitmapimage.EndInit();
return bitmapimage;
【讨论】:
【参考方案2】:对其他人来说,这是可行的:
//If you get 'dllimport unknown'-, then add 'using System.Runtime.InteropServices;'
[DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DeleteObject([In] IntPtr hObject);
public ImageSource ImageSourceFromBitmap(Bitmap bmp)
var handle = bmp.GetHbitmap();
try
return Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
finally DeleteObject(handle);
【讨论】:
你是我的英雄。用它来为 Bitmap 类做一个扩展,效果很好。干得好。 @ARidder101 我确定我是从其他人那里得到的。 这种方法提供了非常低质量的透明度。 Mike Strobel 下面的回答 (***.com/a/26261562/418362) 要好得多,不需要任何互操作。 让我知道当我没有调用 DeleteObject(handle) 时会发生什么。我有一个问题。谢谢。 早在 .NET 2.0 天的 Windows XP 上,可以同时打开 10.000 个句柄的限制。当达到该限制时,机器冻结了。 - 所以不调用删除,意味着你会泄漏一个句柄。 .NET 可以在某处适当地清理它,但您很可能会受到性能影响。'【参考方案3】:dethSwatch - 感谢您在上面的回答!它帮助很大!在实现它之后,我得到了想要的行为,但我发现我在程序的另一部分遇到了内存/句柄问题。我将代码更改如下,使其更加冗长,问题就消失了。再次感谢!
[DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DeleteObject([In] IntPtr hObject);
public ImageSource ImageSourceForBitmap(Bitmap bmp)
var handle = bmp.GetHbitmap();
try
ImageSource newSource = Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
DeleteObject(handle);
return newSource;
catch (Exception ex)
DeleteObject(handle);
return null;
【讨论】:
你的一个更漂亮的变体:) ``` var handle = bmp.GetHbitmap();尝试 返回 Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); 捕捉 返回空值; 最后 Win32.DeleteObject(handle); ```【参考方案4】:对我来说最简单的解决方案:
ImageBrush myBrush = new ImageBrush();
var bitmap = System.Drawing.Image.FromFile("pic1.bmp");
Bitmap bitmap = new System.Drawing.Bitmap(image);//it is in the memory now
var bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(),IntPtr.Zero,Int32Rect.Empty,BitmapSizeOptions.FromEmptyOptions());
myBrush.ImageSource = bitmapSource;
cover.MainGrid.Background = myBrush;
cover.Show();
bitmap.Dispose();
【讨论】:
我认为GetHbitmap的hande应该被释放。【参考方案5】:为了搜索者的利益,我基于detailed solution 创建了一个快速转换器。
目前没有问题。
using System;
using System.Drawing;
using System.IO;
using System.Windows.Media.Imaging;
namespace XYZ.Helpers
public class ConvertBitmapToBitmapImage
/// <summary>
/// Takes a bitmap and converts it to an image that can be handled by WPF ImageBrush
/// </summary>
/// <param name="src">A bitmap image</param>
/// <returns>The image as a BitmapImage for WPF</returns>
public BitmapImage Convert(Bitmap src)
MemoryStream ms = new MemoryStream();
((System.Drawing.Bitmap)src).Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
BitmapImage image = new BitmapImage();
image.BeginInit();
ms.Seek(0, SeekOrigin.Begin);
image.StreamSource = ms;
image.EndInit();
return image;
【讨论】:
今天你是我的神 我喜欢这个。我喜欢这个。【参考方案6】:我不相信ImageSourceConverter
会从System.Drawing.Bitmap
转换。但是,您可以使用以下内容:
public static BitmapSource CreateBitmapSourceFromGdiBitmap(Bitmap bitmap)
if (bitmap == null)
throw new ArgumentNullException("bitmap");
var rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
var bitmapData = bitmap.LockBits(
rect,
ImageLockMode.ReadWrite,
PixelFormat.Format32bppArgb);
try
var size = (rect.Width * rect.Height) * 4;
return BitmapSource.Create(
bitmap.Width,
bitmap.Height,
bitmap.HorizontalResolution,
bitmap.VerticalResolution,
PixelFormats.Bgra32,
null,
bitmapData.Scan0,
size,
bitmapData.Stride);
finally
bitmap.UnlockBits(bitmapData);
此方案要求源图片为 Bgra32 格式;如果您正在处理其他格式,则可能需要添加转换。
【讨论】:
以上是关于WPF 中Image切换ImageSource做动画的主要内容,如果未能解决你的问题,请参考以下文章