ImageViewにビットマップを読み込んでいますが、このエラーが表示されます。この制限は、OpenGLハードウェアテクスチャのサイズ制限(2048x2048)に関連するものです。読み込む必要がある画像は、高さ約4,000ピクセルのピンチズーム画像です。
マニフェストでハードウェアアクセラレーションをオフにしようとしましたが、喜びはありません。
<application
Android:hardwareAccelerated="false"
....
>
ImageViewに2048ピクセルを超える画像を読み込むことは可能ですか?
すべてのレンダリングはOpenGLに基づいているため、この制限を超えることはできません(GL_MAX_TEXTURE_SIZE
はデバイスによって異なりますが、最小値は2048x2048であるため、2048x2048未満の画像が収まります)。
このような大きな画像で、ズームアウトしたい場合や、携帯電話でズームしたい場合は、たとえばグーグルマップで見るようなシステムをセットアップする必要があります。画像がいくつかの部分に分割され、いくつかの定義があります。
または、表示する前に画像を縮小することもできます(この質問については ser1352407の答え を参照してください)。
また、画像を保存するフォルダーに注意してください。Androidは画像を自動的に拡大できます。この質問について Pilot_51の答え をご覧ください。
これは質問への直接的な答えではありません(2048を超える画像の読み込み)が、エラーが発生している人にとって考えられる解決策です。
私の場合、画像は両方の寸法で2048より小さく(正確には1280x727)、Galaxy Nexusで特に問題が発生しました。イメージはdrawable
フォルダーにあり、修飾されたフォルダーはありませんでした。 Androidは、密度修飾子のないドロウアブルがmdpiであると想定し、他の密度に合わせてそれらを拡大または縮小します。この場合、xhdpiで2倍に拡大しました。スケーリングを防止するために原因画像をdrawable-nodpi
に移動すると、問題は解決しました。
この方法で画像を縮小しました:
ImageView iv = (ImageView)waypointListView.findViewById(R.id.waypoint_picker_photo);
Bitmap d = new BitmapDrawable(ctx.getResources() , w.photo.getAbsolutePath()).getBitmap();
int nh = (int) ( d.getHeight() * (512.0 / d.getWidth()) );
Bitmap scaled = Bitmap.createScaledBitmap(d, 512, nh, true);
iv.setImageBitmap(scaled);
このダウンサンプリングコードをすべて手動で記述/デバッグしようと何時間も費やす代わりに、Picasso
を使用してみませんか?すべてのタイプおよび/またはサイズのbitmaps
を処理するために作成されました。
私は"ビットマップが大きすぎます。.."問題を取り除くためにこの1行のコードを使用しました:
Picasso.load(resourceId).fit().centerCrop().into(imageView);
イメージファイルをdrawable
フォルダーからdrawable-nodpi
フォルダーに変更すると、うまくいきました。
(AndroidManifest.xml
)に次の2つの属性を追加するとうまくいきました。
Android:largeHeap="true"
Android:hardwareAccelerated="false"
私はピカソを使用しましたが、同じ問題がありました。画像が少なくともサイズ、幅、または高さが大きすぎました。最終的に私はここで解決策を見つけました。表示サイズに応じて大きな画像を縮小し、アスペクト比を維持することもできます。
public Point getDisplaySize(Display display) {
Point size = new Point();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
display.getSize(size);
} else {
int width = display.getWidth();
int height = display.getHeight();
size = new Point(width, height);
}
return size;
}
そして、このメソッドを使用して、ピカソによる画像をロードします。
final Point displySize = getDisplaySize(getWindowManager().getDefaultDisplay());
final int size = (int) Math.ceil(Math.sqrt(displySize.x * displySize.y));
Picasso.with(this)
.load(urlSource)
.resize(size, size)
.centerInside()
.into(imageViewd);
また、パフォーマンスを向上させるために、画像全体ではなく、ディスプレイ画面の幅と高さに応じて画像をダウンロードできます。
public String reviseImageUrl(final Integer displayWidth, final Integer displayHeight,
final String originalImageUrl) {
final String revisedImageUrl;
if (displayWidth == null && displayHeight == null) {
revisedImageUrl = originalImageUrl;
} else {
final Uri.Builder uriBuilder = Uri.parse(originalImageUrl).buildUpon();
if (displayWidth != null && displayWidth > 0) {
uriBuilder.appendQueryParameter(QUERY_KEY_DISPLAY_WIDTH, String.valueOf(displayWidth));
}
if (displayHeight != null && displayHeight > 0) {
uriBuilder.appendQueryParameter(QUERY_KEY_DISPLAY_HEIGHT, String.valueOf(displayHeight));
}
revisedImageUrl = uriBuilder.toString();
}
return revisedImageUrl;
}
final String newImageUlr = reviseImageUrl(displySize.x, displySize.y, urlSource);
その後:
Picasso.with(this)
.load(newImageUlr)
.resize(size, size)
.centerInside()
.into(imageViewd);
編集:getDisplaySize()
display.getWidth()/getHeight()
は非推奨です。 Display
の代わりにDisplayMetrics
を使用します。
public Point getDisplaySize(DisplayMetrics displayMetrics) {
int width = displayMetrics.widthPixels;
int height = displayMetrics.heightPixels;
return new Point(width, height);
}
BitmapRegionDecoder
がトリックを行います。
onDraw(Canvas canvas)
をオーバーライドして、新しいスレッドを開始し、ユーザーに見える領域をデコードできます。
Larchoが指摘したように、APIレベル10以降、BitmapRegionDecoder
を使用して画像から特定の領域を読み込むことができます。これにより、必要な領域だけをメモリに割り当てることで、大きな画像を高解像度で表示できます。私は最近、タッチジェスチャ処理で大きな画像を視覚化するライブラリを開発しました。 ソースコードとサンプルはこちらから入手可能です 。
私は同じ問題を経験しました、ここに私の解決策があります。 Android画面幅と同じ画像の幅を設定し、高さをスケーリングします
Bitmap myBitmap = BitmapFactory.decodeFile(image.getAbsolutePath());
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
Log.e("Screen width ", " "+width);
Log.e("Screen height ", " "+height);
Log.e("img width ", " "+myBitmap.getWidth());
Log.e("img height ", " "+myBitmap.getHeight());
float scaleHt =(float) width/myBitmap.getWidth();
Log.e("Scaled percent ", " "+scaleHt);
Bitmap scaled = Bitmap.createScaledBitmap(myBitmap, width, (int)(myBitmap.getWidth()*scaleHt), true);
myImage.setImageBitmap(scaled);
これは、あらゆるサイズのAndroid画面に適しています。うまくいくかどうか教えてください。
表示レベル
次のコードを使用して、実行時に個々のビューのハードウェアアクセラレーションを無効にできます。
myView.setLayerType(View.LAYER_TYPE_SOFTWARE、null);
Imageviewに直接読み込むのではなく、Glideライブラリを使用します
グライド: https://github.com/bumptech/glide
Glide.with(this).load(Uri.parse(filelocation))).into(img_selectPassportPic);
画像を縮小する:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
// Set height and width in options, does not return an image and no resource taken
BitmapFactory.decodeStream(imagefile, null, options);
int pow = 0;
while (options.outHeight >> pow > reqHeight || options.outWidth >> pow > reqWidth)
pow += 1;
options.inSampleSize = 1 << pow;
options.inJustDecodeBounds = false;
image = BitmapFactory.decodeStream(imagefile, null, options);
画像はreqHeightとreqWidthのサイズで縮小されます。私が理解しているように、inSampleSizeは2の累乗値のみを取ります。
私は上記のすべての解決策を次々と試してみましたが、どれもうまくいかないようでした!最後に、Androidのカメラで画像をキャプチャし、それらを表示する公式の例を探してみることにしました。公式の例( here )は、ようやく機能する唯一の方法を教えてくれました。以下に、そのサンプルアプリで見つけたソリューションを示します。
public void setThumbnailImageAndSave(final ImageView imgView, File imgFile) {
/* There isn't enough memory to open up more than a couple camera photos */
/* So pre-scale the target bitmap into which the file is decoded */
/* Get the size of the ImageView */
int targetW = imgView.getWidth();
int targetH = imgView.getHeight();
/* Get the size of the image */
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imgFile.getAbsolutePath(), bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
/* Figure out which way needs to be reduced less */
int scaleFactor = 1;
if ((targetW > 0) || (targetH > 0)) {
scaleFactor = Math.min(photoW/targetW, photoH/targetH);
}
/* Set bitmap options to scale the image decode target */
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
/* Decode the JPEG file into a Bitmap */
Bitmap bitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath(), bmOptions);
/* Associate the Bitmap to the ImageView */
imgView.setImageBitmap(bitmap);
imgView.setVisibility(View.VISIBLE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
///*
if (requestCode == PICK_FROM_FILE && resultCode == RESULT_OK && null != data){
uri = data.getData();
String[] prjection ={MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(uri,prjection,null,null,null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(prjection[0]);
ImagePath = cursor.getString(columnIndex);
cursor.close();
FixBitmap = BitmapFactory.decodeFile(ImagePath);
ShowSelectedImage = (ImageView)findViewById(R.id.imageView);
// FixBitmap = new BitmapDrawable(ImagePath);
int nh = (int) ( FixBitmap.getHeight() * (512.0 / FixBitmap.getWidth()) );
FixBitmap = Bitmap.createScaledBitmap(FixBitmap, 512, nh, true);
// ShowSelectedImage.setImageBitmap(BitmapFactory.decodeFile(ImagePath));
ShowSelectedImage.setImageBitmap(FixBitmap);
}
}
このコードは仕事です
小さいサイズの画像を入れたい人のための注意:
Pilot_51のソリューション(画像をdrawable-nodpi
フォルダーに移動する)は機能しますが、別の問題があります:画像が画面に収まるように非常に大きな(2000 x 3800など)解像度にサイズ変更されない限り、画像がTOO SMALLになります-それはあなたのアプリをより重くします。
SOLUTION:画像ファイルをdrawable-hdpi
に入れます-私にとっては魅力的でした。
正しいdrawableサブフォルダーを使用すると解決しました。私の解決策は、フル解像度の画像(1920x1200)をdrawableフォルダーではなくdrawable-xhdpiフォルダーに入れることでした。
また、縮小画像(1280x800)をdrawable-hdpiフォルダーに配置します。
これらの2つの解像度は、私がプログラミングしている2013および2012 Nexus 7タブレットに一致します。他のいくつかのタブレットでもソリューションをテストしました。