コメント
コメントの投稿
※名前とタイトルが入力されていないコメントでは他のコメントとの区別ができません。
入力されていないコメントには返信しませんのであらかじめご了承くださいませ。
using System.IO;
using System.ComponentModel;
using System.Threading.Tasks;
using Android.Graphics;
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms;
[assembly: ExportRenderer(typeof(Xamarin.Forms.Image), typeof(CustomImageRenderer))]
public class CustomImageRenderer : ImageRenderer
{
private bool _isDecoded;
protected override async void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
//baseを呼ぶとOutOfMemmoryが発生しますのでコメントアウト
//base.OnElementPropertyChanged(sender, e);
ImageSource source = Element.Source;
if (source == null)
{
//画像がクリアされた場合は再デコードする為
_isDecoded = false;
}
if (_isDecoded == true ||
source == null ||
e.PropertyName != "Source")
{
//画像が無い場合や他のプロパティの変更の場合は処理を終了する
return;
}
//読み込み用のオプションオブジェクトを生成
//この値をtrueにするとメモリに画像を読み込まず、画像のサイズ情報だけを取得することができます。
var options = new BitmapFactory.Options { InJustDecodeBounds = true };
//画像ファイル読み込み
//オプションのInJustDecodeBoundsがtrueのため実際の画像はメモリに読み込まれません。
await this.GetBitmapAsync(source, options);
//コントロールの縦幅に合わせた画像サイズを再計算します。
//The with and height of the elements will be used to decode the image
var width = (int)Element.Width;
var height = (int)Element.Height;
if (width > 0 && height > 0)
{
//コントロールの大きさに合わせて画像を縮小する為
options.InSampleSize = this.CalculateInSampleSize(options, width, height);
}
else
{
//元画像のまま表示する為
options.InSampleSize = this.CalculateInSampleSize(options, options.OutWidth, options.OutHeight);
}
//画像をメモリに読み込む場合はfalseを指定
options.InJustDecodeBounds = false;
//これで指定した縮尺で画像を読み込めます。
//容量も小さくなるのでOutOfMemoryが発生しにくいです。
Bitmap bitmap = await this.GetBitmapAsync(source, options);
//オリジナルのイメージコントロールに修正した画像ファイルをセットします。
//Set the bitmap to the native control
Control.SetImageBitmap(bitmap);
_isDecoded = true;
}
//イメージソースから非同期でビットマップを取得する
private async Task<Bitmap> GetBitmapAsync(ImageSource source, BitmapFactory.Options options)
{
Bitmap bitmap = null;
if (source.GetType() == typeof(StreamImageSource))
{
System.IO.Stream stream = this.GetStreamFromImageSource(source);
bitmap = await BitmapFactory.DecodeStreamAsync(stream, new Rect(), options);
}
else if (source.GetType() == typeof(FileImageSource))
{
FileImageSource fis = (FileImageSource)source;
bitmap = await BitmapFactory.DecodeFileAsync(fis.File, options);
}
return bitmap;
}
//イメージソースからSystem.IO.Streamを取得する
public Stream GetStreamFromImageSource(ImageSource source)
{
StreamImageSource streamImageSource = (StreamImageSource)source;
System.Threading.CancellationToken cancellationToken = System.Threading.CancellationToken.None;
Task<Stream> task = streamImageSource.Stream(cancellationToken);
Stream stream = task.Result;
return stream;
}
private int CalculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight)
{
// Raw height and width of image
float height = options.OutHeight;
float width = options.OutWidth;
var inSampleSize = 1D;
if (!(height > reqHeight) && !(width > reqWidth)) return (int)inSampleSize;
var halfHeight = (int)(height / 2);
var halfWidth = (int)(width / 2);
// Calculate a inSampleSize that is a power of 2 – the decoder will use a value that is a power of two anyway.
while ((halfHeight / inSampleSize > reqHeight) && (halfWidth / inSampleSize > reqWidth))
{
inSampleSize *= 2;
}
return (int)inSampleSize;
}
}
※名前とタイトルが入力されていないコメントでは他のコメントとの区別ができません。
入力されていないコメントには返信しませんのであらかじめご了承くださいませ。