ภาพรวม
บทความนี้สาธิตวิธีแปลงสตริง Base64 กลับเป็น Bitmap ใน Android ซึ่งเป็นกระบวนการย้อนกลับของการ Encode ใช้เมื่อ: รับข้อมูลรูปจาก API/Server, อ่านจาก Database/SharedPreferences, หรือประมวลผลภาพที่ส่งมาในรูปแบบ String
ขั้นตอนที่ 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"
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="250dp"
android:layout_height="250dp"
android:scaleType="centerCrop"
android:contentDescription="Decoded Image" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Base64 → Bitmap Demo"
android:textSize="16sp"
android:textStyle="bold|italic" />
<Button
android:id="@+id/btnLoadFromString"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="โหลดจาก Base64 String" />
</LinearLayout>
ขั้นตอนที่ 3: MainActivity.java - ครอบคลุม Encode + Decode
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.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import java.io.ByteArrayOutputStream;
public class MainActivity extends AppCompatActivity {
private ImageView imageView;
private TextView tvBase64Preview;
private Button btnLoadFromString;
private String cachedBase64String;
@SuppressLint("WrongThread")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = findViewById(R.id.imageView);
tvBase64Preview = findViewById(R.id.tvBase64Preview);
btnLoadFromString = findViewById(R.id.btnLoadFromString);
// 1. Encode: Bitmap → Base64 (ทำครั้งเดียวตอนเริ่มต้น)
encodeDrawableToBase64();
// 2. Decode: Base64 → Bitmap (เมื่อกดปุ่ม)
btnLoadFromString.setOnClickListener(v -> decodeBase64ToBitmap());
}
// ==================== ENCODE: Drawable/Bitmap → Base64 ====================
private void encodeDrawableToBase64() {
new Thread(() -> {
try {
// โหลด Bitmap จาก Resources
Bitmap originalBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.sample_image);
if (originalBitmap == null) {
runOnUiThread(() -> Toast.makeText(this, "ไม่พบรูปภาพใน Drawable", Toast.LENGTH_SHORT).show());
return;
}
// บีบอัดเป็น JPEG (หรือ PNG)
ByteArrayOutputStream baos = new ByteArrayOutputStream();
originalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, baos); // Quality 90%
byte[] imageBytes = baos.toByteArray();
// Encode เป็น Base64 String
cachedBase64String = Base64.encodeToString(imageBytes, Base64.DEFAULT);
// แสดง Preview (ตัดให้สั้น)
runOnUiThread(() -> {
String preview = cachedBase64String.length() > 100
? cachedBase64String.substring(0, 100) + "..."
: cachedBase64String;
tvBase64Preview.setText("Base64 Preview:\n" + preview);
});
} catch (Exception e) {
e.printStackTrace();
runOnUiThread(() -> Toast.makeText(this, "Encode Error: " + e.getMessage(), Toast.LENGTH_SHORT).show());
}
}).start();
}
// ==================== DECODE: Base64 → Bitmap ====================
private void decodeBase64ToBitmap() {
if (cachedBase64String == null || cachedBase64String.isEmpty()) {
Toast.makeText(this, "ยังไม่มี Base64 String", Toast.LENGTH_SHORT).show();
return;
}
new Thread(() -> {
try {
// 1. Decode Base64 String → byte[]
byte[] decodedBytes = Base64.decode(cachedBase64String, Base64.DEFAULT);
// 2. Decode byte[] → Bitmap
Bitmap decodedBitmap = BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);
if (decodedBitmap != null) {
runOnUiThread(() -> {
imageView.setImageBitmap(decodedBitmap);
Toast.makeText(this, "Decode สำเร็จ! ขนาด: " + decodedBitmap.getWidth() + "x" + decodedBitmap.getHeight(), Toast.LENGTH_SHORT).show();
});
} else {
runOnUiThread(() -> Toast.makeText(this, "Decode ล้มเหลว: ข้อมูลเสียหาย", Toast.LENGTH_SHORT).show());
}
} catch (IllegalArgumentException e) {
runOnUiThread(() -> Toast.makeText(this, "Base64 Format ผิด: " + e.getMessage(), Toast.LENGTH_SHORT).show());
} catch (Exception e) {
e.printStackTrace();
runOnUiThread(() -> Toast.makeText(this, "Error: " + e.getMessage(), Toast.LENGTH_SHORT).show());
}
}).start();
}
// ==================== Utility Methods ====================
/**
* แปลง Base64 String → Bitmap (Static Method สำหรับใช้งานทั่วไป)
*/
public static Bitmap base64ToBitmap(String base64String) {
if (base64String == null || base64String.isEmpty()) return null;
try {
// ลบ Header ถ้ามี (data:image/png;base64,)
if (base64String.contains(",")) {
base64String = base64String.substring(base64String.indexOf(",") + 1);
}
byte[] decodedBytes = Base64.decode(base64String, Base64.DEFAULT);
return BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* แปลง 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[] imageBytes = baos.toByteArray();
return Base64.encodeToString(imageBytes, Base64.DEFAULT);
}
/**
* บันทึก Base64 ลง SharedPreferences
*/
private void saveBase64ToPrefs(String key, String base64) {
getSharedPreferences("ImagePrefs", MODE_PRIVATE)
.edit()
.putString(key, base64)
.apply();
}
/**
* อ่าน Base64 จาก SharedPreferences
*/
private String loadBase64FromPrefs(String key) {
return getSharedPreferences("ImagePrefs", MODE_PRIVATE)
.getString(key, null);
}
}
ขั้นตอนที่ 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>
รูปแบบ Base64 String ที่พบบ่อย
| รูปแบบ | ตัวอย่าง | การจัดการ |
|---|---|---|
| Raw Base64 | /9j/4AAQSkZJRgABAQ... | Decode โดยตรง |
| Data URI | data:image/png;base64,/9j/4AAQ... | ต้องตัดส่วนหน้าออก substring(indexOf(",")+1) |
| JSON Field | {"image": "/9j/4AAQ..."} | Parse JSON แล้ว Decode |
Base64 Flags (Android)
Base64.DEFAULT- มาตรฐาน มี Line Wrap (76 chars)Base64.NO_WRAP- ไม่มี Line Break (เหมาะสำหรับ JSON, URL, SharedPreferences) แนะนำBase64.URL_SAFE- ใช้ - และ _ แทน + และ / (URL Safe)Base64.NO_PADDING- ไม่เติม = ท้ายสตริง
Best Practices
- Thread: Encode/Decode ใน Background Thread (RxJava, Coroutine, Thread)
- Memory: Base64 ใหญ่กว่า Binary ~33% ระวัง OOM กับรูปขนาดใหญ่
- Compression: JPEG Quality 70-90% สมดุลระหว่าง Size/Quality
- Validation: Try-Catch
IllegalArgumentExceptionสำหรับ Base64 ผิดรูปแบบ - Caching: Cache Bitmap ที่ Decode แล้ว (LruCache) หากใช้ซ้ำ
กรณีการใช้งานจริง
- API Response: Server ส่งรูปเป็น Base64 ใน JSON
- Offline Storage: เก็บรูปใน SQLite/Room/String SharedPreferences
- Image Sharing: แปลงเป็น Base64 ส่งผ่าน Intent/Text
- Signature/Canvas: วาดลายเซ็น → Bitmap → Base64 → Upload
- QR/Barcode: Generate Bitmap → Base64 → Print/Share