当前位置: 首页 > news >正文

Android 图片压缩

Android 图片压缩

在android 中进行图片压缩处理, 通常是为了减小图片大小来节省存储空间或者加快网络传输速度.

本文主要记录下android 中原生的压缩图片方法.

1: 使用Bitmap.compress()方法压缩图片

示例代码1:

通过Bitmap的compress()方法将图片压缩为JPEG/PNG格式.

Bitmap bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.image);
ByteArrayOutputStream os = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG,80,os);
byte[] compressImage=os.toByteArray(); 
  1. compress方法中Bitmap.CompressFormat.JPEG指定压缩格式,
  2. 参数80: 压缩质量,范围是0-100,数值越小压缩率越高,当然图片的质量也越差.

由此我们可以延伸出限定图片大小,来循环压缩,具体代码如下:

 /*** 压缩 Bitmap 到指定大小以内(KB)*/private static byte[] compressBitmap(Bitmap bitmap, int maxKb, Bitmap.CompressFormat format) {ByteArrayOutputStream outputStream = new ByteArrayOutputStream();int quality = 100;bitmap.compress(format, quality, outputStream);while (outputStream.toByteArray().length > maxKb * 1024 && quality > 10) {outputStream.reset();quality -= 5;bitmap.compress(format, quality, outputStream);}return outputStream.toByteArray();}

可以看到封装的方法指定maxKb, 初始化时质量为100,拿到图片的原始大小,从而根据大小来循环执行压缩方法.并逐渐降低压缩质量.

2: 缩放图片尺寸压缩

示例代码2:

Bitmap originalBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image);
Bitmap scaledBitmap = Bitmap.createScaledBitmap(originalBitmap, 1024, 768, true); 
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();     
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 80, outputStream);
byte[] compressedImage = outputStream.toByteArray();

示例代码中将图片指定缩放到1024x768,并压缩质量值80.

private static Bitmap scaleBitmap(Bitmap bitmap, int targetWidth, int targetHeight) {return Bitmap.createScaledBitmap(bitmap, targetWidth, targetHeight, true);
}

3: 处理 EXIF 旋转

 /*** 从 Uri 解码图片,并自动处理 EXIF 旋转*/private static Bitmap decodeBitmapFromUri(Context context, Uri uri) throws IOException {ContentResolver resolver = context.getContentResolver();InputStream inputStream = resolver.openInputStream(uri);BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = false;Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options);inputStream.close();// 处理 EXIF 旋转ExifInterface exif = new ExifInterface(resolver.openInputStream(uri));int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);Matrix matrix = new Matrix();switch (orientation) {case ExifInterface.ORIENTATION_ROTATE_90:matrix.postRotate(90);break;case ExifInterface.ORIENTATION_ROTATE_180:matrix.postRotate(180);break;case ExifInterface.ORIENTATION_ROTATE_270:matrix.postRotate(270);break;default:break;}return Bitmap.createBitmap(bitmap, 0, 0, options.outWidth, options.outHeight, matrix, true);}

4: 采样率压缩

采样率是BitmapFactory.Options的重要参数,用于控制图片解码时的缩放比例,合理的设置inSanmpleSize可以有效的减少内存占用,减少oom的出现.

采样率的计算主要通过实际大小以及要求大小来计算,具体的代码如下:

public static int calculateInSampleSize(int actualWidth, int actualHeight, int reqWidth, int reqHeight) {int inSampleSize = 1;if (actualHeight > reqHeight || actualWidth > reqWidth) {int halfWidth = actualWidth / 2;int halfHeight = actualHeight / 2;while ((halfWidth / inSampleSize) >= reqWidth&& (halfHeight / inSampleSize) >= reqHeight) {inSampleSize *= 2;}}return inSampleSize;
}

获取图片的原始大小, 我们可以通过

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; // 只读取元数据,不解码像素
InputStream is = context.getContentResolver().openInputStream(uri);
BitmapFactory.decodeStream(is, null, options);
is.close();

原始图片的宽高,就可以从options.outWidth 和 options.outHeight 得到.

5: 附上源码

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Build;
import android.content.ContentResolver;
import android.content.Context;import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;public class ImageCompressUtils {/*** 压缩图片到指定最大大小(单位 KB),并返回压缩后的字节数组** @param context       上下文* @param uri           图片 Uri* @param maxKb         最大允许大小(KB)* @param format        压缩格式(Bitmap.CompressFormat)* @param inSampleSize  采样率(2 的幂次,例如 1, 2, 4, 8...)* @return              压缩后的图片字节数组*/public static byte[] compressImage(Context context, Uri uri, int maxKb, Bitmap.CompressFormat format, int inSampleSize) throws IOException {Bitmap bitmap = decodeBitmapFromUri(context, uri, inSampleSize);return compressBitmap(bitmap, maxKb, format);}/*** 缩放并压缩图片到指定宽高和大小** @param context       上下文* @param uri           图片 Uri* @param targetWidth   目标宽度* @param targetHeight  目标高度* @param maxKb         最大允许大小(KB)* @param format        压缩格式* @param inSampleSize  采样率(2 的幂次)* @return              压缩后的图片字节数组*/public static byte[] compressToSize(Context context, Uri uri, int targetWidth, int targetHeight, int maxKb, Bitmap.CompressFormat format, int inSampleSize) throws IOException {Bitmap original = decodeBitmapFromUri(context, uri, inSampleSize);Bitmap scaled = scaleBitmap(original, targetWidth, targetHeight);return compressBitmap(scaled, maxKb, format);}/*** 从 Uri 解码图片,支持指定采样率,并自动处理 EXIF 旋转*/private static Bitmap decodeBitmapFromUri(Context context, Uri uri, int inSampleSize) throws IOException {ContentResolver resolver = context.getContentResolver();InputStream inputStream = resolver.openInputStream(uri);BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = false;options.inSampleSize = inSampleSize; // 设置采样率Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options);inputStream.close();// 处理 EXIF 旋转ExifInterface exif = new ExifInterface(resolver.openInputStream(uri));int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);Matrix matrix = new Matrix();switch (orientation) {case ExifInterface.ORIENTATION_ROTATE_90:matrix.postRotate(90);break;case ExifInterface.ORIENTATION_ROTATE_180:matrix.postRotate(180);break;case ExifInterface.ORIENTATION_ROTATE_270:matrix.postRotate(270);break;default:break;}return Bitmap.createBitmap(bitmap, 0, 0, options.outWidth, options.outHeight, matrix, true);}/*** 缩放图片到指定宽高*/private static Bitmap scaleBitmap(Bitmap bitmap, int targetWidth, int targetHeight) {return Bitmap.createScaledBitmap(bitmap, targetWidth, targetHeight, true);}/*** 压缩 Bitmap 到指定大小以内(KB)*/private static byte[] compressBitmap(Bitmap bitmap, int maxKb, Bitmap.CompressFormat format) {ByteArrayOutputStream outputStream = new ByteArrayOutputStream();int quality = 100;bitmap.compress(format, quality, outputStream);while (outputStream.toByteArray().length > maxKb * 1024 && quality > 10) {outputStream.reset();quality -= 5;bitmap.compress(format, quality, outputStream);}return outputStream.toByteArray();}/*** 自动计算合适的采样率(inSampleSize)** @param actualWidth   实际宽度* @param actualHeight  实际高度* @param reqWidth      请求宽度* @param reqHeight     请求高度* @return              合适的采样率*/public static int calculateInSampleSize(int actualWidth, int actualHeight, int reqWidth, int reqHeight) {int inSampleSize = 1;if (actualHeight > reqHeight || actualWidth > reqWidth) {int halfWidth = actualWidth / 2;int halfHeight = actualHeight / 2;while ((halfWidth / inSampleSize) >= reqWidth&& (halfHeight / inSampleSize) >= reqHeight) {inSampleSize *= 2;}}return inSampleSize;}
}

文章转载自:
http://calcaneal.ciuzn.cn
http://breastwork.ciuzn.cn
http://amersfoort.ciuzn.cn
http://chemigraphy.ciuzn.cn
http://acheulean.ciuzn.cn
http://aramaic.ciuzn.cn
http://blah.ciuzn.cn
http://cadet.ciuzn.cn
http://chaetopod.ciuzn.cn
http://cannabinol.ciuzn.cn
http://bandkeramik.ciuzn.cn
http://amphicar.ciuzn.cn
http://bipectinate.ciuzn.cn
http://bucephalus.ciuzn.cn
http://arrayal.ciuzn.cn
http://acromion.ciuzn.cn
http://cardiopulmonary.ciuzn.cn
http://arthrosporic.ciuzn.cn
http://cant.ciuzn.cn
http://apophatic.ciuzn.cn
http://cgs.ciuzn.cn
http://amain.ciuzn.cn
http://caballine.ciuzn.cn
http://actinin.ciuzn.cn
http://bouvet.ciuzn.cn
http://booze.ciuzn.cn
http://bdellium.ciuzn.cn
http://afternoon.ciuzn.cn
http://billet.ciuzn.cn
http://bureaucratic.ciuzn.cn
http://www.dtcms.com/a/281670.html

相关文章:

  • 21.映射字典的值
  • 【强化学习】Reinforcement Learning基础概述
  • 如何进行 Docker 数据目录迁移
  • 三轴云台之深度学习算法篇
  • vscode配置运行完整C代码项目
  • QGIS新手教程9:字段计算器进阶用法与批量处理技巧
  • onecode 3.0 微内核引擎 基础注解驱动的速查手册(服务治理及通讯)
  • Altium Designer(AD)25软件下载及安装教程(7.9)
  • Axios方法完成图书管理页面完整版
  • Redis Desktop Manager(RDM)下载与安装使用教程
  • JavaScript中关于环境对象的拓展
  • 【Qt】 设计模式
  • Docker 镜像推送至 Coding 制品仓库超时问题排查与解决
  • 业务分析业务架构视角
  • 软件测试面试经历分享?
  • 在 SymPy 中精确提取三角函数系数的深度分析
  • LLM面试题目 3
  • 项目进度与预算脱节,如何进行同步管理
  • Linux部署Redis
  • 46. 携带研究材料(01背包二维数组)
  • Java程序员学从0学AI(五)
  • 发票查验接口的计费规则-核验成功返回参数
  • SpringBoot集成RocketMQ的两种方式
  • WGAS+WGCNA分析文章套路
  • LeetCode Hot100 【1.两数之和、2.两数相加、3.无重复字符的最长子串】
  • 动态数组:ArrayList的实现原理
  • 504网关超时可能是哪些原因导致?
  • web前端渡一大师课 01 事件循环
  • 【交流等效负载电阻的推导】
  • SpringBoot 项目搭建的 4 种常用方式,从入门到实践