通常情況下,我們的程式需要從伺服器讀取圖片,但如果需要不止一次讀取某一張圖片的話,就需要做本地緩存了,這樣既為用戶省一點流量,又能顯得你的APP很快。 假如你已經知道了某一張圖片的地址,那麼第一件事就是要把這張圖片下載下來;當然如果是一次性讀取的話,可以直接把圖片地址給Image控制項或者給Bitma ...
通常情況下,我們的程式需要從伺服器讀取圖片,但如果需要不止一次讀取某一張圖片的話,就需要做本地緩存了,這樣既為用戶省一點流量,又能顯得你的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(); } } }
怎麼樣,是不是很簡單?