Questa risposta è riassunta da Caricamento efficiente di bitmap di grandi dimensioni
che spiega come utilizzare inSampleSize per caricare una versione bitmap ridotta.
In particolare , le bitmap di pre-ridimensionamento spiegano i dettagli di vari metodi, come combinarli e quali sono i più efficienti in termini di memoria.
Esistono tre modi principali per ridimensionare una bitmap su Android che hanno proprietà di memoria diverse:
API createScaledBitmap
Questa API accetterà una bitmap esistente e creerà una NUOVA bitmap con le dimensioni esatte che hai selezionato.
Tra i lati positivi, puoi ottenere esattamente le dimensioni dell'immagine che stai cercando (indipendentemente da come appare). Ma lo svantaggio è che questa API richiede una bitmap esistente per funzionare . Significa che l'immagine dovrebbe essere caricata, decodificata e creata una bitmap prima di poter creare una nuova versione più piccola. Questo è l'ideale in termini di ottenere le dimensioni esatte, ma orribile in termini di sovraccarico di memoria aggiuntivo. In quanto tale, questo è un po 'un problema per la maggior parte degli sviluppatori di app che tendono ad essere attenti alla memoria
inSampleSize flag
BitmapFactory.Optionsha una proprietà annotata in quanto inSampleSizeridimensionerà l'immagine durante la decodifica, per evitare la necessità di decodificarla in una bitmap temporanea. Questo valore intero usato qui caricherà un'immagine con una dimensione ridotta di 1 / x. Ad esempio, l'impostazione inSampleSizesu 2 restituisce un'immagine che è la metà delle dimensioni e l'impostazione su 4 restituisce un'immagine che è 1/4 della dimensione. Fondamentalmente le dimensioni dell'immagine saranno sempre un po 'più piccole della dimensione della sorgente.
Dal punto di vista della memoria, l'utilizzo inSampleSizeè un'operazione molto veloce. In effetti, decodificherà solo ogni X pixel dell'immagine nella bitmap risultante. Ci sono due problemi principali con inSampleSizeperò:
Non ti dà risoluzioni esatte . Riduce la dimensione della tua bitmap solo di una potenza di 2.
Non produce il ridimensionamento della migliore qualità . La maggior parte dei filtri di ridimensionamento produce immagini di bell'aspetto leggendo blocchi di pixel e quindi pesandoli per produrre il pixel ridimensionato in questione. inSampleSizeevita tutto questo leggendo solo pochi pixel. Il risultato è abbastanza performante e poca memoria, ma la qualità ne risente.
Se hai a che fare solo con la riduzione della tua immagine di alcune dimensioni pow2 e il filtro non è un problema, non puoi trovare un metodo più efficiente in termini di memoria (o prestazioni) di inSampleSize.
Flag inScaled, inDensity, inTargetDensity
Se è necessario ridimensionare l'immagine a una dimensione che non è uguale a una potenza di due, allora è necessario il inScaled, inDensitye inTargetDensitybandiere di BitmapOptions. Quando il inScaledflag è stato impostato, il sistema ricaverà il valore di ridimensionamento da applicare alla bitmap dividendo il inTargetDensityper i inDensityvalori.
mBitmapOptions.inScaled = true;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth;
// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeResources(getResources(),
mImageIDs, mBitmapOptions);
L'utilizzo di questo metodo ridimensionerà l'immagine e applicherà anche un "filtro di ridimensionamento", ovvero il risultato finale avrà un aspetto migliore perché durante la fase di ridimensionamento sono stati presi in considerazione alcuni calcoli aggiuntivi. Ma attenzione: questo passaggio di filtro aggiuntivo richiede tempo di elaborazione aggiuntivo e può sommarsi rapidamente per immagini di grandi dimensioni, con conseguente ridimensionamento lento e allocazioni di memoria extra per il filtro stesso.
In genere non è una buona idea applicare questa tecnica a un'immagine che è significativamente più grande della dimensione desiderata, a causa del sovraccarico di filtraggio extra.
Combinazione magica
Dal punto di vista della memoria e delle prestazioni, puoi combinare queste opzioni per ottenere i migliori risultati. (impostando il inSampleSize, inScaled, inDensitye inTargetDensityle bandiere)
inSampleSizeverrà prima applicato all'immagine, portandola alla successiva potenza di due MAGGIORE rispetto alla dimensione di destinazione. Quindi, inDensity& inTargetDensityvengono utilizzati per ridimensionare il risultato alle dimensioni esatte desiderate, applicando un'operazione di filtro per ripulire l'immagine.
La combinazione di questi due è un'operazione molto più veloce, poiché il inSampleSizepassaggio ridurrà il numero di pixel su cui il passaggio basato sulla densità risultante dovrà applicare il filtro di ridimensionamento.
mBitmapOptions.inScaled = true;
mBitmapOptions.inSampleSize = 4;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth * mBitmapOptions.inSampleSize;
// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeFile(fileName, mBitmapOptions);
Se devi adattare un'immagine a dimensioni specifiche, e un filtro più gradevole, questa tecnica è il miglior ponte per ottenere la dimensione giusta, ma eseguita con un'operazione di impronta di memoria rapida e ridotta.
Ottenere le dimensioni dell'immagine
Ottenere le dimensioni dell'immagine senza decodificare l'intera immagine Per ridimensionare la tua bitmap, dovrai conoscere le dimensioni in arrivo. Puoi utilizzare il inJustDecodeBoundsflag per ottenere le dimensioni dell'immagine, senza dover decodificare effettivamente i dati dei pixel.
// Decode just the boundaries
mBitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(fileName, mBitmapOptions);
srcWidth = mBitmapOptions.outWidth;
srcHeight = mBitmapOptions.outHeight;
//now go resize the image to the size you want
È possibile utilizzare questo flag per decodificare prima la dimensione, quindi calcolare i valori corretti per il ridimensionamento alla risoluzione di destinazione.