关于图片失真的问题及问题出现的原因
2016-10-19 11:15
295 查看
探究drawable图片的加载
这得从一次掉坑的经历说起。有天下午,都快下班了,测试妹子跑到我工位前,急匆匆地说:图片失真了。哎,又不是失身,急啥嘛。我慢条斯理地瞅瞅了代码:代码没错呀,以前也都是这些的呀。到底是哪里出了幺蛾子呢?经过一番排查,发现是图片放错了地方:本来是该放到drawable-xxhdpi中的但是小手一抖错放到了drawable-xhdpi中导致了图片放大失真。
嗯哼,这个坑我们可能自己踩过,或者说这个现象我们略知一二,但是导致这个现象的原因是什么呢?它的背后隐藏着什么呢?
来吧,一起瞅瞅。
在此,准备了一张图,该图就是我的CSDN博客头像
图片的宽为144,高为180。
然后在res文件夹下建立drawable-ldpi、drawable-mdpi、drawable-hdpi、drawable-xhdpi、drawable-xxhdpi、drawable-xxxdpi文件夹,并且将该图片放入drawable-xxhdpi中
再利用ImageView显示该图片,代码如下:
<code class="language-xml hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">ImageView </span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:id</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"@+id/imageView"</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:layout_width</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"wrap_content"</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:layout_height</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"wrap_content"</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:layout_centerInParent</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"true"</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:src</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"@drawable/lfdfhl"</span>/></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>
运行之后,看一下效果
最后,在Java代码中获取图片的宽高及其所占内存的大小,代码如下:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">getImageInfo</span>() { mImageView.post(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Runnable() { <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">run</span>() { BitmapDrawable bitmapDrawable = (BitmapDrawable) mImageView.getDrawable(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> != bitmapDrawable) { Bitmap bitmap = bitmapDrawable.getBitmap(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> width = bitmap.getWidth(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> height = bitmap.getHeight(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> byteCount = bitmap.getByteCount(); System.out.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"----> width="</span> + width + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">",height="</span> + height); System.out.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"----> byteCount="</span> + byteCount); } } }); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>
输出结果如下:
width=144,height=180,byteCount=103680
嗯哼,获取到的图片宽高和其原本的宽高一致。那么这个byteCount又是怎么算出来的呢?
Android系统在利用drawable中的图片生成Bitmap时默认采用的色彩模式是Bitmap.Config.ARGB_8888;在该模式中一共有四个通道,其中A表示Alpha,R表示Red,G表示Green,B表示Blue;并且这四个通道每个各占8位即一个字节,所以合起来共计4个字节。于是可以算出:144*180*4=103680字节
现在将图片移至drawable-hdpi中,运行后查看效果:
输出结果如下:
width=288,height=360,byteCount=414720
哇哈,看到没有呢?——图片的宽和高都翻倍了,图片所占的内存大小也随之变大了4倍。
继续尝试,在将图片移至drawable-ldpi中,运行后查看效果:
输出结果如下:
width=576,height=720,byteCount=1658880
这就更明显了,图片的宽和高都变大了4倍,图片所占的内存大小也随之变大了16倍。
嗯哼,如果将图片放入drawable-mdpi,drawable-xhdpi,drawable-xxxhdpi中也会发现类似的现象:图片的宽高及其所占内存在按照比例放大或者缩小,详情请参见下图
既然已经看到了这个现象,那就再从源码(Lollipop 5.0)角度来看看当加载drawable中的图片时的具体实现
调用BitmapFactory中的的decodeResource()加载drawable文件夹里的图片,源码如下:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Bitmap <span class="hljs-title" style="box-sizing: border-box;">decodeResource</span>(Resources res, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> id, Options opts) { Bitmap bm = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; InputStream is = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> TypedValue value = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> TypedValue(); is = res.openRawResource(id, value); bm = decodeResourceStream(res, value, is, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>, opts); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (Exception e) { } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">finally</span> { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (is != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) is.close(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (IOException e) { } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (bm == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> && opts != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span 1035b > && opts.inBitmap != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> IllegalArgumentException(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Problem decoding into existing bitmap"</span>); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> bm; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li></ul>
在该方法中第6行调用openRawResource()后,value中就保存了该资源所在文件夹的destiny,这点和刚才的讲解是一致的,不再赘述。在此之后,继续执行decodeResourceStream()
调用decodeResourceStream( )方法
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Bitmap <span class="hljs-title" style="box-sizing: border-box;">decodeResourceStream</span>(Resources res, TypedValue value, InputStream is, Rect pad, Options opts) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (opts == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { opts = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Options(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (opts.inDensity == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> && value != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> density = value.density; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (density == TypedValue.DENSITY_DEFAULT) { opts.inDensity = DisplayMetrics.DENSITY_DEFAULT; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (density != TypedValue.DENSITY_NONE) { opts.inDensity = density; } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (opts.inTargetDensity == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> && res != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { opts.inTargetDensity = res.getDisplayMetrics().densityDpi; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> decodeStream(is, pad, opts); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul>
在该方法中有两个非常重要的操作。
第一步:
为opts.inDensity赋值,请参见代码第6-13行。
经过操作opts.inDensity会被赋值为120、160、240、320、480、640中的一个值
第二步:
为opts.inTargetDensity赋值,请参见代码第14-16行。
经过操作opts.inTargetDensity会被赋值为手机屏幕的densityDpi
调用decodeStream()方法
在该方法中会调用decodeStreamInternal();它又会继续调用nativeDecodeStream( ),该方法是native的;在BitmapFactory.cpp可见这个方法内部又调用了doDecode()它的核心源码如下:
<code class="language-C hljs cpp has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> jobject doDecode(JNIEnv*env,SkStreamRewindable*stream,jobject padding,jobject options) { ...... <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (env->GetBooleanField(options, gOptions_scaledFieldID)) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> density = env->GetIntField(options, gOptions_densityFieldID); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> targetDensity = env->GetIntField(options, gOptions_targetDensityFieldID); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> screenDensity = env->GetIntField(options, gOptions_screenDensityFieldID); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (density != <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> && targetDensity != <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> && density != screenDensity) { scale = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span>) targetDensity / density; } } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">bool</span> willScale = scale != <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1.0f</span>; ...... SkBitmap decodingBitmap; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!decoder->decode(stream, &decodingBitmap, prefColorType,decodeMode)) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> nullObjectReturn(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"decoder->decode returned false"</span>); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> scaledWidth = decodingBitmap.width(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> scaledHeight = decodingBitmap.height(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (willScale && decodeMode != SkImageDecoder::kDecodeBounds_Mode) { scaledWidth = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>(scaledWidth * scale + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.5f</span>); scaledHeight = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>(scaledHeight * scale + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.5f</span>); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (willScale) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> sx = scaledWidth / <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span>(decodingBitmap.width()); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> sy = scaledHeight / <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span>(decodingBitmap.height()); ...... SkPaint paint; SkCanvas canvas(*outputBitmap); canvas.scale(sx, sy); canvas.drawBitmap(decodingBitmap, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.0f</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.0f</span>, &paint); } ...... }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li></ul>
主要步骤分析如下:
第一步:
获取opts.inDensity的值赋给density,请参见代码第4行。
第二步:
获取opts.inTargetDensity的值赋给targetDensity,请参见代码第5行。
第三步:
计算缩放比scale,请参见代码第8行。
从这里也可以看出,这个缩放比scale就等于opts.inTargetDensity/opts.inDensity
第四步:
得到图片原始的宽和高,请参见代码第18-19行。
请注意此时的图像在frameworks/base/core/jni/android/graphics/BitmapFactory.cpp中是一个SkBitmap
第五步:
依据scale计算缩放后SkBitmap的宽和高,请参见代码第21-22行。
第六步:
计算SkBitmap的宽和高缩放的倍数,请参见代码第25-26行。
在此得到宽的缩放倍数为sx, 高的缩放倍数为sy
第七步:
依据sx和sy缩放canvas,请参见代码第30行。
第八步:
画出图片,请参见代码第31行。
至此终于完成了doDecode()版的天龙八部。在梳理了整个过程之后不难发现:对于图片缩放的比例其实还是scale即opts.inTargetDensity/opts.inDensity起了决定性的作用。
好吧,现在回过头瞅瞅我掉进去的那个坑:我的手机华为P7其dpi值为480,有一张图片我把它放到drawable-xxhdpi里在手机上显示出来是不失真的,非常合适;但是错放到了drawable-xhdpi(其TypedValue的value值为320)后再次显示时发现图片被放大了,而且放大了480/320=1.5倍。既然图片被放大了那么该图片所占的内存当然也变大了。
这也就解释了我们有时遇到的类似困惑:为什么图片放在drawable-xxhdpi是正常的,但是放到drawable-mdpi后图片不仅仅放大失真而且所占内存也大幅增加了。
除了刚才提到的drawable-ldpi、drawable-mdpi、drawable-hdpi、drawable-xhdpi、drawable-xxhdpi、drawable-xxxdpi还有一个不得不提,那就是drawable-nodpi。和之前的操作一样,我们把这张图片放入drawable-nodpi会发现此时TypedValue的density值为65535,如果按照刚才的思路图片岂不是要被缩放到无限小?非也!
请看上面的decodeResourceStream()方法的第10行
else if (density != TypedValue.DENSITY_NONE)
我们去源码中看这个字段:
public static final int DENSITY_NONE = 0xffff;
这是一个十六进制的数值,我们将其转换为10进制瞅瞅,嗯哼,它就等于65535。
这个DENSITY_NONE是干嘛的?继续瞅瞅官方文档的解释:
If density is equal to this value, then there is no density associated with the resource and it should not be scaled.
喔,它的意思是说:如果图片放在drawable-nodpi中,那么该图片不会被缩放;也就是说该图片在不同分辨率的手机上都只显示原图的大小。例如,把刚才这张图片放到drawable-nodpi中,那么它在各个手机上显示时它的宽均为144,高均为180。
后语
至此,对于Andoid中常见的度量单位已经介绍完了;关于drawable的加载原理也做了一个完整分析。在明白这些之后,我们再去谈多分辨率的适配也就多了一份从容和自信。
相关文章推荐
- 关于用QPainter画过大的图片出现问题的原因
- 关于winForm界面控件和图片加载时出现闪屏的问题
- android编程中遇到的关于调试百度地图时出现的 java.lang.UnsatisfiedLinkError: initClass 问题的原因及解决办法
- 关于Python 3.x中,使用print函数时出现的语法错误(SyntaxError: invalid syntax)的问题的原因
- 关于Genymotion出现“An error occured while deploying the file.INSTALL_FAILED_INVALID_URI”问题的原因分析
- 关于jar生成exe时出现背景图片无法显示的问题
- YAWL引擎运行失败出现关于log4j问题的原因和解决方法
- 关于部分手机调用系统拍照和相册图片出现旋转问题处理
- 关于 eclipse项目 导入 android studio 中 出现的图片报错问题解决。
- 关于Android7.0版本及其以上系统获取本地数据(图片和文件)报系统出现异常,正在退出问题
- 关于加载图片避免出现内存溢出的问题
- [Android初级]关于使用universal-image-loader加载imagelist出现图片闪烁的问题
- 【游戏开发备注之一】关于Cocos2dx_v1.x版本iphone与Android运行出现图片白块、添加GameCenter报错问题及编译Android闪退的解决办法&&CCLOG与CClog的区别
- 关于用VS写C程序运行时出现"烫"字以及乱码的问题的原因
- ios 关于如何消除在向cell中添加图片文字是时出现的重影问题
- 关于ORACLE出现ORA-00904标识符错误的问题原因
- 关于在iframe中运用zdialog出现topWin.Dialog._Array为空或者不是对象的问题和图片不显示的问题
- 关于upload_max_filesize设置一直是2M,导致dede图片集上传图片出现upload error错误的问题
- 【Python】 关于Python 3.x中,使用print函数时出现的语法错误(SyntaxError: invalid syntax)的问题的原因
- 关于安装.NET Framework 2.0时偶然碰到的问题(提示"Error 205015. 安装程序集..../System.EnterpriseServices.dll失败,原因是出现了系统错误:拒绝访问。")