wpf 可缩放,可显示远程图片的Image

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了wpf 可缩放,可显示远程图片的Image相关的知识,希望对你有一定的参考价值。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Cache;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;


namespace Controls
{
    [TemplatePart(Name = PART_Image, Type = typeof(Image))]
    public class ScalableImage : UserControl
    {
        #region Fields
        private const string PART_Image = "PART_Image";

        #endregion
        private ScaleTransform _scaleTransform;
        private TranslateTransform _translateTransform;
        private TransformGroup _transfromGroup;
        private Image _image;

        Point _start;
        Point _origin;
        /// <summary>
        /// 父容器
        /// </summary>
        private IInputElement _parentElement;

        static ScalableImage()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ScalableImage),
                new FrameworkPropertyMetadata(typeof(ScalableImage)));

        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            _image = GetTemplateChild(PART_Image) as Image;
            _image.RenderTransform = _transfromGroup;
        }

        public ScalableImage()
        {
            Init();
        }

        private void Init()
        {
            _transfromGroup = new TransformGroup();
            _scaleTransform = new ScaleTransform();
            _translateTransform = new TranslateTransform();
            _transfromGroup.Children.Add(_scaleTransform);
            _transfromGroup.Children.Add(_translateTransform);

        }

        protected override void OnRender(DrawingContext dc)
        {
            base.OnRender(dc);
            _parentElement = _image.Parent as IInputElement;
        }

        public string ImageUrl
        {
            get { return (string)GetValue(ImageUrlProperty); }
            set { SetValue(ImageUrlProperty, value); }
        }

        /// <summary>
        /// 图片数据源
        /// </summary>
        public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(ImageSource), typeof(ScalableImage), new PropertyMetadata(null, SourceChangedCallback));
        /// <summary>
        /// 图片数据源
        /// </summary>
        public ImageSource Source
        {
            get
            {
                return (ImageSource)GetValue(SourceProperty);
            }
            set
            {
                SetValue(SourceProperty, value);
            }
        }

        /// <summary>
        /// 是否加载中
        /// </summary>
        public static readonly DependencyProperty IsLoadingProperty = DependencyProperty.Register("IsLoading", typeof(bool), typeof(ScalableImage), new PropertyMetadata(false));
        /// <summary>
        /// 是否加载中
        /// </summary>
        public bool IsLoading
        {
            get
            {
                return (bool)GetValue(IsLoadingProperty);
            }
            set
            {
                SetValue(IsLoadingProperty, value);
            }
        }


        private static void SourceChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ScalableImage dimg = sender as ScalableImage;
            dimg._image.Source = (ImageSource)e.NewValue;
        }

        public BitmapCreateOptions CreateOptions
        {
            get { return ((BitmapCreateOptions)(base.GetValue(CreateOptionsProperty))); }
            set { base.SetValue(CreateOptionsProperty, value); }
        }

        private static async void ImageUrlPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            var url = e.NewValue as string;

            if (string.IsNullOrEmpty(url))
                return;

            var cachedImage = (ScalableImage)obj;
            var bitmapImage = new BitmapImage();

            switch (FileCache.AppCacheMode)
            {
                case FileCache.CacheMode.WinINet:
                    bitmapImage.BeginInit();
                    bitmapImage.CreateOptions = cachedImage.CreateOptions;
                    bitmapImage.UriSource = new Uri(url);
                    bitmapImage.UriCachePolicy = new RequestCachePolicy(RequestCacheLevel.Default);
                    bitmapImage.EndInit();
                    cachedImage.Source = bitmapImage;
                    break;

                case FileCache.CacheMode.Dedicated:
                    try
                    {
                        FileCache.DownloadStateChangedAction = (downloadState) =>
                        {
                            switch (downloadState)
                            {
                                case DownloadState.Process:
                                    cachedImage.IsLoading = true;
                                    break;
                                case DownloadState.Failed:
                                    cachedImage.IsLoading = false;
                                    break;
                                case DownloadState.Success:
                                    cachedImage.IsLoading = false;
                                    break;
                            }
                        };
                        var memoryStream = await FileCache.HitAsync(url);
                        if (memoryStream == null)
                            return;

                        bitmapImage.BeginInit();
                        bitmapImage.CreateOptions = cachedImage.CreateOptions;
                        bitmapImage.StreamSource = memoryStream;
                        bitmapImage.EndInit();
                        cachedImage.Source = bitmapImage;

                    }
                    catch (Exception ex)
                    {
                        
                    }
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        public static readonly DependencyProperty ImageUrlProperty = DependencyProperty.Register("ImageUrl",
            typeof(string), typeof(ScalableImage), new PropertyMetadata("", ImageUrlPropertyChanged));

        public static readonly DependencyProperty CreateOptionsProperty = DependencyProperty.Register("CreateOptions",
            typeof(BitmapCreateOptions), typeof(ScalableImage));

        /// <summary>
        /// 是否可以缩放
        /// </summary>
        public static readonly DependencyProperty CanScaleProperty = DependencyProperty.Register("CanScale",
            typeof(bool), typeof(ScalableImage), new PropertyMetadata(false));
        /// <summary>
        /// 是否可以缩放
        /// </summary>
        public bool CanScale
        {
            get { return (bool)GetValue(CanScaleProperty); }
            set
            {
                SetValue(CanScaleProperty, value);
            }
        }
        /// <summary>
        /// 是否可以缩小
        /// </summary>
        public static readonly DependencyProperty CanScaleSmallerProperty = DependencyProperty.Register("CanScaleSmaller",
            typeof(bool), typeof(ScalableImage), new PropertyMetadata(false));
        /// <summary>
        /// 是否可以缩小
        /// </summary>
        public bool CanScaleSmaller
        {
            get { return (bool)GetValue(CanScaleSmallerProperty); }
            set
            {
                SetValue(CanScaleSmallerProperty, value);
            }
        }

        protected override void OnMouseDown(MouseButtonEventArgs e)
        {


            _start = e.GetPosition(_parentElement);
            _origin = new Point(_translateTransform.X, _translateTransform.Y);
            this.CaptureMouse();
        }

        protected override void OnMouseLeave(MouseEventArgs e)
        {
            ReleaseMouseCapture();
        }

        protected override void OnMouseUp(MouseButtonEventArgs e)
        {
            ReleaseMouseCapture();
        }

        protected override void OnMouseWheel(MouseWheelEventArgs e)
        {
            if (!CanScale) return;

            var point = e.GetPosition(_parentElement); // 实际点击的点  
            var actualPoint = _transfromGroup.Inverse.Transform(point); // 想要缩放的点  

            double zoom = e.Delta > 0 ? .2 : -.2;
            var scaleValue = _scaleTransform.ScaleX + zoom;
            // 是否可以缩到比默认大小还要小
            if (!CanScaleSmaller)
            {
                if (scaleValue < 1)
                {
                    return;
                }
            }
            // 缩放幅度控制
            if (scaleValue < 0.2 || scaleValue > 1.8)
            {
                return;
            }
            _scaleTransform.ScaleX = scaleValue;
            _scaleTransform.ScaleY = scaleValue;
            _translateTransform.X = -((actualPoint.X * (scaleValue - 1))) + point.X - actualPoint.X;
            _translateTransform.Y = -((actualPoint.Y * (scaleValue - 1))) + point.Y - actualPoint.Y;
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (IsMouseCaptured)
            {
                Vector v = _start - e.GetPosition(_parentElement);
                _translateTransform.X = _origin.X - v.X;
                _translateTransform.Y = _origin.Y - v.Y;
            }
        }
    }

    public static class FileCache
    {
        public static Action<DownloadState> DownloadStateChangedAction;
        public enum CacheMode
        {
            WinINet,
            Dedicated
        }

        // Record whether a file is being written.
        private static readonly Dictionary<string, bool> IsWritingFile = new Dictionary<string, bool>();

        static FileCache()
        {
            // default cache directory - can be changed if needed from App.xaml
            AppCacheDirectory = string.Format("{0}\\{1}\\Cache\\",
                Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
                Process.GetCurrentProcess().ProcessName);
            AppCacheMode = CacheMode.Dedicated;
        }

        /// <summary>
        ///     Gets or sets the path to the folder that stores the cache file. Only works when AppCacheMode is
        ///     CacheMode.Dedicated.
        /// </summary>
        public static string AppCacheDirectory { get; set; }

        /// <summary>
        ///     Gets or sets the cache mode. WinINet is recommended, it‘s provided by .Net Framework and uses the Temporary Files
        ///     of IE and the same cache policy of IE.
        /// </summary>
        public static CacheMode AppCacheMode { get; set; }

        public static async Task<MemoryStream> HitAsync(string url)
        {
            DownloadStateChangedAction?.Invoke(DownloadState.Process);

            if (!Directory.Exists(AppCacheDirectory))
            {
                Directory.CreateDirectory(AppCacheDirectory);
            }
            var uri = new Uri(url);
            var fileNameBuilder = new StringBuilder();
            using (var sha1 = new SHA1Managed())
            {
                var canonicalUrl = uri.ToString();
                var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(canonicalUrl));
                fileNameBuilder.Append(BitConverter.ToString(hash).Replace("-", "").ToLower());
                if (Path.HasExtension(canonicalUrl))
                    fileNameBuilder.Append(Path.GetExtension(canonicalUrl));
            }

            var fileName = fileNameBuilder.ToString();
            var localFile = string.Format("{0}\\{1}", AppCacheDirectory, fileName);
            var memoryStream = new MemoryStream();

            FileStream fileStream = null;
            if (!IsWritingFile.ContainsKey(fileName) && File.Exists(localFile))
            {
                using (fileStream = new FileStream(localFile, FileMode.Open, FileAccess.Read))
                {
                    await fileStream.CopyToAsync(memoryStream);
                }
                memoryStream.Seek(0, SeekOrigin.Begin);
                DownloadStateChangedAction?.Invoke(DownloadState.Success);
                return memoryStream;
            }

            var request = WebRequest.Create(uri);
            request.Timeout = 30;
            try
            {
                var response = await request.GetResponseAsync();
                var responseStream = response.GetResponseStream();
                if (responseStream == null)
                    return null;
                if (!IsWritingFile.ContainsKey(fileName))
                {
                    IsWritingFile[fileName] = true;
                    fileStream = new FileStream(localFile, FileMode.Create, FileAccess.Write);
                }

                using (responseStream)
                {
                    var bytebuffer = new byte[100];
                    int bytesRead;
                    do
                    {
                        bytesRead = await responseStream.ReadAsync(bytebuffer, 0, 100);
                        if (fileStream != null)
                            await fileStream.WriteAsync(bytebuffer, 0, bytesRead);
                        await memoryStream.WriteAsync(bytebuffer, 0, bytesRead);
                    } while (bytesRead > 0);
                    if (fileStream != null)
                    {
                        await fileStream.FlushAsync();
                        fileStream.Dispose();
                        IsWritingFile.Remove(fileName);
                    }
                }
                memoryStream.Seek(0, SeekOrigin.Begin);
                DownloadStateChangedAction?.Invoke(DownloadState.Success);
                return memoryStream;
            }
            catch (WebException)
            {
                DownloadStateChangedAction?.Invoke(DownloadState.Failed);
                return null;
            }
        }
    }

    public enum DownloadState
    {
        Process,
        Failed,
        Success
    }
}
<Style TargetType="{x:Type ScalableImage}">
        
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type dui:ScalableImage}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <DuiBusy x:Name="duiBusy" BorderThickness="0" BusyText="请稍后..." IsBusy="{Binding IsLoading,RelativeSource={RelativeSource TemplatedParent}}" IsShowBusyMark="True">
                            <Grid Background="Transparent">
                                <Image x:Name="PART_Image"></Image>
                            </Grid>
                        </DuiBusy>
                       
                    </Border>
                    
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

 

以上是关于wpf 可缩放,可显示远程图片的Image的主要内容,如果未能解决你的问题,请参考以下文章

QT中给各控件增加背景图片(可缩放可旋转)的几种方法

如何在可缩放滚动视图中绘制可点击的网格对象,从远程 json 数据中获取数据?

如何在 WPF 中保持可缩放、可滚动内容的纵横比?

应使用哪些滚动视图和图像视图设置在 iOS 中显示可缩放图片?

如何在 SwiftUI 中使用 .svg 图片

可缩放时间轴和录像片段选择器的实现