Saya sedang membangun aplikasi sosial intensif gambar tempat gambar dikirim dari server ke perangkat. Jika perangkat memiliki resolusi layar yang lebih kecil, saya perlu mengubah ukuran bitmap, di perangkat, agar sesuai dengan ukuran tampilan yang diinginkan.
Masalahnya adalah bahwa menggunakan createScaledBitmap menyebabkan saya mengalami banyak kesalahan kehabisan memori setelah mengubah ukuran sekumpulan gambar mini.
Apa cara paling hemat memori untuk mengubah ukuran bitmap di Android?
android
performance
bitmap
out-of-memory
Colt McAnlis
sumber
sumber
Jawaban:
Ada tiga cara dominan untuk mengubah ukuran bitmap di Android yang memiliki properti memori berbeda:
createScaledBitmap API
API ini akan menggunakan bitmap yang ada, dan membuat bitmap BARU dengan dimensi yang tepat yang Anda pilih.
Di sisi positifnya, Anda bisa mendapatkan ukuran gambar yang Anda cari (terlepas dari tampilannya). Namun sisi negatifnya, API ini membutuhkan bitmap yang sudah ada agar dapat berfungsi . Artinya gambar harus dimuat, didekodekan, dan dibuat bitmap, sebelum dapat membuat versi baru yang lebih kecil. Ini sangat ideal dalam hal mendapatkan dimensi yang tepat, tetapi mengerikan dalam hal overhead memori tambahan. Dengan demikian, ini adalah semacam pemecah kesepakatan bagi sebagian besar pengembang aplikasi yang cenderung sadar memori
tanda inSampleSize
BitmapFactory.Options
memiliki propertiinSampleSize
yang akan mengubah ukuran gambar Anda saat mendekodekannya, untuk menghindari kebutuhan untuk mendekode ke bitmap sementara. Nilai integer yang digunakan di sini akan memuat gambar dengan ukuran yang diperkecil 1 / x. Misalnya, menyetelinSampleSize
ke 2 mengembalikan gambar berukuran setengah, dan Menyetelnya ke 4 mengembalikan gambar berukuran 1/4. Pada dasarnya ukuran gambar akan selalu lebih kecil dari ukuran sumber Anda.Dari perspektif memori, penggunaan
inSampleSize
adalah operasi yang sangat cepat. Secara efektif, ini hanya akan mendekode setiap piksel X dari gambar Anda ke bitmap yang dihasilkan. Ada dua masalah utama denganinSampleSize
:Itu tidak memberi Anda resolusi yang tepat . Ini hanya mengurangi ukuran bitmap Anda dengan beberapa pangkat 2.
Itu tidak menghasilkan pengubahan ukuran kualitas terbaik . Sebagian besar filter pengubah ukuran menghasilkan gambar yang terlihat bagus dengan membaca blok piksel, dan kemudian menimbangnya untuk menghasilkan piksel yang diubah ukurannya.
inSampleSize
menghindari semua ini dengan hanya membaca setiap beberapa piksel. Hasilnya cukup baik, dan memori rendah, tetapi kualitas buruk.Jika Anda hanya berurusan dengan mengecilkan gambar Anda dengan beberapa ukuran pow2, dan pemfilteran tidak menjadi masalah, maka Anda tidak dapat menemukan metode yang lebih efisien memori (atau kinerja efisien) daripada
inSampleSize
.tanda inScaled, inDensity, inTargetDensity
Jika Anda perlu menskalakan gambar ke dimensi yang tidak sama dengan pangkat dua, Anda memerlukan
inScaled
,inDensity
daninTargetDensity
benderaBitmapOptions
. KetikainScaled
bendera telah disetel, sistem akan mendapatkan nilai skala untuk diterapkan ke bitmap Anda dengan membaginyainTargetDensity
denganinDensity
nilai.Menggunakan metode ini akan mengubah ukuran gambar Anda, dan juga menerapkan 'filter pengubah ukuran', hasil akhirnya akan terlihat lebih baik karena beberapa perhitungan tambahan telah diperhitungkan selama langkah pengubahan ukuran. Namun berhati-hatilah: langkah filter ekstra itu, membutuhkan waktu pemrosesan ekstra , dan dapat dengan cepat bertambah untuk gambar besar, mengakibatkan pengubahan ukuran yang lambat, dan alokasi memori ekstra untuk filter itu sendiri.
Biasanya bukan ide yang baik untuk menerapkan teknik ini pada gambar yang secara signifikan lebih besar dari ukuran yang Anda inginkan, karena overhead pemfilteran ekstra.
Kombinasi Ajaib
Dari perspektif memori dan kinerja, Anda dapat menggabungkan opsi ini untuk hasil terbaik. (pengaturan
inSampleSize
,inScaled
,inDensity
daninTargetDensity
bendera)inSampleSize
pertama-tama akan diterapkan pada gambar, membuatnya menjadi kekuatan dua LEBIH BESAR berikutnya dari ukuran target Anda. Kemudian,inDensity
&inTargetDensity
digunakan untuk menskalakan hasil ke dimensi yang tepat yang Anda inginkan, menerapkan operasi filter untuk membersihkan gambar.Menggabungkan keduanya adalah operasi yang jauh lebih cepat, karena
inSampleSize
langkah tersebut akan mengurangi jumlah piksel yang diperlukan untuk menerapkan langkah berbasis Densitas untuk menerapkan filter pengubahan ukurannya.Jika Anda perlu menyesuaikan gambar dengan dimensi tertentu, dan beberapa pemfilteran yang lebih baik, maka teknik ini adalah jembatan terbaik untuk mendapatkan ukuran yang tepat, tetapi dilakukan dalam operasi footprint yang cepat dan memiliki memori rendah.
Mendapatkan dimensi gambar
Mendapatkan ukuran gambar tanpa mendekode seluruh gambar Untuk mengubah ukuran bitmap Anda, Anda harus mengetahui dimensi yang masuk. Anda dapat menggunakan
inJustDecodeBounds
bendera untuk membantu Anda mendapatkan dimensi gambar, tanpa perlu benar-benar mendekode data piksel.Anda dapat menggunakan tanda ini untuk mendekode ukuran terlebih dahulu, lalu menghitung nilai yang tepat untuk penskalaan ke resolusi target Anda.
sumber
destination width
misinya atau singkatnyaJawaban ini bagus (dan akurat), tetapi juga sangat rumit. Daripada menemukan kembali roda, pertimbangkan pustaka seperti Glide , Picasso , UIL , Ion , atau beberapa lainnya yang menerapkan logika kompleks dan rawan kesalahan ini untuk Anda.
Colt sendiri bahkan merekomendasikan untuk melihat Glide dan Picasso dalam Video Pola Kinerja Bitmaps Pra-penskalaan .
Dengan menggunakan pustaka, Anda bisa mendapatkan setiap efisiensi yang disebutkan dalam jawaban Colt, tetapi dengan API yang jauh lebih sederhana yang bekerja secara konsisten di setiap versi Android.
sumber