前言
[代码]java代码:
1 2 3 4 5 |
|
特别喜欢系统中一些小而精的工具类,有的时候分析一下别有一番味道。
ThumbnailUtils是系统内置的一个生成缩略图的工具类,只有512行代码,网上有很多使用ThumbnailUtils的例子,刚好我个人正在整理Bitmap的相关资料,希望从中也能有所收获。
几个概念
像素规范
系统中对缩略图的像素定义了三种规范:
对于开发者,只支持MINI_KIND和MICRO_KIND两种类型。为什么是这个像素呢?因为ThumbnailUtils中定义如下:
[代码]java代码:
1 2 3 4 5 6 |
|
其中MAX_NUM_PIXELS_MICRO_THUMBNAIL的值之前是128 128,在4.2+版本上被调整为160 120,原因很简单,现在手机拍摄照片比例普遍是4:3,如果不是这个比例生成缩略图的时候需要更多的计算。
尺寸规范
系统中对MINI_KIND和MICRO_KIND两种类型的图片尺寸做了限制,强调一下,是“系统”。
[代码]java代码:
1 2 |
|
当然这两个字段是@hide的,是专门系统用的。
如果图片缩略图,MINI_KIND则等比例缩到360,MICRO_KIND则缩放为96 x 96的正方形(实现方法参考下面的#最合适的缩略图)
如果视频缩略图,MINI_KIND则等比例缩到512(这个512是写死在代码里的magic number),MICRO_KIND则缩放为96 x 96的正方形(实现方法参考下面的#最合适的缩略图)
Exif格式
Exif是一种图像文件格式,它的数据存储与JPEG格式是完全相同的。实际上Exif格式就是在JPEG格式头部插入了数码照片的信息,包括拍摄时的光圈、快门、白平衡、ISO、焦距、日期时间等各种和拍摄条件以及相机品牌、型号、色彩编码、拍摄时录制的声音以及GPS全球定位系统数据、缩略图等。
具体元信息,可参考f/b/media/java/android/media/ExifInterface.java
这里我特别指出ExifInterface的两点,在大家工作中很有可能会碰到:
[代码]java代码:
01 02 03 04 05 06 07 08 09 10 11 12 13 |
|
最合适的缩略图
等比例缩放只需要按Bitmap.createBitmap即可,但是Thumbnail的缩略图生成算法中为了从中间截图最合适的部分,包含了裁剪的逻辑。主要分两步:
1. 先缩放:按照填满的思想缩放到目标大小
2. 再裁剪:从中间裁剪目标大小的区域
[代码]java代码:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
|
基于上面的算法,ThumbnailUtils对外提供了如下接口生成缩略图:
[代码]java代码:
1 2 3 |
|
视频缩略图
使用MediaMetadataRetriever读取视频第一帧Bitmap,然后据此再生成缩略图。
如果kind为Thumbnails.MINI_KIND,就等比例生成最大宽或者高为512的小图。
如果king为Thumbnails.MICRO_KIND,就使用上面讲的最合适的缩略图算法,生成96 x 96的正方形小图
[代码]java代码:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
内部方法
ThumbnailUtils其实对外的方法就上面三个演示的三个方法,除此之外,内部还有两部分,一部分是生成图片文件的缩略图,另外一部分就是未使用的无用代码。
计算SampleSize
系统中新加入一张图,就要生成缩略图了,最重要的就是计算SampleSize了,ThumbnailUtils提供了两种算法:
按目标最小边(minSideLength)
定义最小边的缩放比例
(int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength))
按目标像素(maxNumOfPixels)
定义像素的缩放比例
(int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels))
具体实现
同时支持不指定限制,也做了一个默认值处理,实现如下:
[代码]java代码:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
但是上面的缩放比例不是标准的2的次放,不符合BitmapFactory的规范,再封装一下:
[代码]java代码:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 |
|
从EXIF中选取缩略图
只支持JPG中读取EXIF信息。
这里不是说EXIF有缩略图就用这个缩略图,而是会先用高宽算出文件本身的TargetSize对应的缩略图,和EXIF中缩放到TargetSize对应的缩略图比较,哪个大取哪个。
[代码]java代码:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
|
图片文件缩略图
如果是MINI_KIND,尺寸最小边缩放到320左右,像素缩放到512 x 387。否则就是MICRO_KIND,尺寸最大边缩放到96,像素所放到160 x 120。
如果图片是JPG,参考上面的方法从EXIF中选取缩略图。否则,用decodeFileDescriptor()老老实实等比例生成缩略图。
最终成功后,如果是MICRO_KIND,还要裁剪为96 x 96的正方形。
[代码]java代码:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
|
这里你可能注意到了,如果从EXIF的代码中获取本身文件缩略图用的是decodeFile(),而后面非JPG图片获取缩略图用decodeFileDescriptor(),为什么呢?
不知道,也许是开发者“Ray Chen”忘记了,只改了一部分,另外一部分为了稳定性也没改。
据网上资料看,decodeFileDescriptor()比decodeFile()更省内存,没有论证,仅供参考。
未使用的无用代码
在ThumbnailUtils有一些私有方法,但是自己又没有去调用,暂且把这些方法定位无用代码吧:
[代码]java代码:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
|
小结
通过学习ThumbnailUtils生成缩略图的方方面面,结合自己的经验实践,从此生成缩略图无忧。
零零散散写的有点乱,但基本上能运行到的每行代码都覆盖到了,对于理解ThumbnailUtils这个类来说,应该够了。
共同学习,写下你的评论
评论加载中...
作者其他优质文章