BitmapFactory.Options

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
發佈了47 篇原創文章 · 獲贊 3 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章