首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Android 圖片資源轉換完全手冊:Drawable、Bitmap、byte[] 互轉

     編輯:Java 相關知識

常見轉換場景概覽

Android 開發中頻繁需要在不同圖片表示之間轉換,本文整理四大核心轉換路徑,附帶完整程式碼與效能建議。

來源目標關鍵 API典型用途
DrawableBitmapCanvas, Bitmap.createBitmap()自定義 View 繪製、圖片處理
ResourcesBitmapBitmapFactory.decodeResource()載入 App 內嵌資源
Bitmapbyte[]Bitmap.compress(), ByteArrayOutputStream網路傳輸、資料庫存儲、Intent 傳遞
byte[]BitmapBitmapFactory.decodeByteArray()網路接收、資料庫讀取、檔案載入

1. Drawable → Bitmap

public static Bitmap drawableToBitmap(Drawable drawable) {
    if (drawable instanceof BitmapDrawable) {
        return ((BitmapDrawable) drawable).getBitmap(); // 已是 BitmapDrawable 直接取得
    }

    int width = drawable.getIntrinsicWidth();
    int height = drawable.getIntrinsicHeight();
    if (width <= 0 || height <= 0) return null; // 無固有尺寸(如 GradientDrawable)

    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);
    drawable.setBounds(0, 0, width, height);
    drawable.draw(canvas);
    return bitmap;
}

注意:getIntrinsicWidth/Height() 可能回傳 -1(無固有尺寸),需處理回退邏輯。

2. Resources → Bitmap

public static Bitmap decodeResource(Resources res, @DrawableRes int resId, 
                                    int reqWidth, int reqHeight) {
    // 先解碼邊界資訊
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    // 計算縮放比例
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // 實際解碼
    options.inJustDecodeBounds = false;
    options.inPreferredConfig = Bitmap.Config.ARGB_8888;
    return BitmapFactory.decodeResource(res, resId, options);
}

private static int calculateInSampleSize(BitmapFactory.Options options, 
                                         int reqWidth, int reqHeight) {
    if (reqWidth == 0 || reqHeight == 0) return 1;
    int inSampleSize = 1;
    while (options.outWidth / inSampleSize > reqWidth 
        || options.outHeight / inSampleSize > reqHeight) {
        inSampleSize <<= 1;
    }
    return inSampleSize;
}

最佳實踐:必須使用 inSampleSize 避免載入超大圖片導致 OOM,尤其在 RecyclerView/ListView 列表圖片載入。

3. Bitmap → byte[]

public static byte[] bitmapToBytes(Bitmap bitmap, Bitmap.CompressFormat format, int quality) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    bitmap.compress(format, quality, baos);
    return baos.toByteArray();
}

// 使用範例
byte[] pngBytes = bitmapToBytes(bitmap, Bitmap.CompressFormat.PNG, 100); // 無損
byte[] jpgBytes = bitmapToBytes(bitmap, Bitmap.CompressFormat.JPEG, 85);  // 有損,品質 85%

格式選擇:PNG 無損適合圖示、透明背景;JPEG 有損適合照片,品質 75-90% 平衡體積與畫質。

4. byte[] → Bitmap

public static Bitmap bytesToBitmap(byte[] data) {
    if (data == null || data.length == 0) return null;
    return BitmapFactory.decodeByteArray(data, 0, data.length);
}

// 含尺寸限制版本(防 OOM)
public static Bitmap bytesToBitmap(byte[] data, int maxWidth, int maxHeight) {
    if (data == null || data.length == 0) return null;
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeByteArray(data, 0, data.length, options);
    options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeByteArray(data, 0, data.length, options);
}

進階:Glide/Picasso 等圖片載入庫

實際專案強烈建議使用成熟庫處理圖片載入、快取、轉換:

// Glide 範例
Glide.with(context)
    .load(url)
    .override(300, 300)
    .apply(new RequestOptions().format(DecodeFormat.PREFER_ARGB_8888))
    .into(imageView);

// 自定義轉換
public class CircleCropTransformation extends BitmapTransformation {
    @Override protected Bitmap transform(BitmapPool pool, Bitmap toTransform, 
                                         int outWidth, int outHeight) {
        return circleCrop(pool, toTransform);
    }
}

記憶體管理關鍵提醒

  • Bitmap.recycle() (API < 11) 手動回收原生記憶體
  • API 11+ 使用 inBitmap 重用記憶體(需相容尺寸與配置)
  • 大量圖片處理時考慮 LruCache 記憶體快取 + DiskLruCache 磁碟快取
  • 避免在主執行緒解碼大圖,使用 ExecutorService 或 Kotlin 協程
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved