质量压缩

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

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

这个方法有三个参数:

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

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

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

返回值:

 如果成功把压缩数据写入写入输出流,则返回 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

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

 属性 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

好文链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: