Android---性能优化之图片压缩

质量压缩

质量压缩会用到 Bitmap.compress()。

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

这个方法有三个参数:

\bullet Bitmap.CompressFormat format:图像的压缩格式(jpeg ,png, webp); 

\bullet int quality:图像压缩率,0--100。0 压缩率为 100%,100 意味着不压缩;

\bullet OutputStream stream:写入压缩数据的数据流。

返回值:

\bullet 如果成功把压缩数据写入写入输出流,则返回 true;

代码:

    /**
     * TODO 图片质量压缩
     * @param image 要压缩的图片
     * @param maxImageSize 最大质量(单位:KB)
     * @return
     */
    private Bitmap compressImageQuality(Bitmap image, int maxImageSize) {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // TODO 将 Bitmap 写入到 baos 这个输出流中(ByteArrayOutputStream)
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);

        int options = 100;
        do {

            options -= 10;
            baos.reset();
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);

        }while (baos.toByteArray().length / 1024 > maxImageSize && options > 0);

        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        Bitmap compressedImage = BitmapFactory.decodeStream(bais, null, null);
        // 把压缩后的图片保存到相册
        saveImageToGallery(this, compressedImage, "compress_image.png");
        //
        return compressedImage;
    }

尺寸压缩

Options

\bullet 属性 inJustDecodeBounds,如果该值为 true,那么将不返回实际的 bitmap,也不给其分配内存空间这样就避免内存溢出了。但允许我们查询图片的信息,这其中就包括图片大小信息,options.outHeight(图片原始高度)和 option.outWidth(图片原始宽度)

\bullet 属性 inSampleSize,我们可以使用它实现缩放,如果被设置为一个值,在图片解码时,将图片按照指定的比例进行缩小,从而降低图片的尺寸。例如,inSampleSize=2,则取出的缩略图的宽和高都是原始图片的 1/2,图片大小就为原始大小的 1/4。

两次 decode,传入不同的 options 配置:

 第一次 inJustDecodeBounds = false,获取 outHeight/outWidth 原始宽高,不加载图片到内存里。再获取合适的 inSampleSize 后,然后再设置  inJustDecodeBounds = true,把合适的图像正真加载到内存里面来。

代码:

/**
     * 对图片进行尺寸压缩
     */
    private Bitmap compressImageSize(String imagePath, int reqWidth, int reqHeight){
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        // 参数1:要解码的文件的完整文件路径
        BitmapFactory.decodeFile(imagePath, options);
        
        // 图片的原始宽高
        int height = options.outHeight;
        int width = options.outWidth;
        int inSampleSize = 1; // 刚开始的缩放比例为1

        // 计算图片缩放比例
        if (height > reqHeight || width > reqWidth) {
            int halfHeight = height / 2;
            int halfWidth = width / 2;
            while ((halfHeight / inSampleSize) >= reqHeight
                    && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2; // 扩大缩放比例,为 2^n
            }

        }

        // 使用计算出的缩放比例解码图片
        options.inSampleSize = inSampleSize;
        options.inJustDecodeBounds = false;
        Bitmap compressImageSize = BitmapFactory.decodeFile(imagePath, options);
        // 保存图片到相册
        saveImageToGallery(this, compressImageSize, "compress_size.png");
        return compressImageSize;
    }

 这个方法接收三个参数:图片路径、期望的宽度和期望的高度。

图片的路径:iamgePath 该怎么传。我这里是以打开相册选取一张图片,然后在 onActivityResult 回调中,回去到一个 Uri。

//TODO 获取选择的图片
Uri uri = data.getData();
// TODO 获取图片路径
mImagePath = getRealPathFromURI(uri);

然后再调用 getRealPathFromURI() 函数来获取到选择图片的真实路径。

 /**
     * 根据 Uri 获取图片的真实路径
     * TODO 在 onActivityResult() 回调中获取到图片的 Uri, 然后通过‘ContentResolver' 获取到图片的时间路径
     */
    private String getRealPathFromURI(Uri contentUri){
        String[] projection = {MediaStore.Images.Media.DATA};
        Cursor cursor = getContentResolver().query(contentUri, projection, null, null, null);
        if (cursor == null) {
            return contentUri.getPath();
        }else {
            cursor.moveToFirst();
            int index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            String path = cursor.getString(index);
            cursor.close();
            return path;
        }
    }

 首先,我们使用 BitmapFactory.Options 的 inJustDecodeBounds 属性解码图片,这个属性设置为 true 表示只读取图片的原始宽度和高度不会真正加载图片到内存中。接着,我们根据图片的原始宽度和高度,计算出一个合适的 inSampleSize, 最后使用这个 inSampleSize 解码图片,得到一个缩小了尺寸的 Bitmap 对象。

值得注意的是,使用 inSampleSize 进行图片压缩时,可能会导致图片的质量变差。这是因为 inSampleSize 实际上是将图片缩小了,相当于降低了图片的分辨率。因此,使用这种方式进行图片压缩时,需要根据实际情况选择合适的 inSampleSize 值,以平衡图片的尺寸和质量。

Native 压缩

libjpeg 是一个完全用 C 语言编写的库,包含了被广泛使用的 JPEG 解码、JPEG 编码和其他的 JPEG 功能的实现。

libjpeg-turbo 图像编解码器,使用了 SIMD 指令来加速 x86、x86-64、ARM 和 Power PC 系统上的 JPEG 压缩和解压缩,libjpeg-turbo 的速度通常是 libjepg 的 2-6 倍

使用 libjpeg 对图像数据压缩的流程:

完整 Demo

提供上面质量/尺寸压缩的完整代码:包括打开相册的操作、把压缩的图片保存到相册(查看压缩前后图片质量/尺寸的变化)和 xml 等。

链接:https://pan.baidu.com/s/18wzW1l2mZA8XTVmwO3wKJg 
提取码:7j4r

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/13022.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PS封装格式:GB28181协议RTP传输

在安防行业,有个协议是无论如何都要适配的,因为公安监控网络用的就是它,它就是:GB28181。而这份协议主要由海康制定,所以除了海康其他厂商想要适配都会少许有点儿麻烦。 1. GB28181要求的RTP流格式     首先&…

C++ 类之间的纵向关系-继承

目录 继承的基本概念 定义 使用方法 内存空间 继承下构造析构执行的顺序 构造函数 析构函数 继承的优点 继承方式 public protected private 隐藏 回顾函数重载 隐藏 父类指针指向子类对象 优点 出现的问题 类成员函数指针 普通的函数指针 类成员函数指针 类…

RK3568平台开发系列讲解(调试篇)debugfs 分析手段

🚀返回专栏总目录 文章目录 一、enable debugfs二、debugfs API三、使用示例沉淀、分享、成长,让自己和他人都能有所收获!😄 📢Linux 上有一些典型的问题分析手段,从这些基本的分析方法入手,你可以一步步判断出问题根因。这些分析手段,可以简单地归纳为下图: 从这…

6、索引的数据结构

3.3 常见的索引概念 索引按照物理实现方式,索引可以分为 2 种:聚簇和非聚簇索引 1、聚簇索引 5、索引的代价 空间上的代价 每建立一个索引都要为它建立一棵B树,每一棵B树的每一个节点都是一个数据页,一个页默认会占用 16KB 的存…

(排序11)排序的时间复杂度,空间复杂度,稳定性总结

图片总结 内排序时间复杂度总结 内部排序:数据元素全部放在内存中的排序。. 在内排序当中比较快的有希尔排序,堆排序,快速排序,归并排序,这四个排序的时间复杂度都是O(n*logn)。其中希尔排序的时间复杂度更加准确的来…

62. 不同路径

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。 问总共有多少条不同的路径? 示例 1…

微电网两阶段鲁棒优化经济调度方法(Python代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

【网络编程】TCP

✨个人主页:bit me👇 ✨当前专栏:Java EE初阶👇 目 录 🔮一. TCP流套接字编程💿二. TCP中的长短连接📀三. 写一个 TCP 版本的 回显服务器-客户端 🔮一. TCP流套接字编程 ServerSock…

网络视频监控如何入门?如何安装和配置、设备选择和实时监控?

网络视频监控是一种先进的安全技术,它可以通过互联网连接到远程视频服务器,使用户可以随时随地监控所关注的地点。本文将介绍网络视频监控的基础入门知识,包括安装和配置、设备选择和实时监控等方面。 一、安装和配置 在进行网络视频监控前&…

Opencv+Python笔记(四)图像的形态学处理

1.腐蚀与膨胀 膨胀用来处理缺陷问题,把缺陷填补掉,提高亮区面积; 腐蚀用来处理毛刺问题,把毛刺腐蚀掉,降低亮区面积。 腐蚀操作可以消除噪点,同时消除部分边界值,导致目标图像整体缩小。 膨胀…

C#+asp.net基于web的大学社团管理信息系统

本系统的模块是分为用户模块和管理员模块,管理员负责学生管理模块、社团管理模块、公告管理模块、留言管理模块、加入社团管理模块、活动管理模块、管理员管理模块。社团管理员则负责预约管理模块、活动报名的审核等。。 系统具有三类系统用户分别是:系统…

用于测试FDIA在现实约束下可行性的FDIA建模框架(Matlab代码实现)

目录 💥1 概述 📚2 运行结果 🎉3 参考文献 👨‍💻4 Matlab代码 💥1 概述 信息通信技术的发展和智能设备的引入使电力系统逐渐演变为电力信息物理系统,而信息层与物理层之间的深度耦合也加剧…

【测试面试】吐血整理,大厂测试开发岗面试题(1~4面),拿下年40w...

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 自动化测试面试题&…

【文件系统和系统日志分析】

目录 一、inode和block概述block(块)inode(索引节点) 二、inode内容三、inode的号码3.1、查看inode号码的方法 四、inode的大小磁盘分区后的结构访问文件的简单流程 五、删除乱码文件六、inode节点耗尽故障处理6.1、模拟inode节点…

SSM整合的基本思路梳理

SSM整合的简单思路流程 基本思路 我在整合的时候一般习惯从MyBatis开始向上构建,也就是在开始一个项目的时候先将DAO层搭建起来,再向上整合Spring以及SpringMVC。按照这个流程,可以做出一个比较简单的大致流程作为参考,帮助我们…

[MySQL]基本数据类型及表的基本操作

一、常用的数据类型 1.1 数据库表的列类型 数值 1 2 3.14 tinyint 十分小的数据 1个字节smallint 较小的数据 2个字节mediumint 中等大小的数据 3个字节int 标准的整数 4个字节big 较大的数据 8个字节float 浮点数 4个字节double 浮点数 小数 8个字节(精度问题&am…

JSON的用法和说明

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。 JSON建构于两种结构: "名称/值"对的集合。理解为对象 值的有序列表。理解为数组 JSON具有以下这些形式: 对象是一个无序的“ ’名称/值‘ 对”集合。一个…

【排序】快速排序(递归和非递归)

快速排序 前言图解大致思路对于hoare版本对于挖坑法对于前后指针法 实现方法递归非递归 快排的优化(基于递归的优化)三数取中法小区间优化 时间复杂度和空间复杂度 前言 快速排序,听名字就比较霸道,效率根名字一样,非…

永久免费内网穿透不限制速度

市面上的免费内网穿透大都有格式各样的限制,什么限制流量啊,每个月要签到打卡啊,还有更改域名地址等,只有神卓互联内网穿透是永久免费没有限制的,白嫖也可以。 这篇文章分享了3个方案,按照性能和综合指标排…

项目驱动的编写

驱动代码直接使用nfs传输,设备树直接在开发板中修改设备树文件 1、修改好设备树,在内核顶层make dtbs ,然后替代tftp目录中的设备树文件 2、使用内核源码编译生成驱动程序,然后传送到开发板中,使用insmod动态加载 LCD驱动 1、初始…