Android对图片常用(拍照,图库,拖拉,压缩上传)操作
2016-11-13 21:47
597 查看
本篇博客内容:
android app拍照功能
部分手机上拍照图片旋转问题
android图库获取图片功能
查看图片,进行缩放,拖拉功能
压缩图片,上传功能
Android 拍照功能:
一般的拍照功能是调用系统中相机来实现,即通过Intent来调用其他运用程序(相机运用程序)来实现。众所周知,通过Intent调用手机上的其他运用程序,都应该先检查手机上是否装有能Intent开启的其他程序。代码如下:
从代码可知,调用开启相机是通过startActivityForResult(), 那返回的是什么呢?
一个压缩后的Bitmap,还是一个图片的path. ?以上代码产生的是一个系统压缩后返回的Bitmap。在onActivityResult()中Intent#Bundle,Bundle中data(key)对应的值(value).
一个系统压缩后的Bitmap实际作用不大,适合做一个图标。 若是需要按尺寸来加载图片,然后将图片压缩上传,利用以上代码是完全行不通的。 这时候,便需要知道相机拍照产生的原始图片的Path,根据path来实现项目需求。
实际开发中,会指定图片的路径,即图片产生到指定文件下,且指定图片格式为.png 。将图片存储路径通过Intent#putExtra()告诉系统。
向sd-card写入信息,权限是少不了的:
在onActivityResult中获取拍照成功的标示,这里系统将不会返回有任何数据,这时候需要自己开启异步线程去按适屏计算加载图片:
高效和快速加载图片,请参考 Android高效加载Bitmap
部分手机上回遇到图片旋转问题,这时候需要使用到ExifInterface这类,手动回复图片原本方向:
最后创建一个主线程捆绑的Handler,进行加载适屏处理后的bitmap:
拍照效果如下:
1.选择拍照功能:
2.相机运用进行拍照:
3.加载拍照产生的图片:
android图库获取图片功能
获取图库中相片,也是通过Intent来开启图库运用来实现的。
在 onActivityResult中接收图库返回的信息,这里是返回一个Uri。
根据Uri来查询图库的数据库,找到图片路径,从而加载图片:
最后创建一个主线程捆绑的Handler,进行加载图库选中的bitmap:
效果如下:
1.在图库中选中图片:
2.加载选中的图片 :
android 查看图片,进行缩放,拖拉功能
1.首先加载适屏的图片,通过设置Matrix 来,放置到中间:
2.进行设置缩放,和拖拉的功能代码:
先实现 View.OnTouchListener类,复写onTouch(View v, MotionEvent event)方法。
效果如下:
这里没有制作gif来显示效果,感兴趣的可以下载项目来体验效果:
android 压缩图片
现在的手机拍照产生的相片都了几M,甚至可能是5M多,上传到服务器是不会上传那么大的图片的。这边需要用到压缩。
压缩图片一般通过Bitmap#compress()来实现的。 一般都是通过for循环来计算最小压缩体积:
这里是将Bitmap按最小体积量来压缩成byte[]来上传的。
经过测试发现,若是一个几M的图片进行这样的压缩处理,时间花费是很久的,甚至可能是几分钟时间。
这里的的处理方式是:按上传的体积量来计算出图片的分辨率,按这个分辨率来加载适合的图片,然后将这个图片再来编码成byte[]
最后将图片对应的byte[]通过volley中自定义的MultiPartRequest上传:
效果图在 Volley源码分析之自定义MultiPartRequest(文件上传)案例中
项目代码:http://download.csdn.net/detail/hexingen/9681762
相关知识点:
Volley源码分析之自定义MultiPartRequest(文件上传)
android app拍照功能
部分手机上拍照图片旋转问题
android图库获取图片功能
查看图片,进行缩放,拖拉功能
压缩图片,上传功能
Android 拍照功能:
一般的拍照功能是调用系统中相机来实现,即通过Intent来调用其他运用程序(相机运用程序)来实现。众所周知,通过Intent调用手机上的其他运用程序,都应该先检查手机上是否装有能Intent开启的其他程序。代码如下:
//MediaStore.ACTION_IMAGE_CAPTURE开启手机中相机 Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); //检查手机上是否装有Intent对应开启的程序 if (intent.resolveActivity(getPackageManager()) != null) { startActivityForResult(intent, requestCode); } }
从代码可知,调用开启相机是通过startActivityForResult(), 那返回的是什么呢?
一个压缩后的Bitmap,还是一个图片的path. ?以上代码产生的是一个系统压缩后返回的Bitmap。在onActivityResult()中Intent#Bundle,Bundle中data(key)对应的值(value).
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) { Bundle extras = data.getExtras(); Bitmap imageBitmap = (Bitmap) extras.get("data"); mImageView.setImageBitmap(imageBitmap); } }
一个系统压缩后的Bitmap实际作用不大,适合做一个图标。 若是需要按尺寸来加载图片,然后将图片压缩上传,利用以上代码是完全行不通的。 这时候,便需要知道相机拍照产生的原始图片的Path,根据path来实现项目需求。
实际开发中,会指定图片的路径,即图片产生到指定文件下,且指定图片格式为.png 。将图片存储路径通过Intent#putExtra()告诉系统。
private String imagePath1; /** * 打开相机 */ public void openCamera(int requestCode) { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (intent.resolveActivity(getPackageManager()) != null) { File bitmapCacheFile = BitmapUtils.getBitmapDiskFile(BaseApplication.getAppContext()); if (bitmapCacheFile != null) { imagePath1 = bitmapCacheFile.getAbsolutePath(); //指定拍照存储路径 intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(bitmapCacheFile)); startActivityForResult(intent, requestCode); } } } /** * 获得存储bitmap的文件 * getExternalFilesDir()提供的是私有的目录,在app卸载后会被删除 * * @param context * @param * @return */ public static File getBitmapDiskFile(Context context) { String cachePath; if (Environment.MEDIA_MOUNTED.equals(Environment .getExternalStorageState()) || !Environment.isExternalStorageRemovable()) { cachePath = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES).getPath(); } else { cachePath = context.getFilesDir().getPath(); } return new File(cachePath + File.separator + getBitmapFileName()); } public static final String bitmapFormat = ".png"; /** * 生成bitmap的文件名:日期,md5加密 * * @return */ public static String getBitmapFileName() { StringBuilder stringBuilder = new StringBuilder(); try { final MessageDigest mDigest = MessageDigest.getInstance("MD5"); String currentDate = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); mDigest.update(currentDate.getBytes("utf-8")); byte[] b = mDigest.digest(); for (int i = 0; i < b.length; ++i) { String hex = Integer.toHexString(0xFF & b[i]); if (hex.length() == 1) { stringBuilder.append('0'); } stringBuilder.append(hex); } } catch (Exception e) { e.printStackTrace(); } String fileName = stringBuilder.toString() + bitmapFormat; return fileName; }
向sd-card写入信息,权限是少不了的:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
在onActivityResult中获取拍照成功的标示,这里系统将不会返回有任何数据,这时候需要自己开启异步线程去按适屏计算加载图片:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == CAREMA) { if (resultCode == RESULT_OK) { //开启工作线程去加载,拍照产生的图片 new Thread(loadBitmapRunnable).start(); } } } /** * 根据path路径,找到file,从而生成bitmap */ private Runnable loadBitmapRunnable = new Runnable() { @Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); try { Thread.sleep(500); Bitmap bitmap = BitmapUtils.decodeFileCreateBitmap(imagePath1 , iv.getWidth(), iv.getHeight()); handler.obtainMessage(CAREMA, bitmap).sendToTarget(); } catch (Exception e) { e.printStackTrace(); } } }; public synchronized static Bitmap decodeFileCreateBitmap(String path, int targetWith, int targerHeight) { try { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(path, options); options.inSampleSize = calculateScaleSize(options, targetWith, targerHeight); options.inJustDecodeBounds = false; Bitmap bitmap = BitmapFactory.decodeFile(path, options); return getNormalBitamp(bitmap, path); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 采用向上取整的方式,计算压缩尺寸 * * @param options * @param targetWith * @param targerHeight * @return */ private static int calculateScaleSize(BitmapFactory.Options options, int targetWith, int targerHeight) { int simpleSize; if (targetWith > 0&&targerHeight>0) { int scaleWith = (int) Math.ceil((options.outWidth * 1.0f) / targetWith); int scaleHeight = (int) Math.ceil((options.outHeight * 1.0f) / targerHeight); simpleSize = Math.max(scaleWith, scaleHeight); } else { simpleSize = 1; } return simpleSize; }
高效和快速加载图片,请参考 Android高效加载Bitmap
部分手机上回遇到图片旋转问题,这时候需要使用到ExifInterface这类,手动回复图片原本方向:
/** * 根据存储的bitamp中旋转角度,来创建正常的bitamp * * @param bitmap * @param path * @return */ public static Bitmap getNormalBitamp(Bitmap bitmap, String path) { int rotate = getBitmapRotate(path); Bitmap normalBitmap=null; switch (rotate) { case 90: case 180: case 270: try { Matrix matrix = new Matrix(); matrix.postRotate(rotate); normalBitmap = bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth() , bitmap.getHeight(), matrix, true); if (bitmap != null && !bitmap.isRecycled()) { bitmap.recycle(); } } catch (Exception e) { e.printStackTrace(); normalBitmap=bitmap; } break; default: normalBitmap=bitmap; break; } return normalBitmap; } /** * ExifInterface :这个类为jpeg文件记录一些image 的标记 * 这里,获取图片的旋转角度 * * @param path * @return */ public static int getBitmapRotate(String path) { int degree = 0; try { ExifInterface exifInterface = new ExifInterface(path); int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION , ExifInterface.ORIENTATION_NORMAL); switch (orientation) { case ExifInterface.ORIENTATION_ROTATE_90: degree = 90; break; case ExifInterface.ORIENTATION_ROTATE_180: degree = 180; break; case ExifInterface.ORIENTATION_ROTATE_270: degree = 270; break; } } catch (Exception e) { e.printStackTrace(); } return degree; }
最后创建一个主线程捆绑的Handler,进行加载适屏处理后的bitmap:
private Handler handler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { if (msg.what == CAREMA) { if (msg.obj instanceof Bitmap) { iv.setImageBitmap((Bitmap) msg.obj); } } return false; } });
拍照效果如下:
1.选择拍照功能:
2.相机运用进行拍照:
3.加载拍照产生的图片:
android图库获取图片功能
获取图库中相片,也是通过Intent来开启图库运用来实现的。
/** * 打开图库 */ public void openMapStorage(int requestCode) { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("image/*"); if (intent.resolveActivity(getPackageManager()) != null) { startActivityForResult(intent, requestCode); } }
在 onActivityResult中接收图库返回的信息,这里是返回一个Uri。
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == PHOTO) { if (resultCode == RESULT_OK) { uri = data.getData(); new Thread(loadUriCreateBitmapRunnable).start(); } } }
根据Uri来查询图库的数据库,找到图片路径,从而加载图片:
/** * 根据Uri,查询到path,找到对应的file,生成bitmap */ private Runnable loadUriCreateBitmapRunnable = new Runnable() { @Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); Cursor cursor = null; try { Thread.sleep(500); if (uri != null) { cursor = getContentResolver().query(uri, new String[]{MediaStore.Images.Media.DATA}, null, null, null); if (cursor != null && cursor.moveToFirst()) { imagePath1 = cursor.getString( cursor.getColumnIndex(MediaStore.Images.Media.DATA)); if (imagePath1 != null) { Bitmap bitmap = BitmapUtils.decodeFileCreateBitmap(imagePath1, iv.getWidth(), iv.getHeight()); handler.obtainMessage(CAREMA, bitmap).sendToTarget(); } } } } catch (Exception e) { e.printStackTrace(); } finally { if (cursor != null) { cursor.close(); } } } };
最后创建一个主线程捆绑的Handler,进行加载图库选中的bitmap:
private Handler handler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { if (msg.what == CAREMA) { if (msg.obj instanceof Bitmap) { iv.setImageBitmap((Bitmap) msg.obj); } } return false; } });
效果如下:
1.在图库中选中图片:
2.加载选中的图片 :
android 查看图片,进行缩放,拖拉功能
1.首先加载适屏的图片,通过设置Matrix 来,放置到中间:
private Runnable loadBitmapRunnable = new Runnable() { @Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); try { Thread.sleep(500); Bitmap bitmap = BitmapUtils.decodeFileCreateBitmap(path , toucher_iv.getWidth(), toucher_iv.getHeight()); handler.obtainMessage(0, bitmap).sendToTarget(); } catch (Exception e) { e.printStackTrace(); } } }; //记录当前图片的Matrix private Matrix beforeMatrix = new Matrix(); private Handler handler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { if (msg.what == 0) { bitmap = (Bitmap) msg.obj; if (bitmap == null) { return false; } float y = ((getPhoneMetrics(BaseApplication.getAppContext()).heightPixels - bitmap.getHeight()) / 2); if (y > 0) { beforeMatrix.setTranslate(0, y); toucher_iv.setImageMatrix(beforeMatrix); } toucher_iv.setImageBitmap(bitmap); } return false; } });
2.进行设置缩放,和拖拉的功能代码:
先实现 View.OnTouchListener类,复写onTouch(View v, MotionEvent event)方法。
//记录当前图片的Matrix private Matrix beforeMatrix = new Matrix(); //改变状态后的Matrix private Matrix changeMatrix = new Matrix(); //记录当前图片处于的状态 private int currentState = 0;//当前状态 private final static int MOVE = 1;//拖动 private final static int SCALLE = 2;//缩放 //记录两个坐标(float类型) private PointF before_PointF = new PointF(); //记录下一开两个手指间的距离: private float before_Distance; //记录下开始时,两个手指间的中心点 private PointF midPointf; /** * 1.拖动分析: * 在原本Matrix基础上添加移动的x,y距离,实现拖动 * 做法:先记录开始的Matrix1, * 然后计算移动的x,y, * 创建一个以Matrix1为基础的新的Matrix2,添加移动的x,y * 图片设置新的Matrix2 * <p/> * <p/> * 2.缩放分析: * 先记录中心点(缩放,旋转都需要用到),原本的Matrix,原本手指间距离,通过距离比率来设置 * * @param v * @param event * @return */ @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction() & MotionEvent.ACTION_MASK) { //手指压下屏幕 case MotionEvent.ACTION_DOWN: currentState = MOVE; beforeMatrix.set(toucher_iv.getImageMatrix()); before_PointF.set(event.getX(), event.getY()); break; //手指在滑动 case MotionEvent.ACTION_MOVE: if (currentState == MOVE) {//拖动状态 float distance_x = event.getX() - before_PointF.x; float ditance_y = event.getY() - before_PointF.y; changeMatrix.set(beforeMatrix); changeMatrix.postTranslate(distance_x, ditance_y); } else if (currentState == SCALLE) {//缩放状态 float endDistance = distance(event); if (endDistance > 10f) { float scale = endDistance / before_Distance; changeMatrix.set(beforeMatrix); changeMatrix.postScale(scale, scale, midPointf.x, midPointf.y); } } break; //手指离开触摸 case MotionEvent.ACTION_UP: currentState = 0; break; //多一个手指在触摸 case MotionEvent.ACTION_POINTER_DOWN: currentState = SCALLE; //开始时,两个手指间距离 before_Distance = distance(event); if (before_Distance > 10f) { midPointf = mid(event); beforeMatrix.set(toucher_iv.getImageMatrix()); } break; //还有手指在触摸 case MotionEvent.ACTION_POINTER_UP: currentState = 0; break; } toucher_iv.setImageMatrix(changeMatrix); return true; } /** * 计算两个手指间的距离 */ private float distance(MotionEvent event) { float dx = event.getX(1) - event.getX(0); float dy = event.getY(1) - event.getY(0); /** 使用勾股定理返回两点之间的距离 */ return (float) Math.sqrt(dx * dx + dy * dy); } /** * 计算两个手指间的中间点 */ private PointF mid(MotionEvent event) { float midX = (event.getX(1) + event.getX(0)) / 2; float midY = (event.getY(1) + event.getY(0)) / 2; return new PointF(midX, midY); }
效果如下:
这里没有制作gif来显示效果,感兴趣的可以下载项目来体验效果:
android 压缩图片
现在的手机拍照产生的相片都了几M,甚至可能是5M多,上传到服务器是不会上传那么大的图片的。这边需要用到压缩。
压缩图片一般通过Bitmap#compress()来实现的。 一般都是通过for循环来计算最小压缩体积:
这里是将Bitmap按最小体积量来压缩成byte[]来上传的。
public static byte[] bitmapCompressToByteArray(Bitmap bitmap, int bitmapSize, boolean isRecycle) { int quality = 100;//范围0~100 ByteArrayOutputStream byteArrayOutputStream = null; try { byteArrayOutputStream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG,quality,byteArrayOutputStream); while (byteArrayOutputStream.toByteArray().length/1024>bitmapSize){ if(quality<=10){ break; } byteArrayOutputStream.reset(); quality-=10; bitmap.compress(Bitmap.CompressFormat.PNG,quality,byteArrayOutputStream); } byte[] b = byteArrayOutputStream.toByteArray(); if (isRecycle) { bitmap.recycle(); } return b; } catch (Exception e) { e.printStackTrace(); return null; } finally { try { if (byteArrayOutputStream != null) { byteArrayOutputStream.close(); } } catch (Exception e1) { e1.printStackTrace(); } } }
经过测试发现,若是一个几M的图片进行这样的压缩处理,时间花费是很久的,甚至可能是几分钟时间。
这里的的处理方式是:按上传的体积量来计算出图片的分辨率,按这个分辨率来加载适合的图片,然后将这个图片再来编码成byte[]
/** * 将bitmap编码成byte[] */ private Runnable bitmapEndecodeByteRunnable = new Runnable() { @Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); try { //这里是250*250大小的图片 byte[] b = BitmapUtils.bitmapCompressToByteArray( BitmapUtils.decodeFileCreateBitmap(imagePath1 , 250, 250), 200, true); handler.obtainMessage(FILEUPLOAD, b).sendToTarget(); } catch (Exception e) { e.printStackTrace(); } } };
最后将图片对应的byte[]通过volley中自定义的MultiPartRequest上传:
private Handler handler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { if (msg.what == FILEUPLOAD) { byte[] b = (byte[]) msg.obj; if (b != null) { sendFileUploadRequest(b); } } return false; } }); /** * 将bitmap编码成byte[],然后上传到服务器 * * @param bitmap */ public void sendFileUploadRequest(byte[] bitmap) { System.out.print("开始上传"); MultiPartRequest<JsonBean> request = new MultiPartRequest<>(Request.Method.POST, "http://192.168.1.102:8080/SSMProject/file/fileUpload", JsonBean.class, new Response.Listener<JsonBean>() { @Override public void onResponse(JsonBean jsonBean) { path_tv.setText("bitmap存储在:"+jsonBean.path); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { Toast.makeText(MultiPartRequestActivity.this, volleyError.getMessage(), Toast.LENGTH_LONG).show(); } }); request.addFile(bitmap); request.setRetryPolicy(new DefaultRetryPolicy(50000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT)); request.setTag(TAG); VolleySingleton.getInstance().addToRequestQueue(request); }
效果图在 Volley源码分析之自定义MultiPartRequest(文件上传)案例中
项目代码:http://download.csdn.net/detail/hexingen/9681762
相关知识点:
Volley源码分析之自定义MultiPartRequest(文件上传)
相关文章推荐
- Android拍照得到全尺寸图片并进行压缩/拍照或者图库选择 压缩后 图片 上传
- android 拍照或者图库选择 压缩后 图片 上传
- android 类似于微博拍照上传,压缩图片,避免oom
- Android手机拍照,相册拿取图片,压缩上传,7.0权限
- android 手机拍照上传项目的开发-----Camera1.2(图片文件的翻转及缩放操作)
- Android部分手机拍照上传返回为空处理,和拍照后图片压缩后保存到指定路径下
- Android调用系统相机、图库、裁剪图片并压缩上传(适配7.0)
- Android调用系统相机、图库、裁剪图片并压缩上传(适配7.0)
- Android:Camera的使用,并处理手机拍照后上传图片被旋转的问题
- android 手机拍照上传项目的开发-----JAVA利用socket传图片给linux服务器
- android选择图片或拍照图片上传到服务器(包括上传参数)
- Android如何实现压缩图片后再上传至服务器
- android选择图片或拍照图片上传到服务器(包括上传参数)
- 解决android有的手机拍照后上传图片被旋转的问题
- 解决android有的手机拍照后上传图片被旋转的问题
- android图片的上传、下载和一些缩放操作
- Android上传头像,图片剪裁,压缩图片
- Android上传头像,图片剪裁,压缩图片
- 解决android有的手机拍照后上传图片被旋转的问题
- 解决android有的手机拍照后上传图片被旋转的问题