问题
今天无意中发现了一个问题,通过Bitmap的getWidth和getHeight方法获取到的图片尺寸与实际的尺寸(1920*1080)不一致,后来更进一步发现,把这张图片分别放在raw、drawable-mdpi、drawable-hdpi、drawable-xhdpi、drawable-xxhdpi、drawable-xxxhdpi时,通过以上两个方法获取到的尺寸也都不一致。
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.img_mac_os_x); if (bitmap != null) { Log.i("xp.chen", "decode bitmap "+bitmap.getWidth()+", bitmap height: "+bitmap.getHeight()); }
下面是把图片分别放在raw、drawable-mdpi、drawable-hdpi、drawable-xhdpi、drawable-xxhdpi、drawable-xxxhdpi时,通过Bitmap的getWidth()/getHeight()分别获取到的尺寸:
raw:I/xp.chen: decode bitmap 7680, bitmap height: 4320
drawable-mdpi:I/xp.chen: decode bitmap 7680, bitmap height: 4320
drawable-hdpi:I/xp.chen: decode bitmap 5120, bitmap height: 2880
drawable-xhdpi:I/xp.chen: decode bitmap 3840, bitmap height: 2160
drawable-xxhdpi:I/xp.chen: decode bitmap 2560, bitmap height: 1440
drawable-xxxhdp:I/xp.chen: decode bitmap 1920, bitmap height: 1080
为什么会这样
首先要知道的是,除了raw文件夹,上述的其它文件夹主要是用来适配不同屏幕的显示密度的,放在不同文件夹里等于是告诉系统,我这张图片是针对哪一种显示密度的设备,如果图片放置的文件夹与实际运行的设备密度不一致,那么系统会对这张图片进行放大或缩小。比如:我把图片放置在xhdpi(dpi是320)里面,但是我实际运行的设备是640,xxxhdpi里又没有放置任何图片,那么这个时候系统就会对放置在xhdpi里的同名图片进行缩放。
在屏幕dpi为160时,1dp = 1px,也就是说如果运行设备的屏幕的dpi是160时,图片是可以1:1正常显示的,查看当前屏幕的dpi和density可以通过下列API:
float density = getResources().getDisplayMetrics().density; int densityDpi = getResources().getDisplayMetrics().densityDpi;
通过测试,我手机的dpi为640,density是4,也就是说当我把图片放在xxxhdpi里时,图片可以正常匹配,系统不会做任何处理,所以上面放在xxxhdpi时,运行的Log是正确的,刚好是1920*1080,那放置到其它的文件夹里的尺寸是如何计算的呢?个人猜测应该是这样:当放置在
drawable-mdpi时,该文件夹对应的dpi是160,density是1,实际屏幕dpi是640,密度是4,不符合要求,放大4倍 ,(7680*4320);
drawable-hdpi时,该文件夹对应的dpi是240,density是1.5,实际屏幕dpi是640,密度是4,不符合要求,放大2.666 (4/1.5) 倍, (5120*2880);
drawable-xhdpi时,该文件夹对应的dpi是320,density是2,实际屏幕dpi是640,密度是4,不符合要求,放大2 (4/2) 倍, (3840*2160);
drawable-xxhdpi时,该文件夹对应的dpi是480,density是3,实际屏幕dpi是640,密度是4,不符合要求,放大1.333 (4/3) 倍, (2560*1440);
drawable-xxxhdpi时,该文件夹对应的dpi是640,density是4,实际屏幕dpi是640,密度是4,符合要求,正常显示, (1920*1080);
因此导致了使用BitmapFactory在decode图片时发生了上述的差异,那么是否有什么途径可以保证decode图片时,得到的图片尺寸与实际的图片尺寸相一致呢?这里有两种方法:
第一种方法,如果仅仅是为了获取图片的尺寸,不需要获取其对应的Bitmap,可以通过下列方式:
BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.img_mac_os_x, options); Log.i("xp.chen", "decode bitmap "+options.outWidth+", bitmap height: "+options.outHeight);
这里通过 options.outWidth 和 options.outHeight 拿到的就是图片实际的宽高,经测试刚好是1920*1080,注意这里返回的bitmap对象是NULL。
第二种方法,不仅仅是为了要拿到图片的尺寸,也需要拿到对应的Bitmap,可以通过下列方式:
BitmapFactory.Options options = new BitmapFactory.Options(); options.inScaled = false; Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.img_mac_os_x, options); if (bitmap != null) { Log.i("xp.chen", "decode bitmap "+bitmap.getWidth()+", bitmap height: "+bitmap.getHeight()); }
设置 options.inScaled 为false,等于告诉系统,不要对该图片进行缩放,通过这种方法拿到的宽高也是1920*1080。