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 |