1、图片的基本知识
1.文件形式(即以二进制形式存在于硬盘上)
获取大小(Byte):
File.length()
2.流的形式(即以二进制形式存在于内存中)
获取大小(Byte):
new FileInputStream(File).available()
3.Bitmap形式
获取大小(Byte):
Bitmap.getByteCount()
这三种形式的区别: 文件形式和流的形式对图片体积大小并没有影响,也就是说,如果你手机SD卡上的如果是100K,那么通过流的形式读到内存中,也一定是占100K的内存,注意是流的形式,不是Bitmap的形式,当图片以Bitmap的形式存在时,其占用的内存会瞬间变大, 我试过500K文件形式的图片加载到内存,以Bitmap形式存在时,占用内存将近10M,当然这个增大的倍数并不是固定的。
bitmap大小=图片长度(px) x 图片宽度(px) x 单位像素占用的字节数
色彩模式:
单位像素所占字节数就是图片的色彩模式。当一个颜色表现形式越多,那么画面整体的色彩就会更丰富,图片质量就会越高,当然,图片占用的储存空间也越大。
在BitmapFactory.Options.inPreferredConfig这里可以找到,一共有4种, ARGB代表:A 透明度 , R 红色, G 绿色, B 蓝色
默认色彩模式为ARGB_8888
质量压缩:
Bitmap.compress(CompressFormat format, int quality, OutputStream stream)
这个方法有三个参数,是布尔类型的返回值
CompressFormat 指定的Bitmap被压缩成的图片格式,只支持JPEG,PNG,WEBP三种。
quality 图片压缩质量的控制,范围为0~100,0表示压缩后体积最小,但是质量也是最差,100表示压缩后体积最大,但是质量也是最好的(个人认为相当于未压缩),有些格式,例如png,它是无损的,所以会忽略这个值。
OutputStream 压缩后的数据会写入这个字节流中。
该方法是压缩图片的质量, 注意它不会减少图片的像素,比方说, 你的图片是300K的, 1280*700像素的, 经过该方法压缩后, File形式的图片是在100以下, 以方便上传服务器, 但是你BitmapFactory.decodeFile到内存中,变成Bitmap时,它的像素仍然是1280*700,
计算图片像素的方法是 bitmap.getWidth()和bitmap.getHeight(),
图片是由像素组成的, 每个像素又包含什么呢? 熟悉PS的人知道, 图片是有色相,明度和饱和度构成的.
二次采样:
该方法就是对Bitmap形式的图片进行压缩, 也就是通过设置采样率, 减少Bitmap的像素, 从而减少了它所占用的内存。
2、压缩图片的目的与方法:
一,避免占用内存过多。二,可能要上传图片,如果图片太大,浪费流量。(有时候需要上传原图除外)
1、避免内存过多的压缩方法:
归根结底,图片是要显示在界面组件上的,所以还是要用到bitmap,从上面可得出Bitmap的在内存中的大小只和图片尺寸和色彩模式有关,那么要想改变Bitmap在内存中的大小,要么改变尺寸,要么改变色彩模式。
2、避免上传浪费流量的压缩方法:
改变图片尺寸(二次采样),改变色彩模式,改变图片质量都行。正常情况下,先改变图片尺寸和色彩模式,再改变图片质量。
3、工具类示例:
package com.example.administrator.downloadimgdemo.compressutils;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
/**
* Created by Administrator on 2017/5/4.
*/
public class CompressImageUtil {
/**
* 质量压缩方法:限制100kb,不改变分辨率
*
* @param image
* @return
*/
public static Bitmap compressImage(Bitmap image) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
int options = 100;
while (baos.toByteArray().length / 1024 > 100) {
baos.reset();
options -= 5;
image.compress(Bitmap.CompressFormat.JPEG, options, baos);
}
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
Bitmap bitmap = BitmapFactory.decodeStream(bais, null, null);
return bitmap;
}
/**
* 图片按比例大小压缩方法:二次采样压缩
*
* @param srcPath (根据路径获取图片并压缩)
* @return
*/
public static Bitmap getImage(String srcPath) {
//1.获取原始图片的长和宽
//inJustDecodeBounds设置为true,可以不把图片读到内存中,但依然可以计算出图片的大小
BitmapFactory.Options newOpts = new BitmapFactory.Options();
newOpts.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
int height = newOpts.outHeight;
int width = newOpts.outWidth;
//2.计算压缩比例
//inSampleSize为1表示宽度和高度不缩放,为2表示压缩后的宽度与高度为原来的1/2
int reqHeight = 800;
int reqWidth = 480;
int be = 1;//be=1表示不缩放
if (width/reqWidth > height/reqHeight && width > reqWidth) {//取比率较大者且比率大于1
be = (int) (width / reqWidth);
} else if (height/reqHeight > width/reqWidth && height > reqHeight) {
be = (int) (height / reqHeight);
}
newOpts.inSampleSize = be;//设置缩放比例
// newOpts.inPreferredConfig = Config.RGB_565;//降低图片从ARGB888到RGB565
//3.缩放并压缩图片
newOpts.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
return bitmap;
}
/**
* 图片按比例大小压缩方法:二次采样
*
* @param image (根据Bitmap图片压缩)
* @return
*/
public static Bitmap compressScale(Bitmap image) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
//判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出
if (baos.toByteArray().length / 1024 > 1024) {
baos.reset();
image.compress(Bitmap.CompressFormat.JPEG, 50, baos);
}
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
//1.获取原始图片的长和宽
//inJustDecodeBounds设置为true,可以不把图片读到内存中,但依然可以计算出图片的大小
// 开始读入图片,此时把options.inJustDecodeBounds 设回true了
BitmapFactory.Options newOpts = new BitmapFactory.Options();
newOpts.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeStream(bais, null, newOpts);
int height = newOpts.outHeight;
int width = newOpts.outWidth;
//2.计算压缩比例
//be为1表示宽度和高度不缩放,为2表示压缩后的宽度与高度为原来的1/2
int reqHeight = 800;
int reqWidth = 480;
int be = 1;//be=1表示不缩放
if (width/reqWidth > height/reqHeight && width > reqWidth) {//取比率较大者且比率大于1
be = (int) (width / reqWidth);
} else if (height/reqHeight > width/reqWidth && height > reqHeight) {
be = (int) (height / reqHeight);
}
newOpts.inSampleSize = be;//设置缩放比例
// newOpts.inPreferredConfig = Config.RGB_565;//降低图片从ARGB888到RGB565
//3.缩放并压缩图片
// 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
newOpts.inJustDecodeBounds = false;
bais = new ByteArrayInputStream(baos.toByteArray());
bitmap = BitmapFactory.decodeStream(bais, null, newOpts);
return bitmap;
}
}