Android性能优化--图片压缩

Android图片压缩有多种压缩方式,常用的有质量压缩、尺寸压缩、采样率压缩以及通过JNI调用libjpeg库来进行压缩。(尺寸压缩,质量压缩底层也是通过调用native的方法进行压缩的,而native中的则是通过Skia这个库实现的,但是,最终还是调用了libjpeg库进行压缩的。)

1.质量压缩

保持像素的前提下改变图片的位深及透明度(即:通过算法抹掉(同化)图片中的一些某点附近 相近的像素)达到降低质量压缩文件的目的。
使用场景:将图片压缩后将图片上传到服务器,或者保存到本地,根据实际需求

    /**
     * 质量压缩
     * 设置bitmap options属性,降低图片的质量,像素不会减少
     * 第一个参数为需要压缩的bitmap图片对象,第二个参数为压缩后图片保存的位置
     * 设置options 属性0-100,来实现压缩(因为png是无损压缩,所以该属性对png是无效的)
     *
     * @param bmp
     * @param file
     */
    public static void qualityCompress(Bitmap bmp, File file) {
        // 0-100 100为不压缩
        int quality = 20;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // 把压缩后的数据存放到baos中
        bmp.compress(Bitmap.CompressFormat.JPEG, quality, baos);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(baos.toByteArray());
            fos.flush();
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

2.尺寸压缩

通过减少单位尺寸的像素值,真正意义上的降低像素(通过缩放图片像素来减少图片占用内存大小)
使用场景:缓存缩略图的时候(头像处理)

    /**
     * 尺寸压缩(通过缩放图片像素来减少图片占用内存大小)
     *
     * @param bmp
     * @param file
     */

    public static void sizeCompress(Bitmap bmp, File file) {
        // 尺寸压缩倍数,值越大,图片尺寸越小
        int ratio = 8;
        // 压缩Bitmap到对应尺寸
        Bitmap result = Bitmap.createBitmap(bmp.getWidth() / ratio, bmp.getHeight() / ratio, Config.ARGB_8888);
        Canvas canvas = new Canvas(result);
        Rect rect = new Rect(0, 0, bmp.getWidth() / ratio, bmp.getHeight() / ratio);
        canvas.drawBitmap(bmp, null, rect, null);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // 把压缩后的数据存放到baos中
        result.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(baos.toByteArray());
            fos.flush();
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

3.采样率压缩

设置图片的采样率,降低图片像素
好处:是不会先将大图片读入内存,大大减少了内存的使用,也不必考虑将大图片读入内存后的释放事宜。
问题:因为采样率是整数,所以不能很好的保证图片的质量。如我们需要的是在2和3采样率之间,用2的话图片就大了一点,但是用3的话图片质量就会有很明显的下降,这样也无法完全满足我的需要。

    /**
     * 5.采样率压缩(设置图片的采样率,降低图片像素)
     *
     * @param filePath
     * @param file
     */
    public static void samplingRateCompress(String filePath, File file) {
        // 数值越高,图片像素越低
        int inSampleSize = 8;
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = false;
//          options.inJustDecodeBounds = true;//为true的时候不会真正加载图片,而是得到图片的宽高信息。
        //采样率
        options.inSampleSize = inSampleSize;
        Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // 把压缩后的数据存放到baos中
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        try {
            if (file.exists()) {
                file.delete();
            } else {
                file.createNewFile();
            }
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(baos.toByteArray());
            fos.flush();
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    } 

4.通过JIN调用libjpeg库压缩

Android图像处理引擎的漏洞
通常IOS拍的照片1M左右还比Android拍出来的照片5M的还要清晰,都是在同一个环境下,保存的都是JPEG
(1)历程
1995年 JPEG处理引擎,用于最初的在PC上面处理图片的引擎。
2005年 skia开源的引擎, 开发了一套基于JPEG处理引擎的第二次开发。便于浏览器的使用。
2007年安卓用的skia引擎(阉割版),谷歌拿了skia,去掉一个编码算法—哈夫曼算法。采用定长编码算法。但是解码还是保留了哈夫曼算法,导致了图片处理后文件变大了。
(2)原因
当时由于CPU和内存在手机上都非常吃紧 性能差,由于哈夫曼算法非常吃CPU,被迫用了其他的算法。
(3)优化方案
绕过安卓Bitmap API层,来自己编码实现—-修复使用哈夫曼算法。

JIN开发步骤
(1)准备工作

(1)http://www.ijg.org/下载JPEG引擎使用的库---libjpeg库,
基于该引擎来做一定的开发----自己实现编码,JNI开发。
(2)导入库文件libjpegbither.so
(3)导入头文件
(4)写mk文件——Android.mk、Applicatoin.mk
(5)写代码——C++:XX.cpp、C:XX.c

(2)开发过程

(1)将android的bitmap解码,并转换成RGB数据
   一个图片信息---像素点(argb),alpha去掉
(2)JPEG对象分配空间以及初始化
(3)指定压缩数据源
(4)获取文件信息
(5)为压缩设置参数,比如图像大小、类型、颜色空间
   boolean arith_code;       
  /* TRUE=arithmetic coding, FALSE=Huffman */
(6)开始压缩——jpeg_start_compress()
(7)压缩结束——jpeg_finish_compress()
(8)释放资源

代码:

    /**
     * 1.JNI终极压缩(通过JNI图片压缩把Bitmap保存到指定目录)
     *
     * @param image    bitmap对象
     * @param filePath 要保存的指定目录
     * @Description: 通过JNI图片压缩把Bitmap保存到指定目录
     */
    public static void jniUltimateCompress(Bitmap image, String filePath) {
        // 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
        int quality = 20;
        // JNI调用保存图片到SD卡 这个关键
        NativeUtil.saveBitmap(image, quality, filePath, true);
    }

    /**
     * 1.JNI基本压缩(不保存Bitmap)
     *
     * @param bit      bitmap对象
     * @param fileName 指定保存目录名
     * @param optimize 是否采用哈弗曼表数据计算 品质相差5-10倍
     * @Description: JNI基本压缩
     */
    public static void jniBasicCompress(Bitmap bit, String fileName, boolean optimize) {
        saveBitmap(bit, DEFAULT_QUALITY, fileName, optimize);
    }

/**
     * 调用native方法
     *
     * @param bit
     * @param quality
     * @param fileName
     * @param optimize
     * @Description:函数描述
     */
    private static void saveBitmap(Bitmap bit, int quality, String fileName, boolean optimize) {
        compressBitmap(bit, bit.getWidth(), bit.getHeight(), quality, fileName.getBytes(), optimize);
    }

    /**
     * 调用底层 bitherlibjni.c中的方法
     *
     * @param bit
     * @param w
     * @param h
     * @param quality
     * @param fileNameBytes
     * @param optimize
     * @return
     * @Description:函数描述
     */
    private static native String compressBitmap(Bitmap bit, int w, int h, int quality, byte[] fileNameBytes,
                                                boolean optimize);

    /**
     * 加载lib下两个so文件
     */
    static {
        System.loadLibrary("jpegbither");
        System.loadLibrary("bitherjni");
    }

转自:https://blog.csdn.net/chenliguan/article/details/54409442

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,923评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,154评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,775评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,960评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,976评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,972评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,893评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,709评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,159评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,400评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,552评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,265评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,876评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,528评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,701评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,552评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,451评论 2 352

推荐阅读更多精彩内容