“Bitmap terlalu besar untuk diunggah ke dalam tekstur”

154

Saya memuat bitmap ke ImageView, dan melihat kesalahan ini. Saya mengumpulkan batas ini berkaitan dengan batas ukuran untuk tekstur perangkat keras OpenGL (2048x2048). Gambar yang saya perlu memuat adalah gambar pinch-zoom sekitar 4.000 piksel.

Saya sudah mencoba mematikan akselerasi perangkat keras dalam manifes, tetapi tidak ada sukacita.

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

Apakah mungkin memuat gambar yang lebih besar dari 2048 piksel ke dalam ImageView?

Ollie C
sumber
1
Bagi siapa pun yang mencari di sini, jangan lupa untuk menempatkan gambar Anda dalam tampilan gulir jika Anda ingin digulir. Itu akan menghilangkan kesalahan. Saya membuang-buang waktu sebelum menyadari bahwa itu adalah masalah saya.
Jason Ridge
Bagi siapa pun yang ingin menampilkan gambar besar masih menjaga kualitas gambar, lihat perpustakaan di @stoefln jawaban di bawah ini. Saya menggunakannya dan patut dicoba. Jelas lebih baik daripada inSampleSizependekatan.
Mahendra Liya
1
@ Joan Tiup jawaban saat ini tidak berfungsi dalam kasus Anda? Jika tidak, mohon uraikan masalah yang Anda hadapi dalam konteks pertanyaan ini?
Pravin Divraniya
1
hey @ VC.One - ini adalah hal yang aneh untuk dikerjakan tentang laki-laki saya. Saya seharusnya mengklik "Hadiah jawaban yang ada". Tidak ada yang mengganggu menekan tombol "terbaik" pada SO popup itu, karena itu konyol :) Semuanya diselesaikan sekarang ketika saya mengklik bounty. Bersulang!!
Fattie
1
Saya mencoba untuk selalu membayar hadiah (saya tidak suka mengumpulkan poin). Saya kira, jika Anda mengklik profil saya, maka bounty, @ VC. Seseorang akan melihat banyak QA yang sangat bagus dari SO selama bertahun-tahun !!!!!!!!!!!!!!!
Fattie

Jawaban:

48

Semua rendering didasarkan pada OpenGL, jadi tidak Anda tidak dapat melampaui batas ini ( GL_MAX_TEXTURE_SIZEtergantung pada perangkat, tetapi minimum adalah 2048x2048, sehingga gambar yang lebih rendah dari 2048x2048 akan sesuai).

Dengan gambar besar seperti itu, jika Anda ingin memperbesar, dan di ponsel, Anda harus menyiapkan sistem yang mirip dengan apa yang Anda lihat di google maps misalnya. Dengan gambar terpecah menjadi beberapa bagian, dan beberapa definisi.

Atau Anda dapat memperkecil gambar sebelum menampilkannya (lihat jawaban user1352407 pada pertanyaan ini).

Dan juga, berhati-hatilah dengan folder tempat Anda meletakkan gambar, Android dapat secara otomatis memperbesar gambar. Silahkan lihat pada jawaban Pilot_51 ini di bawah pertanyaan ini.

jptsetung
sumber
23
Jika ini masalahnya, bagaimana aplikasi Galeri memungkinkan tampilan dan manipulasi gambar yang diambil dengan kamera? 2048x2048 hanya berupa gambar 4MP, dan banyak ponsel Android mengambil foto yang jauh lebih besar dari ini dan aplikasi Galeri tampaknya tidak memiliki masalah.
Ollie C
3
Karena GL_MAX_TEXTURE_SIZE tergantung pada perangkat.
jptsetung
24
Ini benar-benar tidak masuk akal. Saya mengalami masalah yang sama sekarang - dengan gambar 1286x835 piksel. DAN: hanya pada Galaxy Nexus saya mendapatkan pesan kesalahan ini dan tidak ada gambar! Kelihatannya konyol bahwa smartphone kelas atas tidak dapat menampilkan gambar sekecil ini! Pahlawan HTC saya mampu menampilkan itu! Apa yang dapat saya?
Zordid
1
Lihat jawaban Romain di sini: stackoverflow.com/questions/7428996/…
Ben Lee
3
@OllieC Saya juga ingin tahu bagaimana aplikasi galeri melakukannya. Jadi kalau ada yang tahu, atau punya contoh untuk menampilkan gambar besar, itu akan bagus.
Innova
408

Ini bukan jawaban langsung untuk pertanyaan (memuat gambar> 2048), tetapi solusi yang mungkin bagi siapa pun yang mengalami kesalahan.

Dalam kasus saya, gambar lebih kecil dari 2048 di kedua dimensi (tepatnya 1280x727) dan masalah ini secara khusus dialami pada Galaxy Nexus. Gambar ada di drawablefolder dan tidak ada folder yang memenuhi syarat. Android menganggap drawable tanpa kualifikasi kepadatan adalah mdpi dan menskalakannya ke atas atau ke bawah untuk kepadatan lainnya, dalam hal ini ditingkatkan 2x untuk xhdpi. Memindahkan gambar pelakunya ke drawable-nodpiuntuk mencegah penskalaan menyelesaikan masalah.

Pilot_51
sumber
3
Saya mengalami masalah memori saat mencoba memuat drawable. Menghabiskan 2 jam mencoba memahami mengapa ini terjadi. Terima kasih atas jawaban tidak langsungnya.
TrueCoke
16
Ini adalah jawaban yang benar dan harus ditandai seperti itu.
wblaschko
3
Sekitar tiga setengah bulan sekarang saya telah memprogram hampir penuh waktu di Android dan saya baru menyadari hal ini. Tampaknya bodoh untuk membuat folder yang drawabletersembunyi drawable-mdpi. Ini juga menjelaskan mengapa spidol peta khusus saya tampak buruk (mereka ditingkatkan, kemudian diturunkan).
theblang
10
ya apa-apaan! Saya pikir 99% programmer Android berpikir "drawable" berarti "jangan skala ini".
Matt Logan
3
Ini adalah jawaban paling bermanfaat yang pernah saya lihat, di mana saja. Yang bisa saya katakan adalah saya mengirim hadiah! TERIMA KASIH.
Fattie
105

Saya telah memperkecil gambar dengan cara ini:

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);
pengguna1352407
sumber
2
terima kasih, createScaledBitmap sangat membantu bagi saya untuk dapat menunjukkan bitmap yang terlalu besar
Boy
Memecahkan masalah saya .. terima kasih. Sebenarnya saya mengambil gambar dari kamera dan ditampilkan di ImageView di Samsung Galaxy S4 dengan 4.4.2
Mitesh Shah
maaf, tapi saya tidak dapat mendeteksi apa yang "w"
Bobbelinio
1
Maaf, apa ctxartinya ini ?
Ameer Sabith
1
@AmeerSabith sepertinya ctx adalah objek Konteks (Aktivitas menjalankan Anda misalnya)
Matt
34

Alih-alih menghabiskan berjam-jam mencoba menulis / men-debug semua kode downsampling ini secara manual, mengapa tidak menggunakan Picasso? Itu dibuat untuk berurusan dengan bitmapssemua jenis dan / atau ukuran.

Saya telah menggunakan satu baris kode ini untuk menghapus masalah "bitmap terlalu besar ...." saya :

Picasso.load(resourceId).fit().centerCrop().into(imageView);
Phileo99
sumber
Menggunakan centerCrop () tanpa memanggil ulang ukuran () akan menghasilkan IllegalStateException. Perpustakaan memaksa untuk memanggil ukuran ketika pusat tanaman digunakan.
Zsolt Boldizsár
Itu masuk akal, karena memotong menyiratkan bahwa Anda mengubah ukuran gambar.
Phileo99
2
Solusi cepat, mudah dan sederhana. Tidak yakin apakah itu yang terbaik, tetapi saya mendapatkan apa yang saya inginkan. Terima kasih banyak
Nabin
masih mendapatkan kesalahan yang sama ketika menggunakan target dengan Picasso, untuk gambar berukuran lebih besar :(
Narendra Singh
Coba gunakan versi 2.5.3-SNAPSHOT, sepertinya sekarang berfungsi dengan benar dengan gambar besar
Anton Malmygin
20

Tambahan 2 atribut berikut di ( AndroidManifest.xml) bekerja untuk saya:

android:largeHeap="true"
android:hardwareAccelerated="false"
Sachin Lala
sumber
Ini memperbaiki masalah saya di perangkat Samsung. Terima kasih
Hitesh Bisht
16

Mengubah file gambar ke drawable-nodpifolder dari drawablefolder bekerja untuk saya.

Asha Antony
sumber
Ini akan mencegah Android dari mencoba skala gambar secara otomatis berdasarkan dimensi perangkat dan kepadatan layar; inilah mengapa solusi ini bekerja. Android akan mencoba skala apa pun di drawablefolder secara otomatis.
Chris Cirefice
10

Saya menggunakan Picasso dan memiliki masalah yang sama. gambar terlalu besar setidaknya dalam ukuran, lebar atau tinggi. akhirnya saya menemukan solusinya di sini. Anda dapat menurunkan skala gambar besar sesuai dengan ukuran layar dan juga menjaga aspek rasio:

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

dan gunakan metode ini untuk memuat gambar oleh 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);

juga untuk kinerja yang lebih baik Anda dapat mengunduh gambar sesuai dengan lebar dan tinggi layar tampilan, bukan keseluruhan gambar:

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

lalu:

    Picasso.with(this)
                .load(newImageUlr)
                .resize(size, size)
                .centerInside()
                .into(imageViewd);

EDIT: getDisplaySize ()

display.getWidth()/getHeight()sudah ditinggalkan. Alih-alih Displaydigunakan DisplayMetrics.

public Point getDisplaySize(DisplayMetrics displayMetrics) {
        int width = displayMetrics.widthPixels;
        int height = displayMetrics.heightPixels;
        return new Point(width, height);
}
Sherry
sumber
6

BitmapRegionDecoder lakukan triknya.

Anda dapat mengesampingkan onDraw(Canvas canvas), memulai Thread baru dan mendekode area yang terlihat oleh pengguna.

Larcho
sumber
5

Seperti yang ditunjukkan oleh Larcho, mulai dari API level 10, Anda dapat menggunakan BitmapRegionDecoderuntuk memuat wilayah tertentu dari suatu gambar dan dengan itu, Anda dapat menyelesaikan untuk menampilkan gambar besar dalam resolusi tinggi dengan mengalokasikan dalam memori hanya wilayah yang dibutuhkan. Baru-baru ini saya mengembangkan lib yang menyediakan visualisasi gambar besar dengan penanganan gerakan sentuh. Kode sumber dan sampel tersedia di sini .

diegocarloslima
sumber
3

Lihat level

Anda dapat menonaktifkan akselerasi perangkat keras untuk tampilan individual saat runtime dengan kode berikut:

myView.setLayerType (View.LAYER_TYPE_SOFTWARE, null);

marveson
sumber
3

Saya mengalami masalah yang sama, ini solusi saya. atur lebar gambar sama dengan lebar layar android dan kemudian timbang tingginya

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

Ini lebih baik untuk ukuran layar Android apa pun. beri tahu saya jika itu berhasil untuk Anda.

Abhijit Gujar
sumber
2

Perkecil gambar:

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

Gambar akan diperkecil pada ukuran reqHeight dan reqWidth. Seperti yang saya mengerti inSampleSize hanya mengambil kekuatan 2 nilai.

vtlinh
sumber
bagaimana cara mengetahui reqHight dan reqWidth? Maksud saya, apakah kita perlu memperbaikinya ke nilai statis? atau kita dapat mengubah perangkat wrt itu?
Prashanth Debbadwar
2

Gunakan pustaka Glide alih-alih langsung memuat ke tampilan gambar

Glide: https://github.com/bumptech/glide

Glide.with(this).load(Uri.parse(filelocation))).into(img_selectPassportPic);
Sai Gopi N
sumber
2
Menggunakan Glide bukannya Picasso membantu. Sepertinya Glide menangani masalah seperti itu secara default
Johnny Five
1

Saya mencoba semua solusi di atas, satu demi satu, selama beberapa jam, dan sepertinya tidak ada yang berhasil! Akhirnya, saya memutuskan untuk mencari-cari contoh resmi tentang pengambilan gambar dengan kamera Android, dan menampilkannya. Contoh resmi (di sini ), akhirnya memberi saya satu-satunya metode yang berhasil. Di bawah ini saya menyajikan solusi yang saya temukan di aplikasi contoh itu:

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);
}
nemesisfixx
sumber
0

CATATAN UNTUK MEREKA YANG INGIN MEMASANG GAMBAR UKURAN KECIL:

Solusi Pilot_51 (memindahkan gambar Anda ke drawable-nodpifolder) berfungsi, tetapi memiliki masalah lain: Itu membuat gambar TERLALU KECIL di layar kecuali gambar diubah ukurannya menjadi resolusi yang sangat besar (seperti 2000 x 3800) agar sesuai dengan layar - kemudian membuat aplikasi Anda lebih berat .

SOLUSI : letakkan file gambar Anda di drawable-hdpi- Ini bekerja seperti pesona bagi saya.

mudah
sumber
1
Anda hanya menutupi masalah kepadatan gambar Anda. Pada perangkat keras dengan kepadatan rendah gambar Anda akan terlihat lebih besar.
Rupp
saya juga tidak berpikir bahwa solusi Pilot_51 memiliki masalah, Anda harus menggunakan ukuran gambar yang sesuai sesuai kebutuhan Anda
Nilabja
0

Menggunakan benar ditarik subfolder dipecahkan itu untuk saya. Solusi saya adalah untuk menempatkan gambar resolusi penuh saya (1920x1200) ke dalam ditarik-xhdpi folder, bukan ditarik folder.

Saya juga meletakkan gambar yang diperkecil (1280x800) ke drawable-hdpi folder .

Kedua resolusi ini cocok dengan program Nexus 7 tablet 2013 dan 2012 yang saya pemrograman. Saya juga menguji solusinya pada beberapa tablet lain.

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

    }
}

Kode ini berfungsi

Alobaidi
sumber