记Android 本地图片压缩上传到服务器走过的弯路

在android应用开发中,涉及到本地图片上传的一般都会先对图片进行压缩再上传。
常见的压缩方式有两种:一种是利用BitmapFactory.Options对图片进行尺寸上的压缩,具体方法如下:
/**
     * 把原图按比例压缩
     *
     * @param srcPath 原图的路径
     * @param maxSize 指定的图片最大尺寸
     * @return 压缩后的图片
     */
    public Bitmap getCompressPhoto(String srcPath, int maxSize) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        //开始读入图片,此时把options.inJustDecodeBounds 设回true了
        options.inJustDecodeBounds = true;
        Bitmap bitmap = BitmapFactory.decodeFile(srcPath, options);//此时返回bm为空
        options.inJustDecodeBounds = false;
        int sampleSize = 1;//1代表不压缩
        if (options.outHeight > 0 && options.outWidth > 0) {
            while (options.outHeight / sampleSize > maxSize || options.outWidth / sampleSize > maxSize) {
                sampleSize = sampleSize + 1;
            }
        } else {
            sampleSize = sampleSize << 1;
        }
        options.inSampleSize = sampleSize;//设置缩放比例
        try {
            //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
            bitmap = BitmapFactory.decodeFile(srcPath, options);
        } catch (OutOfMemoryError e) {
            options.inSampleSize *= 2;
            bitmap = BitmapFactory.decodeFile(srcPath, options);
        }
        return bitmap;
    }

另外一种是按指定内存大小压缩,具体方法如下:

/**
     * 质量压缩方法
     *
     * @param srcPath 原图的路径
     * @param maxByte 需要压缩到多大内存大小(单位:kb)
     * @return
     */
    public static Bitmap compressImage(String srcPath, int maxByte) {
        Bitmap image = BitmapFactory.decodeFile(srcPath);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
        int options = 90;
        while (baos.toByteArray().length / 1024 > maxByte) { // 循环判断如果压缩后图片是否大于maxByte,大于继续压缩
            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;
    }

注意,上面两种方法得到的都是Bitmap 对象,而上传到服务器的图片一般都是传一个File类型,所以还要把压缩后的Bitmap 存储到本地,然后根据存储路径得到File来上传。那么问题就来了,第一种方法确实可以得到预期的尺寸压缩效果。但是第二种质量压缩之后,传到服务器,在服务端查看会大于想要压缩的内存大小。
原因就是下面这段代码:

ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());// 把压缩后的数据baos存放到ByteArrayInputStream中

        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);// 把ByteArrayInputStream数据生成图片

这里后的ByteArrayOutputStream 确实达到了指定大小以内,但是又把它转为了Bitmap对象,转换之后的Bitmap对象就变大了,因为bitmap所占内存大小是由图片的宽高和色彩模式Bitmap.Config(代表一个像素占多少个字节)来决定的,Bitmap.Config有下面几种值,Bitmap.Config.ARGB_8888占4个Byte,Bitmap.Config.RGB_565占2个Byte,Bitmap.Config ARGB_4444占2个Byte,Bitmap.Config ALPHA_8占1个Byte,具体计算是:
宽 * 高 * Bitmap.Config所占内存。
找到原因之后,就有解决办法了,我们在对图片进行质量压缩之后,不再转为Bitmap存储,而直接把压缩后的ByteArrayOutputStream存成File来上传。所以对上面的质量压缩方法修改如下:

/**
     * 质量压缩
     * 
      * @param srcPath 原图路径
     * @param context 
     * @param max 要压缩到多大以内(单位:kb)
     * @return
     */ 
    public String compressReSave(String srcPath, Context context, int max) {
        String filePath = "";
        Bitmap image = BitmapFactory.decodeFile(srcPath);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
        int options = 90;
        while (baos.toByteArray().length / 1024 > max) { // 循环判断如果压缩后图片是否大于maxkb,大于继续压缩
            baos.reset(); // 重置baos即清空baos
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);// 这里压缩options%,把压缩后的数据存放到baos中
            if (options > 10){
                options -= 10;// 每次都减少10
            } else {
                options -= 5;
            }

            if (options == 5){//这里最多压缩到5,options不能小于0
                break;
            }
        }
        FileOutputStream outStream = null;
        filePath = createFile(context, "myImg");
        try {
            outStream = new FileOutputStream(filePath);
            // 把数据写入文件
            outStream.write(baos.toByteArray());
            // 记得要关闭流!
            outStream.close();
            return filePath;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                if (outStream != null) {
                    // 记得要关闭流!
                    outStream.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
public static String createFile(Context context, String pathName) {
        String path = "";
        File file = null;
        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
            file = new File(Environment.getExternalStorageDirectory().getPath() + File.separator + pathName);
        } else {
            file = new File(context.getFilesDir().getPath() + File.separator + pathName);
        }
        if (file != null) {
            if (!file.exists()) {
                file.mkdir();
            }
            File output = new File(file, System.currentTimeMillis() + ".png");
            try {
                if (output.exists()) {
                    output.delete();
                } else {
                    output.createNewFile();
                }
                path = output.getAbsolutePath();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return path;
    }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值