BitmapFactory.Options與drawable之間的關係
在開發安卓程序的時候,我們經常把圖片放在[drawable][6]、[drawable-hdpi][6]等等下,這對解析出的bitmap有什麼影響嗎?
解析一張drawable圖片走的方法:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.xx);
public static Bitmap decodeResource(Resources res, int id) {
return decodeResource(res, id, null);
}
decodeResource會調用decodeResourceStream方法
public static Bitmap decodeResourceStream(Resources res, TypedValue value,
InputStream is, Rect pad, Options opts) {
validate(opts);
if (opts == null) {
opts = new Options();
}
if (opts.inDensity == 0 && value != null) {
//拿到ID資源所在目錄的像素密度
final int density = value.density;
if (density == TypedValue.DENSITY_DEFAULT) {
//如果在默認drawable目錄,設置inDensity爲默認值(160dpi)
opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
} else if (density != TypedValue.DENSITY_NONE) {
//如果在其它drawable目錄,設置inDensity爲對應值(比如drawable-hdpi,設置inDensity=240)
opts.inDensity = density;
}
}
if (opts.inTargetDensity == 0 && res != null) {
//設置inTargetDensity爲屏幕像素密度
opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
}
return decodeStream(is, pad, opts);
}
因爲傳進的opts爲空,首先創建一個Options,然後給Options的inDensity和inTargetDensity賦值。可見解析圖片和圖片所在目錄和當前設備有關。decodeStream方法內部最終調用nativeDecodeStream方法。
private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,Rect padding, Options opts);
/frameworks/base/core/jni/android/graphics/BitmapFactory.cpp
static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage,
474 jobject padding, jobject options) {
475
476 jobject bitmap = NULL;
477 SkAutoTUnref<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage));
478
479 if (stream.get()) {
480 // Need to buffer enough input to be able to rewind as much as might be read by a decoder
481 // trying to determine the stream's format. Currently the most is 64, read by
482 // SkImageDecoder_libwebp.
483 // FIXME: Get this number from SkImageDecoder
484 SkAutoTUnref<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(stream, 64));
485 SkASSERT(bufferedStream.get() != NULL);
486 // for now we don't allow purgeable with java inputstreams
487 bitmap = doDecode(env, bufferedStream, padding, options, false, false);
488 }
489 return bitmap;
490}
在doDecode中有這樣一組代碼
if (env->GetBooleanField(options, gOptions_scaledFieldID)) {
250 const int density = env->GetIntField(options, gOptions_densityFieldID);
251 const int targetDensity = env->GetIntField(options, gOptions_targetDensityFieldID);
252 const int screenDensity = env->GetIntField(options, gOptions_screenDensityFieldID);
253 if (density != 0 && targetDensity != 0 && density != screenDensity) {
254 scale = (float) targetDensity / density;
255 }
256 }
native代碼中會根據inDensity和inTargetDensity計算scale。
int scaledWidth = decodingBitmap.width();
331 int scaledHeight = decodingBitmap.height();
332
333 if (willScale && mode != SkImageDecoder::kDecodeBounds_Mode) {
334 scaledWidth = int(scaledWidth * scale + 0.5f);
335 scaledHeight = int(scaledHeight * scale + 0.5f);
336 }
因此我們可以得出結論,放在drawable目錄下的圖片,在解析時是要進行縮放的。scale = (float) inTargetDensity / inDensity;
目錄 | inDensity |
---|---|
drawable | 160 |
drawable-ldpi | 120 |
drawable-mdpi | 160 |
drawable-hdpi | 240 |
drawable-xhdpi | 320 |
drawable-xxhdpi | 480 |
drawable-xxxhdpi | 640 |