Vektör çekilebilirinden bitmap alma


134

Uygulamamda bir bildirim için büyük bir simge ayarlamam gerekiyor. LargeIcon bir Bitmap olmalı ve benim çekilebilir öğelerim vektör görüntüleridir (Android'deki yeni özellik, bu bağlantıya bakın ) Sorun, vektör görüntüsü olan bir kaynağın kodunu çözmeye çalıştığımda, bir boş değer döndürdüğümdür.

İşte kod örneği:

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

Bu örnekte, R.drawable.vector_menu_objectifs yerine "normal" bir resim, örneğin bir png ile değiştirdiğimde, sonuç boş değil (doğru bit eşlemi alıyorum) Eksik bir şey var mı?


1
Had benzer sorun değil, çözüm ancak geçici bir çözüm: stackoverflow.com/questions/33548447/...
Daha

Yanıtlar:


233

API üzerinde kontrol edildi: 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;
}

GÜNCELLEME:

Proje notu:

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

Modül derecesi:

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

Teşekkür ederim. 23 den SDK sürümü başlangıç çalışmıyor Önceki cevap
Paha

2
Bu benim için harika çalışıyor. API 15 üzerinde sorunsuz çalışıyor
vera

4
AppCompatDrawableManager@RestrictTo(LIBRARY_GROUP)dahili olarak işaretlenmiştir ve onu kullanmamanız gerekir (API'sı önceden haber verilmeksizin değiştirilebilir). ContextCompatBunun yerine kullanın .
mradzinski

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Bitmap.setHasAlpha(boolean)' on a null object referencebu hatta çalışmıyorBitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
kullanıcı25

5
Bu çözümle ilgili sorunlarım vardı. Benim için şunu kullanıyorum: ContextCompat yerine AppCompatResources bunu düzeltti: Drawable drawable = AppCompatResources.getDrawable (context, drawableId);
Mike T

64

Aşağıdaki yöntemi kullanabilirsiniz:

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

bazen birleştirdiğim:

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
umarım @liltof geri gelir ve bunu yanıt olarak işaretler. Unutulmaması gereken tek şey, her iki yöntemin de targetAPi sarmalayıcısını istemesidir - ancak android studio bunu size söyleyecektir.
roberto tomás

1
Bunu yapmaya çalışmak için yaklaşık iki gün harcadım, şimdi svg dosyası sorununu düşündüm. Teşekkür ederim!
sparkly_frog

1
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Bitmap.setHasAlpha(boolean)' on a null object referencebu hatta çalışmıyorBitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(), vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
kullanıcı25

45

Kullanmak isteyen varsa Android konum Haritası KOTLIN için size uzatma yöntemini kullanabilirsiniz Drawable#toBitmap()diğer cevaplar aynı etkiyi elde etmek için:

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

veya

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

Bunu ve diğer yararlı uzantı yöntemlerini eklemek için aşağıdakileri modül düzeyinize eklemeniz gerekir. build.gradle

repositories {
    google()
}

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

Projenize bağımlılık eklemek için en son talimatlar için buraya bakın .

Bunun herhangi bir alt sınıfı için işe yarayacağını Drawableve eğer bir ise Drawable, BitmapDrawabletemelini kullanmak için kısayol olacağını unutmayın Bitmap.


Kotlin için buradaki en basit çözüm budur.
Adam Hurwitz

1
Benim için mükemmel çalışıyor VectorDrawable.
ubuntudroid

Bu en iyi seçenektir .. varsayılan androidx işlevsellik sağlar
Reshma,

27

Önceki cevaplara dayanarak, hem VectorDrawable hem de BitmapDrawable ile eşleşecek ve en az API 15 ile uyumlu olacak şekilde basitleştirilebilir.

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

Daha sonra gradle dosyanızı eklemeniz gerekir:

android {
    defaultConfig {
        vectorDrawables.useSupportLibrary = true
    }
}

Lollipop öncesinde VectorDrawableCompat'ı ve Lollipop'ta VectorDrawable'ı kullanır.

DÜZENLE

@ User3109468 yorumundan sonraki koşulu düzenledim


1
VectorDrawable'ın çekilebilir örneği || VectorDrawableCompat'ın çekilebilir örneğinin tarafları değiştirilmiş olmalıdır. VectorDrawable olmadığında, var olduğu için önce VectorDrawableCompat'ın kontrol edilmesi gerektiğinde bir Sınıf Bulunamadı sonucunu verir.
Warrick

VertorDrawable'ın tür denetimi şu şekilde tanımlanabilir(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && drawable instanceof VectorDrawable)
chmin

6

@Alexey için tebrikler

İşte Kotlinuzantıları kullanan sürümContext

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
}

Örnek kullanım Activity:

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

1

API 16 - JellyBean ile Vektör Çekilebilir Cihazlarda test edilmiştir

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

Doğru en boy oranına sahip görüntüyü dönüştürmek için aşağıdaki kodu kullanın (örneğin, bildirim simgesi için):

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

Eğer vectorgörüntü intrinsicWidthveintrinsicHeight küçük ve büyük görünüme bit eşlem görüntülemek için deneyin, o zaman sonuç bulanık göreceksiniz.

Bu durumda, daha iyi görüntü elde etmek için bitmap'iniz için yeni bir genişlik / yükseklik sağlayabilirsiniz (veya xml olarak vektör boyutunu artırabilirsiniz, ancak daha esnek olabilir desireWidthve desireHeightsağlayabilir).

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
}

Umarım yardımcı olur


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

Çıktınızı istenen bir çıktı boyutuna ölçekleyebilmek istiyorsanız, aşağıdaki parçacığı deneyin:

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

Bu size istediğiniz boyutta bit eşlem verir. Ek olarak, ihtiyaç duymayanlarla daha iyi performans için her görüntüye bağlı olarak şeffaflığı korumanıza veya korumanıza izin verir.

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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.