Diese Antwort wird unter Effizientes Laden großer Bitmaps zusammengefasst. Hier wird
erläutert, wie Sie inSampleSize zum Laden einer verkleinerten Bitmap-Version verwenden.
In Bitmaps vor der Skalierung werden insbesondere die Details verschiedener Methoden erläutert, wie sie kombiniert werden und welche speichereffizientesten sind.
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 als inSampleSize
, 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 beispielsweise inSampleSize
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 Hauptprobleme inSampleSize
:
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
und inTargetDensity
Flaggen von BitmapOptions
. Wenn das inScaled
Flag gesetzt wurde, leitet das System den Skalierungswert ab, der auf Ihre Bitmap angewendet werden soll, indem es inTargetDensity
durch die inDensity
Werte dividiert wird .
mBitmapOptions.inScaled = true;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth;
// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeResources(getResources(),
mImageIDs, mBitmapOptions);
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
und inTargetDensity
Flags)
inSampleSize
wird zuerst auf das Bild angewendet und erreicht die nächste Zweierpotenz, die größer ist als Ihre Zielgröße. Anschließend wird inDensity
& 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.
mBitmapOptions.inScaled = true;
mBitmapOptions.inSampleSize = 4;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth * mBitmapOptions.inSampleSize;
// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeFile(fileName, mBitmapOptions);
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.
// Decode just the boundaries
mBitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(fileName, mBitmapOptions);
srcWidth = mBitmapOptions.outWidth;
srcHeight = mBitmapOptions.outHeight;
//now go resize the image to the size you want
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.