Android压缩图片和libjpeg库

前言

Fjpeg使用

Fjpeg

注意

如何使用

如何压缩图片只改变在硬盘的存储大小

如何改变图片分辨率让其Bitmap对象可以加载到内存中

关于重载版本

开始学习之旅

补充知识的结论

修改图片分辨率 防止在Android加载Bitmap的时候oom内存溢出

解决方案1

解决方案2

希望压缩图片方便网络传输

第一种方案利用Bitmapcompress方法压缩

第二种利用libjpeg压缩

在Android50测试两个 图片压缩

在Android60测试两个 图片压缩

解释Android50和60为什么压缩率差别

定长编码

哈夫曼编码

编译libjpeg前言

编译libjpeg步骤

创建Demo项目

撸代JAVA层代码

撸C代码

最终我们看下完整代码

参考文献

编译好的静态库和头文件

前言:

在Android开发时我们往往有如对图片如下的需求:

1. 希望压缩图片方便网络传输

2. 修改图片分辨率 防止在android加载Bitmap的时候oom(内存溢出)

所以我就写了一个工具类Fjpeg封装二次采样和libjpeg进行图片压缩操作。

本文就是讲述我们写Fjpeg的学习过程

Fjpeg使用

源码地址

Fjpeg

封装libjpeg对图片进行压缩,和二次采样等代码封装

我们知道在Android 6.0以下 系统对图片的编码采用’定长编码’之后才采用‘哈夫曼编码’。

所以本框架封装libjpeg 进行对图片进行编码 ,方便网络传输等

我们知道Android加载Bitmap图片时候 如果图片分辨率过大 我们需要对图片进行分辨率裁剪 在进行显示

所以本框架封装了二次采样代码

注意:

libjpeg压缩不能改变图片分辨率,只能改变存储在硬盘中的大小。也就是说他的目的在于网络传输。

所以如果你想加载大图请使用本框架封装的二次采样代码即可

如何使用?

在你moudle的build.gradle中的dependencies添加以下代码

compile ‘com.fmy:fjpeg:1.0.0@aar

比如:

dependencies {

...

compile 'com.fmy:fjpeg:1.0.0@aar'

...

}1234512345

如何压缩图片(只改变在硬盘的存储大小)

/**

* 第一个参数:压缩后 文件输出路径,

* 第二个参数:需要压缩Bitmap对象

* 第三个参数:压缩质量 1-100 1是最小的

* 第四个参数:是否启用哈夫曼编码

* 第五个参数:回调 包含 开始前、错误、结束

* 第六个参数:是否使用子线程

*/

ImageUtils.compressQC(new File(Environment.getExternalStorageDirectory(), "测试剥离框架.jpg").getAbsolutePath(), bitmap, 1, true, new NativeCallBack() {

//开始前回调

@Override

public void startCompress() {

Log.d(TAG, "startCompress() called");

}

//错误回调

@Override

public void error(int errorNum, String description) {

Log.d(TAG, "error() called with: errorNum = [" + errorNum + "], description = [" + description + "]");

}

//完成结束回调 如果发生错误讲不会回调次方法

@Override

public void finish(String filePath) {

Log.d(TAG, "finish() called with: filePath = [" + filePath + "]");

}

}, true);123456789101112131415161718192021222324252627123456789101112131415161718192021222324252627

如何改变图片分辨率(让其Bitmap对象可以加载到内存中)

//从mipmap中读取。此方法ImageUtils.compressPxSampleSize存在多个重载版本

//如:从文件 、从资源、从io流、字节数组等

Bitmap bitmap = ImageUtils.compressPxSampleSize(getResources(), R.mipmap.timg, 1000, 1000);123123

关于重载版本

这里写图片描述

开始学习之旅:

Android的Bitmap对象在加载时 内存大小为:

宽的像素*高的像素*位图格式(如ARGB8888)11

注意:

这里的宽高是不是你放入文件夹中数据。需要换算

举例:

环境如下:

1. 一张图片宽高为:1000*1000

2. 格式为:ARGB8888(每一个像素点4个字节)

3. 将此图片放入:mipmap-xhdpi(320dpi density:2.0)

4. 设备density:4.0 densityDpi:640

(google规定160dpi density:1 那么 320dpi 的density自然等于2。关于这块基础知识不做详细介绍)

第一步:换算xhdpi和设备dpi

缩放比=设备密度/图文所在文件密度= 4/2 = 2

所以图片大小应为:

图片高 x 图片宽 x 缩放比 x 图片格式内存(图片每一个像素点颜色需要多少个字节保存)

最终: 4/2*1000*1000*8 = 16000000

口说无凭证那么请看如下单元测试:

这里写图片描述

输出结果:

这里写图片描述

补充知识的结论

所以可以知道一个Bitmap只会和它的 分辨率和图片格式有关。

所以我们的需求:

2. 修改图片分辨率 防止在Android加载Bitmap的时候oom(内存溢出) 只能修改分辨率和格式实现,我们一般从改变的图片分辨率入手,而libjpeg改变不是改变Bitmap内存大小 而是存储大小。

这里举例说明如下:

假设我有一张图片 在硬盘存储的时候大小为:100kb 然后经过libjpeg变成10kb 。但是分辨率没有改变。所以载入内存的时候大小是一样的。但是可以方便我们存储和传输。

修改图片分辨率 防止在Android加载Bitmap的时候oom(内存溢出)

我们来看一下我们如何解决这个需求

解决方案1:

利用canvas修改分辨率:

/**

*

* 2. 尺寸压缩

通过缩放图片像素来减少图片占用内存大小

* @param bmp

* @param file

*/

public static void compressBitmapToFile(Bitmap bmp, File file){

// 尺寸压缩倍数,值越大,图片尺寸越小

int ratio = 8;

// 压缩Bitmap到对应尺寸

Bitmap result = Bitmap.createBitmap(bmp.getWidth() / ratio, bmp.getHeight() / ratio, Bitmap.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();

}

}

123456789101112131415161718192021222324252627282930123456789101112131415161718192021222324252627282930

解决方案2:

我们最常见的修改采样率:

代码来自

/**

* @param filePath 要加载的图片路径

* @param destWidth 显示图片的控件宽度

* @param destHeight 显示图片的控件的高度

* @return

*/

public static Bitmap getBitmap(String filePath, int destWidth, int destHeight) {

//第一次采样

BitmapFactory.Options options = new BitmapFactory.Options();

//该属性设置为true只会加载图片的边框进来,并不会加载图片具体的像素点

options.inJustDecodeBounds = true;

//第一次加载图片,这时只会加载图片的边框进来,并不会加载图片中的像素点

BitmapFactory.decodeFile(filePath, options);

//获得原图的宽和高

int outWidth = options.outWidth;

int outHeight = options.outHeight;

//定义缩放比例

int sampleSize = 1;

while (outHeight / sampleSize > destHeight || outWidth / sampleSize > destWidth) {

//如果宽高的任意一方的缩放比例没有达到要求,都继续增大缩放比例

//sampleSize应该为2的n次幂,如果给sampleSize设置的数字不是2的n次幂,那么系统会就近取值

sampleSize *= 2;

}

/********************************************************************************************/

//至此,第一次采样已经结束,我们已经成功的计算出了sampleSize的大小

/********************************************************************************************/

//二次采样开始

//二次采样时我需要将图片加载出来显示,不能只加载图片的框架,因此inJustDecodeBounds属性要设置为false

options.inJustDecodeBounds = false;

//设置缩放比例

options.inSampleSize = sampleSize;

options.inPreferredConfig = Bitmap.Config.ARGB_8888;

//加载图片并返回

return BitmapFactory.decodeFile(filePath, options);

}



宁波胸部整形医院http://www.iyestar.com/xbzx/



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值