"Bitmap troppo grande per essere caricato in una trama"


154

Sto caricando una bitmap in ImageView e vedo questo errore. Raccolgo questo limite si riferisce a un limite di dimensione per le trame hardware OpenGL (2048x2048). L'immagine che devo caricare è un'immagine zoom con pizzico di circa 4.000 pixel di altezza.

Ho provato a disattivare l'accelerazione hardware nel manifest, ma nessuna gioia.

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

È possibile caricare un'immagine più grande di 2048 pixel in un ImageView?


1
Per chiunque cerchi qui, non dimenticare di mettere la tua immagine in una vista di scorrimento se vuoi che sia scorrevole. Questo eliminerà l'errore. Ho perso un po 'di tempo prima di rendermi conto che era il mio problema.
Jason Ridge,

Per tutti coloro che desiderano visualizzare immagini di grandi dimensioni mantenendo comunque la qualità dell'immagine, consultare la libreria nella risposta @stoefln di seguito. L'ho usato e vale la pena provare. Decisamente meglio inSampleSizedell'approccio.
Mahendra Liya,

1
@Joe Blow la risposta attuale non ha funzionato nel tuo caso? In caso negativo, ti preghiamo di approfondire la questione che hai affrontato nel contesto di questa domanda?
Pravin Divraniya,

1
hey @ VC.One - è una cosa strana essere sconvolto per il mio uomo. Avrei dovuto fare clic su "Ricompensa risposta esistente". Nessuno si preoccupa noiosamente di premere il pulsante "migliore" su quel popup SO, perché è sciocco :) Ora è tutto risolto mentre facevo clic sulla taglia. Saluti!!
Fattie,

1
Cerco di pagare sempre taglie (non mi piace raccogliere punti). Immagino, se fai clic sul mio profilo, quindi taglie, @ VC.Uno vedrai molti QA davvero eccezionali da SO negli anni !!!!!!!!!!!!!!!
Fattie,

Risposte:


48

Tutto il rendering si basa su OpenGL, quindi non puoi superare questo limite ( GL_MAX_TEXTURE_SIZEdipende dal dispositivo, ma il minimo è 2048x2048, quindi qualsiasi immagine inferiore a 2048x2048 si adatta).

Con immagini così grandi, se vuoi ingrandire, e su un dispositivo mobile, dovresti configurare un sistema simile a quello che vedi su Google Maps, ad esempio. Con l'immagine divisa in più pezzi e diverse definizioni.

Oppure puoi ridimensionare l'immagine prima di visualizzarla (vedi la risposta dell'utente1352407 su questa domanda).

Inoltre, fai attenzione alla cartella in cui metti l'immagine, Android può ridimensionare automaticamente le immagini. Dai un'occhiata alla risposta di Pilot_51 qui sotto su questa domanda.


23
In tal caso, in che modo l'app Galleria consente la visualizzazione e la manipolazione delle immagini scattate con la fotocamera? 2048x2048 è solo un'immagine da 4 MP e molti telefoni Android scattano foto molto più grandi di questa e l'app Galleria non sembra avere problemi.
Ollie C

3
Perché GL_MAX_TEXTURE_SIZE dipende dal dispositivo.
jptsetung,

24
Questo non ha davvero alcun senso. Ho riscontrato lo stesso problema ora, con un'immagine di 1286x835 pixel. E: solo su un Galaxy Nexus ricevo questo messaggio di errore e nessuna immagine! Sembra ridicolo che uno smartphone top-of-the-edge non sia in grado di visualizzare un'immagine così piccola! Il mio HTC Hero è in grado di visualizzarlo! Cosa posso fare?
Zordid,

1
Vedi la risposta di Romain qui: stackoverflow.com/questions/7428996/…
Ben Lee

3
@OllieC Vorrei anche sapere come lo fanno le app della galleria. Quindi, se qualcuno lo sa, o ha un esempio per mostrare immagini di grandi dimensioni, sarebbe fantastico.
Innova,

408

Questa non è una risposta diretta alla domanda (caricamento di immagini> 2048), ma una possibile soluzione per chiunque abbia riscontrato l'errore.

Nel mio caso, l'immagine era più piccola del 2048 in entrambe le dimensioni (1280x727 per l'esattezza) e il problema era stato riscontrato in modo specifico su un Galaxy Nexus. L'immagine era nella drawablecartella e nessuna delle cartelle qualificate. Android presuppone che i drawable senza un qualificatore di densità siano mdpi e li ridimensioni su o giù per altre densità, in questo caso ridimensionati di 2x per xhdpi. Spostare l'immagine del colpevole drawable-nodpiper evitare il ridimensionamento ha risolto il problema.


3
Ho riscontrato problemi di memoria durante il tentativo di caricare i disegni. Ho trascorso 2 ore cercando di capire perché questo stesse accadendo. Grazie per la risposta indiretta.
TrueCoke il

16
Questa è la risposta corretta e deve essere contrassegnata come tale.
wblaschko,

3
Sono circa tre mesi e mezzo che sto programmando quasi a tempo pieno su Android e proprio ora me ne sono reso conto. Sembra stupido per rendere drawableessenzialmente una drawable-mdpicartella nascosta . Ciò ha anche spiegato il motivo per cui i miei indicatori di mappa personalizzati sembravano orribili (venivano ingranditi, quindi ridimensionati).
theblang

10
si che diavolo! penso che il 99% dei programmatori Android pensi che "disegnabile" significhi "non ridimensionare".
Matt Logan,

3
Questa è la risposta più utile che abbia mai visto, ovunque. Tutto quello che posso dire è che sto inviando una taglia! GRAZIE.
Fattie,

105

Ho ridimensionato l'immagine in questo modo:

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
grazie, createScaledBitmap mi è stato utile per poter mostrare una bitmap troppo grande
Ragazzo

Risolto il mio problema .. grazie. In realtà stavo prendendo l'immagine dalla fotocamera e la visualizzazione in ImageView in Samsung Galaxy S4 con 4.4.2
Mitesh Shah,

scusa, ma non riesco a rilevare cosa sia "w"
Bobbelinio

1
Scusa, cosa ctxsignifica?
Ameer Sabith,

1
@AmeerSabith sembra che ctx sia un oggetto Context (ad esempio l'attività in esecuzione)
Matt

34

Invece di passare ore e ore a cercare di scrivere / eseguire il debug di tutto questo codice di downsampling manualmente, perché non utilizzarlo Picasso? È stato creato per affrontarebitmaps tutti i tipi e / o dimensioni.

Ho usato questa singola riga di codice per rimuovere il mio problema "bitmap troppo grande ...." :

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

L'uso di centerCrop () senza chiamare resize () si tradurrà in IllegalStateException. La libreria forza a chiamare il ridimensionamento quando viene utilizzato il ritaglio centrale.
Zsolt Boldizsár,

Questo ha perfettamente senso, perché il ritaglio implica che stai ridimensionando l'immagine.
Phileo99,

2
Soluzione rapida, facile e semplice. Non sono sicuro che sia il migliore, ma ho ottenuto quello che volevo. Grazie mille
Nabin

continua a ottenere lo stesso errore quando viene utilizzato il target con Picasso, per le immagini di dimensioni maggiori :(
Narendra Singh

Prova a utilizzare la versione 2.5.3-SNAPSHOT, sembra che ora funzioni correttamente con immagini di grandi dimensioni
Anton Malmygin,

20

L'aggiunta dei seguenti 2 attributi in ( AndroidManifest.xml) ha funzionato per me:

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

Questo risolto il mio problema sul dispositivo Samsung. Grazie
Hitesh Bisht il

16

Cambiare il file immagine in una drawable-nodpicartella dalla drawablecartella ha funzionato per me.


Ciò impedirà ad Android di provare a ridimensionare automaticamente l'immagine in base alle dimensioni del dispositivo e alla densità dello schermo; ecco perché questa soluzione funziona. Android proverà a ridimensionare automaticamente qualsiasi cosa nella drawablecartella.
Chris Cirefice,

10

Ho usato Picasso e ho avuto lo stesso problema. l'immagine era troppo grande almeno per dimensioni, larghezza o altezza. finalmente ho trovato la soluzione qui. puoi ridimensionare l'immagine grande in base alle dimensioni del display e anche mantenere le proporzioni:

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

e utilizza questo metodo per caricare l'immagine di 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);

inoltre, per prestazioni migliori, è possibile scaricare l'immagine in base alla larghezza e all'altezza dello schermo, non dell'intera immagine:

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

e poi:

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

EDIT: getDisplaySize ()

display.getWidth()/getHeight()è deprecato. Invece di Displayusare DisplayMetrics.

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

6

BitmapRegionDecoder fa il trucco.

Puoi ignorare onDraw(Canvas canvas), avviare un nuovo thread e decodificare l'area visibile all'utente.


5

Come indicato da Larcho, a partire dal livello API 10, è possibile utilizzare BitmapRegionDecoderper caricare aree specifiche da un'immagine e, con ciò, è possibile ottenere di mostrare un'immagine di grandi dimensioni in alta risoluzione allocando in memoria solo le aree necessarie. Di recente ho sviluppato una libreria che fornisce la visualizzazione di immagini di grandi dimensioni con la gestione dei gesti tattili. Il codice sorgente e gli esempi sono disponibili qui .


3

Visualizza livello

È possibile disabilitare l'accelerazione hardware per una singola vista in fase di esecuzione con il seguente codice:

myView.setLayerType (View.LAYER_TYPE_SOFTWARE, null);


3

Ho riscontrato lo stesso problema, ecco la mia soluzione. imposta la larghezza dell'immagine uguale alla larghezza dello schermo Android e quindi ridimensiona l'altezza

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

Questo è meglio per schermi Android di qualsiasi dimensione. fammi sapere se funziona per te.


2

Riduci immagine:

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

L'immagine verrà ridimensionata alla dimensione di reqHeight e reqWidth. Come ho capito in SampleSize, accetta solo una potenza di 2 valori.


come sapere reqHeight e reqWidth? Voglio dire, dobbiamo ripararlo su un valore statico? o possiamo cambiare quei dispositivi wrt?
Prashanth Debbadwar,

2

Usa la libreria Glide invece di caricarla direttamente in imageview

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

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

2
L'uso di Glide al posto di Picasso ha aiutato. Sembra che Glide gestisca questi problemi per impostazione predefinita
Johnny Five,

1

Ho provato tutte le soluzioni sopra, una dopo l'altra, per parecchie ore, e nessuna sembrava funzionare! Alla fine, ho deciso di cercare un esempio ufficiale riguardante l'acquisizione di immagini con la fotocamera di Android e la loro visualizzazione. L'esempio ufficiale ( qui ), infine, mi ha dato l'unico metodo che ha funzionato. Di seguito presento la soluzione che ho trovato in quell'app di esempio:

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

NOTA PER CHI DESIDERA INSERIRE IMMAGINI DI PICCOLE DIMENSIONI:

La soluzione di Pilot_51 (muovendo le immagini in drawable-nodpicartelle) funziona, ma ha un altro problema: Rende le immagini TROPPO PICCOLO sullo schermo a meno che le immagini non vengano ridimensionate a una risoluzione molto grande (come 2000 x 3800) per adattarsi allo schermo - quindi rende l'app più pesante .

SOLUZIONE : inserisci i tuoi file di immagini drawable-hdpi- Per me ha funzionato come un incantesimo.


1
Stai solo mascherando il tuo problema di densità dell'immagine. Su hardware a bassa densità, le immagini appariranno più grandi.
Rupps,

inoltre non penso che la soluzione di Pilot_51 abbia problemi, dovresti usare le dimensioni dell'immagine appropriate secondo le tue esigenze
Nilabja,

0

Usando la sottocartella disegnabile corretta risolto per me. La mia soluzione era quella di mettere la mia immagine a piena risoluzione (1920x1200) nella cartella drawable-xhdpi , anziché nella cartella drawable .

Ho anche inserito un'immagine ridotta (1280x800) nella cartella drawable-hdpi .

Queste due risoluzioni corrispondono ai tablet Nexus 7 2013 e 2012 che sto programmando. Ho anche testato la soluzione su alcuni altri tablet.


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

    }
}

Questo codice funziona

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.