图片压缩

项目中用到了图片上传,拍照和直接上传本地图片,但现在的手机普遍拍出来的照片都很大,基本都是3M左右,上传这么大的图片费流量不说,上传时间也很久,肯定是必须要压缩的。

1.质量压缩Bitmap

Bitmap类有个compress()方法,可以将bitmap图片压缩到指定质量。

public boolean compress (Bitmap.CompressFormat format, int quality, OutputStream stream)

quality——是压缩质量,值越大,压缩后图片的大小越大。

CompressFormat——有三个值可选,JPEG,PNG和WEBP需要注意的是,如果选用PNG格式的话,quality是无效的

quality的解释:

Hint to the compressor, 0-100. 0 meaning compress for small size, 100 meaning compress for max quality. Some formats, like PNG which is lossless, will ignore the quality setting

代码:

假设sd卡上MyPic目录下都是图片,取第一张来压缩

注意:bitmap在内存中大小和在sd卡中大小是不同的。

//质量压缩(宽,高不变,即像素不变,压缩的是透明度和位深)
File folder = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
        + "/MyPic/");
File[] files = folder.listFiles();
File file = files[0];//获取第一张图片
double sdSize = file.length() / 1024;//sd卡中的大小,直接文件的大小
Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
int cacheSize = bitmap.getByteCount() / 1024;//内存中大小
Log.i("test", "压缩前图片内存中大小是: " + cacheSize + "K, SD卡中大小是: " + sdSize 
+ "K 宽度是: " + bitmap.getWidth() + " 高度是: " + bitmap.getHeight());

结果:

压缩前图片内存中大小是: 2840K, SD卡中大小是: 57.0K 宽度是: 640 高度是: 1136

压缩图片并保存

String newPath = Environment.getExternalStorageDirectory().getAbsolutePath() +
        "/MyPic/test_compressed.jpg";
try {
    //文件输出流,直接压缩后保存到指定路径
    FileOutputStream fos = new FileOutputStream(newPath);
    //quality越大,压缩后的大小越大,取值0-100
    bitmap.compress(Bitmap.CompressFormat.JPEG, 50, fos);
    fos.flush();
    fos.close();
    bitmap.recycle();

    sdSize = new File(newPath).length() / 1024;
    bitmap = BitmapFactory.decodeFile(newPath);
    cacheSize = bitmap.getByteCount() / 1024;
    Log.i("test", "压缩前图片内存中大小是: " + cacheSize + "K, SD卡中大小是: " + sdSize
            + "K 宽度是: " + bitmap.getWidth() + " 高度是: " + bitmap.getHeight());
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

还可以用二进制输出流,如果上传图片分享图片是二进制流的情况。

ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, baos);
byte[] bytes = baos.toByteArray();
bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);

结果:

压缩前图片内存中大小是: 2840K, SD卡中大小是: 57.0K 宽度是: 640 高度是: 1136
压缩后图片内存中大小是: 2840K, SD卡中大小是: 24.0K 宽度是: 640 高度是: 1136

别忘了添加读写sd卡的权限:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

可以看到结果,大小被压缩了,但图片宽高即像素并没有改变,图片占的内存与像素有关,所以也并没有改变。

2.宽高压缩BitmapFactory.Options

options.inSampleSize表示的是压缩比率。值大于1的时候才有效,表示宽高的缩短比例,小于1的时候默认按照1来。最终的取值都是按照2的倍数来,最好设置成2的倍数。

代码:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;//宽高压缩比例
bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), options);
try {
    FileOutputStream fos = new FileOutputStream(newPath);
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);//同比例保存到文件
    File myPic = new File(newPath);
    sdSize = myPic.length() / 1024;
    cacheSize = bitmap.getByteCount() / 2014;
    Log.i("test", "压缩后图片内存中大小是: " + cacheSize + "K, SD卡中大小是: " + sdSize
            + "K 宽度是: " + bitmap.getWidth() + " 高度是: " + bitmap.getHeight());
} catch (FileNotFoundException e) {
    e.printStackTrace();
}

结果:

压缩前图片内存中大小是: 2840K, SD卡中大小是: 57.0K 宽度是: 640 高度是: 1136
压缩后图片内存中大小是: 360K, SD卡中大小是: 41.0K 宽度是: 320 高度是: 568

可以看到宽高,都缩短到了原来1/2,大小和内存中大小都改变了。

options.inSampleSize这个值一般需要动态获取,此时还需要inJustDecodeBounds这个属性。

这里写图片描述

true的时候并不返回bitmap本身,但可以获取宽高,可以用来计算inSampleSize,以免oom,之后再设置为false,即可再压缩图片。

代码:

Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
Log.i("test", "压缩前图片内存中大小是: " + bitmap.getByteCount() 
        + "K 宽度是: " + bitmap.getWidth() + " 高度是: " + bitmap.getHeight());

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;//设置为true时,并不返回bitmap,不用担心oom

BitmapFactory.decodeFile(file.getAbsolutePath(), options);//执行完后已经获得原图的宽和高
//计算出需要缩放的比例,按照传入的宽高
options.inSampleSize = getSampliSize(options, 400, 800);

options.inJustDecodeBounds = false;//设置为false,返回bitmap,要开始压缩了
bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), options);
Log.i("test", "压缩后图片内存中大小是: " + bitmap.getByteCount() 
        + "K 宽度是: " + bitmap.getWidth() + " 高度是: " + bitmap.getHeight());

getSampliSize()方法代码:

private int getSampliSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {

    //获取真实宽和高来计算需要的inSampleSize值
    int width = options.outWidth;
    int height = options.outHeight;

    //调整到高比宽大的模式,调整都相同的模式比较
    if (height < width) {
        int temp = height;
        height = width;
        width = temp;
    }
    if (reqHeight < reqWidth) {
        int temp = reqHeight;
        reqHeight = reqWidth;
        reqWidth = temp;
    }

    int inSampleSize = 1;
    // 只要有一个缩放到给定的值后就停止,即此时缩放的比例是最接近给定的大小的
    while (width / inSampleSize / 2 >= reqWidth
            && height / inSampleSize / 2 >= reqHeight) {
        inSampleSize *= 2;
    }
    Log.i("test", "isSampleSize " + inSampleSize);
    return inSampleSize;

结果:

压缩前图片内存中大小是: 63700992K 宽度是: 3456 高度是: 4608
isSampleSize 4
压缩后图片内存中大小是: 3981312K 宽度是: 864 高度是: 1152

最后封装一个图片压缩的工具类:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值