Ich habe eine große Bitmap (sagen wir 3888x2592) in einer Datei. Jetzt möchte ich die Größe dieser Bitmap auf 800 x 533 ändern und sie in einer anderen Datei speichern. Normalerweise würde ich die Bitmap durch Aufrufen der Bitmap.createBitmap
Methode skalieren, aber als erstes Argument wird eine Quell-Bitmap benötigt, die ich nicht angeben kann, da das Laden des Originalbilds in ein Bitmap-Objekt natürlich den Speicher überschreiten würde (siehe hier zum Beispiel).
Ich kann die Bitmap auch nicht lesen, wenn ich beispielsweise a BitmapFactory.decodeFile(file, options)
bereitstelle BitmapFactory.Options.inSampleSize
, da ich die Größe auf eine genaue Breite und Höhe ändern möchte. Bei Verwendung inSampleSize
würde die Größe der Bitmap auf 972 x 648 (wenn ich sie verwende inSampleSize=4
) oder auf 778 x 518 (wenn ich sie verwende inSampleSize=5
, was nicht einmal eine Zweierpotenz ist) geändert .
Ich möchte auch vermeiden, das Bild mit inSampleSize mit beispielsweise 972 x 648 in einem ersten Schritt zu lesen und es dann in einem zweiten Schritt auf genau 800 x 533 zu ändern, da die Qualität im Vergleich zu einer direkten Größenänderung des Originalbilds schlecht wäre.
Um meine Frage zusammenzufassen: Gibt es eine Möglichkeit, eine große Bilddatei mit 10 MP oder mehr zu lesen und in einer neuen Bilddatei zu speichern, deren Größe auf eine bestimmte neue Breite und Höhe angepasst wurde, ohne eine OutOfMemory-Ausnahme zu erhalten?
Ich habe auch versucht BitmapFactory.decodeFile(file, options)
, die Werte Options.outHeight und Options.outWidth manuell auf 800 und 533 zu setzen, aber das funktioniert nicht so.
Antworten:
Nein. Ich würde es lieben, wenn mich jemand korrigiert, aber ich habe den von Ihnen versuchten Ansatz zum Laden / Ändern der Größe als Kompromiss akzeptiert.
Hier sind die Schritte für alle, die surfen:
inSampleSize
das immer noch ein Bild ergibt, das größer als Ihr Ziel ist.BitmapFactory.decodeFile(file, options)
und übergeben Sie inSampleSize als Option.Bitmap.createScaledBitmap()
.quelle
Justin Antwort in Code übersetzt (funktioniert perfekt für mich):
quelle
System.gc()
Sie bitte nicht anDies sind die "kombinierten" Lösungen von 'Mojo Risin' und 'Ofir'. Dadurch erhalten Sie ein Bild mit proportionaler Größe und den Grenzen für maximale Breite und maximale Höhe.
Für mich hat es bei 5 MegaPixel-Bildern eine gute Leistung erbracht.
quelle
Warum nicht die API verwenden?
quelle
Der beste Code, den ich bisher gesehen habe, ist die Dokumentation für das Foto-Tool.
Siehe den Abschnitt "Dekodieren eines skalierten Bildes".
http://developer.android.com/training/camera/photobasics.html
Die vorgeschlagene Lösung ist eine Größenänderung und dann eine Skalierungslösung wie die anderen hier, aber sie ist recht ordentlich.
Ich habe den folgenden Code der Einfachheit halber als sofort einsatzbereite Funktion kopiert.
quelle
Nachdem Sie diese Antworten und die Android-Dokumentation gelesen haben, finden Sie hier den Code zum Ändern der Bitmap-Größe, ohne sie in den Speicher zu laden:
quelle
Wenn ich große Bitmaps habe und deren Größe dekodieren möchte, verwende ich Folgendes
quelle
Dies kann für andere Personen nützlich sein, die sich mit dieser Frage befassen. Ich habe Justins Code neu geschrieben, damit die Methode auch das gewünschte Zielgrößenobjekt empfangen kann. Dies funktioniert sehr gut bei der Verwendung von Canvas. Alle Gutschriften sollten an JUSTIN für seinen großartigen Anfangscode gehen.
Justins Code ist SEHR effektiv, um den Aufwand für die Arbeit mit großen Bitmaps zu reduzieren.
quelle
Ich weiß nicht, ob meine Lösung die beste Vorgehensweise ist, aber ich habe mithilfe der Optionen
inDensity
und eine Bitmap mit der gewünschten SkalierunginTargetDensity
geladen.inDensity
ist0
zunächst, wenn keine zeichnbare Ressource geladen wird, daher dient dieser Ansatz zum Laden von Nicht-Ressourcen-Bildern.Die Variablen
imageUri
,maxImageSideLength
undcontext
sind Parameter meiner Methode. Aus Gründen der Übersichtlichkeit habe ich nur die Methodenimplementierung ohne das Umschließen von AsyncTask veröffentlicht.quelle
In Anbetracht dessen, dass Sie die Größe auf die exakte Größe anpassen und so viel Qualität wie nötig beibehalten möchten, sollten Sie dies versuchen.
Motivation: Eine mehrstufige Skalierung kann zu einer höheren Bildqualität führen. Es gibt jedoch keine Garantie dafür, dass sie besser funktioniert als die Verwendung von High inSampleSize. Eigentlich denke ich, dass Sie auch inSampleSize wie 5 (nicht pow of 2) verwenden können, um eine direkte Skalierung in einem Vorgang zu erzielen. Oder verwenden Sie einfach 4 und dann können Sie dieses Bild einfach in der Benutzeroberfläche verwenden. Wenn Sie es an den Server senden, können Sie es auf der Serverseite auf die exakte Größe skalieren, sodass Sie erweiterte Skalierungstechniken verwenden können.
Hinweise: Wenn die in Schritt 3 geladene Bitmap mindestens viermal größer ist (also die 4 * Zielbreite <Breite), können Sie wahrscheinlich mehrere Größenänderungen verwenden, um eine bessere Qualität zu erzielen. Zumindest funktioniert das in generischem Java. In Android haben Sie nicht die Möglichkeit, die für die Skalierung verwendete Interpolation anzugeben. http://today.java.net/pub/a/today/2007/04/03/perils-of- image-getscaledinstance.html
quelle
Ich habe folgenden Code verwendet:
Ich habe versucht, das Originalbild ist 1230 x 1230, und die Bitmap lautet 330 x 330.
Und wenn ich 2590 x 3849 ausprobiert habe, habe ich OutOfMemoryError.
Ich habe es verfolgt, es wirft immer noch OutOfMemoryError in die Zeile "BitmapFactory.decodeStream (is, null, options);", wenn die ursprüngliche Bitmap zu groß ist ...
quelle
Der obige Code wurde etwas sauberer. InputStreams haben endlich eine enge Umhüllung, um sicherzustellen, dass sie auch geschlossen werden:
* Hinweis
Eingabe: InputStream ist, int w, int h
Ausgabe: Bitmap
quelle
Um das Bild auf die "richtige" Weise zu skalieren, ohne Pixel zu überspringen, müssten Sie sich in den Bilddecoder einhängen, um das Downsampling zeilenweise durchzuführen. Android (und die zugrunde liegende Skia-Bibliothek) bietet keine solchen Hooks, sodass Sie Ihre eigenen rollen müssten. Angenommen, Sie sprechen von JPEG-Bildern, ist es am besten, libjpeg direkt in C zu verwenden.
Angesichts der Komplexität ist die Verwendung der zweistufigen Teilstichprobe und dann der Neuskalierung wahrscheinlich am besten für Apps vom Typ Bildvorschau geeignet.
quelle
Hier ist ein Artikel, der einen anderen Ansatz zur Größenänderung verfolgt. Es wird versucht, die größtmögliche Bitmap basierend auf dem verfügbaren Speicher im Prozess in den Speicher zu laden und dann die Transformationen durchzuführen.
http://bricolsoftconsulting.com/2012/12/07/handling-large-images-on-android/
quelle
Wenn Sie unbedingt eine Schrittgröße ändern möchten, können Sie wahrscheinlich die gesamte Bitmap laden, wenn android: largeHeap = true, aber wie Sie sehen, ist dies nicht wirklich ratsam.
Aus docs: android: largeHeap Gibt an, ob die Prozesse Ihrer Anwendung mit einem großen Dalvik-Heap erstellt werden sollen. Dies gilt für alle für die Anwendung erstellten Prozesse. Dies gilt nur für die erste in einen Prozess geladene Anwendung. Wenn Sie eine gemeinsam genutzte Benutzer-ID verwenden, um mehreren Anwendungen die Verwendung eines Prozesses zu ermöglichen, müssen alle diese Option konsistent verwenden, da sonst unvorhersehbare Ergebnisse erzielt werden. Die meisten Apps sollten dies nicht benötigen und sich stattdessen darauf konzentrieren, die Gesamtspeicherauslastung zu reduzieren, um die Leistung zu verbessern. Das Aktivieren dieser Option garantiert auch keine feste Erhöhung des verfügbaren Speichers, da einige Geräte durch ihren insgesamt verfügbaren Speicher eingeschränkt sind.
quelle
Auf der Android-Entwickler-Website gibt es einen großartigen Artikel zu diesem Thema: Effizientes Laden großer Bitmaps
quelle
Das hat bei mir funktioniert. Die Funktion erhält einen Pfad zu einer Datei auf der SD-Karte und gibt eine Bitmap in der maximal anzeigbaren Größe zurück. Der Code stammt von Ofir mit einigen Änderungen wie Bilddatei auf SD statt einer Ressource und die Breite und Höhe werden vom Anzeigeobjekt abgerufen.
quelle
Hier ist der Code, den ich verwende und der keine Probleme beim Dekodieren großer Bilder im Speicher von Android hat. Ich konnte Bilder mit einer Größe von mehr als 20 MB dekodieren, solange meine Eingabeparameter bei 1024 x 1024 liegen. Sie können die zurückgegebene Bitmap in einer anderen Datei speichern. Unter dieser Methode befindet sich eine weitere Methode, mit der ich Bilder auch auf eine neue Bitmap skaliere. Fühlen Sie sich frei, diesen Code zu verwenden, wie Sie möchten.
HINWEIS: Methoden haben nichts miteinander zu tun, außer die oben beschriebene Dekodierungsmethode für createScaledBitmap-Aufrufe. Beachten Sie, dass sich Breite und Höhe vom Originalbild ändern können.
quelle
oder:
quelle
Ich verwende
Integer.numberOfLeadingZeros
, um die beste Stichprobengröße und bessere Leistung zu berechnen.Vollständiger Code in Kotlin:
quelle
Ändern Sie die Größe der Bitmap mithilfe des folgenden Codes
Das gleiche wird auch im folgenden Tipp / Trick erklärt
http://www.codeproject.com/Tips/625810/Android-Image-Operations-Using-BitmapFactory
quelle