Bitmap pic = ...; // 從資源解碼或網絡獲取
pic.setPixels(pix, 0, pic.getWidth(), 0, 0, pic.getWidth(), pic.getHeight());
// java.lang.IllegalStateException: bitmap is not mutable
從資源、文件、網絡解碼得到的 Bitmap 默認不可變 (isMutable() == false)。setPixels()、setPixel() 要求 Bitmap 可變。
// 方案一:copy() 獲取可變副本 (推薦)
Bitmap mutableBitmap = pic.copy(Bitmap.Config.ARGB_8888, true); // true = mutable
// 現在可以修改
mutableBitmap.setPixels(pix, 0, width, 0, 0, width, height);
// 方案二:createBitmap 重繪 (適合需縮放/轉換)
Bitmap mutableBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(mutableBitmap);
canvas.drawBitmap(pic, 0, 0, null);
// 再修改 mutableBitmap
// 方案三:解碼時直接獲取可變 Bitmap (API 19+ inBitmap 複用)
BitmapFactory.Options options = new BitmapFactory.Options();
options.inMutable = true; // 關鍵!
Bitmap mutableBitmap = BitmapFactory.decodeResource(res, R.drawable.xxx, options);
public Bitmap processBitmap(Bitmap source) {
if (source == null) return null;
// 1. 確保可變
Bitmap bitmap = source.isMutable() ? source : source.copy(Bitmap.Config.ARGB_8888, true);
int width = bitmap.getWidth();
int height = bitmap.getHeight();
// 2. 獲取像素數組
int[] pixels = new int[width * height];
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
// 3. 處理像素 (示例:灰度化)
for (int i = 0; i < pixels.length; i++) {
int color = pixels[i];
int r = Color.red(color);
int g = Color.green(color);
int b = Color.blue(color);
int gray = (int) (0.299 * r + 0.587 * g + 0.114 * b);
pixels[i] = Color.argb(Color.alpha(color), gray, gray, gray);
}
// 4. 寫回
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
return bitmap;
}
int[] 導致 OOM,可用 getPixels/setPixels 分行處理ImageDecoder (API 28+) + Bitmap.mutableCopy() (API 34+)| 誤區 | 事實 |
|---|---|
| 以為 decode 後直接能改 | 資源/文件/網絡解碼 Bitmap 默認 immutable |
| 用 createBitmap(src) 以為可變 | createBitmap 返回的也可能不可變,需指定 Config 且不共享內存 |
| 忽略 inMutable 選項 | API 19+ 解碼階段即可獲取可變 Bitmap,避免額外 copy 開銷 |