所遇问题
最近在项目开发中,需要用到一个分享的功能。当我千辛万苦的把整个页面的绘制出来转换成比bitmap的时候,算了下,大概最长的图片高度应该有9000+,点击分享到微信,嗯哼?!什么情况?调不起微信客户端,mmp.
找坑
查看微信官方开发者文档,里面有提到调不起的主要原因有:
- 微信是否安装
- 调用时的Apk包名和签名是否与开放平台填写的一致
- 检查发送时的缩略图大小是否超过32k
发现坑
对于上面的3点,第一点是不用看的嘛。来看看第2点:
调用时的Apk包名和签名是否与开放平台填写的一致
,意思是在申请微信分享key的时候所填写的包名是否与现在所打包出来的包名是否一致,还有打包出来的apk签名是否与后台所配置的签名MD5一致,可以去微信开发者下载签名检验工具检验。
经调试发现,分享整个应用的时候(就是有标题有内容有网页链接)时,微信分享是能调起来的,说明以上第二点所提到的问题不存在,那只有第3点了。来看看第三点:
检查发送时的缩略图大小是否超过32k
,这是什么gui,内牛满面.
由于项目中所分享的图片是整个页面的长图,初分享时只是简单的进行质量压缩,并没有进行深度压缩,导致的官方所说的缩略图大小不能大于32k的限制使得调不起微信来分享。
填坑
既然知道了问题在哪里,对于技术宅来说解决问题就再容易不过了,马上开干。说到底还是图片的压缩问题而已,下面说说常见的几种bitmap的压缩方式,条件是在使得能调起微信分享的情况下,最大化图片的质量,以防止深度压缩导致的模糊不清。
- 使用RGB_565的config
Bitmap.createBitmap(finalWidth, finalHeight, Bitmap.Config.RGB_565);
在创建一个bitmap的时候,第三个参数有4种配置,分别是:
Bitmap.Config ALPHA_8 表示8位Alpha位图,即A=8,一个像素点占用1个字节,它没有颜色,只有透明度
Bitmap.Config ARGB_4444 表示16位ARGB位图,即A=4,R=4,G=4,B=4,一个像素点占4+4+4+4=16位,2个字节
Bitmap.Config ARGB_8888 表示32位ARGB位图,即A=8,R=8,G=8,B=8,一个像素点占8+8+8+8=32位,4个字节
Bitmap.Config RGB_565 表示16位RGB位图,即R=5,G=6,B=5,它没有透明度,一个像素点占5+6+5=16位,2个字节
ARGB 分别表示三原色+透明度,这个不展开了。
用Bitmap.Config.RGB_565处理的图片大小相比ARGB_8888减少了一半的内存,但是长宽并没有变化。
- 质量压缩
先看代码
public static Bitmap compressBitmap(Bitmap tmp) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
tmp.compress(Bitmap.CompressFormat.JPEG, 100, baos);
int op = 90;
while (baos.toByteArray().length > 192 * 1024 && op >= 0) {
baos.reset();
tmp.compress(Bitmap.CompressFormat.JPEG, op, baos);
op -= 10;
}
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
return decodeStream(isBm);
}
这种压缩方式称之为质量压缩,宽度和高度不变,质量降低,相应的bitmap所占的内存也降低。
这里的192是我项目中规定的,根据微信分享所规定的32k大小限制,我这边并不太理解,在调试中发现bitmap的baos.toByteArray().length
大小只要小于196左右,就能调起微信的分享,所以我限制192也算是刚刚好吧,在这里希望有谁清楚这个的,不妨给我指点指点,它们之间有什么联系没有,不过不要把我p的太过哈,留点面子给我讨点饭吃,好穷的我。
- 采样率压缩
不知道大家还记不记得Bitmap.Options.inSampleSize这个属性,继续看看
ByteArrayOutputStream baos = new ByteArrayOutputStream();
tmp.compress(Bitmap.CompressFormat.JPEG, 100, baos);
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(isBm, null, options);
options.inJustDecodeBounds = false;
float be = options.outWidth / 480;
options.inSampleSize = (int) Math.rint(be);
return BitmapFactory.decodeStream(isBm,null,options);
这种方式中,设置inSampleSize的值(int类型)后,假如设为2,则宽和高都为原来的1/2,宽高都减少了,自然内存也降低了。
- 缩放法压缩
public static Bitmap compressBitmap(Bitmap tmp) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
tmp.compress(Bitmap.CompressFormat.JPEG, 100, baos);
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
decodeStream(isBm, null, options);
options.inJustDecodeBounds = false;
Matrix matrix = new Matrix();
matrix.setScale(0.8f, 0.8f);
tmp = Bitmap.createBitmap(tmp, 0, 0, options.outWidth, options.outHeight, matrix, true);
baos.reset();
tmp.compress(Bitmap.CompressFormat.JPEG, 100, baos);
while (baos.toByteArray().length > 192 * 1024) {
matrix.setScale(0.9f, 0.9f);
tmp = Bitmap.createBitmap(tmp, 0, 0, options.outWidth, options.outHeight, matrix, true);
baos.reset();
tmp.compress(Bitmap.CompressFormat.JPEG, 100, baos);
}
isBm = new ByteArrayInputStream(baos.toByteArray());
return BitmapFactory.decodeStream(isBm, null, options);
}
这种方式可以慢慢的根据你设置的条件一点点的对图片的大小进行缩减,关于martix更多信息,自行谷歌。
- 混合压缩
所谓的混合压缩,其实就是把上面的几种方式按照不一样的顺序进行重新整理。以下是我所做项目的压缩方法
public static Bitmap compressBitmap(Bitmap tmp) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
tmp.compress(Bitmap.CompressFormat.JPEG, 100, baos);
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
decodeStream(isBm, null, options);
options.inJustDecodeBounds = false;
Matrix matrix = new Matrix();
matrix.setScale(0.8f, 0.8f);
tmp = Bitmap.createBitmap(tmp, 0, 0, options.outWidth, options.outHeight, matrix, true);
baos.reset();
tmp.compress(Bitmap.CompressFormat.JPEG, 50, baos);
while (baos.toByteArray().length > 192 * 1024) {
isBm = new ByteArrayInputStream(baos.toByteArray());
tmp = decodeStream(isBm, null, options);
matrix.setScale(0.95f, 0.95f);
tmp = Bitmap.createBitmap(tmp, 0, 0, tmp.getWidth(), tmp.getHeight(), matrix, true);
baos.reset();
tmp.compress(Bitmap.CompressFormat.JPEG, 70, baos);
}
isBm = new ByteArrayInputStream(baos.toByteArray());
return decodeStream(isBm, null, options);
}
这种对质量会比较好
public static Bitmap depthCompressBitmap(Bitmap tmp) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
tmp.compress(Bitmap.CompressFormat.JPEG, 100, baos);
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
decodeStream(isBm, null, options);
options.inJustDecodeBounds = false;
float be = options.outWidth / 480;
float scale = 0.55f;
if (be >= 2) {
scale = 0.35f;
}
Matrix matrix = new Matrix();
matrix.setScale(scale, scale);
tmp = Bitmap.createBitmap(tmp, 0, 0, options.outWidth, options.outHeight, matrix, true);
baos.reset();
tmp.compress(Bitmap.CompressFormat.JPEG, 50, baos);
int op = 40;
while (baos.toByteArray().length > 192 * 1024) {
baos.reset();
tmp.compress(Bitmap.CompressFormat.JPEG, op, baos);
op -= 10;
if (op <= 0) {
break;
}
}
if (baos.toByteArray().length > 192 * 1024) {
isBm = new ByteArrayInputStream(baos.toByteArray());
tmp = BitmapFactory.decodeStream(isBm, null, options);
matrix.setScale(0.8f, 0.8f);
tmp = Bitmap.createBitmap(tmp, 0, 0, tmp.getWidth(), tmp.getHeight(), matrix, true);
baos.reset();
tmp.compress(Bitmap.CompressFormat.JPEG, 70, baos);
}
isBm = new ByteArrayInputStream(baos.toByteArray());
return decodeStream(isBm, null, options);
}
这种是直接减半压缩,和上面对比,在不同的图片中所得到的效果不一样,自行试验,还有其他的自己组合,这里只提供思路。
经过这种处理之后的图片,再点击分享,完美的调起微信分享,辣鸡人生。
参考文章:
bitmap的六种压缩方式,Android图片压缩