最近在项目中碰到图片的问题,相册的照片大概普遍在4M往上,项目中需要用低功耗蓝牙(BLE)传输,要求把图片压缩到10K左右,但是我尝试了很多方法,压缩100倍之后(40kb)左右就不能压缩了,再低的话,基本就看不清图片了(很模糊,跟马赛克一样),尺寸也压缩到了要求的最小值,我现在尺寸压缩,质量压缩,jni底层压缩全部用上了,最多压到40K左右就不能再往下了,不然完全看不清,但是BLE的传输带宽实在有限,40K的图片估计得十分钟往上了,有没有对图片的压缩比较精通的老哥给帮忙指教一下还有什么办法?不胜感激

解决方案 »

  1.   

    分享一下我用过的这些方法,我觉得很不错,压缩后图片很清晰~你可以根据需要选择~  /**
         * 根据路径获得图片信息并按比例压缩,返回bitmap
         */
        public static Bitmap getSmallbitmap(String filePath) {
            final BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true; // 只解析图片边缘,获取宽高
            BitmapFactory.decodeFile(filePath, options);
            // 计算缩放比
            options.inSampleSize = calculateInSampleSize(options, 480, 800);
            // 完整解析图片返回bitmap
            options.inJustDecodeBounds = false;
            return BitmapFactory.decodeFile(filePath, options);
        }
        /**
         * 质量压缩方法
         *
         * @param image
         * @return
         */
        public static Bitmap compressImage(Bitmap image) {        ByteArrayOutputStream baos = new ByteArrayOutputStream();
            image.compress(Bitmap.CompressFormat.JPEG, 100, baos);// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
            int options = 90;        while (baos.toByteArray().length / 1024 > 100) { // 循环判断如果压缩后图片是否大于100kb,大于继续压缩
                baos.reset(); // 重置baos即清空baos
                image.compress(Bitmap.CompressFormat.JPEG, options, baos);// 这里压缩options%,把压缩后的数据存放到baos中
                options -= 10;// 每次都减少10
            }
            ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());// 把压缩后的数据baos存放到ByteArrayInputStream中
            Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);// 把ByteArrayInputStream数据生成图片
            return bitmap;
        }
        /**
         * 图片按比例大小压缩方法
         *
         * @param image (根据Bitmap图片压缩)
         * @return
         */
        public static Bitmap compressScale(Bitmap image) {        ByteArrayOutputStream baos = new ByteArrayOutputStream();
            image.compress(Bitmap.CompressFormat.JPEG, 100, baos);        // 判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出
            if (baos.toByteArray().length / 1024 > 1024) {
                baos.reset();// 重置baos即清空baos
                image.compress(Bitmap.CompressFormat.JPEG, 80, baos);// 这里压缩50%,把压缩后的数据存放到baos中
            }
            ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
            BitmapFactory.Options newOpts = new BitmapFactory.Options();
            // 开始读入图片,此时把options.inJustDecodeBounds 设回true了
            newOpts.inJustDecodeBounds = true;
            Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
            newOpts.inJustDecodeBounds = false;
            int w = newOpts.outWidth;
            int h = newOpts.outHeight;
            // 现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
            // float hh = 800f;// 这里设置高度为800f
            // float ww = 480f;// 这里设置宽度为480f
            float hh = 512f;
            float ww = 512f;
            // 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
            int be = 1;// be=1表示不缩放
            if (w > h && w > ww) {// 如果宽度大的话根据宽度固定大小缩放
                be = (int) (newOpts.outWidth / ww);
            } else if (w < h && h > hh) { // 如果高度高的话根据高度固定大小缩放
                be = (int) (newOpts.outHeight / hh);
            }
            if (be <= 0)
                be = 1;
            newOpts.inSampleSize = be; // 设置缩放比例
            // newOpts.inPreferredConfig = Config.RGB_565;//降低图片从ARGB888到RGB565        // 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
            isBm = new ByteArrayInputStream(baos.toByteArray());
            bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);        return compressImage(bitmap);// 压缩好比例大小后再进行质量压缩        //return bitmap;
        }
        /**
         * 计算压缩比
         * @param options
         * @param reqWidth
         * @param reqHeight
         * @return
         */
        public static int calculateInSampleSize(BitmapFactory.Options options,
                                                int reqWidth, int reqHeight) {
            final int height = options.outHeight;
            final int width = options.outWidth;
            int inSampleSize = 1;
            if (height > reqHeight || width > reqWidth) {
                final int heightRatio = Math.round((float) height / (float) reqHeight);
                final int widthRatio = Math.round((float) width / (float) reqWidth);
                inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
            }
            return inSampleSize;
        }