Android实现图片压缩并上传到服务器

转自:http://write.blog.csdn.net/postedit/70599061
最近公司又叫开发了一个新项目,这个项目中上传图片用的蛮多的,于是整理一下,记录自己的心得体验
刚入手的时候,对于图片的大小还没有概念,(以前上传图片都是用户头像,对大小没什么要求),心想之间上传就是了,和以前一样,那成想到,上传一张图片还好,上传多张图片慢成狗,这时候,我还是无动于衷,直到有一天,服务器端也意识到了,图片太大对数据库没好处,只会让数据库变得无比庞大,限制的上传图片的大小,单张图片最大为2w,此时的我,再也不能无动于衷了,默默的进行图片的压缩,而我对于图片的压缩可以用一无所知来形容,尽管上学的时候学习过,只好借鉴Google了,压缩图片方法大致分为如下几类

  • 质量压缩
  • 采样率压缩
  • 缩放法压缩
  • RGB_565
  • createScaledBitmap
参考文章:http://blog.csdn.net/harryweasley/article/details/51955467
而我采用的是质量压缩方法
压缩前的图片截图:
Android实现图片压缩并上传到服务器
文章图片

点击其中一张图片
Android实现图片压缩并上传到服务器
文章图片

上传并压缩后的截图
Android实现图片压缩并上传到服务器
文章图片

点击其中一张小图
Android实现图片压缩并上传到服务器
文章图片

在送一张好图
Android实现图片压缩并上传到服务器
文章图片

由肉眼辨别,貌似压缩前和压缩后的分辨率·,没有什么区别。
我也简单的做了一下对比,压缩前图片的大小为5w左右,压缩后的大小为100k左右,这似乎满足了我的需求(内心有点小激动!)
代码说明首先说明一下,使用的网络请求库是:Retrofit2+Rxjava2ps 还不知道这个是什么东东的童鞋,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; } }

【Android实现图片压缩并上传到服务器】//简单的封装了一下网络请求工具类RetorfitFactory
public class RetrofitFactory { private static RetrofitFactory mRetrofitFactory; private staticAPIFunction 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; } publicAPIFunction API(){ return mAPIFunction; } }

代理API接口类APIFunction
/** * @author yemao * @date 2017/4/9 * @description API接口! */ public interface APIFunction { //上传单张图片 @POST("服务器地址") Observable imageUpload(@Part() MultipartBody.Part img); //上传多张图片 @POST("服务器地址") Observable imagesUpload(@Part() List imgs); }
上传图片的的工具类
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() { } }); }

到了这里就大功告成了!

    推荐阅读