[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

請參考:

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 的屬性,可以將大圖部放入記憶體中,就可以進行採樣



從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/


當麻許的超技八 2014 | Donma Hsu Design.