您的位置:首页 > 其它

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

2014-08-13 08:51 555 查看
/**
* 测试代码,通过在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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: