学习笔记 - 深究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 */
95
96GLOBAL(void)
97jpeg_calc_output_dimensions (j_decompress_ptr cinfo)
98/* Do computations that are needed before master selection phase */
99{
100#ifdef IDCT_SCALING_SUPPORTED
101 int ci;
102 jpeg_component_info *compptr;
103#endif
104
105 /* Prevent application from calling me at wrong times */
106 if (cinfo->global_state != DSTATE_READY)
107 ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
108
109#ifdef IDCT_SCALING_SUPPORTED
110
111 /* 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 to
140 * 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 }
156
157 /* 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 }
172
173#else /* !IDCT_SCALING_SUPPORTED */
174
175 /* 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 */
181
182#endif /* IDCT_SCALING_SUPPORTED */
183
184 /* 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 != 3
192 cinfo->out_color_components = RGB_PIXELSIZE;
193 break;
194#endif /* else share code with YCbCr */
195#ifdef ANDROID_RGB
196 case JCS_RGB_565:
197#endif
198 case JCS_YCbCr:
199 cinfo->out_color_components = 3;
200 break;
201 case JCS_CMYK:
202 case JCS_YCCK:
203#ifdef ANDROID_RGB
204 case JCS_RGBA_8888:
205#endif
206 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);
214
215 /* 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 else
219 cinfo->rec_outbuf_height = 1;
220}
221 // Cross Reference: /external/jpeg/jutils.c
// http://androidxref.com/2.2.3/xref/external/jpeg/jutils.c 67/*
68 * Arithmetic utilities
69 */
70
71 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}
78
79 //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.html
public 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;
}
学习笔记 - 深究Bitmap压缩避免OOM的核心inSampleSize的最佳取值的更多相关文章
- 通过编写串口助手工具学习MFC过程——(十)UpdateData()用法和编辑框的赋值、取值
通过编写串口助手工具学习MFC过程 因为以前也做过几次MFC的编程,每次都是项目完成时,MFC基本操作清楚了,但是过好长时间不再接触MFC的项目,再次做MFC的项目时,又要从头开始熟悉.这次通过做一个 ...
- NodeJS学习笔记 (1)资源压缩-zlib(ok)
原文: https://github.com/chyingp/nodejs-learning-guide/blob/master/README.md 自己的跟进学习: 概览 做过web性能优化的同学, ...
- 学习笔记45—Linux压缩集
1.压缩功能 安装 sudo apt-get install rar 卸载 sudo apt-get remove rar 2.解压功能 安装 sudo apt-get install unrar 卸 ...
- 学习笔记:状态压缩DP
我们知道,用DP解决一个问题的时候很重要的一环就是状态的表示,一般来说,一个数组即可保存状态.但是有这样的一些题 目,它们具有DP问题的特性,但是状态中所包含的信息过多,如果要用数组来保存状态的话需要 ...
- Android 学习笔记之Bitmap位图的旋转
位图的旋转也可以借助Matrix或者Canvas来实现. 通过postRotate方法设置旋转角度,然后用createBitmap方法创建一个经过旋转处理的Bitmap对象,最后用drawBitmap ...
- Android 学习笔记之Bitmap位图虽触摸点移动
package xiaosi.bitmap; import android.app.Activity; import android.os.Bundle; public class mianActiv ...
- Android 学习笔记之Bitmap位图的缩放
位图的缩放也可以借助Matrix或者Canvas来实现. 通过postScale(0.5f, 0.3f)方法设置旋转角度,然后用createBitmap方法创建一个经过缩放处理的Bitmap对象,最后 ...
- Android学习笔记之Bitmap位图虽触摸点移动
package xiaosi.bitmap; import android.app.Activity; import android.os.Bundle; public class mianActiv ...
- Android学习笔记之Bitmap位图的旋转
位图的旋转也可以借助Matrix或者Canvas来实现. 通过postRotate方法设置旋转角度,然后用createBitmap方法创建一个经过旋转处理的Bitmap对象,最后用drawBitmap ...
随机推荐
- http://www.mxchip.com/talk/news/jishuwenzhang/2014-09-11/67.html
http://www.mxchip.com/talk/news/jishuwenzhang/2014-09-11/67.html
- lintcode:数飞机
数飞机 给出飞机的起飞和降落时间的列表,用 interval 序列表示. 请计算出天上同时最多有多少架飞机? 如果多架飞机降落和起飞在同一时刻,我们认为降落有优先权. 样例 对于每架飞机的起降时间列表 ...
- 使用PowerDesigner进行数据库建模入门
阅读目录 两种重要模型 创建表和主外键 创建视图和存储过程 生成数据库 PowerDesigner(简称PD)是一种强大的数据库建模工具,使用PD可以创建业务模型,UML类图等,当然最主要的功能是数据 ...
- MIT算法导论——第二讲.Solving Recurrence
本栏目(Algorithms)下MIT算法导论专题是个人对网易公开课MIT算法导论的学习心得与笔记.所有内容均来自MIT公开课Introduction to Algorithms中Charles E. ...
- TCL语言笔记:TCL中的数学函数
一.TCL数学函数列表 函数名 说明 举例 abs(arg) 取绝对值 set a –10 ; #a=-10 set a [expr abs($a)]; # a=10 acos(arg) 反余弦 s ...
- Apollo,Python,Delphi与Oracle之间的神话关系
在希腊历史上Delphi曾被认为是世界的中心,Apollo杀死Python后将其据为己有,在其神庙上刻有Oracle,曰:Γνωθι δεαυτόν (认识你自己自身关怀,Cognosce te ip ...
- Eliza Doolittle lyrics Big City
Eliza Doolittle lyrics Big City 歌词很好,现在还没有,以后添加进来.
- php模拟用户自动在qq空间发表文章的方法
我们这里是一个简单的利用php来模拟登录后再到QQ空间发送文章的一个简单的程序,有需要的朋友可以参考,或改进可以给我意见,代码如下: <?php //模拟get post请求函数 http:// ...
- linux系统的文件类型学习
linux是一个文件型操作系统,在linux下一切皆文件. 目录.字符设备.块设备.管道.套接字.符号连接文件等在linux下统统都是文件. linux下的文件类型分为以下几种类型: 1. 正规文件, ...
- 【HDOJ】5632 Rikka with Array
1. 题目描述$A[i]$表示二级制表示的$i$的数字之和.求$1 \le i < j \le n$并且$A[i]>A[j]$的$(i,j)$的总对数. 2. 基本思路$n \le 10^ ...