如何在不下载的情况下从ImageSource保存图像?

时间:2012-06-20 08:09:34

标签: xaml windows-8 microsoft-metro

这是我之前提问how should a metro app cache images for tombstoning (and should it)?

的扩展

我发现的解决方案是使用HttpClient,但这会导致Web服务器上每个文件不必要的第二次命中。

是否有保存Image / ImageSource的现有图像/流(使用ImageOpened事件以确保它可用)?

解决方案必须适用于当前的RP API,因为这是一个从CP进行大量更改的区域。

3 个答案:

答案 0 :(得分:2)

首先请注意,没有做任何自定义(即使用URI作为Image.Source),已经实现了某种缓存,就好像你的应用程序旁边有一个Fiddler,你和#39; ll看到请求发出一次,而不是每次都显示一个项目。

这就是说,如果你想要某种持久性缓存,你可以创建一个转换器来检查所需的图像是否在App的临时目录中,如果不是这样的话就下载它。

这是一种方法:

public sealed class UriToCachedImageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        Uri uri = value as Uri;
        if (uri == null)
            return null;

        // Don't let user know those are images, yet keep a unique and consistent name.
        string fileName = Path.GetFileName(uri.AbsolutePath);
        StorageFile file = null;
        try
        {
            Task<StorageFile> task = ApplicationData.Current.TemporaryFolder.GetFileAsync(fileName).AsTask<StorageFile>();
            task.Wait();
            file = task.Result;
        }
        catch (AggregateException ex)
        {
            if (ex.InnerException is FileNotFoundException)
            {
                // http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/1eb71a80-c59c-4146-aeb6-fefd69f4b4bb/
            }
            else
            {
                throw;
            }
        }

        if (file == null)
        {
            // File isn't present in cache => download it.

            // This creates a file in the app's INetCache
            // but we can't retrieve its path or know its name for sure
            // hence we're not using this file as our cache file.
            Task<StorageFile> streamTask = StorageFile.CreateStreamedFileFromUriAsync(fileName, uri, RandomAccessStreamReference.CreateFromUri(uri)).AsTask<StorageFile>();
            streamTask.Wait();
            StorageFile storageFile = streamTask.Result;

            // Copy file to our temporary directory (can't move as we don't have write access on the initial file).
            Task<StorageFile> copyTask = storageFile.CopyAsync(ApplicationData.Current.TemporaryFolder, fileName, NameCollisionOption.ReplaceExisting).AsTask<StorageFile>();
            copyTask.Wait();
            file = copyTask.Result;
        }

        Task<IRandomAccessStreamWithContentType> openTask = file.OpenReadAsync().AsTask<IRandomAccessStreamWithContentType>();
        openTask.Wait();
        IRandomAccessStreamWithContentType randomAccessStream = openTask.Result;

        BitmapImage bitmapImage = new BitmapImage();
        bitmapImage.SetSource(randomAccessStream);
        return bitmapImage;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

注意:此代码段还说明了如何从同步方法调用异步方法;)

答案 1 :(得分:0)

我看不到从ImageOpened事件中做出我需要的方法,而是找到了一个工作模型。

而不是将图像uri绑定到Image Source并让metro下载图像,而是绑定到Image的Tag,然后在数据绑定完成后循环遍历xaml中的每个Image并将图像下载为RandomAccessStream,保存流并将Image Source设置为从流创建的BitmapImage。

RandomAccessStreamReference rasf = RandomAccessStreamReference.CreateFromUri(new Uri(MyImage.Tag as string));
BitmapImage bitmapImage = new BitmapImage();
var ras = await rasf.OpenReadAsync();
bitmapImage.SetSource(ras);
MyImage.Source = bitmapImage;

我还通过将代码放在转换器和视图模型属性中来调查自动化过程,但由于异步调用,这些都不可能。

答案 2 :(得分:0)

你也可以使用FFImageLoading(https://github.com/molinch/FFImageLoading/)或查看其来源以了解它是如何实现的(https://github.com/molinch/FFImageLoading/tree/master/FFImageLoading.Windows

功能

  • Xamarin.iOS(最低iOS 7),Xamarin.Android(最低Android 4),Xamarin.Forms和Windows(WinRT,UWP)支持
  • 可配置的磁盘和内存缓存
  • 类似下载/加载请求的重复数据删除
  • 错误并加载占位符支持
  • 图像可以自动下采样到指定大小(内存使用量减少)
  • WebP支持
  • 图片加载淡入式动画支持
  • 可以重试图片下载(RetryCount,RetryDelay)
  • 默认情况下,Android透明度处于禁用状态(可配置)。节省50%的内存
  • 转换支持
    • BlurredTransformation
    • CircleTransformation,RoundedTransformation,CornersTransformation
    • ColorSpaceTransformation,GrayscaleTransformation,SepiaTransformation
    • FlipTransformation
    • 支持自定义转换(本机平台IT转换实现)

这很简单:

<ff:FFImage Name="image"
    VerticalAlignment="Stretch" 
    HorizontalAlignment="Stretch"
    LoadingPlaceholder="loading.png"
    ErrorPlaceholder="error.png"
    CacheDuration="30"
    RetryCount="3"
    RetryDelay="250"
    DownsampleHeight="300"
    Source="http://lorempixel.com/output/city-q-c-600-600-5.jpg">
</ff:FFImage>

示例项目:https://github.com/molinch/FFImageLoading/tree/master/samples/Simple.WinPhone.Sample