「ビットマップが大きすぎてテクスチャにアップロードできません」


154

ビットマップをImageViewに読み込んでいますが、このエラーが表示されます。この制限は、OpenGLハードウェアテクスチャのサイズ制限(2048x2048)に関連しています。ロードする必要がある画像は、高さが約4,000ピクセルのピンチズーム画像です。

マニフェストでハードウェアアクセラレーションをオフにしようとしましたが、喜びはありません。

    <application
        android:hardwareAccelerated="false"
        ....
        >

2048ピクセルより大きい画像をImageViewに読み込むことはできますか?


1
ここを見る人は、スクロール可能にしたい場合は、画像をスクロールビューに配置することを忘れないでください。これでエラーが解消されます。それが私の問題だと悟る前に、私は時間を無駄にしました。
Jason Ridge

画質を維持したまま大きな画像を表示したい場合は、下の@stoefln回答のライブラリを参照してください。私はそれを使用し、試してみる価値があります。間違いなくinSampleSizeアプローチよりも優れています。
Mahendra Liya、2015

1
@ジョー・ブローの現在の答えはあなたの場合うまくいきませんでしたか?いいえの場合、この質問に関連して直面した問題について詳しく説明してください。
Pravin Divraniya 2016年

1
ね@ @ VC.One-それは私の男について働きかけるのは奇妙なことです。「既存の回答をリワードする」をクリックすればよかった。それがばかげているので、だれもそのSOポップアップの「ベスト」ボタンをうんざりして押すことを気にしません:)バウンティをクリックしたときにすべて解決されました。乾杯!!
Fattie、

1
私は常に報奨金を支払うようにしています(ポイントを集めるのは好きではありません)。私のプロフィールをクリックすると、報奨金、@ VC.Oneをクリックすると、何年にもわたってSOの本当に素晴らしいQAがたくさん表示されます!!!!!!!!!!!!!!!
Fattie、

回答:


48

すべてのレンダリングはOpenGLに基づいているため、この制限を超えることはできません(GL_MAX_TEXTURE_SIZEデバイスによって異なりますが、最小値は2048x2048であるため、2048x2048未満のすべてのイメージに適合します)。

このような大きな画像で、ズームアウトしたい場合やモバイルで使用する場合は、たとえばGoogleマップに表示されるのと同様のシステムをセットアップする必要があります。画像をいくつかの部分に分割し、いくつかの定義を付けます。

または、表示する前に画像を縮小することもできます(この質問に関するuser1352407の回答を参照してください)。

また、画像をどのフォルダに配置するかに注意してください。Androidは画像を自動的に拡大します。見ていPilot_51の答えこの質問に以下を。


23
この場合、ギャラリーアプリでは、カメラで撮影した画像をどのように表示および操作できますか?2048x2048は4MPの画像にすぎず、多くのAndroidスマートフォンはこれよりもはるかに大きな写真を撮ります。ギャラリーアプリには問題がないようです。
Ollie C

3
GL_MAX_TEXTURE_SIZEはデバイスに依存するためです。
jptsetung 2012

24
これは実際には意味がありません。1286x835ピクセルの画像で、同じ問題が発生しました。さらに、Galaxy Nexusでのみ、このエラーメッセージが表示され、画像が表示されません。最先端のスマートフォンではこのような小さな画像を表示できないのは、とんでもないことのようです。私のHTC Heroはそれを表示できます!私に何ができる?
Zordid

1
ここを参照してくださいロマンの答え:stackoverflow.com/questions/7428996/...
ベン・リー

3
@OllieCギャラリーアプリがどのように実行するかについても知りたいです。したがって、誰かが知っている場合、または大きな画像を表示する例がある場合、それは素晴らしいことです。
Innova 2013年

408

これは質問(2048以上の画像の読み込み)に対する直接の回答ではありませんが、エラーが発生している人には可能な解決策です。

私の場合、画像は両方のサイズ(正確には1280x727)で2048より小さく、この問題はGalaxy Nexusで特に発生しました。画像はdrawableフォルダ内にあり、適格なフォルダはありませんでした。Androidは、密度修飾子のないドローアブルをmdpiであると想定し、他の密度に合わせて拡大または縮小します。この場合、xhdpiの場合は2倍に拡大されます。drawable-nodpi問題のある画像をに移動してスケーリングを防止すると、問題は解決しました。


3
ドローアブルを読み込もうとしてメモリの問題が発生していました。なぜこれが起こっているのかを理解するために2時間を費やしました。間接的な回答をありがとう。
TrueCoke 2013

16
これは正解であり、そのようにマークする必要があります。
wblaschko 2014

3
約3か月半、Androidでほぼフルタイムのプログラミングをしてきましたが、今これに気づきました。drawable基本的に隠しdrawable-mdpiフォルダを作成するのは馬鹿げているようです。これは、カスタムマップマーカーがひどく見えた理由も説明しました(それらは拡大されてから縮小されました)。
theblang 2014

10
うん、一体何だ!Androidプログラマーの99%は、「ドローアブル」は「これをスケーリングしない」という意味だと思っています。
Matt Logan、

3
これは、私がこれまでに見た中で最も役立つ回答です。私が言えることは、賞金を送ることだけです!ありがとう。
Fattie 2016年

105

私はこの方法で画像を縮小しました:

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);

2
おかげで、createScaledBitmapは、大きすぎるビットマップを表示するのに役立ちました
Boy

私の問題を解決しました。実際、私はカメラから画像を撮り、Samsung Galaxy S4のImageViewに4.4.2で表示していました
Mitesh Shah

申し訳ありませんが、「w」とは何なのか
わかり

1
すみません、これctxはどういう意味ですか?
Ameer Sabith

1
@AmeerSabithは、ctxがコンテキストオブジェクトのように見えます(たとえば、実行中のアクティビティ)
Matt

34

このダウンサンプリングコードをすべて手動で記述/デバッグしようとするのに何時間も費やす代わりに、なぜ使用しないのPicassoですか?それはbitmapsすべてのタイプおよび/またはサイズを扱うために作られました。

この1行のコードを使用して、「ビットマップが大きすぎます...」の問題を解決しました。

Picasso.load(resourceId).fit().centerCrop().into(imageView);

resize()を呼び出さずにcenterCrop()を使用すると、IllegalStateExceptionが発生します。中央クロップが使用されている場合、ライブラリはサイズ変更を強制的に呼び出します。
ZsoltBoldizsár2015

トリミングは画像のサイズを変更することを意味するため、これは完全に理にかなっています。
Phileo99

2
高速、簡単、シンプルなソリューション。それが最高かどうかはわかりませんが、欲しいものは手に入りました。どうもありがとうございました
ナビン

より大きなサイズの画像の場合、ピカソでターゲットを使用しても同じエラーが発生します:(
Narendra Singh

バージョン2.5.3-SNAPSHOTを使用してみてください。大きな画像でも正しく機能するようです
Anton Malmygin

20

AndroidManifest.xml)に次の2つの属性を追加するとうまくいきました:

android:largeHeap="true"
android:hardwareAccelerated="false"

これでSamsungデバイスの問題が解決しました。ありがとう
Hitesh Bisht

16

画像ファイルをdrawable-nodpiフォルダからdrawableフォルダに変更することは私にとってはうまくいきました。


これにより、Androidがデバイスのサイズと画面密度に基づいて画像を自動スケーリングしようとするのを防ぎます。これが、このソリューションが機能する理由です。Androidは、drawableフォルダー内のすべてのものを自動スケーリングしようとします。
Chris Cirefice 2017年

10

私はピカソを使用しましたが、同じ問題がありました。画像のサイズ、幅、高さが少なくとも大きすぎます。最後に私はここで解決策を見つけました。大きな画像をディスプレイサイズに合わせて縮小し、アスペクト比を維持することもできます。

    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;
}

このメソッドを使用して、Picassoで画像をロードします。

    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);
}

6

BitmapRegionDecoder トリックを行います。

をオーバーライドしonDraw(Canvas canvas)、新しいスレッドを開始して、ユーザーに表示される領域をデコードできます。


5

Larchoが指摘したように、APIレベル10 BitmapRegionDecoderから、画像から特定の領域を読み込むために使用できます。これにより、必要な領域のみをメモリに割り当てることで、大きな画像を高解像度で表示できます。私は最近、タッチジェスチャ処理で大きな画像の視覚化を提供するライブラリを開発しました。ソースコードとサンプルはこちらから入手できます


3

ビューレベル

次のコードを使用して、実行時に個々のビューのハードウェアアクセラレーションを無効にできます。

myView.setLayerType(View.LAYER_TYPE_SOFTWARE、null);


3

私は同じ問題を経験しました、これが私の解決策です。画像の幅を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画面に適しています。それがあなたのために働くかどうか私に知らせてください。


2

画像を縮小:

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の累乗の値しか取りません。


reqHeightとreqWidthを知る方法は?それを静的な値に修正する必要があるということですか?または、それらのwrtデバイスを変更できますか?
Prashanth Debbadwar 16

2

imageviewに直接ロードする代わりにGlideライブラリを使用する

グライド:https : //github.com/bumptech/glide

Glide.with(this).load(Uri.parse(filelocation))).into(img_selectPassportPic);

2
ピカソの代わりにグライドを使うと助けになった。Glideはデフォルトでこのような問題を処理しているようです
Johnny Five

1

私は上記のすべての解決策を次々と何時間も試しましたが、どれもうまくいかなかったようです!最後に、Androidのカメラで画像をキャプチャして表示することに関する公式の例を探すことにしました。公式の例(ここ)は、最後に機能する唯一の方法を私に与えました。以下に、そのサンプルアプリで見つけたソリューションを示します。

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);
}

0

小さいサイズの画像を入れたい場合の注意:

(にあなたのイメージを移動Pilot_51のソリューションdrawable-nodpiフォルダ)が動作しますが、別の問題があります。それは、画像になりTOO SMALL画像がフィット画面に非常に大きな(X 3800 2000など)の解像度にリサイズされていない限り、画面上を-それは、あなたのアプリが重くなります。

解決策:画像ファイルを入れてくださいdrawable-hdpi-それは私にとって魅力のように機能しました。


1
画像濃度の問題を覆い隠しているだけです。低密度のハードウェアでは、画像が大きく見えます。
16年

また、Pilot_51のソリューションに問題があるとは思わないので、必要に応じて適切な画像サイズを使用する必要があります
Nilabja

0

適切なドローアブルサブフォルダーを使用して解決しました。私のソリューションは、私の中に、フル解像度の画像(1920×1200)を置くことでした描画可能xhdpiの代わりに、フォルダ描画可能なフォルダ。

また、縮小した画像(1280x800)をdrawable-hdpiフォルダーに入れました。

これら2つの解像度は、プログラミングしている2013および2012のNexus 7タブレットと一致します。他のいくつかのタブレットでもソリューションをテストしました。


0
@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);

    }
}

このコードは仕事です

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.