Android学习-使用Async-Http实现图片压缩并上传功能
前言
(转载请注明出处,谢谢!)
最近在做一个小项目,项目中要实现上传图片到服务器,而这个例子是实现图片的尺寸压缩,将获取到的压缩图片转为流,然后使用Async-Http开源框架实现图片流的上传,然后在服务器端将流写入本地。
效果图
<center>
<center>安卓端</center>
<center>
<center>服务器端</center>
解决
安卓端
一、点击加载本地相册选择图片,然后加载到ImageView中去,并获取图片地址以供后面图片上传时使用。
//点击图片打开选择图片界面 photo.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //使用Intent触发选择Action Intent intent = new Intent(Intent.ACTION_PICK, null); //打开系统提供的图片选择界面 intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*"); //传参以在返回本界面时触发加载图片的功能 startActivityForResult(intent, 0x1); } });
//在选择图片后返回本界面调用此方法@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == 0x1 && resultCode == RESULT_OK) { if (data != null) { ContentResolver resolver = getContentResolver(); try { // 获取圖片URI Uri uri = data.getData(); // 将URI转换为路径: String[] proj = { MediaStore.Images.Media.DATA }; Cursor cursor = managedQuery(uri, proj, null, null, null); // 这个是获得用户选择的图片的索引值 int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); // 最后根据索引值获取图片路径 photoPath = cursor.getString(column_index); // 压缩成800*480 bitmap = BitmapUtils.decodeSampledBitmapFromFd(photoPath, 480, 800); // 设置imageview显示图片 photo.setImageBitmap(bitmap); // 设置textview显示路径 path.setText(photoPath); } catch (Exception e) { e.printStackTrace(); } } } }
二、图片压缩。在我们需要上传图片时,我们不可能直接把原图上传到服务器,因为一般图片的大小都超过3,4M,所以我们在上传之前需要对图片进行压缩,我是把图片压缩放到了一个工具类,主要是对图片进行尺寸压缩。
public class BitmapUtils { private 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 halfHeight = height / 2; final int halfWidth = width / 2; //循环,如果halfHeight和halfWidth同时大于最小宽度和最小高度时,inSampleSize乘2, //最后得到的宽或者高都是最接近最小宽度或者最小高度的 while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2; } } return inSampleSize; } /** * 根据Resources压缩图片 * * @param res * @param resId * @param reqWidth * @param reqHeight * @return */ public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); options.inJustDecodeBounds = false; Bitmap src = BitmapFactory.decodeResource(res, resId, options); return src; } /** * 根据地址压缩图片 * * @param pathName * @param reqWidth 最小宽度 * @param reqHeight 最小高度 * @return */ public static Bitmap decodeSampledBitmapFromFd(String pathName, int reqWidth, int reqHeight) { final BitmapFactory.Options options = new BitmapFactory.Options(); // 若要对图片进行压缩,必须先设置Option的inJustDecodeBounds为true才能进行Option的修改 options.inJustDecodeBounds = true; // 第一次decodeFile是获取到options.outHeight和options.outWidth BitmapFactory.decodeFile(pathName, options); // options.inSampleSize是图片的压缩比,例如原来大小是100*100,options.inSampleSize为1,则不变, // options.inSampleSize为2,则压缩成50*50 options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // 重新设置options.inJustDecodeBounds为false,不能修改option options.inJustDecodeBounds = false; // 根据options重新加载图片 Bitmap src = BitmapFactory.decodeFile(pathName, options); return src; } }
三、将Bitmap转为String,同时使用BASE64加密,使传输更加安全,这是我的工具类,里面再一次进行压缩是质量压缩,压缩比例是30%,具体自己调
public class Utils { // 将bitmap转成string类型通过Base64 public static String BitmapToString(Bitmap bitmap) { ByteArrayOutputStream bao = new ByteArrayOutputStream(); // 将bitmap压缩成30% bitmap.compress(Bitmap.CompressFormat.JPEG, 30, bao); // 将bitmap转化为一个byte数组 byte[] bs = bao.toByteArray(); // 将byte数组用BASE64加密 String photoStr = Base64.encodeToString(bs, Base64.DEFAULT); // 返回String return photoStr; } }
四、通过Async-Http实现图片上传
public void upload(String url) { // 将bitmap转为string,并使用BASE64加密 String photo = Utils.BitmapToString(bitmap); // 获取到图片的名字 String name = photoPath.substring(photoPath.lastIndexOf("/")).substring(1); // new一个请求参数 RequestParams params = new RequestParams(); // 将图片和名字添加到参数中 params.put("photo", photo); params.put("name", name); AsyncHttpClient client = new AsyncHttpClient(); // 调用AsyncHttpClient的post方法 client.post(url, params, new AsyncHttpResponseHandler() { @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) { Toast.makeText(getApplicationContext(), "上传失败!", Toast.LENGTH_SHORT).show(); } @Override public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { Toast.makeText(getApplicationContext(), "上传成功!", Toast.LENGTH_SHORT).show(); } }); }
服务器端
一、创建一个新的Servlet,在doget方法里面实现
public class UpLoadPhotoServlet extends HttpServlet { /** * */ private static final long serialVersionUID = 1L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); response.setContentType("text/html"); // 获取文件名 String name = request.getParameter("name"); // 获取图片 String photo = request.getParameter("photo"); // 将传进来的图片的string格式进行处理 byte[] bs = new BASE64Decoder().decodeBuffer(photo); // 写到E盘Img文件夹下的a.jpg文件。注:Img文件夹一定要存在 FileOutputStream fos = new FileOutputStream("E:/Img/" + name); fos.write(bs); fos.flush(); fos.close(); PrintWriter writer = response.getWriter(); writer.print("上传成功"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }