Skip to content

Instantly share code, notes, and snippets.

@imwower
Created June 30, 2014 01:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save imwower/741794a255f6f9546755 to your computer and use it in GitHub Desktop.
Save imwower/741794a255f6f9546755 to your computer and use it in GitHub Desktop.
async image
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