J'ai une grande image bitmap (disons 3888x2592) dans un fichier. Maintenant, je veux redimensionner ce bitmap en 800x533 et l'enregistrer dans un autre fichier. Normalement, je redimensionnerais le bitmap en appelant la Bitmap.createBitmap
méthode, mais il a besoin d'un bitmap source comme premier argument, que je ne peux pas fournir car le chargement de l'image d'origine dans un objet Bitmap dépasserait bien sûr la mémoire (voir ici , par exemple).
Je ne peux pas non plus lire le bitmap avec, par exemple, BitmapFactory.decodeFile(file, options)
en fournissant un BitmapFactory.Options.inSampleSize
, car je veux le redimensionner à une largeur et une hauteur exactes. Utiliser inSampleSize
redimensionnerait le bitmap à 972x648 (si j'utilise inSampleSize=4
) ou à 778x518 (si j'utilise inSampleSize=5
, ce qui n'est même pas une puissance de 2).
Je voudrais également éviter de lire l'image en utilisant inSampleSize avec, par exemple, 972x648 dans une première étape, puis la redimensionner exactement à 800x533 dans une deuxième étape, car la qualité serait médiocre par rapport à un redimensionnement direct de l'image d'origine.
Pour résumer ma question: existe-t-il un moyen de lire un fichier image volumineux avec 10MP ou plus et de l'enregistrer dans un nouveau fichier image, redimensionné à une nouvelle largeur et hauteur spécifique, sans obtenir une exception OutOfMemory?
J'ai également essayé BitmapFactory.decodeFile(file, options)
et défini manuellement les valeurs Options.outHeight et Options.outWidth sur 800 et 533, mais cela ne fonctionne pas de cette façon.
Réponses:
Non . J'aimerais que quelqu'un me corrige, mais j'ai accepté l'approche de chargement / redimensionnement que vous avez essayée comme compromis.
Voici les étapes pour toute personne naviguant:
inSampleSize
qui donne toujours une image plus grande que votre cible.BitmapFactory.decodeFile(file, options)
, en passant inSampleSize en option.Bitmap.createScaledBitmap()
.la source
Réponse de Justin traduite en code (fonctionne parfaitement pour moi):
la source
System.gc()
Il s'agit des solutions «combinées» de Mojo Risin et «Ofir». Cela vous donnera une image redimensionnée proportionnellement avec les limites de la largeur maximale et de la hauteur maximale.
Pour moi, il a bien fonctionné sur les images de 5 mégapixels et ci-dessous.
la source
Pourquoi ne pas utiliser l'API?
la source
Reconnaissant l'autre excellente réponse jusqu'à présent, le meilleur code que j'ai vu à ce jour se trouve dans la documentation de l'outil de prise de photo.
Voir la section intitulée "Décoder une image mise à l'échelle".
http://developer.android.com/training/camera/photobasics.html
La solution qu'elle propose est une solution de redimensionnement puis de mise à l'échelle comme les autres ici, mais c'est assez soigné.
J'ai copié le code ci-dessous comme une fonction prête à l'emploi pour plus de commodité.
la source
Après avoir lu ces réponses et la documentation Android, voici le code pour redimensionner le bitmap sans le charger en mémoire:
la source
Lorsque j'ai de grandes images bitmap et que je veux les décoder redimensionnées, j'utilise ce qui suit
la source
Cela peut être utile pour quelqu'un d'autre qui examine cette question. J'ai réécrit le code de Justin pour permettre à la méthode de recevoir également l'objet de taille cible requis. Cela fonctionne très bien lors de l'utilisation de Canvas. Tout le mérite devrait revenir à JUSTIN pour son excellent code initial.
Le code de Justin est TRÈS efficace pour réduire la surcharge de travail avec de grands bitmaps.
la source
Je ne sais pas si ma solution est la meilleure pratique, mais j'ai réussi à charger une image bitmap avec la mise à l'échelle souhaitée en utilisant les options
inDensity
etinTargetDensity
.inDensity
est0
initialement lorsque vous ne chargez pas une ressource pouvant être dessinée, cette approche consiste donc à charger des images sans ressource.Les variables
imageUri
,maxImageSideLength
etcontext
sont des paramètres de ma méthode. J'ai publié uniquement l'implémentation de la méthode sans le wrapper AsyncTask pour plus de clarté.la source
Étant donné que vous souhaitez redimensionner à la taille exacte et que vous souhaitez conserver autant de qualité que nécessaire, je pense que vous devriez essayer cela.
Motivation: la mise à l'échelle en plusieurs étapes peut vous donner une image de meilleure qualité, mais il n'y a aucune garantie que cela fonctionnera mieux que d'utiliser une taille inSampleSize élevée. En fait, je pense que vous pouvez également utiliser inSampleSize comme 5 (pas une puissance de 2) pour avoir une mise à l'échelle directe en une seule opération. Ou utilisez simplement 4 et vous pouvez simplement utiliser cette image dans l'interface utilisateur. si vous l'envoyez au serveur - vous pouvez faire une mise à l'échelle à la taille exacte côté serveur qui vous permet d'utiliser des techniques de mise à l'échelle avancées.
Remarques: si le bitmap chargé à l'étape 3 est au moins 4 fois plus grand (donc le 4 * targetWidth <width), vous pouvez probablement utiliser plusieurs redimensionnements pour obtenir une meilleure qualité. au moins cela fonctionne en java générique, dans android vous n'avez pas la possibilité de spécifier l'interpolation utilisée pour la mise à l'échelle http://today.java.net/pub/a/today/2007/04/03/perils-of- image-getscaledinstance.html
la source
J'ai utilisé du code comme celui-ci:
J'ai essayé l'image d'origine est 1230 x 1230, et le bitmap dit est 330 x 330.
Et si essayé 2590 x 3849, je vais avoir OutOfMemoryError.
Je l'ai tracé, il lance toujours OutOfMemoryError sur la ligne "BitmapFactory.decodeStream (is, null, options);", si le bitmap d'origine est trop grand ...
la source
Le code ci-dessus a rendu un peu plus propre. InputStreams a finalement fermé l'habillage pour s'assurer qu'il se ferme également:
* Remarque
Entrée: InputStream est, int w, int h
Sortie: Bitmap
la source
Pour redimensionner l'image de la manière "correcte", sans sauter aucun pixel, vous devez vous connecter au décodeur d'image pour effectuer le sous-échantillonnage ligne par ligne. Android (et la bibliothèque Skia qui le sous-tend) ne fournit pas de tels crochets, vous devez donc rouler le vôtre. En supposant que vous parlez d'images jpeg, votre meilleur pari serait d'utiliser libjpeg directement, en C.
Compte tenu des complexités impliquées, l'utilisation du sous-échantillon en deux étapes puis de la mise à l'échelle est probablement la meilleure pour les applications de type prévisualisation d'image.
la source
Voici un article qui adopte une approche différente du redimensionnement. Il tentera de charger le plus grand bitmap possible en mémoire en fonction de la mémoire disponible dans le processus, puis effectuera les transformations.
http://bricolsoftconsulting.com/2012/12/07/handling-large-images-on-android/
la source
Si vous voulez absolument faire un redimensionnement en une étape, vous pouvez probablement charger l'intégralité du bitmap si android: largeHeap = true mais comme vous pouvez le voir, ce n'est pas vraiment conseillé.
De docs: android: largeHeap Si les processus de votre application doivent être créés avec un grand tas Dalvik. Cela s'applique à tous les processus créés pour l'application. Elle ne s'applique qu'à la première application chargée dans un processus; si vous utilisez un ID utilisateur partagé pour autoriser plusieurs applications à utiliser un processus, elles doivent toutes utiliser cette option de manière cohérente sinon elles auront des résultats imprévisibles. La plupart des applications ne devraient pas en avoir besoin et devraient plutôt se concentrer sur la réduction de leur utilisation globale de la mémoire pour de meilleures performances. L'activation de cela ne garantit pas non plus une augmentation fixe de la mémoire disponible, car certains appareils sont limités par leur mémoire totale disponible.
la source
Il y a un excellent article sur ce problème exact sur le site Web du développeur Android: Chargement efficace de grands bitmaps
la source
Cela a fonctionné pour moi. La fonction obtient un chemin d'accès à un fichier sur la carte SD et renvoie un bitmap dans la taille maximale affichable. Le code est d'Ofir avec quelques changements comme le fichier image sur sd au lieu d'une Ressource et le witdth et heigth sont obtenus à partir de l'objet d'affichage.
la source
Voici le code que j'utilise qui n'a aucun problème à décoder de grandes images en mémoire sur Android. J'ai pu décoder des images plus grandes que 20 Mo tant que mes paramètres d'entrée sont d'environ 1024x1024. Vous pouvez enregistrer le bitmap renvoyé dans un autre fichier. En dessous de cette méthode se trouve une autre méthode que j'utilise également pour redimensionner les images sur un nouveau bitmap. N'hésitez pas à utiliser ce code à votre guise.
REMARQUE: les méthodes n'ont rien à voir les unes avec les autres, sauf la méthode de décodage des appels createScaledBitmap ci-dessus. La largeur et la hauteur des notes peuvent changer par rapport à l'image d'origine.
la source
ou:
la source
J'utilise
Integer.numberOfLeadingZeros
pour calculer la meilleure taille d'échantillon, de meilleures performances.Code complet en kotlin:
la source
Redimensionnez le bitmap à l'aide du code suivant
La même chose est également expliquée dans l'astuce / astuce suivante
http://www.codeproject.com/Tips/625810/Android-Image-Operations-Using-BitmapFactory
la source