Je suis en train de créer une application sociale à forte intensité d'images où les images sont envoyées du serveur à l'appareil. Lorsque l'appareil a des résolutions d'écran plus petites, je dois redimensionner les bitmaps, sur l'appareil, pour correspondre à leurs tailles d'affichage prévues.
Le problème est que l'utilisation de createScaledBitmap me provoque de nombreuses erreurs de mémoire insuffisante après le redimensionnement d'une horde d'images miniatures.
Quel est le moyen le plus efficace de redimensionner les bitmaps sur Android?
android
performance
bitmap
out-of-memory
Colt McAnlis
la source
la source
Réponses:
Il existe trois méthodes dominantes pour redimensionner une image bitmap sur Android qui ont des propriétés de mémoire différentes:
API createScaledBitmap
Cette API prendra un bitmap existant et créera un NOUVEAU bitmap avec les dimensions exactes que vous avez sélectionnées.
Du côté positif, vous pouvez obtenir exactement la taille d'image que vous recherchez (quel que soit son aspect). Mais l'inconvénient est que cette API nécessite un bitmap existant pour fonctionner . Cela signifie que l'image devrait être chargée, décodée et un bitmap créé avant de pouvoir créer une nouvelle version plus petite. C'est idéal pour obtenir vos dimensions exactes, mais horrible en termes de surcharge de mémoire supplémentaire. En tant que tel, c'est une sorte de rupture pour la plupart des développeurs d'applications qui ont tendance à être conscients de leur mémoire
Indicateur inSampleSize
BitmapFactory.Options
a une propriété notée carinSampleSize
cela redimensionnera votre image lors de son décodage, pour éviter d'avoir à décoder en une image bitmap temporaire. Cette valeur entière utilisée ici chargera une image à une taille réduite 1 / x. Par exemple, le réglageinSampleSize
sur 2 renvoie une image qui fait la moitié de la taille et le réglage sur 4 renvoie une image qui fait 1 / 4ème de la taille. Fondamentalement, les tailles d'image seront toujours plus petites que la taille de votre source.Du point de vue de la mémoire, l'utilisation
inSampleSize
est une opération très rapide. En effet, il ne décodera que chaque Xème pixel de votre image dans votre bitmap résultant. Cependant, il y a deux problèmes principauxinSampleSize
:Cela ne vous donne pas de résolutions exactes . Cela ne réduit la taille de votre bitmap que d'une puissance de 2.
Il ne produit pas le meilleur redimensionnement de qualité . La plupart des filtres de redimensionnement produisent de belles images en lisant des blocs de pixels, puis en les pondérant pour produire le pixel redimensionné en question.
inSampleSize
évite tout cela en lisant simplement tous les quelques pixels. Le résultat est assez performant et la mémoire est faible, mais la qualité en souffre.Si vous ne faites que réduire votre image d'une taille pow2 et que le filtrage n'est pas un problème, vous ne pouvez pas trouver de méthode plus efficace en mémoire (ou plus efficace en termes de performances) que
inSampleSize
.Indicateurs inScaled, inDensity, inTargetDensity
Si vous avez besoin de mettre à l'échelle une image à une dimension qui n'est pas égale à une puissance de deux, vous aurez besoin des indicateurs
inScaled
,inDensity
etinTargetDensity
deBitmapOptions
. Une fois l'inScaled
indicateur défini, le système dérivera la valeur de mise à l'échelle à appliquer à votre bitmap en divisant leinTargetDensity
par lesinDensity
valeurs.L'utilisation de cette méthode redimensionnera votre image et lui appliquera également un `` filtre de redimensionnement '', c'est-à-dire que le résultat final sera meilleur car des mathématiques supplémentaires ont été prises en compte lors de l'étape de redimensionnement. Mais attention: cette étape de filtrage supplémentaire prend du temps de traitement supplémentaire et peut rapidement s'additionner pour les grandes images, ce qui entraîne des redimensionnements lents et des allocations de mémoire supplémentaires pour le filtre lui-même.
Ce n'est généralement pas une bonne idée d'appliquer cette technique à une image beaucoup plus grande que la taille souhaitée, en raison de la surcharge de filtrage supplémentaire.
Combinaison magique
Du point de vue de la mémoire et des performances, vous pouvez combiner ces options pour obtenir les meilleurs résultats. (réglage de la
inSampleSize
,inScaled
,inDensity
etinTargetDensity
drapeaux)inSampleSize
sera d'abord appliqué à l'image, l'amenant à la prochaine puissance de deux PLUS GRANDE que votre taille cible. Ensuite,inDensity
&inTargetDensity
sont utilisés pour mettre à l'échelle le résultat aux dimensions exactes que vous souhaitez, en appliquant une opération de filtre pour nettoyer l'image.La combinaison de ces deux éléments est une opération beaucoup plus rapide, car l'
inSampleSize
étape réduira le nombre de pixels dont l'étape basée sur la densité résultante aura besoin pour appliquer son filtre de redimensionnement.Si vous avez besoin d'adapter une image à des dimensions spécifiques et d' un filtrage plus agréable, cette technique est le meilleur pont pour obtenir la bonne taille, mais effectuée dans une opération rapide et à faible encombrement mémoire.
Obtenir les dimensions de l'image
Obtenir la taille de l'image sans décoder l'image entière Pour redimensionner votre bitmap, vous aurez besoin de connaître les dimensions entrantes. Vous pouvez utiliser l'
inJustDecodeBounds
indicateur pour vous aider à obtenir les dimensions de l'image, sans avoir besoin de décoder réellement les données de pixel.Vous pouvez utiliser cet indicateur pour décoder d'abord la taille, puis calculer les valeurs appropriées pour la mise à l'échelle en fonction de votre résolution cible.
la source
destination width
ou dstWidth pour faire courtAussi agréable (et précise) que soit cette réponse, elle est également très compliquée. Plutôt que de réinventer la roue, pensez à des bibliothèques comme Glide , Picasso , UIL , Ion ou tout autre qui implémentent cette logique complexe et sujette aux erreurs pour vous.
Colt lui-même recommande même de jeter un coup d'œil à Glide et Picasso dans la vidéo des modèles de performances Bitmaps de pré-mise à l'échelle .
En utilisant des bibliothèques, vous pouvez obtenir toute l'efficacité mentionnée dans la réponse de Colt, mais avec des API beaucoup plus simples qui fonctionnent de manière cohérente sur toutes les versions d'Android.
la source