1. Android图片压缩,Drawable和Bitmap转换,bitmap和base64转换,网络资源图片转化成bitmap,File-Base64-MultipartFile之间相互转换
1.1. Drawable和Bitmap之间的转化
1.1.1. bitmap和Drawable间的区别
Bitmap - 称作位图,一般位图的文件格式后缀为bmp,当然编码器也有很多如RGB565、RGB888。作为一种逐像素的显示对象执行效率高,但是缺点也很明显存储效率低。我们理解为一种存储对象比较好。
Drawable - 作为Android平下通用的图形对象,它可以装载常用格式的图像,比如GIF、PNG、JPG,当然也支持BMP,当然还提供一些高级的可视化对象,比如渐变、图形等。
两者间的简单对比:
对比项 | Bitmip | Drawable |
---|---|---|
显示清晰度 | 相同 | 相同 |
电内存占比 | 大 | 小 |
支持压缩 | 是 | 是 |
支持色相色差调整 | 是 | 否 |
支持旋转 | 是 | 是 |
支持透明色 | 是 | 是 |
绘图速度 | 慢 | 快 |
支持像素操作 | 是 | 否 |
Drawable在内存占用和绘制速度这两个非常关键的点上胜过Bitmap
我们经常会遇到需要在代码中获取资源文件下图片的问题
Bitmap bmp = BitmapFactory.decodeResource(getResources(),R.drawable.ic );
或者
Drawable drawable = getResources().getDrawable(R.drawable.ic);
或者
iv.setImageResource(R.drawable.ic_launcher);
获取路径下的图片资源:
String fileName = "/data/data/com.test/aa.png;
Bitmap bm = BitmapFactory.decodeFile(fileName);
iv.setImageBitmap(bm); //占用内存
1.1.2. Drawable转换成Bitmap
第一种:
BitmapDrawable bd = (BitmapDrawable) drawable;
Bitmap bm= bd.getBitmap();
第二种:
public static Bitmap drawableToBitmap(Drawable drawable) {
// 取 drawable 的长宽
int w = drawable.getIntrinsicWidth();
int h = drawable.getIntrinsicHeight();
// 取 drawable 的颜色格式
Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
: Bitmap.Config.RGB_565;
// 建立对应 bitmap
Bitmap bitmap = Bitmap.createBitmap(w, h, config);
// 建立对应 bitmap 的画布
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, w, h);
// 把 drawable 内容画到画布中
drawable.draw(canvas);
return bitmap;
}
1.1.3. Bitmap转换成Drawable
第一种:
Drawable drawable = new BitmapDrawable(bitmap);
第二种:
BitmapDrawable bd= new BitmapDrawable(getResource(), bm);
BitmapDrawable是Drawable的子类,可以直接使用。
1.2. Drawable和Bitmap之间的转化
1.2.1. bitmap和base64之间的转换
public class BitmapUtil {
/**
* bitmap转为base64
* @param bitmap
* @return
*/
public static String bitmapToBase64(Bitmap bitmap) {
String result = null;
ByteArrayOutputStream baos = null;
try {
if (bitmap != null) {
baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
baos.flush();
baos.close();
byte[] bitmapBytes = baos.toByteArray();
result = Base64.encodeToString(bitmapBytes, Base64.DEFAULT);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (baos != null) {
baos.flush();
baos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
/**
* base64转为bitmap
* @param base64Data
* @return
*/
public static Bitmap base64ToBitmap(String base64Data) {
byte[] bytes = Base64.decode(base64Data, Base64.DEFAULT);
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
}
}
1.2.2. 注意事项
当我们通过站长工具进行图片和Base64的转换时,会有一段前缀信息data:image/jpeg;base64,
如果Base64中带有这样的前缀信息,我们需要将其去除之后,才能调用上面的Bitmap.base64ToBitmap()方法,将其转换为Bitmap。
1.2.3. bitmap转换工具
package ***.***.***.***;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.Base64;
import android.view.View;
import android.view.View.MeasureSpec;
import android.widget.ImageView;
import com.***.***.R;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* 描述:图片处理类.
*
*/
public class AbImageUtil {
/**
* The tag.
*/
private static String TAG = "AbImageUtil";
private static OnImageUtilsListener onImageUtilsListener;
public void setOnImageUtilsListener(OnImageUtilsListener listener) {
onImageUtilsListener = listener;
}
public interface OnImageUtilsListener {
void backBitmap(Bitmap bt);
}
/**
* 描述:缩放图片.压缩
*
* @param file File对象
* @param newWidth 新图片的宽
* @param newHeight 新图片的高
* @return Bitmap 新图片
*/
@SuppressWarnings("resource")
public static Bitmap scaleImg(File file, int newWidth, int newHeight) {
Bitmap resizeBmp = null;
try {
BitmapFactory.Options opts = new BitmapFactory.Options();
// 设置为true,decodeFile先不创建内存 只获取一些解码边界信息即图片大小信息
opts.inJustDecodeBounds = true;
// BitmapFactory.decodeFile(file.getPath(), opts);
BitmapFactory.decodeFileDescriptor(new FileInputStream(file.getPath()).getFD(), null, opts);
if (newWidth != -1 && newHeight != -1) {
// inSampleSize=2表示图片宽高都为原来的二分之一,即图片为原来的四分之一
// 缩放可以将像素点打薄
int srcWidth = opts.outWidth; // 获取图片的原始宽度
int srcHeight = opts.outHeight;// 获取图片原始高度
int destWidth = 0;
int destHeight = 0;
// 缩放的比例
double ratio = 0.0;
if (srcWidth < newWidth || srcHeight < newHeight) {
ratio = 0.0;
destWidth = srcWidth;
destHeight = srcHeight;
// 按比例计算缩放后的图片大小
} else if (srcWidth > srcHeight) {
ratio = (double) srcWidth / newWidth;
destWidth = newWidth;
destHeight = (int) (srcHeight / ratio);
} else {
ratio = (double) srcHeight / newHeight;
destHeight = newHeight;
destWidth = (int) (srcWidth / ratio);
}
// 缩放的比例,缩放是很难按准备的比例进行缩放的,目前我只发现只能通过inSampleSize来进行缩放,其值表明缩放的倍数,SDK中建议其值是2的指数值
opts.inSampleSize = (int) ratio + 1;
// 设置大小
opts.outHeight = destHeight;
opts.outWidth = destWidth;
} else {
opts.inSampleSize = 1;
}
// 创建内存
opts.inJustDecodeBounds = false;
// 使图片不抖动
opts.inDither = false;
resizeBmp = BitmapFactory.decodeFileDescriptor(new FileInputStream(file.getPath()).getFD(), null, opts);
// resizeBmp = BitmapFactory.decodeFile(file.getPath(), opts);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return resizeBmp;
}
/**
* 描述:缩放图片,不压缩的缩放.
*
* @param bitmap the bitmap
* @param newWidth 新图片的宽
* @param newHeight 新图片的高
* @return Bitmap 新图片
*/
public static Bitmap scaleImg(Bitmap bitmap, int newWidth, int newHeight) {
if (bitmap == null) {
return null;
}
if (newHeight <= 0 || newWidth <= 0) {
return bitmap;
}
// 获得图片的宽高
int width = bitmap.getWidth();
int height = bitmap.getHeight();
if (width <= 0 || height <= 0) {
return null;
}
// 计算缩放比例
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// 取得想要缩放的matrix参数
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
// 得到新的图片
Bitmap newBm = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
return newBm;
}
/**
* 描述:缩放图片.
*
* @param bitmap the bitmap
* @param scale 比例
* @return Bitmap 新图片
*/
public static Bitmap scaleImg(Bitmap bitmap, float scale) {
Bitmap resizeBmp = null;
try {
// 获取Bitmap资源的宽和高
int bmpW = bitmap.getWidth();
int bmpH = bitmap.getHeight();
// 注意这个Matirx是android.graphics底下的那个
Matrix mt = new Matrix();
// 设置缩放系数,分别为原来的0.8和0.8
mt.postScale(scale, scale);
resizeBmp = Bitmap.createBitmap(bitmap, 0, 0, bmpW, bmpH, mt, true);
} catch (Exception e) {
e.printStackTrace();
}
return resizeBmp;
}
/**
* 描述:裁剪图片.
*
* @param file File对象
* @param newWidth 新图片的宽
* @param newHeight 新图片的高
* @return Bitmap 新图片
*/
public static Bitmap cutImg(File file, int newWidth, int newHeight) {
Bitmap newBitmap = null;
try {
BitmapFactory.Options opts = new BitmapFactory.Options();
// 设置为true,decodeFile先不创建内存 只获取一些解码边界信息即图片大小信息
opts.inJustDecodeBounds = true;
BitmapFactory.decodeFileDescriptor(new FileInputStream(file.getPath()).getFD(), null, opts);
// BitmapFactory.decodeFile(file.getPath(), opts);
if (newWidth != -1 && newHeight != -1) {
// inSampleSize=2表示图片宽高都为原来的二分之一,即图片为原来的四分之一
// 缩放可以将像素点打薄,裁剪前将图片缩放一些
int srcWidth = opts.outWidth; // 获取图片的原始宽度
int srcHeight = opts.outHeight;// 获取图片原始高度
int destWidth = 0;
int destHeight = 0;
int cutSrcWidth = newWidth * 2;
int cutSrcHeight = newHeight * 2;
// 缩放的比例
double ratio = 0.0;
if (srcWidth < cutSrcWidth || srcHeight < cutSrcHeight) {
ratio = 0.0;
destWidth = srcWidth;
destHeight = srcHeight;
// 按比例计算缩放后的图片大小
} else if (srcWidth > srcHeight) {
ratio = (double) srcWidth / cutSrcWidth;
destWidth = cutSrcWidth;
destHeight = (int) (srcHeight / ratio);
} else {
ratio = (double) srcHeight / cutSrcHeight;
destHeight = cutSrcHeight;
destWidth = (int) (srcWidth / ratio);
}
// 缩放的比例,缩放是很难按准备的比例进行缩放的,目前我只发现只能通过inSampleSize来进行缩放,其值表明缩放的倍数,SDK中建议其值是2的指数值
opts.inSampleSize = (int) ratio + 1;
// 设置大小
opts.outHeight = destHeight;
opts.outWidth = destWidth;
} else {
opts.inSampleSize = 1;
}
// 创建内存
opts.inJustDecodeBounds = false;
// 使图片不抖动
opts.inDither = false;
// Bitmap resizeBmp = BitmapFactory.decodeFile(file.getPath(), opts);
Bitmap resizeBmp = BitmapFactory.decodeFileDescriptor(new FileInputStream(file.getPath()).getFD(), null, opts);
if (resizeBmp != null