首页 > 代码库 > 学习笔记 - 深究Bitmap压缩避免OOM的核心inSampleSize的最佳取值

学习笔记 - 深究Bitmap压缩避免OOM的核心inSampleSize的最佳取值

    /**     * 测试代码,通过在SDCard根目录放置几种不同大小的图片, 来自动测试压缩方式是否有效同时看是否会内存不够.     *      * @since      * By:AsionTang     * At:2014年3月20日     *      */    public static final void test()    {    //常用照片分辨率    final int[][] list = new int[][]    {    { 15000, 13600 },    { 14000, 12600 },    { 13000, 11600 },    { 12000, 10600 },    { 11000, 9600 },    { 10000, 8600 },    { 9000, 7600 },    { 8000, 6000 },    { 7000, 6000 },    { 8000, 4600 },    { 4080, 2720 },    { 3264, 2488 },    { 3000, 2000 },    { 2560, 1920 },    { 2272, 1704 },    { 2048, 1536 },    { 1600, 1200 },    { 1280, 960 },    { 1024, 768 },    { 800, 600 },    { 640, 480 },    { 480, 320 } };    for (int i = 0; i < list.length; i++)    {        final int w = list[i][0];        //      final int h = list[i][1];        final File f = new File(Environment.getExternalStorageDirectory(), w + ".jpg");        if (!f.exists())        continue;        final Bitmap b = getResizedImage(f.getAbsolutePath(), 640);        saveBitmapToSd(b, 50, f.getAbsolutePath().replace(".jpg", ".png"));        recycleQuietly(b);    }    }    /**     * 这里因为使用的是二次Bitmap编码,所以使用prevPowerOf2往小的值取     *      * @param w     * @param h     * @param maxSize     * @param saveMemory     *            省内存模式: 
* true: 计算SampleSize时,往上取值尽可能大.则最终图片最长边 尺寸 * 小于等于maxSize(小概率会大于maxSize,如输入某些特殊尺寸时,见 * {@link #nextPowerOf2(int)})
* false: 计算SampleSize时,往下取值尽可能小.则最终图片最长边 尺寸 * 大于等于maxSize(没见过小于maxSize的情况) * @return */ @SuppressWarnings("unused") private static final int computeSampleSize(final int w, final int h, final double maxSize, final boolean saveMemory) { final int initialSize = (int) Math.max(w / maxSize, h / maxSize); //原来: 这里因为使用的是二次Bitmap编码,所以使用prevPowerOf2往小的值取,这样第一次取到的Bitmap大小肯定大于maxSize //现在: 这里因为使用的是二次Bitmap编码[支持缩小和扩大图片],所以使用 nextPowerOf2 取尽量小的值,肯定[小于]maxSize,这时,再将其[扩大]maxSize即可! // 经过测试test,最终生成的图片: // 小于3000以上的像素原图: 生成的新图文件[几乎等于]使用prevPowerOf2生成的新图片,即两文件MD5值大概率情况下都会相等. // 大于3000以上的像素原图: 生成的新图文件大小略小于使用prevPowerOf2生成的新图片,使用BCompare图片对比容差25时,看不出多少差异. if (saveMemory) return nextPowerOf2(initialSize); return prevPowerOf2(initialSize); } /** * 在不进行二次Bitmap编码大小的情况下,可直接使用此nextPowerOf2获得更高的采样比值,以便缩小为更小的Bitmap * 但是可能不太稳定,如原图为1024x768时,生成的目标尺寸也大的,小的都有. * * * initialSize:23 trueSize 32:15000x13600 468x425 * initialSize:21 trueSize 32:14000x12600 437x393 * initialSize:20 trueSize 32:13000x11600 406x362 * initialSize:18 trueSize 32:12000x10600 375x331 * initialSize:17 trueSize 32:11000x9600 343x300 * initialSize:15 trueSize 16:10000x8600 625x537 * initialSize:14 trueSize 16:9000x7600 562x475 * initialSize:12 trueSize 16:8000x6000 500x375 * initialSize:10 trueSize 16:7000x6000 437x375 * initialSize:12 trueSize 16:8000x4600 500x287 * initialSize:06 trueSize 08:4080x2720 510x340 * initialSize:05 trueSize 08:3264x2488 408x311 * initialSize:04 trueSize 04:3000x2000 750x500 * initialSize:04 trueSize 04:2560x1920 640x480 * initialSize:03 trueSize 04:2272x1704 568x426 * initialSize:03 trueSize 04:2048x1536 512x384 * initialSize:02 trueSize 02:1600x1200 800x600 * initialSize:02 trueSize 02:1280x960 640x480 * initialSize:01 trueSize 01:1024x768 1024x768 * initialSize:01 trueSize 01:800x600 800x600 * initialSize:01 trueSize 01:640x480 640x480 * * * * // Returns the next power of two. * // Returns the input if it is already power of 2. * // Throws IllegalArgumentException if the input is <= 0 or * // the answer overflows. * * * 最终值往大的取(重采样得的图片尺寸越小) * * @param n * @return */ private static final int nextPowerOf2(int n) { if (n <= 0 || n > (1 << 30)) return 1; n -= 1; n |= n >> 16; n |= n >> 8; n |= n >> 4; n |= n >> 2; n |= n >> 1; return n + 1; } /** * 1.这里追求的目标是:尽可能的接近目标MaxSize的大小,可以大于等于MaxSize大小
* 2.第二步再将接近MaxSize大小的Bitmap再次真正编码为边长为MaxSize大小的Bitmap! * * * initialSize:23 trueSize 16:15000x13600 937x850 * initialSize:21 trueSize 16:14000x12600 875x787 * initialSize:20 trueSize 16:13000x11600 812x725 * initialSize:18 trueSize 16:12000x10600 750x662 * initialSize:17 trueSize 16:11000x9600 687x600 * initialSize:15 trueSize 08:10000x8600 1250x1075 * initialSize:14 trueSize 08:9000x7600 1125x950 * initialSize:12 trueSize 08:8000x6000 1000x750 * initialSize:10 trueSize 08:7000x6000 875x750 * initialSize:12 trueSize 08:8000x4600 1000x575 * initialSize:06 trueSize 04:4080x2720 1020x680 * initialSize:05 trueSize 04:3264x2488 816x622 * initialSize:04 trueSize 04:3000x2000 750x500 * initialSize:04 trueSize 04:2560x1920 640x480 * initialSize:03 trueSize 02:2272x1704 1136x852 * initialSize:03 trueSize 02:2048x1536 1024x768 * initialSize:02 trueSize 02:1600x1200 800x600 * initialSize:02 trueSize 02:1280x960 640x480 * initialSize:01 trueSize 01:1024x768 1024x768 * initialSize:01 trueSize 01:800x600 800x600 * initialSize:01 trueSize 01:640x480 640x480 * * * * // Returns the previous power of two. * // Returns the input if it is already power of 2. * // Throws IllegalArgumentException if the input is <= 0 * * * 最终值往小的取(重采样得的图片尺寸越大) * * @param n * @return */ private static final int prevPowerOf2(final int n) { if (n <= 0) return 1; return Integer.highestOneBit(n); }原始图最长边:1600px目标图最长边:52px图片缩放比例:原始图最长边 / 目标图最长边 = 30.77 系统默认: options.inSampleSize = 图片缩放比例 实际inSampleSize: 24 实际读取出的图片最长边:原宽 / 24 = 66(与目标图最长边相差:14px) 内存占用尽量小: options.inSampleSize = 系统默认SampleSize + 大一级别加8 实际inSampleSize: = 32 实际读取出的图片最长边:原宽 / 32 = 50(与目标图最长边相差:-2px)【最优解】(允许实际图小于目标图时)原始图最长边:1600px目标图最长边:65px图片缩放比例:原始图最长边 / 目标图最长边 = 24.62 系统默认: options.inSampleSize = 图片缩放比例 实际inSampleSize: 24 实际读取出的图片最长边:原宽 / 24 = 66(与目标图最长边相差:1px)【最优解】 内存占用尽量小: options.inSampleSize = 系统默认SampleSize + 大一级别加8 实际inSampleSize: = 32 实际读取出的图片最长边:原宽 / 32 = 50(与目标图最长边相差:-15px)原始图最长边:1600px目标图最长边:58px图片缩放比例:原始图最长边 / 目标图最长边 = 27.58 系统默认: options.inSampleSize = 图片缩放比例 实际inSampleSize: 24 实际读取出的图片最长边:原宽 / 24 = 66(与目标图最长边相差:8px)【最优解】 内存占用尽量小: options.inSampleSize = 系统默认SampleSize + 大一级别加8 实际inSampleSize: = 32 实际读取出的图片最长边:原宽 / 32 = 50(与目标图最长边相差:-8px)【最优解】(允许实际图小于目标图时,且低内存运行时)新算法只有在inSampleSize 大于 24时,才有价值。例如当想从一张分辨率最长边大于 10240 的图片,取一张640的小缩略图时,缩放比为:10304/640=16.1,此时设置给inSampleSize时,系统会将其“向”// 找到真正使用inSampleSize的地方了,但是换了一个变量名名字为scale_denom// Cross Reference: /external/jpeg/jdmaster.c// http://androidxref.com/2.2.3/xref/external/jpeg/jdmaster.c#97/*90 * Compute output image dimensions and related values.91 * NOTE: this is exported for possible use by application.92 * Hence it mustn‘t do anything that can‘t be done twice.93 * Also note that it may be called before the master module is initialized!94 */9596GLOBAL(void)97jpeg_calc_output_dimensions (j_decompress_ptr cinfo)98/* Do computations that are needed before master selection phase */99{100#ifdef IDCT_SCALING_SUPPORTED101 int ci;102 jpeg_component_info *compptr;103#endif104105 /* Prevent application from calling me at wrong times */106 if (cinfo->global_state != DSTATE_READY)107 ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);108109#ifdef IDCT_SCALING_SUPPORTED110111 /* Compute actual output image dimensions and DCT scaling choices. */112 if (cinfo->scale_num * 8 <= cinfo->scale_denom) {113 /* Provide 1/8 scaling */114 cinfo->output_width = (JDIMENSION)115 jdiv_round_up((long) cinfo->image_width, 8L);116 cinfo->output_height = (JDIMENSION)117 jdiv_round_up((long) cinfo->image_height, 8L);118 cinfo->min_DCT_scaled_size = 1;119 } else if (cinfo->scale_num * 4 <= cinfo->scale_denom) {120 /* Provide 1/4 scaling */121 cinfo->output_width = (JDIMENSION)122 jdiv_round_up((long) cinfo->image_width, 4L);123 cinfo->output_height = (JDIMENSION)124 jdiv_round_up((long) cinfo->image_height, 4L);125 cinfo->min_DCT_scaled_size = 2;126 } else if (cinfo->scale_num * 2 <= cinfo->scale_denom) {127 /* Provide 1/2 scaling */128 cinfo->output_width = (JDIMENSION)129 jdiv_round_up((long) cinfo->image_width, 2L);130 cinfo->output_height = (JDIMENSION)131 jdiv_round_up((long) cinfo->image_height, 2L);132 cinfo->min_DCT_scaled_size = 4;133 } else {134 /* Provide 1/1 scaling */135 cinfo->output_width = cinfo->image_width;136 cinfo->output_height = cinfo->image_height;137 cinfo->min_DCT_scaled_size = DCTSIZE;138 }139 /* In selecting the actual DCT scaling for each component, we try to140 * scale up the chroma components via IDCT scaling rather than upsampling.141 * This saves time if the upsampler gets to use 1:1 scaling.142 * Note this code assumes that the supported DCT scalings are powers of 2.143 */144 for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;145 ci++, compptr++) {146 int ssize = cinfo->min_DCT_scaled_size;147 while (ssize < DCTSIZE &&148 (compptr->h_samp_factor * ssize * 2 <=149 cinfo->max_h_samp_factor * cinfo->min_DCT_scaled_size) &&150 (compptr->v_samp_factor * ssize * 2 <=151 cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size)) {152 ssize = ssize * 2;153 }154 compptr->DCT_scaled_size = ssize;155 }156157 /* Recompute downsampled dimensions of components;158 * application needs to know these if using raw downsampled data.159 */160 for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;161 ci++, compptr++) {162 /* Size in samples, after IDCT scaling */163 compptr->downsampled_width = (JDIMENSION)164 jdiv_round_up((long) cinfo->image_width *165 (long) (compptr->h_samp_factor * compptr->DCT_scaled_size),166 (long) (cinfo->max_h_samp_factor * DCTSIZE));167 compptr->downsampled_height = (JDIMENSION)168 jdiv_round_up((long) cinfo->image_height *169 (long) (compptr->v_samp_factor * compptr->DCT_scaled_size),170 (long) (cinfo->max_v_samp_factor * DCTSIZE));171 }172173#else /* !IDCT_SCALING_SUPPORTED */174175 /* Hardwire it to "no scaling" */176 cinfo->output_width = cinfo->image_width;177 cinfo->output_height = cinfo->image_height;178 /* jdinput.c has already initialized DCT_scaled_size to DCTSIZE,179 * and has computed unscaled downsampled_width and downsampled_height.180 */181182#endif /* IDCT_SCALING_SUPPORTED */183184 /* Report number of components in selected colorspace. */185 /* Probably this should be in the color conversion module... */186 switch (cinfo->out_color_space) {187 case JCS_GRAYSCALE:188 cinfo->out_color_components = 1;189 break;190 case JCS_RGB:191#if RGB_PIXELSIZE != 3192 cinfo->out_color_components = RGB_PIXELSIZE;193 break;194#endif /* else share code with YCbCr */195#ifdef ANDROID_RGB196 case JCS_RGB_565:197#endif198 case JCS_YCbCr:199 cinfo->out_color_components = 3;200 break;201 case JCS_CMYK:202 case JCS_YCCK:203#ifdef ANDROID_RGB204 case JCS_RGBA_8888:205#endif206 cinfo->out_color_components = 4;207 break;208 default: /* else must be same colorspace as in file */209 cinfo->out_color_components = cinfo->num_components;210 break;211 }212 cinfo->output_components = (cinfo->quantize_colors ? 1 :213 cinfo->out_color_components);214215 /* See if upsampler will want to emit more than one row at a time */216 if (use_merged_upsample(cinfo))217 cinfo->rec_outbuf_height = cinfo->max_v_samp_factor;218 else219 cinfo->rec_outbuf_height = 1;220}221// Cross Reference: /external/jpeg/jutils.c// http://androidxref.com/2.2.3/xref/external/jpeg/jutils.c67/*68 * Arithmetic utilities69 */7071 GLOBAL(long)72 jdiv_round_up (long a, long b)73/* Compute a/b rounded up to next integer, ie, ceil(a/b) */74/* Assumes a >= 0, b > 0 */75{76 return (a + b - 1L) / b;77}7879//Cross Reference: /packages/apps/Camera/src/com/android/camera/Camera.java//http://androidxref.com/2.2.3/xref/packages/apps/Camera/src/com/android/camera/Camera.java//相机拍照完毕 居然还发送广播sendBroadcast(new Intent("com.android.camera.NEW_PICTURE", mLastContentUri));//那么现在就有3种方式获取相机图片的方法了// 在这里能找到inSampleSize 真正使用的地方。// 1.Cross Reference: /frameworks/base/core/jni/android/graphics/BitmapFactory.cpp// http://androidxref.com/2.2.3/xref/frameworks/base/core/jni/android/graphics/BitmapFactory.cpp// 2.// 官网的DEMO例子里计算inSampleSize的方法// Loading Large Bitmaps Efficiently | Android Developers// http://developer.android.com/intl/zh-cn/training/displaying-bitmaps/load-bitmap.htmlpublic static int calculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2; } } return inSampleSize;}private static final void test2(final String imagePath){ final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(imagePath, options); double w = options.outWidth; for (int i = 1; i < 129; i++) { options.inSampleSize = i; BitmapFactory.decodeFile(imagePath, options); double b = w / options.outWidth; android.util.Log.e("size:" + i + " w:" + options.outWidth, "h:" + options.outHeight + "trueSize:" + b); }}缩放比:1 w:15560 h:9725 计算后对应的inSampleSize:1.0缩放比:2 w:7780 h:4863 计算后对应的inSampleSize:2.0缩放比:3 w:7780 h:4863 计算后对应的inSampleSize:2.0缩放比:4 w:3890 h:2432 计算后对应的inSampleSize:4.0缩放比:5 w:3890 h:2432 计算后对应的inSampleSize:4.0缩放比:6 w:3890 h:2432 计算后对应的inSampleSize:4.0缩放比:7 w:3890 h:2432 计算后对应的inSampleSize:4.0缩放比:8 w:1945 h:1216 计算后对应的inSampleSize:8.0缩放比:9 w:1945 h:1216 计算后对应的inSampleSize:8.0缩放比:10 w:1945 h:1216 计算后对应的inSampleSize:8.0缩放比:11 w:1945 h:1216 计算后对应的inSampleSize:8.0缩放比:12 w:1945 h:1216 计算后对应的inSampleSize:8.0缩放比:13 w:1945 h:1216 计算后对应的inSampleSize:8.0缩放比:14 w:1945 h:1216 计算后对应的inSampleSize:8.0缩放比:15 w:1945 h:1216 计算后对应的inSampleSize:8.0缩放比:16 w:972 h:608 计算后对应的inSampleSize:16.008230452674898缩放比:17 w:972 h:608 计算后对应的inSampleSize:16.008230452674898缩放比:18 w:972 h:608 计算后对应的inSampleSize:16.008230452674898缩放比:19 w:972 h:608 计算后对应的inSampleSize:16.008230452674898缩放比:20 w:972 h:608 计算后对应的inSampleSize:16.008230452674898缩放比:21 w:972 h:608 计算后对应的inSampleSize:16.008230452674898缩放比:22 w:972 h:608 计算后对应的inSampleSize:16.008230452674898缩放比:23 w:972 h:608 计算后对应的inSampleSize:16.008230452674898缩放比:24 w:648 h:405 计算后对应的inSampleSize:24.012345679012345缩放比:25 w:648 h:405 计算后对应的inSampleSize:24.012345679012345缩放比:26 w:648 h:405 计算后对应的inSampleSize:24.012345679012345缩放比:27 w:648 h:405 计算后对应的inSampleSize:24.012345679012345缩放比:28 w:648 h:405 计算后对应的inSampleSize:24.012345679012345缩放比:29 w:648 h:405 计算后对应的inSampleSize:24.012345679012345缩放比:30 w:648 h:405 计算后对应的inSampleSize:24.012345679012345缩放比:31 w:648 h:405 计算后对应的inSampleSize:24.012345679012345缩放比:32 w:486 h:304 计算后对应的inSampleSize:32.016460905349795缩放比:33 w:486 h:304 计算后对应的inSampleSize:32.016460905349795缩放比:34 w:486 h:304 计算后对应的inSampleSize:32.016460905349795缩放比:35 w:486 h:304 计算后对应的inSampleSize:32.016460905349795缩放比:36 w:486 h:304 计算后对应的inSampleSize:32.016460905349795缩放比:37 w:486 h:304 计算后对应的inSampleSize:32.016460905349795缩放比:38 w:486 h:304 计算后对应的inSampleSize:32.016460905349795缩放比:39 w:486 h:304 计算后对应的inSampleSize:32.016460905349795缩放比:40 w:389 h:243 计算后对应的inSampleSize:40.0缩放比:41 w:389 h:243 计算后对应的inSampleSize:40.0缩放比:42 w:389 h:243 计算后对应的inSampleSize:40.0缩放比:43 w:389 h:243 计算后对应的inSampleSize:40.0缩放比:44 w:389 h:243 计算后对应的inSampleSize:40.0缩放比:45 w:389 h:243 计算后对应的inSampleSize:40.0缩放比:46 w:389 h:243 计算后对应的inSampleSize:40.0缩放比:47 w:389 h:243 计算后对应的inSampleSize:40.0缩放比:48 w:324 h:202 计算后对应的inSampleSize:48.02469135802469缩放比:49 w:324 h:202 计算后对应的inSampleSize:48.02469135802469缩放比:50 w:324 h:202 计算后对应的inSampleSize:48.02469135802469缩放比:51 w:324 h:202 计算后对应的inSampleSize:48.02469135802469缩放比:52 w:324 h:202 计算后对应的inSampleSize:48.02469135802469缩放比:53 w:324 h:202 计算后对应的inSampleSize:48.02469135802469缩放比:54 w:324 h:202 计算后对应的inSampleSize:48.02469135802469缩放比:55 w:324 h:202 计算后对应的inSampleSize:48.02469135802469缩放比:56 w:277 h:173 计算后对应的inSampleSize:56.17328519855596缩放比:57 w:277 h:173 计算后对应的inSampleSize:56.17328519855596缩放比:58 w:277 h:173 计算后对应的inSampleSize:56.17328519855596缩放比:59 w:277 h:173 计算后对应的inSampleSize:56.17328519855596缩放比:60 w:277 h:173 计算后对应的inSampleSize:56.17328519855596缩放比:61 w:277 h:173 计算后对应的inSampleSize:56.17328519855596缩放比:62 w:277 h:173 计算后对应的inSampleSize:56.17328519855596缩放比:63 w:277 h:173 计算后对应的inSampleSize:56.17328519855596缩放比:64 w:243 h:152 计算后对应的inSampleSize:64.03292181069959缩放比:65 w:243 h:152 计算后对应的inSampleSize:64.03292181069959缩放比:66 w:243 h:152 计算后对应的inSampleSize:64.03292181069959缩放比:67 w:243 h:152 计算后对应的inSampleSize:64.03292181069959缩放比:68 w:243 h:152 计算后对应的inSampleSize:64.03292181069959缩放比:69 w:243 h:152 计算后对应的inSampleSize:64.03292181069959缩放比:70 w:243 h:152 计算后对应的inSampleSize:64.03292181069959缩放比:71 w:243 h:152 计算后对应的inSampleSize:64.03292181069959缩放比:72 w:216 h:135 计算后对应的inSampleSize:72.03703703703704缩放比:73 w:216 h:135 计算后对应的inSampleSize:72.03703703703704缩放比:74 w:216 h:135 计算后对应的inSampleSize:72.03703703703704缩放比:75 w:216 h:135 计算后对应的inSampleSize:72.03703703703704缩放比:76 w:216 h:135 计算后对应的inSampleSize:72.03703703703704缩放比:77 w:216 h:135 计算后对应的inSampleSize:72.03703703703704缩放比:78 w:216 h:135 计算后对应的inSampleSize:72.03703703703704缩放比:79 w:216 h:135 计算后对应的inSampleSize:72.03703703703704缩放比:80 w:194 h:121 计算后对应的inSampleSize:80.20618556701031缩放比:81 w:194 h:121 计算后对应的inSampleSize:80.20618556701031缩放比:82 w:194 h:121 计算后对应的inSampleSize:80.20618556701031缩放比:83 w:194 h:121 计算后对应的inSampleSize:80.20618556701031缩放比:84 w:194 h:121 计算后对应的inSampleSize:80.20618556701031缩放比:85 w:194 h:121 计算后对应的inSampleSize:80.20618556701031缩放比:86 w:194 h:121 计算后对应的inSampleSize:80.20618556701031缩放比:87 w:194 h:121 计算后对应的inSampleSize:80.20618556701031缩放比:88 w:176 h:110 计算后对应的inSampleSize:88.4090909090909缩放比:89 w:176 h:110 计算后对应的inSampleSize:88.4090909090909缩放比:90 w:176 h:110 计算后对应的inSampleSize:88.4090909090909缩放比:91 w:176 h:110 计算后对应的inSampleSize:88.4090909090909缩放比:92 w:176 h:110 计算后对应的inSampleSize:88.4090909090909缩放比:93 w:176 h:110 计算后对应的inSampleSize:88.4090909090909缩放比:94 w:176 h:110 计算后对应的inSampleSize:88.4090909090909缩放比:95 w:176 h:110 计算后对应的inSampleSize:88.4090909090909缩放比:96 w:162 h:101 计算后对应的inSampleSize:96.04938271604938缩放比:97 w:162 h:101 计算后对应的inSampleSize:96.04938271604938缩放比:98 w:162 h:101 计算后对应的inSampleSize:96.04938271604938缩放比:99 w:162 h:101 计算后对应的inSampleSize:96.04938271604938缩放比:100 w:162 h:101 计算后对应的inSampleSize:96.04938271604938缩放比:101 w:162 h:101 计算后对应的inSampleSize:96.04938271604938缩放比:102 w:162 h:101 计算后对应的inSampleSize:96.04938271604938缩放比:103 w:162 h:101 计算后对应的inSampleSize:96.04938271604938缩放比:104 w:149 h:93 计算后对应的inSampleSize:104.42953020134229缩放比:105 w:149 h:93 计算后对应的inSampleSize:104.42953020134229缩放比:106 w:149 h:93 计算后对应的inSampleSize:104.42953020134229缩放比:107 w:149 h:93 计算后对应的inSampleSize:104.42953020134229缩放比:108 w:149 h:93 计算后对应的inSampleSize:104.42953020134229缩放比:109 w:149 h:93 计算后对应的inSampleSize:104.42953020134229缩放比:110 w:149 h:93 计算后对应的inSampleSize:104.42953020134229缩放比:111 w:149 h:93 计算后对应的inSampleSize:104.42953020134229缩放比:112 w:138 h:86 计算后对应的inSampleSize:112.7536231884058缩放比:113 w:138 h:86 计算后对应的inSampleSize:112.7536231884058缩放比:114 w:138 h:86 计算后对应的inSampleSize:112.7536231884058缩放比:115 w:138 h:86 计算后对应的inSampleSize:112.7536231884058缩放比:116 w:138 h:86 计算后对应的inSampleSize:112.7536231884058缩放比:117 w:138 h:86 计算后对应的inSampleSize:112.7536231884058缩放比:118 w:138 h:86 计算后对应的inSampleSize:112.7536231884058缩放比:119 w:138 h:86 计算后对应的inSampleSize:112.7536231884058缩放比:120 w:129 h:81 计算后对应的inSampleSize:120.62015503875969缩放比:121 w:129 h:81 计算后对应的inSampleSize:120.62015503875969缩放比:122 w:129 h:81 计算后对应的inSampleSize:120.62015503875969缩放比:123 w:129 h:81 计算后对应的inSampleSize:120.62015503875969缩放比:124 w:129 h:81 计算后对应的inSampleSize:120.62015503875969缩放比:125 w:129 h:81 计算后对应的inSampleSize:120.62015503875969缩放比:126 w:129 h:81 计算后对应的inSampleSize:120.62015503875969缩放比:127 w:129 h:81 计算后对应的inSampleSize:120.62015503875969缩放比:128 w:121 h:76 计算后对应的inSampleSize:128.59504132231405//TO DO:这里根据inJustDecodeBounds=True时,看是否能设置inSampleSise在不编码图像数据情况下拿到新取样后的大小??【经过测试】可以在设置 inJustDecodeBounds = true;后,再设置 inSampleSize ,的确可以再获得待缩小后的 长和宽//TO DO:根据之前的真实测试数据,存在一种非正常的SimpleSize 24!所以是否现在的取SimpleSize算法还不是真正的算法 ???【经过测试】的确存在24的情况,说明算法不是仅仅的2的指数次值。重采样大小:24 原图分辨率:15000x13600 目标分辨率: 625x566重采样大小:24 原图分辨率:14000x12600 目标分辨率:583x525重采样大小:24 原图分辨率:13000x11600 目标分辨率:541x483重采样大小:24 原图分辨率:12000x10600 目标分辨率:500x441重采样大小:16 原图分辨率:11000x9600 目标分辨率: 687x600重采样大小:16 原图分辨率:10000x8600 目标分辨率:625x537重采样大小:16 原图分辨率:9000x7600 目标分辨率:562x475重采样大小:16 原图分辨率:8000x6000 目标分辨率:500x375重采样大小:16 原图分辨率:7000x6000 目标分辨率:437x375重采样大小:8 原图分辨率:8000x4600 目标分辨率:1000x575重采样大小:4 原图分辨率:4080x2720 目标分辨率:1020x680重采样大小:4 原图分辨率:3264x2488 目标分辨率:816x622重采样大小:4 原图分辨率:3000x2000 目标分辨率:750x500重采样大小:4 原图分辨率:2560x1920 目标分辨率:640x480重采样大小:2 原图分辨率:2272x1704 目标分辨率:1136x852重采样大小:2 原图分辨率:2048x1536 目标分辨率:1024x768重采样大小:2 原图分辨率:1600x1200 目标分辨率:800x600重采样大小:1 原图分辨率:1280x960 目标分辨率: 1280x960重采样大小:1 原图分辨率:1024x768 目标分辨率: 1024x768重采样大小:1 原图分辨率:800x600 目标分辨率: 800x600重采样大小:1 原图分辨率:640x480 目标分辨率:640x480 public static void test() { //常用照片分辨率 int[][] list = new int[][] { { 15000, 13600 }, { 14000, 12600 }, { 13000, 11600 }, { 12000, 10600 }, { 11000, 9600 }, { 10000, 8600 }, { 9000, 7600 }, { 8000, 6000 }, { 7000, 6000 }, { 8000, 4600 }, { 4080, 2720 }, { 3264, 2488 }, { 3000, 2000 }, { 2560, 1920 }, { 2272, 1704 }, { 2048, 1536 }, { 1600, 1200 }, { 1280, 960 }, { 1024, 768 }, { 800, 600 }, { 640, 480 } }; for (int i = 0; i < list.length; i++) { int w = list[i][0]; int h = list[i][1]; int s = BitmapUtils.computeSampleSize(w, h, 600, -1); LogEx.e("重采样大小:"+s + "\t原图分辨率:" + w + "\t目标分辨率:" + h, w / s + "x" + h / s); }} /* * Compute the sample size as a function of minSideLength and * maxNumOfPixels. minSideLength is used to specify that minimal width or * height of a bitmap. maxNumOfPixels is used to specify the maximal size in * pixels that is tolerable in terms of memory usage. * * The function returns a sample size based on the constraints. Both size * and minSideLength can be passed in as UNCONSTRAINED, which indicates no * care of the corresponding constraint. The functions prefers returning a * sample size that generates a smaller bitmap, unless minSideLength = * UNCONSTRAINED. * * Also, the function rounds up the sample size to a power of 2 or multiple * of 8 because BitmapFactory only honors sample size this way. For example, * BitmapFactory downsamples an image by 2 even though the request is 3. So * we round up the sample size to avoid OOM. */ private static int computeSampleSize(int width, int height, int minSideLength, int maxNumOfPixels) { int initialSize = computeInitialSampleSize(width, height, minSideLength, maxNumOfPixels); return initialSize <= 8 ? nextPowerOf2(initialSize) : (initialSize + 7) / 8 * 8; } private static int computeInitialSampleSize(int w, int h, int minSideLength, int maxNumOfPixels) { if (maxNumOfPixels == UNCONSTRAINED && minSideLength == UNCONSTRAINED) return 1; int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 : (int) FloatMath.ceil(FloatMath.sqrt((float) (w * h) / maxNumOfPixels)); if (minSideLength == UNCONSTRAINED) { return lowerBound; } else { int sampleSize = Math.min(w / minSideLength, h / minSideLength); return Math.max(sampleSize, lowerBound); } } // Returns the next power of two. // Returns the input if it is already power of 2. // Throws IllegalArgumentException if the input is <= 0 or // the answer overflows. private static int nextPowerOf2(int n) {    if (n <= 0 || n > (1 << 30))    throw new IllegalArgumentException();    n -= 1;    n |= n >> 16;    n |= n >> 8;    n |= n >> 4;    n |= n >> 2;    n |= n >> 1;    return n + 1; }