Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Android

วิธีแปลง Drawable เป็น Bitmap ใน Android

ภาพรวม

บทความนี้สาธิตวิธีแปลง Drawable เป็น Bitmap ใน Android ซึ่งเป็นการทำงานที่พบบ่อยเมื่อต้องการ: บันทึกรูปภาพ, แชร์รูป, อัปโหลด, ประมวลผลภาพ (Image Processing), หรือแสดงใน View ที่รับเฉพาะ Bitmap

ขั้นตอนที่ 1: สร้างโปรเจกต์ใหม่

สร้างโปรเจกต์ Android ใหม่ใน Android Studio

ขั้นตอนที่ 2: ออกแบบ Layout (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="200dp"
        android:layout_height="200dp"
        android:layout_marginBottom="16dp"
        android:scaleType="centerCrop"
        android:src="@drawable/sample_image"
        android:contentDescription="Sample Image" />

    <Button
        android:id="@+id/btnConvert"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="แปลง Drawable → Bitmap" />

    <TextView
        android:id="@+id/tvInfo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:textSize="14sp" />

</LinearLayout>

ขั้นตอนที่ 3: เขียนโค้ด MainActivity (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.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private ImageView imageView;
    private TextView tvInfo;
    private Button btnConvert;

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

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

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

    private void convertDrawableToBitmap() {
        // ดึง Drawable จาก ImageView (หรือ Resources)
        Drawable drawable = imageView.getDrawable();
        // หรือ: Drawable drawable = ContextCompat.getDrawable(this, R.drawable.sample_image);

        if (drawable == null) {
            Toast.makeText(this, "ไม่พบ Drawable", Toast.LENGTH_SHORT).show();
            return;
        }

        Bitmap bitmap = drawableToBitmap(drawable);
        
        if (bitmap != null) {
            // แสดงผล: ตั้งค่า Bitmap กลับเข้า ImageView (เพื่อยืนยัน)
            imageView.setImageBitmap(bitmap);
            
            // แสดงข้อมูล
            String info = String.format(
                "Bitmap Info:\nWidth: %d px\nHeight: %d px\nConfig: %s\nByte Count: %d KB",
                bitmap.getWidth(), bitmap.getHeight(), 
                bitmap.getConfig(), bitmap.getByteCount() / 1024
            );
            tvInfo.setText(info);
            
            Toast.makeText(this, "แปลงสำเร็จ!", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "แปลงไม่สำเร็จ", Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * แปลง Drawable ทุกประเภทเป็น Bitmap
     * รองรับ: BitmapDrawable, VectorDrawable, ShapeDrawable, LayerDrawable, 9-patch, etc.
     */
    public static Bitmap drawableToBitmap(Drawable drawable) {
        if (drawable == null) return null;

        // กรณีที่ 1: เป็น BitmapDrawable อยู่แล้ว
        if (drawable instanceof BitmapDrawable) {
            return ((BitmapDrawable) drawable).getBitmap();
        }

        // กรณีที่ 2: VectorDrawable (API 21+)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && drawable instanceof VectorDrawable) {
            return vectorDrawableToBitmap((VectorDrawable) drawable);
        }

        // กรณีที่ 3: Drawable อื่นๆ (Shape, Layer, Gradient, 9-patch, etc.)
        // สร้าง Bitmap ขนาดเท่า Intrinsic Size
        int width = drawable.getIntrinsicWidth();
        int height = drawable.getIntrinsicHeight();

        // Fallback หาก Intrinsic Size เป็น -1 (ไม่มีขนาดคงที่)
        if (width <= 0) width = 100;
        if (height <= 0) height = 100;

        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        
        // ตั้ง bounds ให้ Drawable แล้ววาดลง Canvas
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);
        
        return bitmap;
    }

    // แปลง VectorDrawable เป็น Bitmap (API 21+)
    private static Bitmap vectorDrawableToBitmap(VectorDrawable vectorDrawable) {
        int width = vectorDrawable.getIntrinsicWidth();
        int height = vectorDrawable.getIntrinsicHeight();
        
        if (width <= 0) width = 100;
        if (height <= 0) height = 100;

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

    // ==================== เพิ่มเติม: วิธีอื่นๆ ====================

    /**
     * โหลดจาก Resources โดยตรงเป็น Bitmap (ไม่ผ่าน Drawable)
     */
    private Bitmap loadBitmapFromResources(int resId) {
        return BitmapFactory.decodeResource(getResources(), resId);
    }

    /**
     * แปลง Bitmap กลับเป็น Drawable
     */
    private void bitmapToDrawableExample(Bitmap bitmap) {
        // สำหรับ API 22+
        android.graphics.drawable.BitmapDrawable drawable = 
            new android.graphics.drawable.BitmapDrawable(getResources(), bitmap);
        imageView.setImageDrawable(drawable);
    }

    /**
     * Resize Bitmap (ย่อ/ขยาย)
     */
    private Bitmap resizeBitmap(Bitmap source, int newWidth, int newHeight) {
        return Bitmap.createScaledBitmap(source, newWidth, newHeight, true);
    }
}

ขั้นตอนที่ 4: 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">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

สรุปวิธีแปลงตามประเภท Drawable

ประเภท Drawableวิธีแปลงหมายเหตุ
BitmapDrawable((BitmapDrawable) drawable).getBitmap()เร็วที่สุด ไม่ต้องสร้างใหม่
VectorDrawable (API 21+)วาดลง Canvas ด้วย vectorDrawable.draw(canvas)ต้องระบุขนาด (Intrinsic หรือกำหนดเอง)
ShapeDrawable, GradientDrawable, LayerDrawable, 9-patchวาดลง Canvas ทั่วไปต้อง setBounds ก่อน draw
ColorDrawableสร้าง Bitmap แล้ว fill สีไม่มี Intrinsic Size

Best Practices

  • Recycle Bitmap: ใช้ bitmap.recycle() เมื่อไม่ใช้แล้ว (API < 19) หรือ ให้ GC จัดการ (API 19+)
  • inSampleSize: ใช้ BitmapFactory.Options.inSampleSize โหลดรูปขนาดเล็กลงหน่วยความจำ
  • Mutable Bitmap: ต้องการ Edit Pixel ใช้ Bitmap.createBitmap(width, height, Config.ARGB_8888) (mutable by default)
  • Thread Safety: Bitmap Operations ควรทำใน Background Thread
  • Memory Leak: ไม่เก็บ Bitmap reference ใน Static Field

การใช้งานจริง (Use Cases)

  • Share Image: Intent.ACTION_SEND ต้องการ Bitmap/Uri
  • Save to Gallery: MediaStore.Images.Media.insertImage() รับ Bitmap
  • Image Processing: OpenCV, RenderScript, ML Kit ต้องการ Bitmap Input
  • Custom View Drawing: Canvas.drawBitmap()
  • Notification Large Icon: NotificationCompat.Builder.setLargeIcon(bitmap)