벡터 드로어 블에서 비트 맵 얻기


132

내 응용 프로그램에서 알림에 큰 아이콘을 설정해야합니다. LargeIcon은 비트 맵이어야하고 드로어 블은 벡터 이미지입니다 (Android의 새로운 기능, 이 링크 참조 ). 문제는 벡터 이미지 인 리소스를 디코딩하려고하면 null이 반환됩니다.

다음은 코드 샘플입니다.

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

이 샘플에서 R.drawable.vector_menu_objectifs를 "일반"이미지, 예를 들어 png로 바꾸면 결과가 null이 아닙니다 (올바른 비트 맵을 얻음) 누락 된 것이 있습니까?


1
있었다 비슷한 문제가 아니라 해결하지만 해결 방법 : stackoverflow.com/questions/33548447/...
보다

답변:


231

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

최신 정보:

프로젝트 gradle :

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

모듈 그래들 :

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

감사합니다. 이전 답변 23에서 시작하는 SDK 버전에서 작동하지 않습니다
Paha

2
이것은 나를 위해 잘 작동합니다. 문제없이 API 15에서 실행
vera

4
AppCompatDrawableManager@RestrictTo(LIBRARY_GROUP)내부 로 표시되어 있으므로 사용해서는 안됩니다 (API는 예고없이 변경 될 수 있음). ContextCompat대신 사용하십시오 .
mradzinski

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Bitmap.setHasAlpha(boolean)' on a null object reference이 라인 에서는 작동하지 않습니다Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
user25

5
이 솔루션에 문제가있었습니다. 나를 위해 : ContextCompat 대신 AppCompatResources를 수정했습니다. Drawable drawable = AppCompatResources.getDrawable (context, drawableId);
Mike T

64

다음 방법을 사용할 수 있습니다.

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

때로는 함께 결합합니다.

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
잘하면 @liltof가 돌아와서 이것을 대답으로 표시합니다. 한 가지 주목할 점은 두 가지 방법 모두 targetAPi 래퍼를 원한다는 것입니다. 그러나 android studio에서 알려줍니다.
roberto tomás

1
나는 svg 파일 문제를 생각 하면서이 작업을 시도하는 데 약 2 일을 보냈습니다. 감사합니다!
sparkly_frog

1
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Bitmap.setHasAlpha(boolean)' on a null object reference이 라인 에서는 작동하지 않습니다Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(), vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
user25

45

Kotlin에 Android KTX 를 사용하려는 경우 확장 방법 Drawable#toBitmap()을 사용 하여 다른 답변과 동일한 효과를 얻을 수 있습니다 .

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

또는

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

이것과 다른 유용한 확장 방법을 추가하려면 모듈 수준에 다음을 추가해야합니다. build.gradle

repositories {
    google()
}

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

프로젝트에 종속성을 추가하는 최신 지침 은 여기 를 참조 하십시오 .

참고이를 위해 작동합니다 어떤 의 서브 클래스 Drawable와 같은 경우 Drawable입니다 BitmapDrawable그것은 기본을 사용하는 바로 가기합니다 Bitmap.


이것이 Kotlin에게 가장 간단한 솔루션입니다.
Adam Hurwitz 2016 년

1
나를 위해 그것은 완벽하게 작동합니다 VectorDrawable.
우분투 로이드

이것이 가장 좋은 옵션입니다. 기본 androidx는 기능을 제공합니다
Reshma

27

이전 답변을 바탕으로 VectorDrawable 및 BitmapDrawable과 일치하고 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");
    }
}

그런 다음 gradle 파일에 추가해야합니다.

android {
    defaultConfig {
        vectorDrawables.useSupportLibrary = true
    }
}

롤리팝 이전에서는 VectorDrawableCompat을 사용하고 롤리팝에서는 VectorDrawable을 사용합니다.

편집하다

@ user3109468의 의견에 따라 조건을 편집했습니다.


1
VectorDrawable의 드로어 블 인스턴스 || VectorDrawableCompat의 드로어 블 인스턴스는 변이 바뀌어야합니다. VectorDrawable이 존재하지 않는 경우, VectorDrawableCompat이 존재하므로 먼저 확인해야 할 때 클래스를 찾을 수 없음
워릭

VertorDrawable의 유형 검사는 다음과 같이 설명 될 수 있습니다.(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && drawable instanceof VectorDrawable)
chmin

6

@Alexey에게 Kudos

다음은 Kotlin확장명을 사용 하는 버전입니다.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
}

의 사용법 예 Activity:

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

1

API 16에서 테스트-벡터 드로어 블이있는 JellyBean

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

다음 코드를 사용하여 이미지 를 올바른 종횡비 로 변환 하십시오 (예 : 알림 아이콘) :

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

귀하의 경우 vector이미지 intrinsicWidthintrinsicHeight작고 당신은 큰 볼에 비트 맵을 표시하려고, 당신은 결과가 흐림입니다 볼 수 있습니다.

이 경우, 당신은 더 나은 이미지를 얻을 수있는 비트 맵에 대한 새 너비 / 높이를 제공 할 수 있습니다 (또는 당신은 XML에서 벡터의 크기를 증가하지만를 제공 할 수 있습니다 desireWidthdesireHeight더 유연 할 수있다).

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
}

도움이되기를 바랍니다.


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

출력을 원하는 출력 크기로 조정하려면 다음 스 니펫을 시도하십시오.

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

원하는 크기의 비트 맵을 제공합니다. 또한 필요하지 않은 이미지의 성능을 높이기 위해 각 이미지에 따라 투명도를 유지하거나 유지하지 않을 수 있습니다.

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;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.