Ich erstelle eine bildintensive soziale App, in der Bilder vom Server an das Gerät gesendet werden. Wenn das Gerät kleinere Bildschirmauflösungen hat, muss ich die Größe der Bitmaps auf dem Gerät an die beabsichtigten Anzeigegrößen anpassen.
Das Problem ist, dass die Verwendung von createScaledBitmap dazu führt, dass ich nach dem Ändern der Größe einer Horde von Miniaturbildern auf viele Speicherfehler stoße .
Was ist die speichereffizienteste Methode, um die Größe von Bitmaps unter Android zu ändern?
android
performance
bitmap
out-of-memory
Colt McAnlis
quelle
quelle
Antworten:
Es gibt drei Möglichkeiten, die Größe einer Bitmap unter Android zu ändern, die unterschiedliche Speichereigenschaften haben:
createScaledBitmap API
Diese API nimmt eine vorhandene Bitmap auf und erstellt eine NEUE Bitmap mit den genauen Dimensionen, die Sie ausgewählt haben.
Auf der positiven Seite können Sie genau die Bildgröße erhalten, die Sie suchen (unabhängig davon, wie es aussieht). Der Nachteil ist jedoch, dass für diese API eine vorhandene Bitmap um zu funktionieren . Das bedeutet, dass das Bild geladen, dekodiert und eine Bitmap erstellt werden muss, bevor eine neue, kleinere Version erstellt werden kann. Dies ist ideal, um Ihre genauen Abmessungen zu erhalten, aber schrecklich in Bezug auf zusätzlichen Speicheraufwand. Als solches ist dies für die meisten App-Entwickler, die dazu neigen, speicherbewusst zu sein, eine Art Deal Breaker
inSampleSize-Flag
BitmapFactory.Options
hat eine Eigenschaft vermerkt alsinSampleSize
, die die Größe Ihres Bildes beim Dekodieren ändert, um zu vermeiden, dass eine temporäre Bitmap dekodiert werden muss. Dieser hier verwendete ganzzahlige Wert lädt ein Bild mit einer um 1 / x reduzierten Größe. Wenn Sie beispielsweiseinSampleSize
auf 2 setzen, wird ein Bild zurückgegeben, das halb so groß ist, und wenn Sie es auf 4 setzen, wird ein Bild zurückgegeben, das 1/4 der Größe entspricht. Grundsätzlich sind die Bildgrößen immer um eine Zweierpotenz kleiner als Ihre Quellgröße.Aus Speichersicht ist die Verwendung
inSampleSize
eine sehr schnelle Operation. Tatsächlich wird nur jedes x-te Pixel Ihres Bildes in die resultierende Bitmap dekodiert. Es gibt jedoch zwei HauptproblemeinSampleSize
:Es gibt Ihnen keine genauen Auflösungen . Die Größe Ihrer Bitmap wird nur um eine Zweierpotenz verringert.
Es wird nicht die beste Größenänderung erzeugt . Die meisten Größenänderungsfilter erzeugen gut aussehende Bilder, indem sie Pixelblöcke lesen und dann gewichten, um das fragliche Pixel mit geänderter Größe zu erzeugen.
inSampleSize
vermeidet dies alles, indem nur alle paar Pixel gelesen wird. Das Ergebnis ist ziemlich performant und hat wenig Speicher, aber die Qualität leidet.Wenn Sie nur mit dem Verkleinern Ihres Bildes um eine bestimmte pow2-Größe zu tun haben und das Filtern kein Problem darstellt, können Sie keine speichereffizientere (oder leistungsfähigere) Methode finden als
inSampleSize
.inScaled-, inDensity-, inTargetDensity-Flags
Wenn Sie ein Bild in eine Dimension skalieren , die zu einer Zweierpotenz ist nicht gleich sind , dann müssen Sie das
inScaled
,inDensity
undinTargetDensity
Flaggen vonBitmapOptions
. Wenn dasinScaled
Flag gesetzt wurde, leitet das System den Skalierungswert ab, der auf Ihre Bitmap angewendet werden soll, indem esinTargetDensity
durch dieinDensity
Werte dividiert wird .Wenn Sie diese Methode verwenden, wird die Größe Ihres Bilds geändert und es wird auch ein "Größenänderungsfilter" darauf angewendet. Das Endergebnis sieht also besser aus, da beim Größenänderungsschritt einige zusätzliche Berechnungen berücksichtigt wurden. Aber seien Sie gewarnt: Dieser zusätzliche Filterschritt nimmt zusätzliche Verarbeitungszeit in Anspruch und kann sich schnell für große Bilder summieren, was zu langsamen Größenänderungen und zusätzlichen Speicherzuweisungen für den Filter selbst führt.
Aufgrund des zusätzlichen Filteraufwands ist es im Allgemeinen keine gute Idee, diese Technik auf ein Bild anzuwenden, das erheblich größer als die gewünschte Größe ist.
Magische Kombination
Aus Sicht des Speichers und der Leistung können Sie diese Optionen kombinieren, um die besten Ergebnisse zu erzielen. (Einstellung der
inSampleSize
,inScaled
,inDensity
undinTargetDensity
Flags)inSampleSize
wird zuerst auf das Bild angewendet und erreicht die nächste Zweierpotenz, die größer ist als Ihre Zielgröße. Anschließend wirdinDensity
&inTargetDensity
verwendet, um das Ergebnis auf die gewünschten Abmessungen zu skalieren und eine Filteroperation anzuwenden, um das Bild zu bereinigen.Das Kombinieren dieser beiden Funktionen ist viel schneller, da durch den
inSampleSize
Schritt die Anzahl der Pixel verringert wird, auf die der resultierende dichtebasierte Schritt angewendet werden muss, um den Größenänderungsfilter anzuwenden.Wenn Sie ein Bild an bestimmte Abmessungen anpassen und eine bessere Filterung durchführen möchten, ist diese Technik die beste Brücke, um die richtige Größe zu erhalten, jedoch in einem schnellen Vorgang mit geringem Speicherbedarf.
Bildabmessungen abrufen
Abrufen der Bildgröße ohne Dekodierung des gesamten Bilds Um die Größe Ihrer Bitmap zu ändern, müssen Sie die eingehenden Abmessungen kennen. Sie können das
inJustDecodeBounds
Flag verwenden, um die Abmessungen des Bildes zu ermitteln, ohne die Pixeldaten tatsächlich dekodieren zu müssen.Mit diesem Flag können Sie zuerst die Größe dekodieren und dann die richtigen Werte für die Skalierung auf Ihre Zielauflösung berechnen.
quelle
destination width
oder dstWidth für kurzSo schön (und genau) diese Antwort auch ist, sie ist auch sehr kompliziert. Anstatt das Rad neu zu erfinden, sollten Sie Bibliotheken wie Glide , Picasso , UIL , Ion in Betracht ziehen oder eine beliebige Anzahl anderer in , die diese komplexe und fehleranfällige Logik für Sie implementieren.
Colt selbst empfiehlt sogar, einen Blick auf Glide und Picasso im Video zu den Leistungsskalen vor der Skalierung von Bitmaps zu werfen .
Durch die Verwendung von Bibliotheken können Sie jede in Colts Antwort erwähnte Effizienz erzielen, jedoch mit erheblich einfacheren APIs, die in jeder Android-Version konsistent funktionieren.
quelle