[Xamarin] 讀取大張的圖片
2014-05-13
手機資源很有限,如果要讀取一張使用者拍的照片,尤其是現在照片都很大,讀取進來後根本就是大到爆掉這時候該怎麼辦
範例: 有兩顆按鈕,首先讀取一張照片近來,並且將照片寫入internal storage,之後再將他從internal storage 中讀取出來
寫入範例:
btnSave.Click += delegate
{
//將ImageView 中的圖片讀取出來
var bitmap = ((BitmapDrawable)FindViewById<ImageView>(Resource.Id.imageView1).Drawable).Bitmap;
//宣告一byte[]
var imgbytes = new byte[bitmap.Width * bitmap.Height * 4];
//用MemoryStream 讀取後轉成byte[]
var stream = new MemoryStream(imgbytes);
//品質設成80%
bitmap.Compress(Bitmap.CompressFormat.Jpeg, 80, stream);
stream.Flush();
WriteAllBytes("sample.jpg", imgbytes);
};
很簡單的範例,先將ImageView 中的照片讀取出來,並且寫入至internal storage 中 ,其中有呼叫到一隻 WriteAllBytes 是我寫的method
請參考:
之後就是讀取的部分,下列程式碼會將 internal storage 中的byte[]讀取出來並且透過 BitmapFactory.DecodeByteArray + BitmapFactory.Options 將圖片讀取,不然很容易手機就exception
從internal storage 讀取圖片:
其中用到從internal storage 圖取 byte 的 ReadAllBytes 還有計算等比採樣的公式這邊也附上程式碼:
範例下載:
public void WriteAllBytes(string filename, byte[] content)
{
//如果前面沒有 / 則補上
if (filename[0] != '/')
{
filename = "/" + filename;
}
//預設讀取 data/data/[package name]/files
if (filename.Contains("/"))
{
Directory.CreateDirectory(GetFileStreamPath("") + filename.Substring(0, filename.LastIndexOf('/')));
}
System.IO.File.WriteAllBytes(GetFileStreamPath("") + filename, content);
}
之後就是讀取的部分,下列程式碼會將 internal storage 中的byte[]讀取出來並且透過 BitmapFactory.DecodeByteArray + BitmapFactory.Options 將圖片讀取,不然很容易手機就exception
其中 inJustDecodeBounds 的屬性,可以將大圖部放入記憶體中,就可以進行採樣
參考文件如下:
http://www.cnblogs.com/leizhenzi/archive/2011/05/14/2046431.html
http://www.javaworld.com.tw/jute/post/view?bid=26&id=312289
http://www.cnblogs.com/leizhenzi/archive/2011/05/14/2046431.html
http://www.javaworld.com.tw/jute/post/view?bid=26&id=312289
從internal storage 讀取圖片:
btnRead.Click += delegate
{
var bytes = ReadAllBytes("sample.jpg");
var options = new BitmapFactory.Options
{
InJustDecodeBounds = true,
};
using (var dispose = BitmapFactory.DecodeByteArray(bytes, 0, bytes.Length, options))
{
}
// 計算Samele
options.InSampleSize = CalculateInSampleSize(options, 500, 500);
// 採樣完後設為false
options.InJustDecodeBounds = false;
var bitmap = BitmapFactory.DecodeByteArray(bytes, 0, bytes.Length, options);
FindViewById<ImageView>(Resource.Id.imageView1).SetImageBitmap(bitmap);
};
其中用到從internal storage 圖取 byte 的 ReadAllBytes 還有計算等比採樣的公式這邊也附上程式碼:
public byte[] ReadAllBytes(string filename)
{
try
{
if (filename[0] != '/')
{
filename = "/" + filename;
}
return System.IO.File.ReadAllBytes(GetFileStreamPath("") + filename);
}
catch (Exception ex)
{
return null;
}
}
public static int CalculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight)
{
var height = (float)options.OutHeight;
var width = (float)options.OutWidth;
var inSampleSize = 1D;
if (height > reqHeight || width > reqWidth)
{
inSampleSize = width > height
? height / reqHeight
: width / reqWidth;
}
return (int)inSampleSize;
}
範例下載:
參考文件:
http://www.cnblogs.com/leizhenzi/archive/2011/05/14/2046431.html
http://www.javaworld.com.tw/jute/post/view?bid=26&id=312289
http://docs.xamarin.com/recipes/android/resources/general/load_large_bitmaps_efficiently/