博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
仿写一个android图片压缩工具
阅读量:6150 次
发布时间:2019-06-21

本文共 8622 字,大约阅读时间需要 28 分钟。

安卓开发图片压缩一直是一个头痛的问题,一不小心就会oom。 我对一个github上的库就行了简单的改写,把代码记录下来,自己也梳理了下图片压缩的过程。

尺寸压缩

尺寸压缩也就是按比例压缩尺寸,当我们需要显示图片时,控件加载的是bitmap,而bitmap的大小主要和尺寸和图片格式有关,这时候我们不需要进行质量压缩

  • 计算采样比(图片压缩比例)
    private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {    // 获得原始宽高    final int height = options.outHeight;    final int width = options.outWidth;    //默认为1(不压缩)    int inSampleSize = 1;    if (height > reqHeight || width > reqWidth) {        //压缩到宽高都小于我们要求的大小        while ((height / inSampleSize) >= reqHeight || (width / inSampleSize) >= reqWidth) {            //android内部只会取2的倍数,也就是一半一半的压缩            inSampleSize *= 2;        }    }    return inSampleSize;}复制代码
  • 压缩尺寸
    static Bitmap decodeSampledBitmapFromFile(File imageFile, int reqWidth, int reqHeight) throws IOException {    BitmapFactory.Options options = new BitmapFactory.Options();    //设置inJustDecodeBounds=true,时BitmapFactory加载图片不返回bitmap,只返回信息,减少内存开销    options.inJustDecodeBounds = true;    //相当于加载空图片获取尺寸信息    BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options);    //用我们上面的方法计算压缩比例    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);    //设置inJustDecodeBounds=false,返回bitmap    options.inJustDecodeBounds = false;    Bitmap scaledBitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options);    //把图片旋转成正确的方向    ExifInterface exif = new ExifInterface(imageFile.getAbsolutePath());    int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);    Matrix matrix = new Matrix();    if (orientation == 6) {        matrix.postRotate(90);    } else if (orientation == 3) {        matrix.postRotate(180);    } else if (orientation == 8) {        matrix.postRotate(270);    }    //复制一份旋转后的bitmap后返回    scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(),            scaledBitmap.getHeight(), matrix, true);    return scaledBitmap;}复制代码

质量压缩

质量压缩代码比较简单但要注意非常耗时

private static ByteArrayOutputStream compressBitmapSize(Bitmap bitmap, Bitmap.CompressFormat compressFormat,                                                            int defaultQuality, long maxSize) {        ByteArrayOutputStream baos = new ByteArrayOutputStream();        int quality = defaultQuality;        bitmap.compress(compressFormat, quality, baos);        //当大于我们指定的大小时,我就继续压缩        while (baos.toByteArray().length / 1024 > maxSize) {            if (quality <= 10) { //压缩比例要大于0                break;            } else {                baos.reset();                quality -= 10;                //quality 表示压缩多少 100 表示不压缩                bitmap.compress(compressFormat, quality, baos);            }        }        return baos;    }复制代码

完整的压缩工具类

public class ImageUtil {    //compress main way    static File compressImage(File imageFile, long size, int reqWith, int reqHeight, Bitmap.CompressFormat compressFormat,                              int quantity, String destinationPath) throws IOException {        FileOutputStream fileOutputStream = null;        File file = new File(destinationPath).getParentFile();        if (!file.exists()) {            file.mkdirs();        }        try {            fileOutputStream = new FileOutputStream(destinationPath);            //先压缩尺寸,防止内存溢出            Bitmap bitmap = decodeSampledBitmapFromFile(imageFile, reqWith, reqHeight);            //ByteArrayOutputStream 不需要关闭            //压缩尺寸            ByteArrayOutputStream baos = compressBitmapSize(bitmap, compressFormat, quantity, size);        fileOutputStream.write(baos.toByteArray());        } finally {            if (fileOutputStream != null) {                fileOutputStream.flush();                fileOutputStream.close();            }        }        return new File(destinationPath);    }    //按照比例压缩图片    static Bitmap decodeSampledBitmapFromFile(File imageFile, int reqWidth, int reqHeight) throws IOException {        BitmapFactory.Options options = new BitmapFactory.Options();        //just need size        options.inJustDecodeBounds = true;        BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options);        //calculate inSampleSize        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);        //real decode bitmap        options.inJustDecodeBounds = false;        Bitmap scaledBitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options);        //rotation of the image        ExifInterface exif = new ExifInterface(imageFile.getAbsolutePath());        int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);        Matrix matrix = new Matrix();        if (orientation == 6) {            matrix.postRotate(90);        } else if (orientation == 3) {            matrix.postRotate(180);        } else if (orientation == 8) {            matrix.postRotate(270);        }        scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(),                scaledBitmap.getHeight(), matrix, true);        return scaledBitmap;    }    //获取采样(压缩比)    private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {        // Raw height and width of image        final int height = options.outHeight;        final int width = options.outWidth;        int inSampleSize = 1;        if (height > reqHeight || width > reqWidth) {            while ((height / inSampleSize) >= reqHeight || (width / inSampleSize) >= reqWidth) {                inSampleSize *= 2;            }        }        return inSampleSize;    }    //压缩尺寸    private static ByteArrayOutputStream compressBitmapSize(Bitmap bitmap, Bitmap.CompressFormat compressFormat,                                                            int defaultQuality, long maxSize) {        ByteArrayOutputStream baos = new ByteArrayOutputStream();        int quality = defaultQuality;        bitmap.compress(compressFormat, quality, baos);        while (baos.toByteArray().length / 1024 > maxSize) {            if (quality <= 10) { // quality must >0                break;            } else {                baos.reset();                quality -= 10;                bitmap.compress(compressFormat, quality, baos);            }        }        return baos;    }}复制代码

封装成一个工厂模式工具类

public class Compressor {    private long maxSize = 1024; //1024kb    private int maxWidth = 800;    private int maxHeight = 800;    private Bitmap.CompressFormat compressFormat = Bitmap.CompressFormat.JPEG;    private int quality = 80;    private String destinationDirectoryPath;    public Compressor(Context context) {        destinationDirectoryPath = context.getCacheDir().getPath() + File.separator + "images";    }    public Compressor setMaxSize(long size) {        this.maxSize = size;        return this;    }    public Compressor setMaxWidth(int maxWidth) {        this.maxWidth = maxWidth;        return this;    }    public Compressor setMaxHeight(int maxHeight) {        this.maxHeight = maxHeight;        return this;    }    public Compressor setCompressFormat(Bitmap.CompressFormat compressFormat) {        this.compressFormat = compressFormat;        return this;    }    public Compressor setQuality(int quality) {        this.quality = quality;        return this;    }    public Compressor setDestinationDirectoryPath(String destinationDirectoryPath) {        this.destinationDirectoryPath = destinationDirectoryPath;        return this;    }        //压缩到文件    public File compressToFile(File imageFile, String compressedFileName) throws IOException {        return ImageUtil.compressImage(imageFile, maxSize, maxWidth, maxHeight, compressFormat, quality,                destinationDirectoryPath + File.separator + compressedFileName);    }    //只压缩尺寸    public Bitmap compressToBitmap(File imageFile) throws IOException {        return ImageUtil.decodeSampledBitmapFromFile(imageFile, maxWidth, maxHeight);    }}复制代码

使用

推荐大家使用WEBP格式的图片,内存更小(png无损格式很大)而且不会损失透明度(jpg没有透明)

  • 简单用法
File file = new Compressor(CompressorActivity.this)                        .compressToFile(getExternalCacheDir().getAbsoluteFile(),                                UUID.randomUUID().toString() + ".jpg");复制代码
  • 指定压缩的参数
File file = new Compressor(CompressorActivity.this)                        .setMaxWidth(1080)                        .setMaxHeight(1080)                        .setQuality(75)                        .setMaxSize(100)                        .setCompressFormat(Bitmap.CompressFormat.WEBP)                        .setDestinationDirectoryPath(getExternalCacheDir().getAbsolutePath())                        .compressToFile(new File(getPath(CompressorActivity.this, uri)), UUID.randomUUID().toString() + ".webp");复制代码

转载地址:http://tlzfa.baihongyu.com/

你可能感兴趣的文章
分布式事务最终一致性常用方案
查看>>
Exchange 2013 PowerShell配置文件
查看>>
JavaAPI详解系列(1):String类(1)
查看>>
HTML条件注释判断IE<!--[if IE]><!--[if lt IE 9]>
查看>>
发布和逸出-构造过程中使this引用逸出
查看>>
Oracle执行计划发生过变化的SQL语句脚本
查看>>
使用SanLock建立简单的HA服务
查看>>
发现一个叫阿尔法城的小站(以后此贴为我记录日常常用网址的帖子了)
查看>>
Subversion使用Redmine帐户验证简单应用、高级应用以及优化
查看>>
Javascript Ajax 异步请求
查看>>
DBCP连接池
查看>>
cannot run programing "db2"
查看>>
mysql做主从relay-log问题
查看>>
Docker镜像与容器命令
查看>>
批量删除oracle中以相同类型字母开头的表
查看>>
Java基础学习总结(4)——对象转型
查看>>
BZOJ3239Discrete Logging——BSGS
查看>>
SpringMVC权限管理
查看>>
spring 整合 redis 配置
查看>>
redhat6.1下chrome的安装
查看>>