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
inSampleSizehoặcBitmapFactory.Optionskhi decode file lớn. - Reuse bitmap: Dùng
inBitmap(API 19+) hoặcBitmapPool(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).