原文链接:微信分享图片压缩问题解决方案 作者:李青
概述 在进行微信分享时,遇到微信分享失败的情况,微信分享对于图片的大小有32k的限制,如果大于的话就会导致失败。所以对于图片的压缩进行了调研,最后得出如下解决方案:
1、统一了图片的质量参数为RGB_565; 问题背景在某些页面调起微信分享时会直接返回失败,但并不是所有的页面都会失败,所以排除是微信分享API的问题。 术语解释
问题分析private void sendReq(IWXAPI iwxapi, BaseReq req) { boolean result = iwxapi.sendReq(req); if(!result) { this.mCallBack.onShareError(this.mActivity, ""); this.mActivity.finish(); } }
由分析可知以上result返回false,在这里是将分享的数据传入分享的API,所以猜测这里应该是参数传入有误,下面是在官网上查看的常见问题(虽然结果返回true,但还是具有参考价值的信息),我们可以看到第三条,检查发送时的缩略图大小是否超过32K,所以微信分享对于图片的大小是有限制的,重新换了一张小点的图,最后分享成功了。
目前的分享流程
从以上流程可以看出来,图片是经过了两次压缩,为什么最后还会有超出大小的情况呢?下面我们来分析一下具体的压缩过程是如何实现的。 /** * 图片压缩比例计算 * * @param options BitmapFactory.Options * @param minSideLength 小边长,单位为像素,如果为-1,则不按照边来压缩图片 * @param maxNumOfPixels 这张片图片最大像素值,单位为byte,如100*1024 * @return 压缩比例,必须为2的次幂 */ public static int computeSampleSize(BitmapFactory.Options options,int minSideLength, int maxNumOfPixels) { int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels); int roundedSize; if (initialSize <= 8) { roundedSize = 1; while (roundedSize < initialSize) { roundedSize <<= 1; } } else { roundedSize = (initialSize + 7) / 8 * 8; } return roundedSize; } /** * 计算图片的压缩比例,用于图片压缩 * @param options BitmapFactory.Options * @param minSideLength 小边长,单位为像素,如果为-1,则不按照边来压缩图片 * @param maxNumOfPixels 这张片图片最大像素值,单位为byte,如100*1024 * @return 压缩比例 */ private static int computeInitialSampleSize(BitmapFactory.Options options,int minSideLength,int maxNumOfPixels) { double w = options.outWidth; double h = options.outHeight; int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math .sqrt(w * h / maxNumOfPixels)); int upperBound = (minSideLength == -1) ? 128 : (int) Math.min( Math.floor(w / minSideLength), Math.floor(h / minSideLength)); if (upperBound < lowerBound) { return lowerBound; } if ((maxNumOfPixels == -1) && (minSideLength == -1)) { return 1; } else if (minSideLength == -1) { return lowerBound; } else { return upperBound; } } 以上的方法是安卓源码中处理缩略图大小的计算方法,我们知道图片的inSampleSize必须为2的幂次,如果不是2的幂次,会以接近2的幂次这个数来进行压缩,所以最后计算出来的inSampleSize必然不能很精确的将图片压缩到我们期望的大小,所以当一张图片太大时,可能第一次压缩并没有达到效果,然后再经过第二次压缩之后还是可能会超过32k,这就导致了最终的微信分享失败。 在我们处理图片的时候发现,会给图片设置质量参数,如下 public static Bitmap makeNormalBitmap(String nativeImagePath,int minSideLength, int maxNumOfPixels){ return makeNormalBitmap(nativeImagePath, minSideLength, maxNumOfPixels,Bitmap.Config.ARGB_4444); } 目前这里设置成了ARGB_4444,那为什么要设置成这个格式呢?应该设置成什么格式呢?还有第二次压缩bmp.compress(CompressFormat.PNG, 100, output);这里为什么设置成PNG,换成JPEG可以吗? 针对以上问题,我做了一番测试,分为ARGB_8888(PNG) ARGB_4444(PNG) RGB_565(PNG) ARGB_8888(JPEG) ARGB_4444(JPEG) RGB_565(JPEG) 分别对图片大小和质量有什么影响。 调研数据分析结果如下:
优化后的解决方案
大部分图片经过前两次压缩都能达到要求,为保证微信分享成功,在第二次压缩后进行判断,如果小于32k就直接分享,如果大于的话就压缩成JPEG格式,通过改变option参数来不断进行压缩,直到满足要求,该方案经过测试已经解决了微信分享失败的问题。 注意点:在最后一步转换成JPEG格式时会不断修改option参数来进行压缩,图片的质量最后可能会影响,在这种情况下需要server配合换掉该图,从客户端的角度来考虑该方案可以保证分享成功,如果图片失真严重的话就需要考虑换图了。 |