Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Android

Chuyển đổi Drawable thành Bitmap trên Android

Giới thiệu

Bài viết này hướng dẫn cách chuyển đổi Drawable thành Bitmap trên Android. Đây là thao tác phổ biến khi cần xử lý pixel, lưu ảnh, chia sẻ, hoặc vẽ lên Canvas.

Các bước thực hiện

Bước 1: Tạo dự án mới

Mở Android Studio, chọn File → New Project và điền thông tin cần thiết.

Bước 2: Thiết kế giao diện (res/layout/activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    android:gravity="center"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:scaleType="centerInside"
        android:contentDescription="Converted bitmap" />

    <Button
        android:id="@+id/btnConvert"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="Chuyển Drawable → Bitmap" />

</LinearLayout>

Bước 3: Viết code chuyển đổi (src/MainActivity.java)

import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.VectorDrawable;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private ImageView imageView;
    private Button btnConvert;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageView = findViewById(R.id.imageView);
        btnConvert = findViewById(R.id.btnConvert);

        btnConvert.setOnClickListener(v -> convertDrawableToBitmap());
    }

    private void convertDrawableToBitmap() {
        // Lấy Drawable từ resource (có thể là BitmapDrawable, VectorDrawable, LayerDrawable...)
        Drawable drawable = getResources().getDrawable(R.drawable.image, getTheme());
        
        if (drawable == null) {
            Toast.makeText(this, "Không tìm thấy drawable", Toast.LENGTH_SHORT).show();
            return;
        }

        Bitmap bitmap = drawableToBitmap(drawable);
        
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
            Toast.makeText(this, "Đã chuyển đổi: " + bitmap.getWidth() + "x" + bitmap.getHeight(), 
                         Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "Chuyển đổi thất bại", Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * Chuyển Drawable bất kỳ thành Bitmap
     * Xử lý đúng cho BitmapDrawable, VectorDrawable, LayerDrawable, ...
     */
    public static Bitmap drawableToBitmap(Drawable drawable) {
        if (drawable == null) return null;

        // Nếu đã là BitmapDrawable, lấy bitmap trực tiếp
        if (drawable instanceof BitmapDrawable) {
            return ((BitmapDrawable) drawable).getBitmap();
        }

        // Xác định kích thước
        int width = drawable.getIntrinsicWidth();
        int height = drawable.getIntrinsicHeight();
        
        // VectorDrawable không có intrinsic size, cần set bounds
        if (width <= 0 || height <= 0) {
            width = 200; // default
            height = 200;
        }

        // Tạo bitmap config phù hợp
        Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE 
            ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
        
        Bitmap bitmap = Bitmap.createBitmap(width, height, config);
        Canvas canvas = new Canvas(bitmap);
        
        // Set bounds và vẽ
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);
        
        return bitmap;
    }

    /**
     * Cách đơn giản cho VectorDrawable (API 21+)
     */
    public static Bitmap vectorDrawableToBitmap(VectorDrawable vectorDrawable, int width, int height) {
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        vectorDrawable.draw(canvas);
        return bitmap;
    }
}

Bước 4: Cấu hình Manifest (androidManifest.xml)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
    package="app.com.sample">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity 
            android:name=".MainActivity"
            android:windowSoftInputMode="adjustPan">
            <intent-filter>
                
                
            </intent-filter>
        </activity>

    </application>
</manifest>

Chạy ứng dụng

Chuẩn bị file image.png/jpg/xml trong res/drawable/. Kết nối thiết bị, nhấn Run. Nhấn nút để chuyển đổi và hiển thị Bitmap.

Các trường hợp Drawable phổ biến

Loại Drawable Cách chuyển đổi Lưu ý
BitmapDrawable (PNG, JPG, WebP) ((BitmapDrawable)drawable).getBitmap() Nhanh nhất, không copy data
VectorDrawable (XML vector) Vẽ lên Canvas với kích thước chỉ định Cần chỉ định width/height, scale tốt
LayerDrawable, StateListDrawable Vẽ lên Canvas Render tất cả layer/state hiện tại
GradientDrawable, ShapeDrawable Vẽ lên Canvas Tạo bitmap từ shape/gradient
AnimatedVectorDrawable Chỉ lấy frame hiện tại Không chuyển đổi được animation
AdaptiveIconDrawable Vẽ lên Canvas API 26+, background + foreground layer

Ngược lại: Bitmap → Drawable

// Bitmap → Drawable
Drawable drawable = new BitmapDrawable(getResources(), bitmap);

// Bitmap → Byte array → Base64 / File
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
// Save to file, upload, encode Base64...

Lưu ý hiệu năng & bộ nhớ

  • Bitmap tốn nhiều RAM: 1 ảnh 4000x3000 ARGB_8888 ≈ 48MB. Luôn dùng inSampleSize hoặc BitmapFactory.Options khi decode file lớn.
  • Reuse bitmap: Dùng inBitmap (API 19+) hoặc BitmapPool (Glide) để tái sử dụng.
  • Không làm trên UI thread cho ảnh lớn - dùng Coroutine/RxJava/Executor.
  • Gọi bitmap.recycle() (API < 19) hoặc để GC tự quản lý (API 19+).
  • Config phù hợp: RGB_565 cho ảnh không có alpha (tiết kiệm 50% RAM).