Lấy Bitmap từ vector có thể vẽ


132

Trong ứng dụng của mình, tôi phải đặt một biểu tượng lớn cho thông báo. LargeIcon phải là Bitmap và các hình vẽ của tôi là hình ảnh vector (tính năng mới trong Android, xem liên kết này ) Vấn đề là khi tôi cố gắng giải mã tài nguyên là hình ảnh vector, tôi nhận được null.

Đây là mẫu mã:

if (BitmapFactory.decodeResource(arg0.getResources(), R.drawable.vector_menu_objectifs) == null)
        Log.d("ISNULL", "NULL");
    else
        Log.d("ISNULL", "NOT NULL");

Trong mẫu này, khi tôi thay thế R.drawable.vector_menu_objectifs bằng một hình ảnh "bình thường", một png cho ví dụ, kết quả không phải là null (tôi nhận được bitmap chính xác) Có thiếu gì không?


1
Có vấn đề tương tự, không phải giải pháp mà là cách giải quyết: stackoverflow.com/questions/33548447/ Đổi
Hơn

Câu trả lời:


231

Đã kiểm tra trên API: 17, 21, 23

public static Bitmap getBitmapFromVectorDrawable(Context context, int drawableId) {
    Drawable drawable = ContextCompat.getDrawable(context, drawableId);
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        drawable = (DrawableCompat.wrap(drawable)).mutate();
    }

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

CẬP NHẬT:

Lớp dự án:

dependencies {
        classpath 'com.android.tools.build:gradle:2.2.0-alpha5'
    }

Học sinh lớp:

android {
    compileSdkVersion 23
    buildToolsVersion '23.0.3'
    defaultConfig {
        minSdkVersion 16
        targetSdkVersion 23
        vectorDrawables.useSupportLibrary = true
    }
    ...
}
...

Cảm ơn bạn. Câu trả lời trước không hoạt động với phiên bản sdk bắt đầu từ 23
Paha

2
Điều này làm việc tuyệt vời cho tôi. Chạy trên API 15 mà không gặp vấn đề gì
vera

4
AppCompatDrawableManagerđược đánh dấu là @RestrictTo(LIBRARY_GROUP)vì vậy nó là nội bộ và bạn không nên sử dụng nó (API của nó có thể thay đổi mà không cần thông báo trước). Sử dụng ContextCompatthay thế.
mradzinski

không hoạt động Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Bitmap.setHasAlpha(boolean)' on a null object referencetrên dòng nàyBitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
user25

5
Tôi đã có vấn đề với giải pháp này. Đối với tôi bằng cách sử dụng: AppCompatResource thay vì ContextCompat đã sửa nó: Drawable drawable = AppCompatResource.getDrawable (bối cảnh, drawableId);
Mike T

64

Bạn có thể sử dụng phương pháp sau:

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static Bitmap getBitmap(VectorDrawable vectorDrawable) {
    Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),
            vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    vectorDrawable.draw(canvas);
    return bitmap;
}

mà đôi khi tôi kết hợp với:

private static Bitmap getBitmap(Context context, int drawableId) {
    Drawable drawable = ContextCompat.getDrawable(context, drawableId);
    if (drawable instanceof BitmapDrawable) {
        return ((BitmapDrawable) drawable).getBitmap();
    } else if (drawable instanceof VectorDrawable) {
        return getBitmap((VectorDrawable) drawable);
    } else {
        throw new IllegalArgumentException("unsupported drawable type");
    }
}

2
hy vọng @liltof quay lại và đánh dấu đây là câu trả lời. Một điều cần lưu ý là cả hai phương thức đều muốn trình bao bọc đíchAPAPi - nhưng studio android sẽ cho bạn biết điều đó.
roberto tomás

1
Tôi đã dành khoảng hai ngày để làm điều này bây giờ khi nghĩ về vấn đề tập tin svg của nó. Cảm ơn bạn!
sparkly_frog

1
không hoạt động Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Bitmap.setHasAlpha(boolean)' on a null object referencetrên dòng nàyBitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(), vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
user25

45

Nếu bạn sẵn sàng sử dụng Android KTX cho Kotlin, bạn có thể sử dụng phương pháp tiện ích mở rộng Drawable#toBitmap()để đạt được hiệu quả tương tự như các câu trả lời khác:

val bitmap = AppCompatResources.getDrawable(requireContext(), drawableId).toBitmap() 

hoặc là

val bitmap = AppCompatResources.getDrawable(context, drawableId).toBitmap() 

Để thêm phương thức này và các phương thức mở rộng hữu ích khác, bạn sẽ cần thêm phần sau vào cấp độ mô-đun của mình build.gradle

repositories {
    google()
}

dependencies {
    implementation "androidx.core:core-ktx:1.2.0"
}

Xem ở đây để được hướng dẫn mới nhất để thêm phụ thuộc vào dự án của bạn.

Lưu ý rằng điều này sẽ làm việc cho bất kỳ lớp con nàoDrawable và nếu Drawablelà một BitmapDrawablephím tắt, nó sẽ sử dụng phím tắt Bitmap.


Đây là giải pháp đơn giản nhất ở đây cho Kotlin.
Adam Hurwitz

1
Đối với tôi nó hoạt động hoàn toàn tốt với VectorDrawable.
ubuntudroid

Đây là tùy chọn tốt nhất .. androidx mặc định cung cấp chức năng
Reshma

27

Dựa trên các câu trả lời trước đó, có thể đơn giản hóa như vậy để phù hợp với cả VectorDrawable và BitmapDrawable và để tương thích với ít nhất API 15.

public static Bitmap getBitmapFromDrawable(Context context, @DrawableRes int drawableId) {
    Drawable drawable = AppCompatResources.getDrawable(context, drawableId);

    if (drawable instanceof BitmapDrawable) {
        return ((BitmapDrawable) drawable).getBitmap();
    } else if (drawable instanceof VectorDrawableCompat || drawable instanceof VectorDrawable) {
        Bitmap 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;
    } else {
        throw new IllegalArgumentException("unsupported drawable type");
    }
}

Sau đó, bạn phải thêm vào tập tin lớp của bạn:

android {
    defaultConfig {
        vectorDrawables.useSupportLibrary = true
    }
}

Trên pre-Lollipop, nó sẽ sử dụng VectorDrawableCompat và trên Lollipop, nó sẽ sử dụng VectorDrawable.

BIÊN TẬP

Tôi đã chỉnh sửa điều kiện theo nhận xét của @ user3109468


1
Ví dụ có thể vẽ được VectorDrawable | | Ví dụ có thể vẽ được VectorDrawableCompat nên đổi bên. Kết quả trong một lớp không tìm thấy khi VectorDrawable không tồn tại, khi VectorDrawableCompat nên được kiểm tra trước vì nó tồn tại.
Warrick

kiểm tra loại của VertorDrawable có thể được mô tả là(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && drawable instanceof VectorDrawable)
chmin 30/11/19

6

Thanh danh đến @Alexey

Đây là Kotlinphiên bản sử dụng tiện ích mở rộng đểContext

fun Context.getBitmapFromVectorDrawable(drawableId: Int): Bitmap? {
    var drawable = ContextCompat.getDrawable(this, drawableId) ?: return null

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        drawable = DrawableCompat.wrap(drawable).mutate()
    }

    val bitmap = Bitmap.createBitmap(
            drawable.intrinsicWidth,
            drawable.intrinsicHeight,
            Bitmap.Config.ARGB_8888) ?: return null
    val canvas = Canvas(bitmap)
    drawable.setBounds(0, 0, canvas.width, canvas.height)
    drawable.draw(canvas)

    return bitmap
}

Ví dụ sử dụng trong Activity:

val bitmap = this.getBitmapFromVectorDrawable(R.drawable.ic_done_white_24dp)

1

Đã thử nghiệm trên API 16 - JellyBean với Vector Drawables

public static Bitmap getBitmapFromVectorDrawable(Context context, int drawableId) {
    Drawable drawable = AppCompatResources.getDrawable(context, drawableId);
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        drawable = (DrawableCompat.wrap(drawable)).mutate();
    }

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

1

Sử dụng mã sau đây để chuyển đổi hình ảnh với tỷ lệ khung hình chính xác (ví dụ: đối với biểu tượng thông báo):

public static Bitmap getBitmapFromVector(Context context, int drawableId) {
    Drawable drawable = ContextCompat.getDrawable(context, drawableId);
    int width = drawable.getIntrinsicWidth();
    int height = drawable.getIntrinsicHeight();
    Bitmap bitmap;
    if (width < height) {    //make a square
        bitmap = Bitmap.createBitmap(height, height, Bitmap.Config.ARGB_8888);
    } else {
        bitmap = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888);
    }
    Canvas canvas = new Canvas(bitmap);
    drawable.setBounds(0, 0,
            drawable.getIntrinsicWidth(),    //use dimensions of Drawable
            drawable.getIntrinsicHeight()
    );
    drawable.draw(canvas);
    return bitmap;
}

0

Nếu bạn vectorhình ảnh intrinsicWidthintrinsicHeightlà nhỏ và bạn cố gắng để hiển thị bitmap để một cái nhìn lớn, sau đó bạn sẽ thấy kết quả là mờ.

Trong trường hợp đó, bạn có thể cung cấp chiều rộng / chiều cao mới cho bitmap của mình để có được hình ảnh tốt hơn (hoặc bạn có thể tăng kích thước vectơ trong xml, nhưng cung cấp desireWidthdesireHeightcó thể linh hoạt hơn).

private fun getBitmap(drawableId: Int, desireWidth: Int? = null, desireHeight: Int? = null): Bitmap? {
    val drawable = AppCompatResources.getDrawable(context, drawableId) ?: return null
    val bitmap = Bitmap.createBitmap(
        desireWidth ?: drawable.intrinsicWidth,
        desireHeight ?: drawable.intrinsicHeight,
        Bitmap.Config.ARGB_8888
    )
    val canvas = Canvas(bitmap)
    drawable.setBounds(0, 0, canvas.width, canvas.height)
    drawable.draw(canvas)
    return bitmap
}

Hy vọng nó sẽ giúp


0
Drawable layerDrawable = (Drawable) imageBase.getDrawable();
Bitmap bitmap = Bitmap.createBitmap(layerDrawable.getIntrinsicWidth(),
        layerDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
layerDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
layerDrawable.draw(canvas);  
imageTeste.setImageBitmap(addGradient(bitmap));

0

Nếu bạn muốn có thể chia tỷ lệ đầu ra của mình thành kích thước đầu ra mong muốn, hãy thử đoạn trích sau:

fun getBitmapFromVectorDrawable(context: Context, drawableId: Int, outputSize: OutputSize? = null): Bitmap? {
    var drawable = ContextCompat.getDrawable(context, drawableId) ?: return null
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        drawable = DrawableCompat.wrap(drawable).mutate()
    }

    var targetBitmap: Bitmap
    if (outputSize != null) {
        targetBitmap = Bitmap.createBitmap(outputSize.width,
                outputSize.height, Bitmap.Config.ARGB_8888)
    } else {
        targetBitmap = Bitmap.createBitmap(drawable.intrinsicWidth,
            drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
    }

    val canvas = Canvas(targetBitmap)
    val scaleX =  targetBitmap.width.toFloat()/drawable.intrinsicWidth.toFloat()
    val scaleY =  targetBitmap.height.toFloat()/drawable.intrinsicHeight.toFloat()
    canvas.scale(scaleX, scaleY)
    drawable.draw(canvas)

    return targetBitmap
}

class OutputSize(val width: Int, val height: Int)

0

Điều này cung cấp cho bạn bitmap theo kích thước bạn muốn. Ngoài ra, nó cho phép bạn duy trì hoặc không trong suốt tùy thuộc vào từng hình ảnh để có hiệu suất tốt hơn với những hình ảnh không cần nó.

public static Bitmap drawableToBitmap(Resources res, int drawableId,
        int width, int height, boolean keepAlpha) {
    Drawable drawable = res.getDrawable(drawableId);
    Bitmap bmp = createBitmap(width, height, keepAlpha ?
            Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
    Canvas cvs = new Canvas(bmp);
    drawable.setBounds(0, 0, width, height);
    drawable.draw(cvs);
    return bmp;
}
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.