Saya memiliki bitmap besar (katakanlah 3888x2592) dalam sebuah file. Sekarang, saya ingin mengubah ukuran bitmap menjadi 800x533 dan menyimpannya ke file lain. Saya biasanya akan skala bitmap dengan memanggil Bitmap.createBitmap
metode tetapi membutuhkan bitmap sumber sebagai argumen pertama, yang saya tidak bisa berikan karena memuat gambar asli ke objek Bitmap tentu saja akan melebihi memori (lihat di sini , misalnya).
Saya juga tidak dapat membaca bitmap dengan, misalnya BitmapFactory.decodeFile(file, options)
, memberikan BitmapFactory.Options.inSampleSize
, karena saya ingin mengubah ukurannya menjadi lebar dan tinggi yang tepat. Menggunakan inSampleSize
akan mengubah ukuran bitmap ke 972x648 (jika saya menggunakan inSampleSize=4
) atau ke 778x518 (jika saya menggunakan inSampleSize=5
, yang bahkan bukan kekuatan 2).
Saya juga ingin menghindari membaca gambar menggunakan inSampleSize dengan, misalnya, 972x648 pada langkah pertama dan kemudian mengubah ukurannya menjadi 800x533 pada langkah kedua, karena kualitasnya akan buruk dibandingkan dengan mengubah ukuran langsung dari gambar asli.
Untuk meringkas pertanyaan saya: Apakah ada cara untuk membaca file gambar besar dengan 10MP atau lebih dan menyimpannya ke file gambar baru, diubah ukurannya menjadi lebar dan tinggi baru tertentu, tanpa mendapatkan pengecualian OutOfMemory?
Saya juga mencoba BitmapFactory.decodeFile(file, options)
dan mengatur nilai Options.outHeight dan Options.outWidth secara manual ke 800 dan 533, tetapi tidak berfungsi seperti itu.
Jawaban:
Tidak. Saya ingin seseorang mengoreksi saya, tetapi saya menerima pendekatan load / resize yang Anda coba sebagai kompromi.
Berikut langkah-langkah untuk siapa saja yang menjelajah:
inSampleSize
yang masih menghasilkan gambar lebih besar dari target Anda.BitmapFactory.decodeFile(file, options)
, lewat inSampleSize sebagai opsi.Bitmap.createScaledBitmap()
.sumber
Jawaban Justin diterjemahkan ke kode (berfungsi sempurna untuk saya):
sumber
System.gc()
tolongIni adalah solusi 'Mojo Risin dan' Ofir "digabungkan". Ini akan memberi Anda ukuran gambar yang proporsional dengan batas lebar maks dan tinggi maks.
Bagi saya itu telah bekerja dengan baik pada gambar 5 MegaPixel di bawah ini.
sumber
Mengapa tidak menggunakan API?
sumber
Mengakui jawaban luar biasa lainnya sejauh ini, kode terbaik yang pernah saya lihat untuk ini adalah dalam dokumentasi untuk alat pengambilan foto.
Lihat bagian berjudul "Decode a Scaled Image".
http://developer.android.com/training/camera/photobasics.html
Solusi yang diajukannya adalah solusi pengubahan ukuran kemudian skala seperti yang lain di sini, tetapi cukup rapi.
Saya telah menyalin kode di bawah ini sebagai fungsi siap pakai untuk kenyamanan.
sumber
Setelah membaca jawaban ini dan dokumentasi android berikut ini adalah kode untuk mengubah ukuran bitmap tanpa memuatnya ke dalam memori:
sumber
Ketika saya memiliki bitmap besar dan saya ingin men-decode ukurannya saya menggunakan yang berikut ini
sumber
Ini mungkin berguna untuk orang lain yang melihat pertanyaan ini. Saya menulis ulang kode Justin untuk memungkinkan metode menerima objek ukuran target yang diperlukan juga. Ini bekerja sangat baik ketika menggunakan Kanvas. Semua kredit harus diberikan kepada JUSTIN untuk kode awal yang bagus.
Kode Justin SANGAT efektif dalam mengurangi overhead bekerja dengan Bitmap besar.
sumber
Saya tidak tahu apakah solusi saya adalah praktik terbaik, tetapi saya mencapai pemuatan bitmap dengan penskalaan yang saya inginkan dengan menggunakan opsi
inDensity
daninTargetDensity
.inDensity
adalah0
awalnya ketika tidak memuat sumber daya ditarik, sehingga pendekatan ini adalah untuk gambar sumber daya non pemuatan.Variabel
imageUri
,maxImageSideLength
dancontext
merupakan parameter dari metode saya. Saya hanya memposting implementasi metode tanpa membungkus AsyncTask untuk kejelasan.sumber
Mempertimbangkan bahwa Anda ingin mengubah ukuran ke ukuran yang tepat dan ingin menjaga kualitas sebanyak yang diperlukan, saya pikir Anda harus mencoba ini.
Motivasi: penskalaan beberapa langkah dapat memberikan gambar berkualitas lebih tinggi, namun tidak ada jaminan bahwa itu akan bekerja lebih baik daripada menggunakan inSampleSize yang tinggi. Sebenarnya, saya pikir Anda juga dapat menggunakan inSampleSize seperti 5 (bukan pow 2) untuk melakukan penskalaan langsung dalam satu operasi. Atau cukup gunakan 4 dan kemudian Anda bisa menggunakan gambar itu di UI. jika Anda mengirimnya ke server - maka Anda dapat melakukan penskalaan ke ukuran tepat di sisi server yang memungkinkan Anda menggunakan teknik penskalaan tingkat lanjut.
Catatan: jika Bitmap yang dimuat di langkah-3 setidaknya 4 kali lebih besar (sehingga lebar target 4 * <Lebar) Anda mungkin dapat menggunakan beberapa ukuran untuk mencapai kualitas yang lebih baik. setidaknya itu berfungsi di generik java, di android Anda tidak memiliki opsi untuk menentukan interpolasi yang digunakan untuk penskalaan http://today.java.net/pub/a/today/2007/04/03/perils-of- image-getscaledinstance.html
sumber
Saya menggunakan kode seperti ini:
Saya mencoba gambar asli 1230 x 1230, dan mendapat bitmap mengatakan 330 x 330.
Dan jika mencoba 2590 x 3849, saya akan mendapat OutOfMemoryError.
Saya menelusurinya, masih membuang OutOfMemoryError on line "BitmapFactory.decodeStream (is, null, options);", jika bitmap asli terlalu besar ...
sumber
Kode di atas sedikit lebih bersih. InputStreams akhirnya menutup pembungkus untuk memastikan mereka ditutup juga:
* Catatan
Input: InputStream adalah, int w, int h
Output: Bitmap
sumber
Untuk skala gambar dengan cara "benar", tanpa melewatkan piksel, Anda harus menghubungkan ke decoder gambar untuk melakukan pengambilan sampel baris demi baris. Android (dan pustaka Skia yang melandasinya) tidak menyediakan kait seperti itu, jadi Anda harus menggulirkannya sendiri. Dengan asumsi Anda berbicara gambar jpeg, taruhan terbaik Anda adalah menggunakan libjpeg secara langsung, dalam C.
Mengingat kompleksitas yang terlibat, menggunakan dua langkah subsampel-lalu-skala ulang mungkin yang terbaik untuk aplikasi jenis pratinjau gambar.
sumber
Berikut adalah artikel yang menggunakan pendekatan berbeda untuk mengubah ukuran. Ini akan mencoba untuk memuat bitmap terbesar ke dalam memori berdasarkan memori yang tersedia dalam proses dan kemudian melakukan transformasi.
http://bricolsoftconsulting.com/2012/12/07/handling-large-images-on-android/
sumber
Jika Anda benar-benar ingin melakukan perubahan ukuran satu langkah, Anda mungkin dapat memuat seluruh bitmap jika android: largeHeap = true tetapi seperti yang Anda lihat ini tidak benar-benar disarankan.
Dari docs: android: largeHeap Apakah proses aplikasi Anda harus dibuat dengan tumpukan Dalvik besar. Ini berlaku untuk semua proses yang dibuat untuk aplikasi. Ini hanya berlaku untuk aplikasi pertama yang dimuat ke dalam suatu proses; jika Anda menggunakan ID pengguna bersama untuk memungkinkan beberapa aplikasi menggunakan proses, mereka semua harus menggunakan opsi ini secara konsisten atau mereka akan memiliki hasil yang tidak dapat diprediksi. Sebagian besar aplikasi seharusnya tidak memerlukan ini dan sebaliknya harus fokus pada pengurangan penggunaan memori secara keseluruhan untuk peningkatan kinerja. Mengaktifkan ini juga tidak menjamin peningkatan yang tetap dalam memori yang tersedia, karena beberapa perangkat dibatasi oleh total memori yang tersedia.
sumber
Ada artikel bagus tentang masalah persis ini di situs web pengembang Android: Memuat Bitmap Besar Secara Efisien
sumber
Ini berhasil untuk saya. Fungsi mendapatkan path ke file pada kartu sd dan mengembalikan Bitmap dalam ukuran maksimum yang dapat ditampilkan. Kode ini dari Ofir dengan beberapa perubahan seperti file gambar di sd bukan Ressource dan witdth dan heigth dapatkan dari Display Object.
sumber
Berikut adalah kode yang saya gunakan yang tidak memiliki masalah mendekode gambar besar dalam memori di Android. Saya telah dapat mendekode gambar yang lebih besar dari 20MB selama parameter input saya sekitar 1024x1024. Anda dapat menyimpan bitmap yang dikembalikan ke file lain. Di bawah metode ini adalah metode lain yang juga saya gunakan untuk skala gambar ke bitmap baru. Jangan ragu untuk menggunakan kode ini seperti yang Anda inginkan.
CATATAN: Metode tidak ada hubungannya dengan satu sama lain kecuali metode decode panggilan createScaledBitmap di atas. Catatan lebar dan tinggi dapat berubah dari gambar asli.
sumber
atau:
sumber
Saya gunakan
Integer.numberOfLeadingZeros
untuk menghitung ukuran sampel terbaik, kinerja lebih baik.Kode lengkap dalam kotlin:
sumber
Ubah ukuran bitmap menggunakan kode berikut
Hal yang sama juga dijelaskan dalam tip / trik berikut
http://www.codeproject.com/Tips/625810/Android-Image-Operations-Using-BitmapFactory
sumber