Làm cách nào để chuyển đổi Drawable thành Bitmap?


947

Tôi muốn đặt một số nhất định Drawablelàm hình nền của thiết bị, nhưng tất cả các chức năng hình nền Bitmapchỉ chấp nhận s. Tôi không thể sử dụng WallpaperManagervì tôi là 2.1.

Ngoài ra, các drawable của tôi được tải xuống từ web và không cư trú R.drawable.



1
vui lòng chọn câu trả lời đúng, đây: stackoverflow.com/a/3035869/4548520
user25

Câu trả lời:


1289

Đoạn mã này giúp.

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

Đây là một phiên bản mà hình ảnh được tải xuống.

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);
}

1
Tôi nghĩ rằng bạn có các giá trị url. sau đó câu trả lời chỉnh sửa của tôi sẽ giúp.
Praveen

str_url đến từ đâu? Tôi không thể tìm thấy bất kỳ hàm Drawable nào liên quan đến chuỗi ... cảm ơn vì sự giúp đỡ của bạn.
Cướp

12
Tôi nghĩ rằng tôi đã tìm thấy một cái gì đó: nếu "draw" là drawable tôi muốn chuyển đổi thành bitmap thì: Bitmap bitmap = ((BitmapDrawable) draw) .getBitmap (); lừa
Cướp

1
@Rob: nếu Drawable của bạn chỉ là BitmapDrawable. (có nghĩa là Drawable của bạn thực sự là một trình bao bọc xung quanh Bitmap, thực tế)
njzk2

2
lưu ý: điều này gây ra java.lang.OutOfMemoryError lớn với JPG
Ai đó ở đâu đó vào

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;
}

41
Đây có vẻ như là câu trả lời duy nhất có thể hoạt động cho bất kỳ loại có thể rút nào và cũng có một giải pháp nhanh chóng cho một drawable đã là BitmapDrawable. +1
Matt Wolfe

1
chỉ cần một sửa đổi: docs nói về BitmapDrawable.getBitmap () rằng nó có thể trở lại null. Tôi nói nó cũng có thể trở lại đã được tái chế.
kelloss

16
Xem ra: getIntrinsicWidth()getIntrinsicHieght()sẽ trả về -1 nếu drawable là một màu đơn sắc.
SD

5
Vì vậy, ... một kiểm tra khác cho ColorDrawable, và chúng tôi có một người chiến thắng. Nghiêm túc mà nói, ai đó làm cho câu trả lời được chấp nhận.
kaay

2
Trái với câu trả lời được gắn cờ, điều này trả lời câu hỏi.
njzk2

214

Điều này chuyển đổi BitmapDrawable thành Bitmap.

Drawable d = ImagesArrayList.get(0);  
Bitmap bitmap = ((BitmapDrawable)d).getBitmap();

9
Đây thực sự là cách tốt nhất? Chắc chắn drawable có thể thuộc loại khác và điều này sẽ ném thời gian chạyException? Ví dụ, nó có thể là một chínPatchDrawble ...?
Dori

4
@Dori bạn có thể bọc mã trong một câu lệnh có điều kiện để kiểm tra xem nó có thực sự là BitmapDrawabletrước khi sử dụng nó không: if (d instanceof BitmapDrawable) { Bitmap bitmap = ((BitmapDrawable)d).getBitmap(); }
Tony Chan

367
Không thể tin 64 upvote? Mã đó rõ ràng chỉ hoạt động nếu dđã một BitmapDrawable, trong trường hợp đó, việc lấy nó dưới dạng bitmap ... sẽ bị lỗi ClassCastExceptiontrong tất cả các trường hợp khác.
Matthias

3
@Matthias không đề cập đến điều đó .. bản thân câu hỏi, cùng tác giả, có 100 phiếu: /
quinestor

2
Điều này là rất chuyên môn cho một trường hợp tầm thường.
njzk2

141

A Drawablecó thể được vẽ lên a Canvasvà a Canvascó thể được hỗ trợ bởi Bitmap:

(Được cập nhật để xử lý chuyển đổi nhanh cho BitmapDrawables và để đảm bảo rằng phần Bitmapđược tạo có kích thước hợp lệ)

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;
}

Điều gì xảy ra nếu param drawable là null?
hrules6872

1
Phương pháp này không hỗ trợ VectorDrawable
Mahmoud


Giả sử bạn có một Drawable không trống, tại sao cần phải kiểm tra xem chiều rộng và chiều cao không bằng 0? Ngoài ra, tại sao bạn cần sử dụng setBound () nếu chúng có cùng kích thước?
Yoav Feuerstein

!. Giải pháp tốt Android 8.0 / sdk 26 ApplicationInfo.loadIcon (PackageManager pm) trả về một AdaptiveIconDrawable Sử dụng mã của bạn có thể giúp tôi đúc AdaptiveIconDrawable để bitmap.
burulangtu

43

PHƯƠNG PHÁP 1 : Hoặc bạn có thể trực tiếp chuyển đổi sang bitmap như thế này

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

PHƯƠNG PHÁP 2 : Bạn thậm chí có thể chuyển đổi tài nguyên thành drawable và từ đó bạn có thể nhận được bitmap như thế này

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

Đối với API> 22 getDrawable phương thức được chuyển đến ResourcesCompatlớp để bạn làm điều gì đó như thế này

Bitmap myLogo = ((BitmapDrawable) ResourcesCompat.getDrawable(context.getResources(), R.drawable.logo, null)).getBitmap();

ResourcesCompat chỉ hoạt động nếu drawable là BitmapDrawable, nếu bạn đang sử dụng VectorDrawable, thì bạn sẽ có CCE.
Brill Pappin

Cả hai đều không hoạt động với tài nguyên VectorDrawable . Xảy ra lỗi sau -android.graphics.drawable.VectorDrawable cannot be cast to android.graphics.drawable.BitmapDrawable
Adam Hurwitz

Giải pháp này hoạt động tốt với Kotlin.
Adam Hurwitz


15

Vì vậy, sau khi xem (và sử dụng) các câu trả lời khác, dường như tất cả chúng đều xử lý ColorDrawablePaintDrawablerất tệ. (Đặc biệt là trên kẹo mút) dường như Shaders đã được điều chỉnh nên các khối màu không được xử lý chính xác.

Tôi đang sử dụng mã sau đây:

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;
}

Không giống như những người khác, nếu bạn gọi setBoundsvào Drawabletrước khi yêu cầu biến nó thành bitmap, nó sẽ vẽ bitmap ở kích thước chính xác!


Sẽ không đặt Bound làm hỏng các giới hạn trước của drawable? Không phải là tốt hơn để lưu trữ và khôi phục nó sau đó?
nhà phát triển Android

@androiddeveloper, nếu giới hạn đã được đặt, chúng tôi chỉ sử dụng những giới hạn đó. Trong một số trường hợp, điều này là cần thiết khi không có giới hạn nào được đặt và không có kích thước nội tại (như ColorDrawables trong một số trường hợp). Vì vậy, chiều rộng và chiều cao sẽ là 0, chúng tôi đưa ra 1x1 có thể vẽ theo cách nó thực sự vẽ một cái gì đó. Tôi có thể lập luận rằng chúng ta có thể thực hiện kiểm tra loại cho ColorDrawable trong những trường hợp đó, nhưng điều này hoạt động với 99% trường hợp. (Bạn có thể sửa đổi nó cho nhu cầu của bạn).
Chris.Jenkins

@ Chris.Jenkins Điều gì xảy ra nếu nó không có giới hạn, và bây giờ nó sẽ có những cái mới? Tôi cũng muốn hỏi một câu hỏi khác: cách tốt nhất để đặt kích thước bitmap (ngay cả đối với BitmapDrawable) được trả về là gì?
nhà phát triển Android

Tôi đề nghị bạn đọc kỹ mã. Nếu Drawablekhông có giới hạn, nó sử dụng IntrinsicWidth/Height. Nếu cả hai đều <= 0, chúng ta đặt canvas thành 1px. Bạn đúng nếu Drawablekhông có giới hạn thì nó sẽ được thông qua (1x1 là hầu hết các trường hợp), nhưng điều này BẮT BUỘC cho những thứ như ColorDrawableKHÔNG có kích thước nội tại. Nếu chúng tôi không làm điều này, nó sẽ ném Exception, bạn không thể vẽ 0x0 vào khung vẽ.
Chris.Jenkins

1
mutate()sẽ tạo một bản sao để lại bản vẽ gốc một mình, điều này sẽ phủ nhận vấn đề quay trở lại trong giới hạn ban đầu. Tôi hiếm khi thay đổi mã dựa trên những điểm đó. Nếu trường hợp sử dụng của bạn yêu cầu nó thêm một câu trả lời khác. Tôi đề nghị bạn tạo một câu hỏi khác để nhân rộng Bitmap.
Chris.Jenkins

13

Có lẽ điều này sẽ giúp ai đó ...

Từ PictureDrawable đến Bitmap, sử dụng:

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; 
}

... thực hiện như vậy:

Bitmap bmp = pictureDrawableToBitmap((PictureDrawable) drawable);

Như với câu trả lời của Rob, bạn đang yêu cầu một loại cụ thể Drawable, trong trường hợp này là a PictureDrawable.
kabuko

4
"Có lẽ điều này sẽ giúp được ai đó ..."
Mauro

11

Đây là giải pháp tốt hơn

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());
}

Mã từ Cách đọc các bit có thể rút ra như InputStream


11

1) có thể vẽ thành Bitmap:

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

2) bitmap để có thể vẽ:

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

10

Đây là phiên bản Kotlin đẹp của câu trả lời được cung cấp bởi @ Chris.Jenkins tại đây: 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


8

Android cung cấp một giải pháp foward không thẳng : BitmapDrawable. Để có được Bitmap, chúng tôi sẽ phải cung cấp id tài nguyên R.drawable.flower_piccho a BitmapDrawablevà sau đó chuyển nó thành a Bitmap.

Bitmap bm = ((BitmapDrawable) getResources().getDrawable(R.drawable.flower_pic)).getBitmap();

5

Sử dụng mã này. Nó sẽ giúp bạn đạt được mục tiêu của mình.

 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;
}

3

BitmapFactory.decodeResource()tự động chia tỷ lệ bitmap, do đó bitmap của bạn có thể bị mờ. Để ngăn chặn tỷ lệ, hãy làm điều này:

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

hoặc là

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

2

nếu bạn đang sử dụng kotlin, sử dụng mã dưới đây. nó sẽ làm việc

// để sử dụng đường dẫn hình ảnh

val image = Drawable.createFromPath(path)
val bitmap = (image as BitmapDrawable).bitmap


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);
        }
    }
}

Tôi nghĩ bạn đọc sai câu hỏi. Câu hỏi đặt ra: làm thế nào để có được một bitmap từ một tài nguyên có thể rút ra không phải là bộ sưu tập hệ thống
kc ochibili

1

Thư viện ImageWorker có thể chuyển đổi bitmap thành drawable hoặc base64 và ngược lại.

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

Thực hiện

Trong cấp độ dự án

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

Trong cấp độ ứng dụng

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

Bạn cũng có thể lưu trữ và truy xuất ảnh bitmap / drawables / base64 từ bên ngoài.

Kiểm tra tại đây. https://github.com/1A Over ALL / ImageWorker /edit / master / ORADME.md

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.