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

news2024/9/26 3:29:55

质量压缩

质量压缩会用到 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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++STL大全----容器篇(上)

(一)概念 STL,英文全称 standard template library,中文可译为标准模板库或者泛型库,其包含有大量的模板类和模板函数,是 C 提供的一个基础模板的集合,用于完成诸如输入/输出、数学计算等功能。…

数据库第一个实验

啦啦啦啦啦,数据库终于要实验了,很担心做不好,要是挂了怎么办 只是自己的作业,可能会有问题,欢迎前来指正 一、题目(100分) 一、创建后面给出的这6个表(20分) 二、用不同…

Ubuntu20.04 个人配置和i3美化

Ubuntu20.04 个人配置和i3美化 本文是基于个人习惯和审美,快速配置一个新ubuntu的步骤。脚本在资源里给出,但仍有部分配置文件需在脚本执行后手动修改,文中已用红色字体标出 更新apt源 备份原来的源更换阿里源 # 备份 sudo mv /etc/apt/sources.list…

Camunda流程引擎查询接口API介绍

Camunda流程引擎底层采用了mybatis作为ORM框架,并封装了一套自己的数据查询接口,以下是几种可以Camunda流程引擎中查询数据的方式。 Java 查询API 。使用 Fluent Java API 来查询流程引擎实体,比如流程实例、任务等。REST 查询API 。通过 RE…

SpringMVC启动流程方式分析-三种方式

SpringMVC的启动方式 本文所叙述的是springmvc放入Tomcat servlet容器的启动方式 第一种Web.xml文件配置 使用传统的web.xml配置文件, 指定DispatchServlet ,当然如果想要父子容器的效果指定一个ContextLoaderListener 上下文加载监听器就行&#xff…

少儿编程 电子学会图形化编程等级考试Scratch三级真题解析(选择题)2022年12月

2022年12月Scratch等级考试一级真题解析 选择题(共25题,每题2分,共50分) 1、默认小猫角色和气球角色都是显示状态,小猫程序如下图所示,气球没有程序,点击绿旗,舞台上最终显示的效果是 A、可能出现6个不同位置的小猫和6个小球 B、可能出现6个不同位置的小猫和1个气球…

【嵌入式Linux】Jetson nano GPIO应用 | 驱动开发 | 官方gpiolib、设备树与chip_driver

GPIO子系统 0.暴露给应用层 应用 $ echo 79 > /sys/class/gpio/export //导出79号gpio 引脚,使得可在应用层访问 $ echo out > /sys/class/gpio/gpio79/direction //设置 为输出 $ echo 1 > /sys/class/gpio/gpio79/value //输出高电平 开灯 $ echo 0…

win10系统部署-zabbix客户端

一、下载win10系统 zabbix客户端 下载地址: 根据自己需求下载 https://www.zabbix.com/cn/download二、win系统安装客户端 1、解压安装包 c:\zabbix 2、编辑zabbix\conf\zabbix_agentd.conf文件 Server127.0.0.1,IP IP是你的zabbix服务器端地址 ServerActive127…

C++的GUI库

1. Qt Qt是一个跨平台的C应用程序开发框架。广泛用于开发GUI程序,这种情况下又被称为部件工具箱。也可用于开发非GUI程序,例如控制台工具和服务器。 2. MFC 微软基础类库(英语:Microsoft Foundation Classes,简称MFC&a…

罗丹明-聚乙二醇-生物素RB-PEG-Biotin;Biotin-PEG-Rhodamine,PEG2000

RB-PEG-Biotin 罗丹明-聚乙二醇-生物素 中文名称:罗丹明-聚乙二醇-生物素 英文名称:RB-PEG-Biotin 分子量(PEG ):2000、3400、5000,其他分子量可以定制。 用 途:仅供科研实验使用。 性状&…

TiDB 6.1/6.5 在 Rocky Linux 8 中的部署升级与 PITR 初体验

作者: 沈阳盛京征信有限公司 原文来源: https://tidb.net/blog/5fa1612a 本文档的主要内容为: TiDB v6.1.0 在 Rocky Linux 8.7 中的离线部署 TiDB v6.1.0 -> TiDB v6.5.1 升级 TiFlash 扩缩容 Haproxy 部署 br 物理备份与恢复 基…

递归算法(JS实现代码)

📝个人主页:爱吃炫迈 💌系列专栏:数据结构与算法 🧑‍💻座右铭:道阻且长,行则将至💗 文章目录递归算法递归的思想递归三要素递归的编程模型递归一般应用场景递归经典案例…

​力扣解法汇总1026. 节点与其祖先之间的最大差值

目录链接: 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目: https://github.com/September26/java-algorithms 原题链接:力扣 描述: 给定二叉树的根节点 root,找出存在于 不同 节点 A 和 B 之间的最大值…

05、SpringBoot开发实用篇

一、热部署什么是热部署?简单说就是你程序改了,现在要重新启动服务器,嫌麻烦?不用重启,服务器会自己悄悄的把更新后的程序给重新加载一遍,这就是热部署。热部署的功能是如何实现的呢?这就要分两…

【技术】封装自己的 Maven Archetype Maven 原型

封装自己的 Maven Archetype Maven 原型 为什么要封装 Maven Archetype?如何封装 Maven Archetype?核心步骤具体步骤构建项目构建原型 archetypeIDEA 导入自定义原型 如何删除自定义的 Maven Archetype ? 为什么要封装 Maven Archetype? 用…

尚融宝19-Nuxt.js入门

目录 一、搜索引擎优化 1、什么是SEO 2、搜索引擎工作流程 二、服务端渲染和客户端渲染 1、什么是服务端渲染 2、什么是客户端渲染 3、两种方式各有什么优缺点? 三、Nuxt.js 1、Nuxt.js介绍 2、Nuxt.js服务器端渲染 四、安装和运行 五、页面、导航和路…

倒计时 1 天!IoTDB X EMQ 智能汽车主题 Meetup 明日不见不散!

期待已久的智能汽车主题 Meetup 活动明日即将举办!天谋科技联手 EMQ、通过数据基础设施平台的实践经验分享,共同为行业用户带来可靠高效的智能制造、智慧车联数据解决方案,快来预约直播,不要错过这场干货满满的智能汽车主题 Meetu…

类中自定义函数并调用and使用钩子函数打印类中变量

在一个类中自定义一个函数A,并在前向传播函数forword中调用这个函数 假设您正在编写一个PyTorch模型,您可以按照以下方式在类中定义函数A,并在forward函数中调用它: import torch import torch.nn as nnclass MyModel(nn.Module)…

Android修行手册 - Android Studio提升性能效率

专栏分享点击跳转>Unity3D特效百例点击跳转>案例项目实战源码点击跳转>游戏脚本-辅助自动化点击跳转>Android控件全解手册点击跳转>Scratch编程案例 👉关于作者 众所周知,人生是一个漫长的流程,不断克服困难,不断…

【Linux】NanoPi-NEO2外接spi-lcd

这是目录一、显示接口1.1、LCD接口1.2、核心板接口二、添加驱动2.1、确认驱动型号2.2、添加驱动三、测试四、附加4.1、交叉编译器安装4.2、内核和module编译4.3、扩展rootfs大小本文使用环境: 电脑:Ubuntu 18.04.5 LTS 开发板:NanoPi-NEO2 50…