zoukankan      html  css  js  c++  java
  • 从文件中加载图片,不占用文件句柄,不缓存图像,一次性使用,方便回收内存方法

    一般人将文件转图片使用以下方式:

    /// <summary>
    /// 文件转图片(不占用文件句柄)
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <param name="toWidth">生成图像宽度</param>
    /// <param name="toHeight">生成图像高度</param>
    /// <returns></returns>
    public static BitmapImage ToBitmapImage(String filePath, Int32? toWidth = null, Int32? toHeight = null)
    {
        if (!File.Exists(filePath))
            return null
        var bmp = new BitmapImage()
        bmp.BeginInit();
        bmp.CacheOption = BitmapCacheOption.OnLoad;
        bmp.CreateOptions = BitmapCreateOptions.PreservePixelFormat
        if (toWidth.HasValue)
            bmp.DecodePixelWidth = toWidth.Value;
        if (toHeight.HasValue)
            bmp.DecodePixelHeight = toHeight.Value
        using (var ms = new MemoryStream(File.ReadAllBytes(filePath)))
        {
            bmp.StreamSource = ms;
            bmp.EndInit();
            bmp.Freeze();
        
        return bmp;
    }

    这里使用了OnLoad图像缓存方式,如果要使用None,那就不能释放MemoryStream,否则图像无法显示;这个缓存也不知道存到什么时候,为了能及时释放内存,就不能使用缓存,MemoryStream对象先作为变量存起来,等到Image.Unloaded触发时再销毁,代码如下:

    public sealed class FileImageBehavior : Behavior<Image> {
        #region 依赖属性
    
        public static readonly DependencyProperty FilePathProperty = DependencyProperty.Register ("FilePath", typeof (String), typeof (FileImageBehavior), new PropertyMetadata (OnFilePathPropertyChanged));
    
        private static void OnFilePathPropertyChanged (DependencyObject d, DependencyPropertyChangedEventArgs e) {
            var obj = (FileImageBehavior) d;
    
            if (obj.AssociatedObject != null && obj.AssociatedObject.IsLoaded)
                obj.OnFilePathChanged ((String) e.NewValue);
        }
    
        /// <summary>
        /// 文件路径
        /// </summary>
        public String FilePath { get => (String) this.GetValue (FilePathProperty); set => this.SetValue (FilePathProperty, value); }
    
        #endregion
    
        #region 私有方法
    
        protected override void OnAttached () {
            base.OnAttached ();
    
            this.AssociatedObject.Loaded += OnLoaded;
            this.AssociatedObject.Unloaded += OnUnloaded;
        }
    
        protected override void OnDetaching () {
            base.OnDetaching ();
    
            this.AssociatedObject.Loaded -= OnLoaded;
            this.AssociatedObject.Unloaded -= OnUnloaded;
        }
    
        private void OnLoaded (Object sender, RoutedEventArgs e) {
            OnFilePathChanged (FilePath);
        }
    
        private void OnUnloaded (Object sender, RoutedEventArgs e) {
    
            this.Release ();
        }
    
        private void OnFilePathChanged (String file) {
            this.Release ();
    
            if (String.IsNullOrEmpty (file) || !File.Exists (file))
                return;
    
            ms = new MemoryStream (File.ReadAllBytes (file));
    
            var bmp = new BitmapImage ();
    
            bmp.BeginInit ();
            bmp.CacheOption = BitmapCacheOption.None;
            bmp.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
    
            if (RenderWidth.HasValue)
                bmp.DecodePixelWidth = RenderWidth.Value; // 设置图像解码后的宽度
            if (RenderHeight.HasValue)
                bmp.DecodePixelHeight = RenderHeight.Value; // 设置图像解码后的高度
    
            bmp.StreamSource = ms;
            bmp.EndInit ();
            bmp.Freeze ();
    
            this.AssociatedObject.Source = bmp;
        }
    
        private void Release () {
            this.AssociatedObject.Source = null;
    
            if (ms != null) {
                ms.Close ();
                ms.Dispose ();
                ms = null;
            }
        }
    
        #endregion
    
        #region 属性
    
        /// <summary>
        /// 显示宽度
        /// </summary>
        public Int32? RenderWidth { get; set; }
        /// <summary>
        /// 显示高度
        /// </summary>
        public Int32? RenderHeight { get; set; }
    
        #endregion
    
        #region 字段
    
        private MemoryStream ms;
    
        #endregion
    }

    使用方式:

    <Image Stretch="Uniform">
        <i:Interaction.Behaviors>
            <wl:FileImageBehavior FilePath="{Binding FilePath}" RenderWidth="180" />
        </i:Interaction.Behaviors>
    </Image>

    下面是更新,上面的使用方式过于复杂了,我发现MemoryStrean即使不手动Dispose也能释放,不会造成内存泄漏,所以从文件加载图片,使用下面的方法就可以:

    /// <summary>
    /// 文件转图片(不占用文件句柄)
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <returns></returns>
    public static BitmapFrame ToBitmapFrame (String filePath) {
        if (!File.Exists (filePath))
            return null;
    
        var ms = new MemoryStream (File.ReadAllBytes (filePath));
    
        var bmp = BitmapFrame.Create (ms, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None);
        bmp.Freeze ();
        return bmp;
    }
    
    /// <summary>
    /// 文件转图片(不占用文件句柄)
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <param name="toWidth">生成图像宽度</param>
    /// <param name="toHeight">生成图像高度</param>
    /// <returns></returns>
    public static BitmapImage ToBitmapImage (String filePath, Int32? toWidth = null, Int32? toHeight = null) {
        if (!File.Exists (filePath))
            return null;
    
        var bmp = new BitmapImage ();
    
        bmp.BeginInit ();
        bmp.CacheOption = BitmapCacheOption.None;
        bmp.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
    
        if (toWidth.HasValue)
            bmp.DecodePixelWidth = toWidth.Value;
        if (toHeight.HasValue)
            bmp.DecodePixelHeight = toHeight.Value;
    
        var ms = new MemoryStream (File.ReadAllBytes (filePath));
    
        bmp.StreamSource = ms;
        bmp.EndInit ();
        bmp.Freeze ();
    
        return bmp;
    }

    用转换器封装就是:

    public sealed class FilePathToBitmapFrameConverter : IValueConverter {
        public Object Convert (Object value, Type targetType, Object parameter, CultureInfo culture) {
            return ImageHelper.ToBitmapFrame ((String) value);
        }
    
        public Object ConvertBack (Object value, Type targetType, Object parameter, CultureInfo culture) {
            return Binding.DoNothing;
        }
    
        private static Lazy<FilePathToBitmapFrameConverter> lazy = new Lazy<FilePathToBitmapFrameConverter> ();
        public static FilePathToBitmapFrameConverter Instance => lazy.Value;
    }
    
    public sealed class FilePathToBitmapImageConverter : IValueConverter {
        public Object Convert (Object value, Type targetType, Object parameter, CultureInfo culture) {
            Int32? width = null, height = null;
    
            if (parameter is String args) {
                var maps = args.Split ('|');
    
                foreach (var map in maps) {
                    var kv = map.Split (':');
    
                    if (kv.Length != 2)
                        continue;
    
                    if ("w".Equals (kv[0], StringComparison.OrdinalIgnoreCase))
                        width = Int32.Parse (kv[1]);
                    else if ("h".Equals (kv[0], StringComparison.OrdinalIgnoreCase))
                        height = Int32.Parse (kv[1]);
                }
            }
    
            return ImageHelper.ToBitmapImage ((String) value, width, height);
        }
    
        public Object ConvertBack (Object value, Type targetType, Object parameter, CultureInfo culture) {
            return Binding.DoNothing;
        }
    
        private static Lazy<FilePathToBitmapImageConverter> lazy = new Lazy<FilePathToBitmapImageConverter> ();
        public static FilePathToBitmapImageConverter Instance => lazy.Value;
    }

    使用起来就是:

    <Image Source="{Binding FilePath,Converter={x:Static wl:FilePathToBitmapImageConverter.Instance},ConverterParameter='w:200'}" />
    <Image Source="{Binding FilePath,Converter={x:Static wl:FilePathToBitmapFrameConverter.Instance}}" />
  • 相关阅读:
    网络安全分析
    java实现 洛谷 P1464 Function
    java实现 洛谷 P1464 Function
    java实现 洛谷 P1014 Cantor表
    java实现 洛谷 P1014 Cantor表
    java实现 洛谷 P1014 Cantor表
    java实现 洛谷 P1014 Cantor表
    java实现 洛谷 P1014 Cantor表
    java实现 洛谷 P1540 机器
    java实现 洛谷 P1540 机器
  • 原文地址:https://www.cnblogs.com/pumbaa/p/13588305.html
Copyright © 2011-2022 走看看