Bagaimana cara mengubah Drawable ke Bitmap?

949

Saya ingin menetapkan tertentu Drawablesebagai wallpaper perangkat, tetapi semua fungsi wallpaper Bitmaphanya menerima . Saya tidak dapat menggunakan WallpaperManagerkarena saya pra 2.1.

Juga, drawables saya diunduh dari web dan tidak tinggal di R.drawable.

rampok
sumber
1
silakan pilih jawaban yang benar, ini: stackoverflow.com/a/3035869/4548520
user25

Jawaban:

1289

Sepotong kode ini membantu.

Bitmap icon = BitmapFactory.decodeResource(context.getResources(),
                                           R.drawable.icon_resource);

Di sini versi di mana gambar diunduh.

String name = c.getString(str_url);
URL url_value = new URL(name);
ImageView profile = (ImageView)v.findViewById(R.id.vdo_icon);
if (profile != null) {
    Bitmap mIcon1 =
        BitmapFactory.decodeStream(url_value.openConnection().getInputStream());
    profile.setImageBitmap(mIcon1);
}
Praveen
sumber
1
saya pikir Anda memiliki nilai url. maka jawaban saya yang diedit akan membantu.
Praveen
dari mana str_url berasal? Saya tidak dapat menemukan fungsi Drawable yang terkait dengan string ... terima kasih atas bantuan Anda.
Rob
12
Saya rasa saya menemukan sesuatu: jika "draw" adalah drawable yang ingin saya konversi menjadi bitmap maka: Bitmap bitmap = ((BitmapDrawable) draw) .getBitmap (); lakukan triknya!
Rob
1
@Rob: jika Drawable Anda hanya BitmapDrawable. (yang artinya Drawable Anda hanyalah pembungkus Bitmap, sebenarnya)
njzk2
2
catatan: ini menyebabkan java.lang.OutOfMemoryError besar-besaran dengan JPG
Someone Somewhere
744
public static Bitmap drawableToBitmap (Drawable drawable) {
    Bitmap bitmap = null;

    if (drawable instanceof BitmapDrawable) {
        BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
        if(bitmapDrawable.getBitmap() != null) {
            return bitmapDrawable.getBitmap();
        }
    }

    if(drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
        bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel
    } else {
        bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    }

    Canvas canvas = new Canvas(bitmap);
    drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    drawable.draw(canvas);
    return bitmap;
}
André
sumber
41
Ini sepertinya satu-satunya jawaban yang akan bekerja untuk semua jenis drawable dan juga memiliki solusi cepat untuk drawable yang sudah menjadi BitmapDrawable. +1
Matt Wolfe
1
hanya satu perubahan: dokumen mengatakan tentang BitmapDrawable.getBitmap () yang mungkin kembali nol. Saya katakan itu mungkin juga kembali sudah didaur ulang.
kellog
16
Awas: getIntrinsicWidth()dan getIntrinsicHieght()akan kembali -1 jika drawable adalah warna solid.
SD
5
Jadi ... cek lagi untuk ColorDrawable, dan kami punya pemenang. Serius, seseorang menjadikan ini jawaban yang diterima.
kaay
2
Bertentangan dengan jawaban yang ditandai, ini menjawab pertanyaan.
njzk2
214

Ini mengkonversi BitmapDrawable ke Bitmap.

Drawable d = ImagesArrayList.get(0);  
Bitmap bitmap = ((BitmapDrawable)d).getBitmap();
rampok
sumber
9
apakah ini benar-benar cara terbaik? Tentunya drawable bisa dari tipe lain dan ini akan melempar runtimeException? Misalnya itu bisa menjadi sembilanPatchDrawble ...?
Dori,
4
@Dori Anda bisa membungkus kode dalam pernyataan bersyarat untuk memeriksa apakah itu memang BitmapDrawablesebelum casting itu: if (d instanceof BitmapDrawable) { Bitmap bitmap = ((BitmapDrawable)d).getBitmap(); }
Tony Chan
367
Tidak percaya 64 upvotes? Kode yang jelas hanya bekerja jika dsudah merupakan suatu BitmapDrawable, dalam hal itu sepele untuk mengambilnya sebagai bitmap ... Akan kecelakaan dengan ClassCastExceptiondalam semua kasus lain.
Matthias
3
@Matthias belum lagi .. pertanyaan itu sendiri, penulis yang sama, memiliki 100 suara: /
quinestor
2
Ini sangat khusus untuk kasus sepele.
njzk2
141

A Drawabledapat ditarik ke Canvas, dan Canvasdapat didukung oleh Bitmap:

(Diperbarui untuk menangani konversi cepat untuk BitmapDrawabledan memastikan bahwa yang Bitmapdibuat memiliki ukuran yang valid)

public static Bitmap drawableToBitmap (Drawable drawable) {
    if (drawable instanceof BitmapDrawable) {
        return ((BitmapDrawable)drawable).getBitmap();
    }

    int width = drawable.getIntrinsicWidth();
    width = width > 0 ? width : 1;
    int height = drawable.getIntrinsicHeight();
    height = height > 0 ? height : 1;

    Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap); 
    drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    drawable.draw(canvas);

    return bitmap;
}
kabuko
sumber
Apa yang terjadi jika param yang dapat ditarik adalah nol?
hrules6872
1
Metode ini tidak mendukung VectorDrawable
Mahmoud
Dengan anggapan Anda mendapatkan Drawable yang tidak kosong, mengapa harus memeriksa lebar dan tinggi yang bukan 0? Juga, mengapa Anda perlu menggunakan setBounds () jika ukurannya sama?
Yoav Feuerstein
Solusi bagus! Aplikasi Android 8.0 / sdk 26 ApplicationInfo.loadIcon (PackageManager pm) mengembalikan AdaptiveIconDrawable。 Gunakan kode Anda dapat membantu saya membuang AdaptiveIconDrawable ke bitmap。
burulangtu
43

METODE 1 : Anda dapat langsung mengonversi ke bitmap seperti ini

Bitmap myLogo = BitmapFactory.decodeResource(context.getResources(), R.drawable.my_drawable);

METODE 2 : Anda bahkan dapat mengubah sumber daya menjadi drawable dan dari situ Anda bisa mendapatkan bitmap seperti ini

Bitmap myLogo = ((BitmapDrawable)getResources().getDrawable(R.drawable.logo)).getBitmap();

Untuk API> 22 getDrawable metode dipindahkan ke ResourcesCompatkelas sehingga untuk itu Anda melakukan sesuatu seperti ini

Bitmap myLogo = ((BitmapDrawable) ResourcesCompat.getDrawable(context.getResources(), R.drawable.logo, null)).getBitmap();
Keyur
sumber
ResourcesCompat hanya berfungsi jika drawable adalah BitmapDrawable, jika Anda menggunakan VectorDrawable, maka Anda akan memiliki CCE.
Brill Pappin
Tak satu pun dari ini bekerja dengan sumber daya VectorDrawable . Kesalahan berikut terjadi -android.graphics.drawable.VectorDrawable cannot be cast to android.graphics.drawable.BitmapDrawable
Adam Hurwitz
Solusi ini berfungsi baik dengan Kotlin.
Adam Hurwitz
31

sangat sederhana

Bitmap tempBMP = BitmapFactory.decodeResource(getResources(),R.drawable.image);
Erfan Bagheri
sumber
6
Ini hanyalah plagiarisme dari jawaban lain atas pertanyaan ini tiga tahun penuh sebelumnya
Nick Cardoso
15

Jadi setelah mencari (dan menggunakan) dari jawaban lain, tampaknya mereka semua menangani ColorDrawabledan PaintDrawableburuk. (Khususnya pada lollipop) sepertinya Shaderada perubahan sehingga blok warna solid tidak ditangani dengan benar.

Saya menggunakan kode berikut sekarang:

public static Bitmap drawableToBitmap(Drawable drawable) {
    if (drawable instanceof BitmapDrawable) {
        return ((BitmapDrawable) drawable).getBitmap();
    }

    // We ask for the bounds if they have been set as they would be most
    // correct, then we check we are  > 0
    final int width = !drawable.getBounds().isEmpty() ?
            drawable.getBounds().width() : drawable.getIntrinsicWidth();

    final int height = !drawable.getBounds().isEmpty() ?
            drawable.getBounds().height() : drawable.getIntrinsicHeight();

    // Now we check we are > 0
    final Bitmap bitmap = Bitmap.createBitmap(width <= 0 ? 1 : width, height <= 0 ? 1 : height,
            Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    drawable.draw(canvas);

    return bitmap;
}

Tidak seperti yang lain, jika Anda memanggil setBoundspada Drawablesebelum meminta untuk mengubahnya menjadi bitmap, itu akan menarik bitmap di ukuran yang benar!

Chris. Jenkins
sumber
Bukankah setBounds akan merusak batas sebelumnya dari drawable? Bukankah lebih baik menyimpan dan mengembalikannya setelah itu?
pengembang android
@androiddeveloper, jika batas telah ditetapkan, kita tetap menggunakan itu. Dalam beberapa kasus ini diperlukan di mana tidak ada batas yang telah ditetapkan dan tidak memiliki ukuran intrinsik (seperti ColorDrawables dalam beberapa kasus). Jadi lebar dan tinggi adalah 0, kami memberikan 1x1 yang dapat digambar sedemikian rupa sehingga benar-benar menarik sesuatu. Saya bisa berargumen bahwa kita bisa melakukan pemeriksaan tipe untuk ColorDrawable dalam kasus-kasus itu, tetapi ini bekerja untuk 99% kasus. (Anda dapat memodifikasinya untuk kebutuhan Anda).
Chris. Jenkins
@ Chris.Jenkins Bagaimana jika tidak ada batasan, dan sekarang akan mendapatkan yang baru? Saya juga ingin mengajukan pertanyaan lain: apa cara terbaik untuk mengatur ukuran bitmap (bahkan untuk BitmapDrawable) yang dikembalikan?
pengembang android
Saya sarankan Anda membaca kode dengan cermat. Jika Drawabletidak memiliki batas yang ditetapkan itu menggunakan IntrinsicWidth/Height. Jika keduanya <= 0, kami mengatur kanvas ke 1px. Anda benar jika Drawabletidak memiliki batas itu akan melewati beberapa (1x1 adalah kebanyakan kasus), tetapi ini DIBUTUHKAN untuk hal-hal seperti ColorDrawableyang TIDAK memiliki ukuran intrinsik. Jika kami tidak melakukan ini, itu akan melempar Exception, Anda tidak dapat menggambar 0x0 ke kanvas.
Chris. Jenkins
1
mutate()akan membuat salinan meninggalkan gambar asli sendiri yang akan meniadakan masalah lewat kembali di batas asli. Saya jarang mengubah kode berdasarkan poin-poin itu. Jika use case Anda membutuhkannya tambahkan jawaban lain. Saya sarankan Anda membuat pertanyaan lain untuk penskalaan Bitmap.
Chris. Jenkins
13

Mungkin ini akan membantu seseorang ...

Dari PictureDrawable ke Bitmap, gunakan:

private Bitmap pictureDrawableToBitmap(PictureDrawable pictureDrawable){ 
    Bitmap bmp = Bitmap.createBitmap(pictureDrawable.getIntrinsicWidth(), pictureDrawable.getIntrinsicHeight(), Config.ARGB_8888); 
    Canvas canvas = new Canvas(bmp); 
    canvas.drawPicture(pictureDrawable.getPicture()); 
    return bmp; 
}

... diimplementasikan seperti itu:

Bitmap bmp = pictureDrawableToBitmap((PictureDrawable) drawable);
Mauro
sumber
Seperti jawaban Rob, Anda memerlukan jenis tertentu Drawable, dalam hal ini a PictureDrawable.
kabuko
4
"Mungkin ini akan membantu seseorang ..."
Mauro
11

Ini resolusi yang lebih baik

public static Bitmap drawableToBitmap (Drawable drawable) {
    if (drawable instanceof BitmapDrawable) {
        return ((BitmapDrawable)drawable).getBitmap();
    }

    Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap); 
    drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    drawable.draw(canvas);

    return bitmap;
}

public static InputStream bitmapToInputStream(Bitmap bitmap) {
    int size = bitmap.getHeight() * bitmap.getRowBytes();
    ByteBuffer buffer = ByteBuffer.allocate(size);
    bitmap.copyPixelsToBuffer(buffer);
    return new ByteArrayInputStream(buffer.array());
}

Kode dari Cara membaca bit yang dapat digambar sebagai InputStream

Dawid Drozd
sumber
11

1) dapat ditarik ke Bitmap:

Bitmap mIcon = BitmapFactory.decodeResource(context.getResources(),R.drawable.icon);
// mImageView.setImageBitmap(mIcon);

2) bitmap ke Drawable:

Drawable mDrawable = new BitmapDrawable(getResources(), bitmap);
// mImageView.setDrawable(mDrawable);
Sanjayrajsinh
sumber
10

Berikut adalah versi Kotlin yang bagus dari jawaban yang diberikan oleh @ Chris.Jenkins di sini: https://stackoverflow.com/a/27543712/1016462

fun Drawable.toBitmap(): Bitmap {
  if (this is BitmapDrawable) {
    return bitmap
  }

  val width = if (bounds.isEmpty) intrinsicWidth else bounds.width()
  val height = if (bounds.isEmpty) intrinsicHeight else bounds.height()

  return Bitmap.createBitmap(width.nonZero(), height.nonZero(), Bitmap.Config.ARGB_8888).also {
    val canvas = Canvas(it)
    setBounds(0, 0, canvas.width, canvas.height)
    draw(canvas)
  }
}

private fun Int.nonZero() = if (this <= 0) 1 else this
tasomaniac
sumber
8

Android menyediakan solusi foward non lurus: BitmapDrawable. Untuk mendapatkan Bitmap, kita harus memberikan id sumber daya R.drawable.flower_picke a BitmapDrawabledan kemudian melemparkannya ke a Bitmap.

Bitmap bm = ((BitmapDrawable) getResources().getDrawable(R.drawable.flower_pic)).getBitmap();
kc ochibili
sumber
5

Gunakan kode ini. Ini akan membantu Anda untuk mencapai tujuan Anda.

 Bitmap bmp=BitmapFactory.decodeResource(getResources(), R.drawable.profileimage);
    if (bmp!=null) {
        Bitmap bitmap_round=getRoundedShape(bmp);
        if (bitmap_round!=null) {
            profileimage.setImageBitmap(bitmap_round);
        }
    }

  public Bitmap getRoundedShape(Bitmap scaleBitmapImage) {
    int targetWidth = 100;
    int targetHeight = 100;
    Bitmap targetBitmap = Bitmap.createBitmap(targetWidth, 
            targetHeight,Bitmap.Config.ARGB_8888);

    Canvas canvas = new Canvas(targetBitmap);
    Path path = new Path();
    path.addCircle(((float) targetWidth - 1) / 2,
            ((float) targetHeight - 1) / 2,
            (Math.min(((float) targetWidth), 
                    ((float) targetHeight)) / 2),
                    Path.Direction.CCW);

    canvas.clipPath(path);
    Bitmap sourceBitmap = scaleBitmapImage;
    canvas.drawBitmap(sourceBitmap, 
            new Rect(0, 0, sourceBitmap.getWidth(),
                    sourceBitmap.getHeight()), 
                    new Rect(0, 0, targetWidth, targetHeight), new Paint(Paint.FILTER_BITMAP_FLAG));
    return targetBitmap;
}
anupam sharma
sumber
3

BitmapFactory.decodeResource()secara otomatis skala bitmap, sehingga bitmap Anda mungkin berubah fuzzy. Untuk mencegah penskalaan, lakukan ini:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
Bitmap source = BitmapFactory.decodeResource(context.getResources(),
                                             R.drawable.resource_name, options);

atau

InputStream is = context.getResources().openRawResource(R.drawable.resource_name)
bitmap = BitmapFactory.decodeStream(is);
John Doe
sumber
2

jika Anda menggunakan kotlin, gunakan kode di bawah ini. ini akan bekerja

// untuk menggunakan jalur gambar

val image = Drawable.createFromPath(path)
val bitmap = (image as BitmapDrawable).bitmap
Sachidananda Sahu
sumber
1
 // get image path from gallery
protected void onActivityResult(int requestCode, int resultcode, Intent intent) {
    super.onActivityResult(requestCode, resultcode, intent);

    if (requestCode == 1) {
        if (intent != null && resultcode == RESULT_OK) {             
            Uri selectedImage = intent.getData();

            String[] filePathColumn = {MediaStore.Images.Media.DATA};
            Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
            cursor.moveToFirst();
            int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
            filePath = cursor.getString(columnIndex);

            //display image using BitmapFactory

            cursor.close(); bmp = BitmapFactory.decodeFile(filepath); 
            iv.setBackgroundResource(0);
            iv.setImageBitmap(bmp);
        }
    }
}
malaikat
sumber
Saya pikir Anda salah membaca pertanyaan. Pertanyaannya bertanya: bagaimana cara mendapatkan bitmap dari sumber daya yang dapat
digambar
1

ImageWorker Library dapat mengonversi bitmap menjadi drawable atau base64 dan sebaliknya.

val bitmap: Bitmap? = ImageWorker.convert().drawableToBitmap(sourceDrawable)

Penerapan

Dalam Gradle Tingkat Proyek

allprojects {
        repositories {
            ...
            maven { url 'https://jitpack.io' }
        }
    }

Di Tingkat Aplikasi Gradle

dependencies {
            implementation 'com.github.1AboveAll:ImageWorker:0.51'
    }

Anda juga dapat menyimpan dan mengambil gambar bitmap / drawables / base64 dari eksternal.

Periksa di sini. https://github.com/1AboveAll/ImageWorker/edit/master/README.md

Himanshu Rawat
sumber