# SelectPicAndCamera **Repository Path**: forezp/SelectPicAndCamera ## Basic Information - **Project Name**: SelectPicAndCamera - **Description**: No description available - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2018-06-28 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # SelectPicAndCamera 最近做项目需要用到拍照和选择相册照片,并显示出来imageview 上,然后压缩上传到服务器中,这本是一个非常常见的功能,但对于图片的处理确实一个技术活,稍微不注意会出现oom,图片压缩也要处理的刚刚好,不能浪费用户的流量,也不能过分的压缩使图片失真,这真的不简单,好在开源中国的安卓端app以开源,本人特意从开源中国整理了这个demo,分享给大家。 进入相册选择照片:注意6.0之后要申请运行时权限,即api23。 ```java Intent intent; if (Build.VERSION.SDK_INT < 19) { intent = new Intent(); intent.setAction(Intent.ACTION_GET_CONTENT); intent.setType("image/*"); startActivityForResult(Intent.createChooser(intent, "选择图片"), ImageUtils.REQUEST_CODE_GETIMAGE_BYSDCARD); } else { intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); intent.setType("image/*"); startActivityForResult(Intent.createChooser(intent, "选择图片"), ImageUtils.REQUEST_CODE_GETIMAGE_BYSDCARD); } ``` 或者拍照: ``` private void toCamera() { // 判断是否挂载了SD卡 String savePath = ""; String storageState = Environment.getExternalStorageState(); if (storageState.equals(Environment.MEDIA_MOUNTED)) { savePath = Environment.getExternalStorageDirectory() .getAbsolutePath() + "/oschina/Camera/"; File savedir = new File(savePath); if (!savedir.exists()) { savedir.mkdirs(); } } // 没有挂载SD卡,无法保存文件 if (TextUtils.isEmpty(savePath)) { // AppContext.showToastShort("无法保存照片,请检查SD卡是否挂载"); return; } String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); String fileName = timeStamp + ".jpg";// 照片命名 File out = new File(savePath, fileName); Uri uri = Uri.fromFile(out); //tweet.setImageFilePath(savePath + fileName); // 该照片的绝对路径 mPhotoPath=savePath + fileName; Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); startActivityForResult(intent, ImageUtils.REQUEST_CODE_GETIMAGE_BYCAMERA); } ``` 在onActivity获取图片信息: ``` @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode != Activity.RESULT_OK) return; if (requestCode == ImageUtils.REQUEST_CODE_GETIMAGE_BYSDCARD) { if (data == null) return; Uri selectedImageUri = data.getData(); if (selectedImageUri != null) { String path = ImageUtils.getImagePath(selectedImageUri, this); setImageFromPath(path); } } else if (requestCode == ImageUtils.REQUEST_CODE_GETIMAGE_BYCAMERA) { //setImageFromPath(tweet.getImageFilePath()); setImageFromPath(mPhotoPath); } } ``` 通过返回的uri获取图片路径 ``` /** * 通过Uri获取文件路径 * 支持图片媒体,文件等 *

* Author qiujuer@live.cn * * @param uri Uri * @param context Context * @return 文件路径 */ @SuppressLint({"NewApi", "Recycle"}) public static String getImagePath(Uri uri, Context context) { String selection = null; String[] selectionArgs = null; // Uri is different in versions after KITKAT (Android 4.4), we need to if (Build.VERSION.SDK_INT >= 19 && DocumentsContract.isDocumentUri(context.getApplicationContext(), uri)) { String authority = uri.getAuthority(); if ("com.android.externalstorage.documents".equals(authority)) { // isExternalStorageDocument final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); return Environment.getExternalStorageDirectory() + "/" + split[1]; } else if ("com.android.providers.downloads.documents".equals(authority)) { // isDownloadsDocument final String id = DocumentsContract.getDocumentId(uri); uri = ContentUris.withAppendedId( Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); } else if ("com.android.providers.media.documents".equals(authority)) { // isMediaDocument final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; if ("image".equals(type)) { uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; } else if ("video".equals(type)) { uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; } else if ("audio".equals(type)) { uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; } selection = "_id=?"; selectionArgs = new String[]{ split[1] }; } } if ("content".equalsIgnoreCase(uri.getScheme())) { String[] projection = {MediaStore.Images.Media.DATA}; Cursor cursor = null; try { cursor = context.getContentResolver() .query(uri, projection, selection, selectionArgs, null); if (cursor != null) { int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); if (cursor.moveToFirst()) { return cursor.getString(column_index); } } } catch (Exception e) { e.fillInStackTrace(); } finally { if (cursor != null) cursor.close(); } } else if ("file".equalsIgnoreCase(uri.getScheme())) { return uri.getPath(); } return null; } ``` 根据图片地址去获取bitmap这时需要自己传入图片的大小即高度和宽度,根据自己的需求去传。 ``` Bitmap bitmap = BitmapCreate.bitmapFromStream(new FileInputStream(path), 512, 512); ``` 图片压缩 ``` /** * 获取一个指定大小的bitmap
* 实际调用的方法是bitmapFromByteArray(data, 0, data.length, w, h); * * @param is 从输入流中读取Bitmap * @param reqWidth 目标宽度 * @param reqHeight 目标高度 */ public static Bitmap bitmapFromStream(InputStream is, int reqWidth, int reqHeight) { if (reqHeight == 0 || reqWidth == 0) { try { return BitmapFactory.decodeStream(is); } catch (OutOfMemoryError e) { } } byte[] data = FileUtils.input2byte(is); return bitmapFromByteArray(data, 0, data.length, reqWidth, reqHeight); } /** * 获取一个指定大小的bitmap * * @param data Bitmap的byte数组 * @param offset image从byte数组创建的起始位置 * @param length the number of bytes, 从offset处开始的长度 * @param reqWidth 目标宽度 * @param reqHeight 目标高度 */ public static Bitmap bitmapFromByteArray(byte[] data, int offset, int length, int reqWidth, int reqHeight) { if (reqHeight == 0 || reqWidth == 0) { try { return BitmapFactory.decodeByteArray(data, offset, length); } catch (OutOfMemoryError e) { } } BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; options.inPurgeable = true; BitmapFactory.decodeByteArray(data, offset, length, options); options = calculateInSampleSize(options, reqWidth, reqHeight); return BitmapFactory.decodeByteArray(data, offset, length, options); } /** * 图片压缩处理(使用Options的方法) *
* 说明 使用方法: * 首先你要将Options的inJustDecodeBounds属性设置为true,BitmapFactory.decode一次图片 。 * 然后将Options连同期望的宽度和高度一起传递到到本方法中。 * 之后再使用本方法的返回值做参数调用BitmapFactory.decode创建图片。 *
* 说明 BitmapFactory创建bitmap会尝试为已经构建的bitmap分配内存 * ,这时就会很容易导致OOM出现。为此每一种创建方法都提供了一个可选的Options参数 * ,将这个参数的inJustDecodeBounds属性设置为true就可以让解析方法禁止为bitmap分配内存 * ,返回值也不再是一个Bitmap对象, 而是null。虽然Bitmap是null了,但是Options的outWidth、 * outHeight和outMimeType属性都会被赋值。 * * @param reqWidth 目标宽度,这里的宽高只是阀值,实际显示的图片将小于等于这个值 * @param reqHeight 目标高度,这里的宽高只是阀值,实际显示的图片将小于等于这个值 */ public static BitmapFactory.Options calculateInSampleSize( final BitmapFactory.Options options, final int reqWidth, final 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的值,这样可以保证最终图片的宽和高 // 一定都会大于等于目标的宽和高。 inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; } // 设置压缩比例 options.inSampleSize = inSampleSize; options.inJustDecodeBounds = false; return options; } ``` 将压缩后的bitmap存在sdcard中,待会儿要上传到服务器中。 ``` /** * 图片写入文件 * * @param bitmap * 图片 * @param filePath * 文件路径 * @return 是否写入成功 */ public static boolean bitmapToFile(Bitmap bitmap, String filePath) { boolean isSuccess = false; if (bitmap == null) { return isSuccess; } File file = new File(filePath.substring(0, filePath.lastIndexOf(File.separator))); if (!file.exists()) { file.mkdirs(); } OutputStream out = null; try { out = new BufferedOutputStream(new FileOutputStream(filePath), 8 * 1024); isSuccess = bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); } catch (FileNotFoundException e) { e.printStackTrace(); } finally { closeIO(out); } return isSuccess; } ``` 将压缩后的bitmap 根据需求进一步缩放,显示在imageview上。 ``` /** * 放大缩小图片 * * @param bitmap * @param w * @param h * @return */ public static Bitmap zoomBitmap(Bitmap bitmap, int w, int h) { Bitmap newbmp = null; if (bitmap != null) { int width = bitmap.getWidth(); int height = bitmap.getHeight(); Matrix matrix = new Matrix(); float scaleWidht = ((float) w / width); float scaleHeight = ((float) h / height); matrix.postScale(scaleWidht, scaleHeight); newbmp = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true); } return newbmp; } ``` 在拍照的过程中,有的机型照片会倒转,这是需要处理一下即可 ``` /** * 读取图片属性:旋转的角度 * @param path 图片绝对路径 * @return degree旋转的角度 */ public static int readPictureDegree(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 (IOException e) { e.printStackTrace(); } return degree; } /** * 旋转图片 * @param angle * @param bitmap * @return */ public static Bitmap rotaingImageView(int angle , Bitmap bitmap) { //旋转图片 动作 Matrix matrix = new Matrix(); matrix.postRotate(angle); System.out.println("angle2=" + angle); // 创建新的图片 Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); return resizedBitmap; } ``` 这些代码百分之七八十来自开源中国。感谢原作者。 [源码下载](https://github.com/forezp/SelectPicAndCamera)