之前写过一个对图片进行高保真压缩的文章,把图片压缩的这么小当然是为了上传的,这次就把图片批量上传的代码也一起贴出来,这个方法是基于xUtils的Http模块
首先这个上传过程要满足一下特性
1、开启多个线程进行图片的批量同时上传
2、每张图片的上传进度都可以获取到,并且显示在界面上
3、如果有一张图片上传失败就宣布上传过程失败,然后等待用户再次发起同样的上传命令
4、所有图片均上传成功后有一个完毕的回调
5、每张图片上传完毕后要从上传服务器得到一个json记录上传图片的id
6、对于已经上传过的图片不再上传第二遍
7、对于已经压缩过的图片不再压缩第二遍
8、对于像三星这样的手机,拍摄出来的照片都是宽度大于高度的躺着的照片,需要根据exif信息将图片旋转后再上传
9、对于压缩的照片,保留原来照片的exif信息
这个工具类里面还包含了几个额外的方法
1、对于sd卡中的一张图片,添加到系统相册中并保存缩略图
2、复制一张照片的exif信息到另一张照片
下面就是上传过程加压缩的代码,其中有一部分是《Android 高质量高压缩比图像压缩》里面的代码
package com.imaginato.qravedconsumer.utils;
import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;
import android.util.Log;
import com.imaginato.qravedconsumer.task.AlxAsynTask;
import com.lidroid.xutils.HttpUtils;
import com.lidroid.xutils.exception.HttpException;
import com.lidroid.xutils.http.RequestParams;
import com.lidroid.xutils.http.ResponseInfo;
import com.lidroid.xutils.http.callback.RequestCallBack;
import com.lidroid.xutils.http.client.HttpRequest;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
/**
* Created by Alex on 2016/4/6.
*/
public class AlxBitmapUtils {
/**
* 传入一个bitmap,根据传入比例进行大小缩放
* @param bitmap
* @param widthRatio 宽度比例,缩小就比1小,放大就比1大
* @param heightRatio
* @return
*/
public static Bitmap scaleBitmap(Bitmap bitmap, float widthRatio, float heightRatio) {
Matrix matrix = new Matrix();
matrix.postScale(widthRatio,heightRatio);
return Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true);
}
/**
* 传入图片路径,根据图片进行压缩,仅压缩大小,不压缩质量,
* @param oriFile 源文件
* @param targetFile 这个和 stream传一个就行,只有穿file的时候才会保留exif信息,但是都会根据旋转角度进行旋转
* @param ifDel 是否需要在压缩完毕后删除原图
*/
public static void compressImage(File oriFile, File targetFile, OutputStream stream,boolean ifDel,int rotateDegree,boolean keepExif) {
if(oriFile ==null || !oriFile.isFile()|| !oriFile.exists())return;
// Log.i("Alex","源图片为"+oriFile);
// Log.i("Alex","目标地址为"+targetFile);
try {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true; // 不读取像素数组到内存中,仅读取图片的信息,非常重要
BitmapFactory.decodeFile(oriFile.getAbsolutePath(), opts);//读取文件信息,存放到Options对象中
// 从Options中获取图片的分辨率
int imageHeight = opts.outHeight;
int imageWidth = opts.outWidth;
int longEdge = Math.max(imageHeight,imageWidth);//取出宽高中的长边
int pixelCount = (imageWidth*imageHeight)>>20;//看看这张照片有多少百万像素
// Log.i("Alex","图片宽为"+imageWidth+"图片高为"+imageHeight+"图片像素数为"+pixelCount+"百万像素");
long size = oriFile.length();
Log.i("Alex","f.length 图片大小为"+(size>>10)+" KB");
//走到这一步的时候,内存里还没有bitmap
Bitmap bitmap = null;
if(pixelCount > 3){//如果超过了3百万像素,那么就首先对大小进行压缩
float compressRatio = longEdge /1280f;
int compressRatioInt = Math.round(compressRatio);
if(compressRatioInt%2!=0 && compressRatioInt!=1)compressRatioInt++;//如果是奇数的话,就给弄成偶数
// Log.i("Alex","长宽压缩比是"+compressRatio+" 偶数化后"+compressRatioInt);
//尺寸压缩
BitmapFactory.Options options = new BitmapFactory.Options();
//目标出来的大小1024*1024 1百万像素,100k
options.inSampleSize = Math.round(compressRatioInt);//注意,此处必须是偶数,根据计算好的比例进行压缩,如果长边没有超过1280*1.5,就不去压缩,否则就压缩成原来的一半
options.inJustDecodeBounds = false;//在decode file的时候,不仅读取图片的信息,还把像素数组到内存
options.inPreferredConfig = Bitmap.Config.RGB_565;//每个像素占四位,即R=5,G=6,B=5,没有透明度,那么一个像素点占5+6+5=16位
//现在开始将bitmap放入内存
bitmap = BitmapFactory.decodeFile(oriFile.getAbsolutePath(), options);//根据压缩比取出大小已经压缩好的bitmap
//此处会打印出存入内存的bitmap大小
}else if(imageHeight*imageWidth>2073600){//如果图片大于1920*1080,为了减少内存开销,使用RGB——565
BitmapFactory.Options options = new BitmapFactory.Options();
//目标出来的大小1024*1024 1百万像素,100k
options.inSampleSize = 1;//注意,此处必须是偶数,根据计算好的比例进行压缩,如果长边没有超过1280*1.5,就不去压缩,否则就压缩成原来的一半
options.inJustDecodeBounds = false;//在decode file的时候,不仅读取图片的信息,还把像素数组到内存
options.inPreferredConfig = Bitmap.Config.RGB_565;//每个像素占四位,即R=5,G=6,B=5,没有透明度,那么一个像素点占5+6+5=16位
//现在开始将bitmap放入内存
bitmap = BitmapFactory.decodeFile(oriFile.getAbsolutePath(), options);//根据压缩比取出大小已经压缩好的bitmap
//此处会打印出存入内存的bitmap大小
}else {//如果是长图或者长边短于1920的图,那么只进行质量压缩
// 现在开始将bitmap放入内存
bitmap = BitmapFactory.decodeFile(oriFile.getAbsolutePath());
//此处会打印出bitmap在内存中占得大小
}