原文: UWP開發中兩種網絡圖檔緩存方法
通常情況下,我們的程式需要從伺服器讀取圖檔,但如果需要不止一次讀取某一張圖檔的話,就需要做本地緩存了,這樣既為使用者省一點流量,又能顯得你的APP很快。
假如你已經知道了某一張圖檔的位址,那麼第一件事就是要把這張圖檔下載下傳下來;當然如果是一次性讀取的話,可以直接把圖檔位址給Image控件或者給Bitmapimage對象(實際上這二者是沒有去别的),但這無法存到本地,隻作為顯示用;但是我們要做的是儲存到本地,這樣肯定是不行的。現在我們就要用到HTTP的東西了,請看下面的代碼:
async static public Task<IInputStream> GetStreamAsync(string url)
{
httpClient = new HttpClient();
var response = await httpClient.GetInputStreamAsync(new Uri(url));
return response;
}
async static public Task<IBuffer> GetBufferAsync(string url)
{
httpClient = new HttpClient();
var ResultStr = await httpClient.GetBufferAsync(new Uri(url));
return ResultStr;
}
這兩個靜态方法分别擷取url位址的buffer資料和輸入流。有了buffer或者stream之後就可以進行下一步-儲存。
當我們下載下傳完成後,首先要做的很有可能是先顯示出來,然後再儲存,是以先把資料寫入到圖檔對象中:
這裡有兩種方法:
1.WriteableBitmap
protected async Task<WriteableBitmap> GetWriteableBitmapAsync(string url)
{
try
{
IBuffer buffer = await GetBufferAsync(url);
if (buffer != null)
{
BitmapImage bi = new BitmapImage();
WriteableBitmap wb = null; Stream stream2Write;
using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
{
stream2Write = stream.AsStreamForWrite();
await stream2Write.WriteAsync(buffer.ToArray(), 0, (int)buffer.Length);
await stream2Write.FlushAsync();
stream.Seek(0);
await bi.SetSourceAsync(stream);
wb = new WriteableBitmap(bi.PixelWidth, bi.PixelHeight);
stream.Seek(0);
await wb.SetSourceAsync(stream);
return wb;
}
}
else
{
return null;
}
}
catch
{
return null;
}
}
2.SoftwareBitmap
public async Task<SoftwareBitmap> GetSoftwareBitmapAsync(string url)
{
try
{
IInputStream inputStream = await GetSteramAsync(url);
IRandomAccessStream memStream = new InMemoryRandomAccessStream();
await RandomAccessStream.CopyAsync(inputStream, memStream);
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(memStream);
SoftwareBitmap sb = await decoder.GetSoftwareBitmapAsync(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
return sb;
}
catch
{
return null;
}
}
這兩種都可以作為展示圖像的資料源,其中WriteableBitmap可以直接給Image.Source , SoftwareBitmap這需要轉為SoftwareBitmap:
SoftwareBitmapSource sbs = new SoftwareBitmapSource();
sbs.SetBitmapAsync(sb);
接下來就是儲存了:WriteableBitmap:
public async Task SaveImageAsync(WriteableBitmap image, string filename)
{
try
{
if (image == null)
{
return;
}
Guid BitmapEncoderGuid = BitmapEncoder.JpegEncoderId;
if (filename.EndsWith("jpg"))
BitmapEncoderGuid = BitmapEncoder.JpegEncoderId;
else if (filename.EndsWith("png"))
BitmapEncoderGuid = BitmapEncoder.PngEncoderId;
else if (filename.EndsWith("bmp"))
BitmapEncoderGuid = BitmapEncoder.BmpEncoderId;
else if (filename.EndsWith("tiff"))
BitmapEncoderGuid = BitmapEncoder.TiffEncoderId;
else if (filename.EndsWith("gif"))
BitmapEncoderGuid = BitmapEncoder.GifEncoderId;
var folder = await _local_folder.CreateFolderAsync("images_cache", CreationCollisionOption.OpenIfExists);
var file = await folder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);
using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoderGuid, stream);
Stream pixelStream = image.PixelBuffer.AsStream();
byte[] pixels = new byte[pixelStream.Length];
await pixelStream.ReadAsync(pixels, 0, pixels.Length);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore,
(uint)image.PixelWidth,
(uint)image.PixelHeight,
96.0,
96.0,
pixels);
await encoder.FlushAsync();
}
}
catch
{
}
}
public async Task WriteToFileAsync(StorageFolder folder,SoftwareBitmap sb,string fileName)
{
if (sb != null)
{
// save image file to cache
StorageFile file = await folder.CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists);
using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
encoder.SetSoftwareBitmap(sb);
await encoder.FlushAsync();
}
}
}
怎麼樣,是不是很簡單?