转自:http://write.blog.csdn.net/postedit/70599061
最近公司又叫开发了一个新项目,这个项目中上传图片用的蛮多的,于是整理一下,记录自己的心得体验
刚入手的时候,对于图片的大小还没有概念,(以前上传图片都是用户头像,对大小没什么要求),心想之间上传就是了,和以前一样,那成想到,上传一张图片还好,上传多张图片慢成狗,这时候,我还是无动于衷,直到有一天,服务器端也意识到了,图片太大对数据库没好处,只会让数据库变得无比庞大,限制的上传图片的大小,单张图片最大为2w,此时的我,再也不能无动于衷了,默默的进行图片的压缩,而我对于图片的压缩可以用一无所知来形容,尽管上学的时候学习过,只好借鉴Google了,压缩图片方法大致分为如下几类
参考文章:http://blog.csdn.net/harryweasley/article/details/51955467
而我采用的是质量压缩方法
压缩前的图片截图:
点击其中一张图片
上传并压缩后的截图
点击其中一张小图
在送一张好图
由肉眼辨别,貌似压缩前和压缩后的分辨率·,没有什么区别。
我也简单的做了一下对比,压缩前图片的大小为5w左右,压缩后的大小为100k左右,这似乎满足了我的需求(内心有点小激动!)
代码说明 首先说明一下,使用的网络请求库是:Retrofit2+Rxjava2 ps 还不知道这个是什么东东的童鞋,I 服了you
压缩图片的工具类BitmapUtil
/**
* Created by yemao on 2017/3/15.
* 关于图片的工具类
*/
public class BitmapUtil {
private static String PHOTO_FILE_NAME = "PMSManagerPhoto";
/**
* 获取图片的旋转角度
*
* @param filePath
* @return
*/
public static int getRotateAngle(String filePath) {
int rotate_angle = 0;
try {
ExifInterface exifInterface = new ExifInterface(filePath);
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
rotate_angle = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotate_angle = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotate_angle = 270;
break;
}
} catch (IOException e) {
e.printStackTrace();
}
return rotate_angle;
}
/**
* 旋转图片角度
*
* @param angle
* @param bitmap
* @return
*/
public static Bitmap setRotateAngle(int angle, Bitmap bitmap) {
if (bitmap != null) {
Matrix m = new Matrix();
m.postRotate(angle);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), m, true);
return bitmap;
}
return bitmap;
}
//转换为圆形状的bitmap
public static Bitmap createCircleImage(Bitmap source) {
int length = source.getWidth() < source.getHeight() ? source.getWidth() : source.getHeight();
Paint paint = new Paint();
paint.setAntiAlias(true);
Bitmap target = Bitmap.createBitmap(length, length, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(target);
canvas.drawCircle(length / 2, length / 2, length / 2, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(source, 0, 0, paint);
return target;
}
/**
* 图片压缩-质量压缩
*
* @param filePath 源图片路径
* @return 压缩后的路径
*/
public static String compressImage(String filePath) {
//原文件
File oldFile = new File(filePath);
//压缩文件路径 照片路径/
String targetPath = oldFile.getPath();
int quality = 50;//压缩比例0-100
Bitmap bm = getSmallBitmap(filePath);//获取一定尺寸的图片
int degree = getRotateAngle(filePath);//获取相片拍摄角度
if (degree != 0) {//旋转照片角度,防止头像横着显示
bm = setRotateAngle(degree,bm);
}
File outputFile = new File(targetPath);
try {
if (!outputFile.exists()) {
outputFile.getParentFile().mkdirs();
//outputFile.createNewFile();
} else {
outputFile.delete();
}
FileOutputStream out = new FileOutputStream(outputFile);
bm.compress(Bitmap.CompressFormat.JPEG, quality, out);
out.close();
} catch (Exception e) {
e.printStackTrace();
return filePath;
}
return outputFile.getPath();
}
/**
* 根据路径获得图片信息并按比例压缩,返回bitmap
*/
public static Bitmap getSmallBitmap(String filePath) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;//只解析图片边沿,获取宽高
BitmapFactory.decodeFile(filePath, options);
// 计算缩放比
options.inSampleSize = calculateInSampleSize(options, 480, 800);
// 完整解析图片返回bitmap
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(filePath, options);
}
public static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
}
//简单的封装了一下网络请求工具类RetorfitFactory
public class RetrofitFactory {
private static RetrofitFactory mRetrofitFactory;
private static APIFunction mAPIFunction;
private RetrofitFactory(){
OkHttpClient mOkHttpClient=new OkHttpClient.Builder()
.connectTimeout(HttpConfig.HTTP_TIME, TimeUnit.SECONDS)
.readTimeout(HttpConfig.HTTP_TIME, TimeUnit.SECONDS)
.writeTimeout(HttpConfig.HTTP_TIME, TimeUnit.SECONDS)
.build();
Retrofit mRetrofit=new Retrofit.Builder()
.baseUrl(HttpConfig.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())//添加gson转换器
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())//添加rxjava转换器
.client(mOkHttpClient)
.build();
mAPIFunction=mRetrofit.create(APIFunction.class);
}
public static RetrofitFactory getInstence(){
if (mRetrofitFactory==null){
synchronized (RetrofitFactory.class) {
if (mRetrofitFactory == null)
mRetrofitFactory = new RetrofitFactory();
}
}
return mRetrofitFactory;
}
public APIFunction API(){
return mAPIFunction;
}
}
代理API接口类APIFunction
/**
* @author yemao
* @date 2017/4/9
* @description API接口!
*/
public interface APIFunction {
//上传单张图片
@POST("服务器地址")
Observable
上传图片的的工具类
package com.yr.example.utils;
import android.content.Context;
import android.os.AsyncTask;
import com.yr.example.http.RetrofitFactory;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
/**
* @author yemao
* @date 2017/4/17
* @description null!
*/
public class UploadUtil {
/**
* 上传单张图片
*
* @param filePath 图片本地路径
* @param observer 观察者
* @throws IOException
*/
public static void uploadImage(final String filePath, final Observer observer) {
new AsyncTask() {
@Override
protected File doInBackground(Integer... params) {
//压缩图片
File file = new File(BitmapUtil.compressImage(filePath));
return null;
}
@Override
protected void onPostExecute(File file) {
super.onPostExecute(file);
RequestBody requestBody = RequestBody.create(MediaType.parse("image/png"), file);
MultipartBody.Part part = MultipartBody.Part.createFormData("file", file.getName(), requestBody);
RetrofitFactory.getInstence().API()
.imageUpload( part)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
}
}.execute();
}
/**
* 上传多张照片
*
* @param mFilesPath 图片本地路径
* @param observer
*/
public static void uploadImages(final ArrayList mFilesPath, final Observer observer) {
new AsyncTask>() {
@Override
protected List doInBackground(Integer... params) {
//压缩图片
final List files = new ArrayList<>();
for (String path : mFilesPath) {
File file = new File(BitmapUtil.compressImage(path));
files.add(file);
}
return files;
}
@Override
protected void onPostExecute(List files) {
super.onPostExecute(files);
List xx = filesToMultipartBodyParts(files);
RetrofitFactory.getInstence().API()
.imagesUpload( xx)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
}
}.execute();
}
/**
* @param files 多图片文件转表单
* @return
*/
public static List filesToMultipartBodyParts(List files) {
List parts = new ArrayList<>(files.size());
for (File file : files) {
RequestBody requestBody = RequestBody.create(MediaType.parse("image/png"), file);
MultipartBody.Part part = MultipartBody.Part.createFormData("files", file.getName(), requestBody);
parts.add(part);
}
return parts;
}
}
使用方法
上传单张图片
public void upload(){
String filepath="图片本地路径";
UploadUtil.uploadImage(filepath, new Observer() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Object o) {
//返回结果
}
@Override
public void onError(Throwable e) {
//上传失败
}
@Override
public void onComplete() {
}
});
}
上传多张图片
public void uploads(){
ArrayList listFilePath=new ArrayList<>();
listFilePath.add("图片1路径");
listFilePath.add("图片2路径");
UploadUtil.uploadImages(listFilePath, new Observer() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Object o) {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
到了这里就大功告成了!