Ta odpowiedź jest zestawione z Loading large bitmaps Efficiently który wyjaśnia, jak korzystać inSampleSize załadować dół skalowane bitmapy wersję.
W szczególności Pre-scaling bitmaps wyjaśnia szczegóły różnych metod , jak je łączyć i które są najbardziej wydajne pod względem pamięci.
Istnieją trzy dominujące sposoby zmiany rozmiaru mapy bitowej na Androida, które mają różne właściwości pamięci:
createScaledBitmap API
Ten interfejs API weźmie w istniejącym bitmapy i utworzyć nową bitmapę z dokładne wymiary, które wybrałeś.
Po stronie plusów możesz uzyskać dokładnie taki rozmiar obrazu, jakiego szukasz (niezależnie od tego, jak wygląda). Ale wadą, jest to, że ten interfejs API wymaga istniejącej mapy bitowej , aby działać. Oznacza to, że obraz musi zostać wczytany, zdekodowany i utworzona mapa bitowa, zanim będzie można utworzyć nową, mniejszą wersję. Jest to idealne rozwiązanie pod względem uzyskania dokładnych wymiarów, ale straszne pod względem dodatkowego obciążenia pamięci. Jako taka, jest to rodzaj-of brakło dla większości twórców aplikacji, którzy wydają się być pamięć świadomej
inSampleSize flag
BitmapFactory.Options
ma właściwość zauważyć jak inSampleSize
że będzie zmienić rozmiar obrazu podczas dekodowania, w celu uniknięcia potrzeba dekodowania do tymczasowej bitmapy. Ta użyta tutaj wartość całkowita spowoduje załadowanie obrazu o zmniejszonej wielkości 1/x. Na przykład ustawienie wartości inSampleSize
na 2 powoduje zwrócenie obrazu o połowę mniejszego, a ustawienie wartości 4 powoduje zwrócenie obrazu o wielkości 1/4 rozmiaru. Zasadniczo rozmiary obrazków zawsze będą miały trochę mocy mniejszej niż rozmiar źródła.
Z perspektywy pamięci korzystanie z inSampleSize
jest naprawdę szybką operacją. Skutecznie, tylko dekoduje każdy X-piksel obrazu w wynikowej bitmapie. Są dwa główne problemy z inSampleSize
jednak:
To nie daje dokładnych uchwał. Zmniejsza tylko rozmiar mapy bitowej o wartość 2.
Nie zapewnia najlepszej jakości zmiana rozmiaru. Większość filtrów zmienia rozmiar, tworząc dobrze wyglądające obrazy, czytając bloki pikseli, a następnie ważąc je, aby uzyskać odpowiedni rozmiar piksela.inSampleSize
omija to wszystko, czytając co kilka pikseli. Rezultat jest dość wydajny i ma niską pamięć, ale cierpi na jakość.
Jeśli masz do czynienia tylko z kurczy swój wizerunek przez jakiegoś rozmiaru pow2 i filtrowanie nie jest problemem, to nie można znaleźć bardziej wydajne pamięci (lub wydajność wydajny) metoda niż inSampleSize
.
inScaled, inDensity, inTargetDensity flags
Jeśli chcesz przeskalować obraz do wymiaru, która nie jest równa sile dwóch, potem musisz się inScaled
, inDensity
i inTargetDensity
flagi BitmapOptions
. Po ustawieniu flagi inScaled
system wyprowadzi wartość skalowania, aby zastosować ją do mapy bitowej, dzieląc wartość inTargetDensity
według wartości inDensity
.
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);
Korzystając z tej metody będzie re-size obraz, a także zastosować „filtr zmiany rozmiaru” do niego, to znaczy, że efekt końcowy będzie wyglądać lepiej, bo jakiś dodatkowy matematyka została uwzględniona na etapie zmiana rozmiaru . Ale ostrzegamy: , że dodatkowy etap filtrowania zajmuje dodatkowy czas przetwarzania i można szybko dodać do dużych obrazów, co powoduje powolne zmiany rozmiaru i dodatkowe alokacje pamięci dla samego filtra.
Zasadniczo nie jest dobrym pomysłem zastosowanie tej techniki do obrazu, który jest znacznie większy niż żądany rozmiar, ze względu na dodatkowe obciążenie filtrujące.
magiczne połączenie
Z pamięcią i perspektywy wydajności, można połączyć te opcje dla najlepszych rezultatów. (Ustawienie inSampleSize
, inScaled
, inDensity
i inTargetDensity
flagi)
inSampleSize
zostaną najpierw zastosowane do obrazu, dostając się do następnego power-of-dwa większe niż wielkości docelowej. Następnie, inDensity
& inTargetDensity
służą do skalowania wyniku do żądanych wymiarów, stosując operację filtra do czyszczenia obrazu.
Połączenie tych dwóch elementów jest o wiele szybszym działaniem, ponieważ krok inSampleSize
spowoduje zmniejszenie liczby pikseli, które będą wymagane w kroku opartym na wartości Gęstość, aby zastosować filtr zmiany rozmiaru.
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);
Jeśli konieczności dopasowania obrazu do konkretnych wymiarów, i jakiś ładniejszy filtrowania, a następnie ta technika jest najlepszy most do uzyskania odpowiedniej wielkości, ale odbywa się w szybki, Ślad niskiej pamięci operacja.
Getting wymiary obrazu
Uzyskiwanie rozmiar obrazu bez dekodowania cały obraz Aby zmienić rozmiar bitmapy, trzeba znać przychodzące wymiary. Możesz użyć flagi inJustDecodeBounds
, aby uzyskać wymiary obrazu, bez konieczności dekodowania danych pikseli.
// 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
Możesz użyć tej flagi zdekodować pierwszy rozmiar, a następnie obliczyć odpowiednie wartości do skalowania do rozdzielczości docelowego.
Czy twój serwer nie może wysłać prawidłowego rozmiaru, aby zapisać pamięć RAM klienta i przepustowość !? – James
Jest to ważne tylko wtedy, gdy posiadałem zasób serwera, miał on dostępny komponent obliczeniowy i we wszystkich przypadkach mógł przewidzieć dokładne wymiary obrazów dla współczynników proporcji, których jeszcze nie widział. Więc jeśli ładujesz zawartość zasobów z CDN innej firmy (jak ja) to nie działa :( –