Le chargement des images de grande taille sans OutOfMemoryError
J'ai un 5000 x 4000 px image que je veux dessiner sur une toile.
J'ai d'abord essayé de le charger à partir de ressources.
Je l'ai mis dans /res/drawable
.
J'ai utilisé la méthode suivante:
InputStream input = getResources().openRawResource(R.drawable.huge_image);
Drawable d = Drawable.createFromStream(input, "image");
d.setBounds(...);
d.draw(canvas);
Il a travaillé comme un charme.
Dans ce cas, le InputStream
est un AssetManager.AssetInputStream
.
Alors maintenant je veux le charger à partir de la carte sd.
Voici ce que j'ai essayé de faire:
File f = new File(path);
Uri uri = Uri.fromFile(f);
InputStream input = mContext.getContentResolver().openInputStream(uri);
Drawable d = Drawable.createFromStream(input, "image");
Dans ce cas, le InputStream
est un FileInputStream
et j'ai eu un OutOfMemoryError
lors de la création de la Drawable
.
Alors je me demandais:
Est-il un moyen de charger l'image sans avoir d'erreur? Ou est-il un moyen de convertir un FileInputStream
à un AssetInputStream
?
Remarque:
Je ne veux pas redimensionner l'image, parce que je suis la mise en œuvre de zoom/pan fonctionnalité.
S'il vous plaît ne me dites pas de lire Le Chargement D'Un Grand Bitmaps Efficacement.
Vous pouvez vérifier l'intégralité de la classe ici. L'erreur se produit lors de l'utilisation de setImageUri()
.
Voici mon Log d'Erreur:
08-13 11:57:54.180: E/AndroidRuntime(23763): FATAL EXCEPTION: main
08-13 11:57:54.180: E/AndroidRuntime(23763): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:468)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:332)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.graphics.drawable.Drawable.createFromStream(Drawable.java:657)
08-13 11:57:54.180: E/AndroidRuntime(23763): at com.benitobertoli.largeimagezoom.ZoomImageView.setDrawablefromUri(ZoomImageView.java:187)
08-13 11:57:54.180: E/AndroidRuntime(23763): at com.benitobertoli.largeimagezoom.ZoomImageView.setImageUri(ZoomImageView.java:588)
08-13 11:57:54.180: E/AndroidRuntime(23763): at com.benitobertoli.largeimagezoom.TestActivity.onKeyDown(TestActivity.java:30)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.view.KeyEvent.dispatch(KeyEvent.java:1257)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.app.Activity.dispatchKeyEvent(Activity.java:2075)
08-13 11:57:54.180: E/AndroidRuntime(23763): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1673)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.view.ViewRoot.deliverKeyEventToViewHierarchy(ViewRoot.java:2493)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.view.ViewRoot.handleFinishedEvent(ViewRoot.java:2463)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.view.ViewRoot.handleMessage(ViewRoot.java:1752)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.os.Handler.dispatchMessage(Handler.java:99)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.os.Looper.loop(Looper.java:144)
08-13 11:57:54.180: E/AndroidRuntime(23763): at android.app.ActivityThread.main(ActivityThread.java:4937)
08-13 11:57:54.180: E/AndroidRuntime(23763): at java.lang.reflect.Method.invokeNative(Native Method)
08-13 11:57:54.180: E/AndroidRuntime(23763): at java.lang.reflect.Method.invoke(Method.java:521)
08-13 11:57:54.180: E/AndroidRuntime(23763): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
08-13 11:57:54.180: E/AndroidRuntime(23763): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
08-13 11:57:54.180: E/AndroidRuntime(23763): at dalvik.system.NativeStart.main(Native Method)
EDIT:
J'ai été le tester mon code sur un HTC Desire A8181.
Après avoir appris que le premier extrait de code ne fonctionnait pas sur certains autres appareils, j'ai testé sur un Samsung Galaxy S2 et sur l'Émulateur.
Résultats:
Lors du chargement de ressources, l'émulateur a donné un OutOfMemoryError
, le Galaxy S2 n'a pas de jeter une exception, mais le retour Drawable
était nulle.
Donc je suppose que pour le moment la seule solution est de sous-échantillonner l'image.
OriginalL'auteur Benito Bertoli | 2012-08-13
Vous devez vous connecter pour publier un commentaire.
Prendre un coup d'oeil à:
http://developer.android.com/reference/android/graphics/BitmapFactory.html
ou
de cette façon, vous pouvez charger votre ensemble de l'image bitmap et de l'afficher sur l'écran.
Vous devez définir les options correctes.
http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html
Je l'ai essayé avec ton code:
fonctionne pour moi.
désolé, j'ai raté ce alors essayer le decodeStream (InputStream est, Rect outPadding, BitmapFactory.Options opte) méthode
Je le répète, je ne veux pas redimensionner l'image.
vous besoin à l'échelle et de la tuile que vous ne pouvez tenir un bitmap 5000x4000px dans la mémoire. de zoom et de panoramique, vous aurez besoin de comprendre à quelle partie de l'image d'origine pour être visible et de charge respectifs des carreaux de mise à l'échelle à la densité de l'écran
btw: le code pour charger l'image à partir de la ressource de vous donner un dépassement de mémoire sur un Galaxy Nexus si le matériel rendu est activé
OriginalL'auteur n3utrino
À mon avis, la meilleure option est de séparer l'image en petits morceaux. Cela permettra d'éviter la demande pour donner une OutOfMemoryException. Voici mon code d'exemple
De la première à obtenir l'image de la Carte SD une de le placer dans un Bitmap
Diviser l'image bitmap (b) - les en petits morceaux. Dans ce cas SPLIT_HEIGHT est de 400.
Maintenant, vous avez une série de petites images. Si vous voulez le faire perfecly, vous pouvez recycler cette image:
À partir de ce moment vous pouvez mettre des petites images sur la toile. Dans mon code j'ai mis les images dans une ScrollView. Le code pour mettre les images sur une Toile est je pense pas très différent.
J'espère que cela va vous aider.
REMARQUE: La résolution maximale pour les images est de 2048*2048 (OpenGL de restrictions ou de quelque chose), de sorte que vous aurez toujours de diviser les images en petits morceaux.
b = BitmapFactory.decodeStream(fis, null, options);
donne déjà une OutOfMemoryError. En outre, vous divisez la bitmap dans 50 plus petits, mais vous êtes toujours en train de charger tous en même temps dans la mémoire, qui donne le même résultat.Si vous définissez android:largeHeap="true" puis faire le code ci-dessus? Comme je l'ai dit dans ma note, vous aurez à les diviser l'image en morceaux parce que la résolution maximale de 2048*2048. Bien sûr, dans ma solution, vous aurez également à séparer l'image en morceaux verticaux (largeur est highter que 2048).
OriginalL'auteur Ceetn
Je ne suis pas sûr de savoir si c'est la bonne façon de le faire, mais encore cela peut résoudre votre problème.
Essayez d'ouvrir votre image dans une webview. Vous serez intégré de zoom et de panoramique et vous n'avez pas à vous soucier de l'ouverture d'un flux d'entrée ou quoi que ce soit d'autre.
Pour ouvrir une image dans webview d'actifs:
Vous pouvez WebSettings pour permettre les contrôles de zoom.
Espérons que cela vous aidera!!
OriginalL'auteur mudit
Si cela a fonctionné lors du chargement de ressources et maintenant il ne fonctionne pas lorsque vous chargez manuellement, puis je soupçonne que vous avez un problème avec la gestion des ressources, probablement une fuite de mémoire.
Ne
OutOfMemoryError
se produisent toujours au début de l'application ou il arrive dans les temps plus tard? Est-il sur la modification de la configuration? Utilisez-vous des champs statiques (si elle est utilisée de manière incorrecte cela conduit souvent à des fuites de mémoire dans une application Android, exemple avec explication cela correspond à votre cas)?Essayez d'utiliser certains outils de profilage (google peut vous aider à trouver quelque chose d'utile).
OutOfMemoryError
se produit sur cette ligneDrawable d = Drawable.createFromStream(input, "image");
quand je suis en cours de chargement à partir de l'Uri. Je ne suis pas à l'aide de champs statiques. Vous pouvez consulter l'intégralité de la classe ici. Je vais appelersetImageUri()
.ce lien est pour le code de travail (image téléchargée à partir de ressources). Apparemment vous n'avez pas à pousser problématique des changements (nouvelle branche?).
Veuillez vérifier à nouveau maintenant. J'ai ajouté un menu. "À partir de Ser" et "à Partir d'un Fichier". L'erreur se produit à l'aide "à Partir d'un Fichier". Vous devez copier
huge_image.png
deres/drawable
à votre sdcard et remplacez le chemin d'accès dans votre code.OriginalL'auteur Marek R