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

Chuyển đổi chuỗi Base64 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 chuỗi Base64 thành Bitmap trên Android. Đây là thao tác ngược lại của encode, thường dùng khi nhận dữ liệu ảnh từ API (JSON), database, hoặc QR code.

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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:padding="16dp">

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

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="Base64 string → Bitmap image"
        android:textSize="16sp"
        android:textStyle="bold|italic" />

</LinearLayout>

Bước 3: Viết code decode (src/MainActivity.java)

import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Base64;
import android.widget.ImageView;
import java.io.ByteArrayOutputStream;

public class MainActivity extends AppCompatActivity {

    private ImageView imageView;

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

        imageView = findViewById(R.id.imageView);

        // Demo: Encode một ảnh resource thành Base64, rồi decode lại
        // Trong thực tế: Base64 string đến từ API/Database
        new Thread(() -> {
            // 1. Encode: Drawable → Bitmap → ByteArray → Base64 String
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            Bitmap originalBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image);
            originalBitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
            byte[] imageBytes = baos.toByteArray();
            String base64String = Base64.encodeToString(imageBytes, Base64.DEFAULT);

            // 2. Decode: Base64 String → ByteArray → Bitmap
            byte[] decodedBytes = Base64.decode(base64String, Base64.DEFAULT);
            Bitmap decodedBitmap = BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);

            // 3. Cập nhật UI trên Main Thread
            runOnUiThread(() -> {
                if (decodedBitmap != null) {
                    imageView.setImageBitmap(decodedBitmap);
                }
            });
        }).start();
    }
}

Bước 4: 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">
            <intent-filter>
                
                
            </intent-filter>
        </activity>

    </application>
</manifest>

Chạy ứng dụng

Chuẩn bị file image.png/jpg trong res/drawable/. Kết nối thiết bị, nhấn Run. Ảh sẽ hiển thị sau khi decode Base64.

Code tiện ích tái sử dụng (Utility Class)

public class BitmapBase64Utils {

    /** Bitmap → Base64 String */
    public static String bitmapToBase64(Bitmap bitmap, Bitmap.CompressFormat format, int quality) {
        if (bitmap == null) return null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bitmap.compress(format, quality, baos);
        byte[] bytes = baos.toByteArray();
        return Base64.encodeToString(bytes, Base64.NO_WRAP); // NO_WRAP: không xuống dòng
    }

    /** Base64 String → Bitmap */
    public static Bitmap base64ToBitmap(String base64String) {
        if (base64String == null || base64String.isEmpty()) return null;
        try {
            // Xử lý Data URI scheme: "data:image/png;base64,xxxx"
            if (base64String.contains(",")) {
                base64String = base64String.substring(base64String.indexOf(",") + 1);
            }
            byte[] bytes = Base64.decode(base64String, Base64.DEFAULT);
            return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
            return null;
        }
    }

    /** Base64 String → Bitmap với Options (giảm RAM cho ảnh lớn) */
    public static Bitmap base64ToBitmap(String base64String, BitmapFactory.Options options) {
        if (base64String == null) return null;
        try {
            byte[] bytes = Base64.decode(base64String, Base64.DEFAULT);
            return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
        } catch (Exception e) {
            return null;
        }
    }

    /** Lưu Base64 string ra file ảnh */
    public static boolean saveBase64ToFile(String base64String, File file) {
        Bitmap bitmap = base64ToBitmap(base64String);
        if (bitmap == null) return false;
        try (FileOutputStream fos = new FileOutputStream(file)) {
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
            return true;
        } catch (IOException e) {
            return false;
        }
    }
}

Các trường hợp thường gặp

Nguồn Base64 Định dạng Xử lý
JSON API response "image": "iVBORw0KGgoAAAANSUhEUg..." Decode trực tiếp
Data URI (HTML/CSS) "data:image/png;base64,iVBORw0K..." Bỏ phần header trước dấu phẩy
Database (TEXT/BLOB) Base64 thuần Decode trực tiếp
QR Code chứa ảnh Base64 nén Decode, có thể cần resize

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

  • Base64 lớn hơn binary ~33%: Ảnh 1MB → Base64 ~1.33MB string.
  • Decode trên Background Thread: BitmapFactory.decodeByteArray tốn thời gian, gây ANR nếu ảnh lớn.
  • OOM Risk: Ảnh lớn (4000x3000) decode trực tiếp → crash. Dùng inSampleSize trong BitmapFactory.Options.
  • inMutable = true (API 19+) nếu cần vẽ lên bitmap sau khi decode.
  • Base64.NO_WRAP: Không chèn newline (\n) mỗi 76 chars - chuẩn RFC 4648, phù hợp JSON.

Ví dụ decode an toàn cho ảnh lớn

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);

// Tính inSampleSize để giảm kích thước (ví dụ max 1024px)
options.inSampleSize = calculateInSampleSize(options, 1024, 1024);
options.inJustDecodeBounds = false;
options.inPreferredConfig = Bitmap.Config.RGB_565; // Tiết kiệm RAM

Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);

Kết luận

Chuyển Base64 ↔ Bitmap là kỹ năng cơ bản. Luôn nhớ: decode trên background thread, xử lý OOM cho ảnh lớn, dùng Base64.NO_WRAP cho JSON.