Created
June 30, 2014 01:56
-
-
Save imwower/741794a255f6f9546755 to your computer and use it in GitHub Desktop.
async image
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Net.Http; | |
using System.Text; | |
using System.Threading.Tasks; | |
using Windows.Security.Cryptography; | |
using Windows.Security.Cryptography.Core; | |
using Windows.Storage; | |
using Windows.Storage.Streams; | |
using Windows.UI.Xaml; | |
using Windows.UI.Xaml.Controls; | |
using Windows.UI.Xaml.Media; | |
using Windows.UI.Xaml.Media.Animation; | |
using Windows.UI.Xaml.Media.Imaging; | |
namespace PianKe.Controls | |
{ | |
public class AsyncImageHelper : DependencyObject | |
{ | |
private const string CachePath = "AsyncImagesCache"; | |
public static readonly DependencyProperty SourceProperty = DependencyProperty.RegisterAttached("AsyncImageSource", typeof(string), typeof(AsyncImageHelper), new PropertyMetadata(default(string), SourcePropertyChanged)); | |
public static void SetAsyncImageSource(DependencyObject image, string value) | |
{ | |
image.SetValue(SourceProperty, value); | |
} | |
public static string GetAsyncImageSource(DependencyObject image) | |
{ | |
return (string)image.GetValue(SourceProperty); | |
} | |
static void SourcePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs ags) | |
{ | |
if (ags.NewValue == ags.OldValue) | |
return; | |
var image = dependencyObject as Image; | |
if (image != null) | |
{ | |
var imageurl = ags.NewValue as string; | |
if (string.IsNullOrEmpty(imageurl)) | |
return; | |
ToLoadPrimitiveImageSource(image, imageurl); | |
} | |
} | |
/// <summary> | |
/// 裝載原始圖片 | |
/// </summary> | |
/// <param name="image"></param> | |
/// <param name="imageurl"></param> | |
static async void ToLoadPrimitiveImageSource(Image image, string imageurl) | |
{ | |
//如果非Http Uri,不執行Image切換 | |
if (!imageurl.StartsWith("http")) return; | |
ImageSource source; | |
if (await CacheImageExists(imageurl)) | |
{ | |
source = await GetImageSourceFromCache(imageurl); | |
} | |
else | |
{ | |
source = await GetImageFromNetWork(imageurl); | |
} | |
if (source == null) return; | |
image.Source = source; | |
//if (imageurl != GetAsyncImageSourceSource(image)) | |
// SetRealImageSource(image, imageurl); | |
//else | |
RunAnimation(image); | |
} | |
/// <summary> | |
/// Image Animation | |
/// 執行一次動畫 | |
/// </summary> | |
/// <param name="img">DependencyObject</param> | |
static void RunAnimation(Image img) | |
{ | |
var sb = new Storyboard(); | |
var opacityChanged = new DoubleAnimation { From = 0, To = 1, Duration = TimeSpan.FromMilliseconds(500) }; | |
Storyboard.SetTarget(opacityChanged, img); | |
Storyboard.SetTargetProperty(opacityChanged, "Opacity"); | |
sb.Children.Add(opacityChanged); | |
sb.Begin(); | |
} | |
/// <summary> | |
/// 擷取唯一檔案名,判斷緩存檔案是否存在 | |
/// </summary> | |
/// <param name="imageurl"></param> | |
/// <returns></returns> | |
static async Task<bool> CacheImageExists(string imageurl) | |
{ | |
try | |
{ | |
var fileName = GetCacheFilePath(imageurl); | |
var file = await ApplicationData.Current.LocalFolder.GetFileAsync(fileName); | |
if (file == null) | |
{ | |
return false; | |
} | |
} | |
catch (Exception) | |
{ | |
return false; | |
} | |
return true; | |
} | |
/// <summary> | |
/// 計算Hash | |
/// 取得唯一緩存檔案名稱 | |
/// </summary> | |
/// <param name="imageUrl"></param> | |
/// <returns></returns> | |
static string GetCacheFilePath(string imageUrl) | |
{ | |
HashAlgorithmProvider hashAlgorithm = HashAlgorithmProvider.OpenAlgorithm("MD5"); | |
// 原文的二进制数据 | |
IBuffer vector = CryptographicBuffer.ConvertStringToBinary(imageUrl, BinaryStringEncoding.Utf8); | |
// 哈希二进制数据 | |
IBuffer digest = hashAlgorithm.HashData(vector); | |
var imageName = CryptographicBuffer.EncodeToHexString(digest); | |
return Path.Combine(CachePath, imageName); | |
} | |
/// <summary> | |
/// 获取网络图片 | |
/// </summary> | |
/// <param name="imageurl"></param> | |
/// <returns></returns> | |
static async Task<BitmapImage> GetImageFromNetWork(string imageurl) | |
{ | |
var httpClient = new HttpClient(); | |
try | |
{ | |
var response = await httpClient.GetAsync(imageurl); | |
response.EnsureSuccessStatusCode(); | |
using (var stream = await response.Content.ReadAsStreamAsync()) | |
{ | |
//CreationCollisionOption.GenerateUniqueName 屬性以確保同一個檔案下載時不會出錯 | |
var storageFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(GetCacheFilePath(imageurl), CreationCollisionOption.GenerateUniqueName); | |
using (var transaction = await storageFile.OpenTransactedWriteAsync()) | |
{ | |
using (var dataWriter = new DataWriter(transaction.Stream)) | |
{ | |
var bytesInStream = new byte[stream.Length]; | |
stream.Read(bytesInStream, 0, bytesInStream.Length); | |
dataWriter.WriteBytes(bytesInStream); | |
transaction.Stream.Size = await dataWriter.StoreAsync(); | |
await transaction.CommitAsync(); | |
} | |
} | |
return await GetImageSourceFromCache(imageurl); | |
} | |
} | |
catch | |
{ | |
} | |
return null; | |
} | |
/// <summary> | |
/// 擷取緩存檔案 | |
/// </summary> | |
/// <param name="imageurl"></param> | |
/// <returns></returns> | |
static async Task<BitmapImage> GetImageSourceFromCache(string imageurl) | |
{ | |
try | |
{ | |
var storageFile = await ApplicationData.Current.LocalFolder.GetFileAsync(GetCacheFilePath(imageurl)); | |
if (storageFile != null) | |
{ | |
using (IRandomAccessStream randomStream = await storageFile.OpenReadAsync()) | |
{ | |
var bitmapImage = new BitmapImage(); | |
bitmapImage.SetSource(randomStream); | |
return bitmapImage; | |
} | |
} | |
} | |
catch | |
{ | |
} | |
return null; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment