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.Options
ha una proprietà annotata in quanto inSampleSize
ridimensionerà 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 inSampleSize
su 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 inSampleSize
però:
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. inSampleSize
evita 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
, inDensity
e inTargetDensity
bandiere di BitmapOptions
. Quando il inScaled
flag è stato impostato, il sistema ricaverà il valore di ridimensionamento da applicare alla bitmap dividendo il inTargetDensity
per i inDensity
valori.
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
, inDensity
e inTargetDensity
le bandiere)
inSampleSize
verrà prima applicato all'immagine, portandola alla successiva potenza di due MAGGIORE rispetto alla dimensione di destinazione. Quindi, inDensity
& inTargetDensity
vengono 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 inSampleSize
passaggio 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 inJustDecodeBounds
flag 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.