PageRenderTime 45ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/BaconographyWP8Core/View/ScalingGifView.xaml.cs

https://github.com/hippiehunter/Baconography
C# | 284 lines | 227 code | 37 blank | 20 comment | 43 complexity | 07ee3a6b4d1c532601f47af77af31383 MD5 | raw file
  1. using System.Linq;
  2. using System.Net;
  3. using System.Windows;
  4. using System.Windows.Controls;
  5. using System.Windows.Navigation;
  6. using Microsoft.Phone.Controls;
  7. using Microsoft.Phone.Shell;
  8. using System.Windows.Media.Imaging;
  9. using System.Windows.Input;
  10. using System.ComponentModel;
  11. using System.Windows.Media;
  12. using BaconographyWP8.PlatformServices;
  13. using System.Threading.Tasks;
  14. using System.IO;
  15. using BaconographyPortable.ViewModel;
  16. using GalaSoft.MvvmLight;
  17. using System;
  18. using Microsoft.Practices.ServiceLocation;
  19. using BaconographyPortable.Services;
  20. using GalaSoft.MvvmLight.Messaging;
  21. using BaconographyPortable.Messages;
  22. using BaconographyWP8Core.Common;
  23. using DXGifRenderWP8;
  24. using System.Threading;
  25. namespace BaconographyWP8.View
  26. {
  27. public partial class ScalingGifView : UserControl
  28. {
  29. public ScalingGifView()
  30. {
  31. InitializeComponent();
  32. Loaded += ScalingGifView_Loaded;
  33. }
  34. void ScalingGifView_Loaded(object sender, RoutedEventArgs e)
  35. {
  36. if (!_loaded)
  37. {
  38. _loaded = true;
  39. if (_interop != null)
  40. {
  41. image.SetContentProvider(_interop.CreateContentProvider());
  42. var result = CoerceScaleImpl(viewport.ActualWidth, viewport.ActualHeight, _interop.Width, _interop.Height, 0.0);
  43. _scale = _coercedScale = _minScale = result.Item1;
  44. ResizeImage(true);
  45. }
  46. }
  47. }
  48. const double MaxScale = 10;
  49. double _scale = 1.0;
  50. double _minScale;
  51. double _coercedScale;
  52. double _originalScale;
  53. bool _loaded = false;
  54. Size _viewportSize;
  55. Point _screenMidpoint;
  56. Point _relativeMidpoint;
  57. private bool _initialLoad = true;
  58. /// <summary>
  59. /// Either the user has manipulated the image or the size of the viewport has changed. We only
  60. /// care about the size.
  61. /// </summary>
  62. void viewport_ViewportChanged(object sender, System.Windows.Controls.Primitives.ViewportChangedEventArgs e)
  63. {
  64. Size newSize = new Size(viewport.Viewport.Width, viewport.Viewport.Height);
  65. if (newSize != _viewportSize)
  66. {
  67. _viewportSize = newSize;
  68. if (!_initialLoad)
  69. {
  70. CoerceScale(true);
  71. ResizeImage(false);
  72. }
  73. else
  74. _initialLoad = false;
  75. }
  76. }
  77. /// <summary>
  78. /// Adjust the size of the image according to the coerced scale factor. Optionally
  79. /// center the image, otherwise, try to keep the original midpoint of the pinch
  80. /// in the same spot on the screen regardless of the scale.
  81. /// </summary>
  82. /// <param name="center"></param>
  83. void ResizeImage(bool center)
  84. {
  85. if (_coercedScale != 0)
  86. {
  87. double newWidth;
  88. double newHeight;
  89. if (_interop != null)
  90. {
  91. newWidth = image.Width = Math.Round(_interop.Width * _coercedScale);
  92. newHeight = image.Height = Math.Round(_interop.Height * _coercedScale);
  93. }
  94. else return;
  95. viewport.Bounds = new Rect(0, 0, newWidth, newHeight);
  96. if (center)
  97. {
  98. viewport.SetViewportOrigin(
  99. new Point(
  100. Math.Round(newWidth / 2),
  101. Math.Round(newHeight / 2)
  102. ));
  103. }
  104. else
  105. {
  106. Point newImgMid = new Point(newWidth * _relativeMidpoint.X, newHeight * _relativeMidpoint.Y);
  107. Point origin = new Point(newImgMid.X - _screenMidpoint.X, newImgMid.Y - _screenMidpoint.Y);
  108. viewport.SetViewportOrigin(origin);
  109. }
  110. }
  111. }
  112. /// <summary>
  113. /// Coerce the scale into being within the proper range. Optionally compute the constraints
  114. /// on the scale so that it will always fill the entire screen and will never get too big
  115. /// to be contained in a hardware surface.
  116. /// </summary>
  117. /// <param name="recompute">Will recompute the min max scale if true.</param>
  118. void CoerceScale(bool recompute)
  119. {
  120. if (viewport != null && _interop != null && _interop.Height != 0 && _interop.Width != 0)
  121. {
  122. var result = CoerceScaleImpl(viewport.ActualWidth, viewport.ActualHeight, _interop.Width, _interop.Height, 0.0);
  123. _minScale = result.Item1;
  124. _coercedScale = _scale = result.Item2;
  125. }
  126. }
  127. private static Tuple<double, double> CoerceScaleImpl(double viewWidth, double viewHeight, double bitmapWidth, double bitmapHeight, double scale)
  128. {
  129. double minX = viewWidth / bitmapWidth;
  130. double minY = viewHeight / bitmapHeight;
  131. var minScale = Math.Min(minX, minY);
  132. return Tuple.Create(minScale, Math.Min(MaxScale, Math.Max(scale, minScale)));
  133. }
  134. Direct3DInterop _interop;
  135. public static readonly DependencyProperty ImageSourceProperty =
  136. DependencyProperty.Register(
  137. "ImageSource",
  138. typeof(object),
  139. typeof(ScalingGifView),
  140. new PropertyMetadata(null)
  141. );
  142. public object ImageSource
  143. {
  144. get { return GetValue(ImageSourceProperty); }
  145. set
  146. {
  147. if (value == null && image != null)
  148. {
  149. image.SetContentProvider(null);
  150. _interop = null;
  151. }
  152. else if (image != null && _interop == null && value is string)
  153. {
  154. SetContentProvider(value as string);
  155. }
  156. else if (image != null && _interop == null && value is byte[])
  157. {
  158. SetContentProvider(value as byte[]);
  159. }
  160. SetValue(ImageSourceProperty, value);
  161. }
  162. }
  163. private void SetContentProvider(byte[] asset)
  164. {
  165. try
  166. {
  167. _interop = new Direct3DInterop(asset);
  168. // Set native resolution in pixels
  169. _interop.WindowBounds = _interop.RenderResolution = _interop.NativeResolution = new Windows.Foundation.Size(_interop.Width, _interop.Height);
  170. image.Height = _interop.Height;
  171. image.Width = _interop.Width;
  172. // Hook-up native component to DrawingSurface
  173. if (_loaded)
  174. {
  175. image.SetContentProvider(_interop.CreateContentProvider());
  176. CoerceScale(true);
  177. ResizeImage(true);
  178. }
  179. }
  180. catch
  181. {
  182. ServiceLocator.Current.GetInstance<INotificationService>().CreateNotification("Invalid Gif detected");
  183. }
  184. }
  185. private async void SetContentProvider(string sourceUrl)
  186. {
  187. Monitor.Enter(this);
  188. try
  189. {
  190. if (_interop != null)
  191. return;
  192. Messenger.Default.Send<LoadingMessage>(new LoadingMessage { Loading = true });
  193. var asset = await SimpleHttpService.GetBytes(sourceUrl);
  194. if (asset == null)
  195. return;
  196. _interop = new Direct3DInterop(asset);
  197. // Set native resolution in pixels
  198. _interop.RenderResolution = _interop.NativeResolution = _interop.WindowBounds = new Windows.Foundation.Size(_interop.Width, _interop.Height);
  199. image.Height = _interop.Height;
  200. image.Width = _interop.Width;
  201. // Hook-up native component to DrawingSurface
  202. image.SetContentProvider(_interop.CreateContentProvider());
  203. _scale = 0;
  204. CoerceScale(true);
  205. _scale = _coercedScale;
  206. ResizeImage(true);
  207. }
  208. catch
  209. {
  210. }
  211. finally
  212. {
  213. Messenger.Default.Send<LoadingMessage>(new LoadingMessage { Loading = false });
  214. Monitor.Exit(this);
  215. }
  216. }
  217. private void myGridGestureListener_PinchDelta(object sender, PinchGestureEventArgs e)
  218. {
  219. Point center = e.GetPosition(image);
  220. _relativeMidpoint = new Point(center.X / image.ActualWidth, center.Y / image.ActualHeight);
  221. var xform = image.TransformToVisual(viewport);
  222. _screenMidpoint = xform.Transform(center);
  223. _coercedScale = _scale = _originalScale * e.DistanceRatio;
  224. ResizeImage(false);
  225. }
  226. private void myGridGestureListener_DoubleTap(object sender, Microsoft.Phone.Controls.GestureEventArgs e)
  227. {
  228. var point = e.GetPosition(image);
  229. _relativeMidpoint = new Point(point.X / image.ActualWidth, point.Y / image.ActualHeight);
  230. var xform = image.TransformToVisual(viewport);
  231. _screenMidpoint = xform.Transform(point);
  232. if (_coercedScale >= (_minScale * 2.5) || _coercedScale < 0)
  233. _coercedScale = _minScale;
  234. else
  235. _coercedScale *= 1.75;
  236. ResizeImage(false);
  237. }
  238. private void myGridGestureListener_PinchStarted(object sender, PinchStartedGestureEventArgs e)
  239. {
  240. _originalScale = _scale;
  241. }
  242. private void myGridGestureListener_PinchCompleted(object sender, PinchGestureEventArgs e)
  243. {
  244. _scale = _coercedScale;
  245. }
  246. }
  247. }