用手机拍摄照片,在android6.0以后需要动态获取权限,部分手机还会出现拍摄完后图片旋转90的问题,比如三星、小米有的机型都会旋转。。。拍摄完的照片还需要压缩后才能上传
步骤为:
1,动态权限获取
2,调起相机拍照
3,获取结果判断是否有图片旋转,若存在旋转则按照相应的角度再恢复正常
4,图片压缩,压缩完成,执行上传
1,动态权限获取使用的是Rxpermissions
在app的gradle里:
repositories {
maven { url "https://jitpack.io" }
}
dependencies {
....
implementation 'com.github.tbruyelle:rxpermissions:0.10.2'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
}
2,正式调相机:
private val mRxPermissions by lazy { RxPermissions(this) }
private val mPhotoUtils by lazy { PhotoUtils(this) }
private var picAuthDir: String? = ""
private var auth_idcard_front_path: String = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
picAuthDir = FileUtils.getImageFileDir(this, "AuthPhoto").toString() + File.separator
auth_idcard_front_path = picAuthDir + "idCardFront" + System.currentTimeMillis() + ".png"
}
mRxPermissions.request(Manifest.permission.CAMERA).subscribe(object : Consumer<Boolean> {
override fun accept(t: Boolean) {
if (t) {
openCamera()
} else {
DeviceUtils.openSettingPage(this, 16)
}
}
})
/**
* 开启相机
*/
private fun openCamera() {
mPhotoUtils.openCamera()
mPhotoUtils.setPhotoPathListener(object : PhotoUtils.OnPhotoPathListener {
override fun onGetPath(path: String) {
//※※※※※此时获取到照片的路径,处理照片
rotatePic(path)
}
})
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == PhotoUtils.REQUEST_CAMERA_CODE) {
mPhotoUtils.onAcitivityResult(requestCode, resultCode, data)
}
}
拍照工具类:
/**
* Created by Lyq
* on 2021-04-14
*/
public class PhotoUtils {
public static int PHOTO_CAMERA_CODE = 1; //相机
public static int PHOTO_ALBUM_CODE = 2; //相册
public static int REQUEST_CAMERA_CODE = 3; //相机requestCode
public static int REQUEST_ALBUM_CODE = 4; //相册requestCode
private Activity mActivity;
private int mSelectType;
private String mFilePath;//文件存储路径
private Uri mFileUri;//文件存储uri
public PhotoUtils(Activity activity) {
mActivity = activity;
}
public void setPhotoType(int type, String filePath) {
this.mSelectType = type;
this.mFilePath = filePath;
File outputImage = new File(filePath);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mFileUri = FileProvider.getUriForFile(mActivity, mActivity.getPackageName() + ".fileProvider", outputImage);
} else {
mFileUri = Uri.fromFile(outputImage);
}
}
private OnPhotoPathListener mPhotoPathListener;
public void setPhotoPathListener(OnPhotoPathListener listener) {
this.mPhotoPathListener = listener;
}
public interface OnPhotoPathListener {
void onGetPath(String path);
}
/**
* 相机拍照
*/
public void openCamera() {
try {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
intent.putExtra(MediaStore.EXTRA_OUTPUT, mFileUri);
if (mSelectType == PHOTO_CAMERA_CODE) {
mActivity.startActivityForResult(intent, REQUEST_CAMERA_CODE);
}
} catch (Exception e) {
e.printStackTrace();
ToastUtils.showToastShort(ResourceUtils.getString(R.string.camera_error));
LogUtils.Companion.e(e.toString());
}
}
public void onAcitivityResult(int requestCode,int resultCode,Intent intent){
if (requestCode == REQUEST_CAMERA_CODE) {
if(mPhotoPathListener !=null){
mPhotoPathListener.onGetPath(mFilePath);
}
}
}
}
3,获取路径判断是否有图片旋转,矫正
/**
* 根据旋转角度,把图片旋转回来
*/
private fun rotatePic(path: String) {
Thread(Runnable {
//图片 旋转问题
val bitmapDegree = ImageSelectUtils.getBitmapDegree(path) //小米是90度bug
val bitmap = BitmapFactory.decodeFile(path)
if (bitmap == null) {
return@Runnable
}
val bitmapNew: Bitmap = ImageSelectUtils.rotateBitmapByDegree(bitmap, bitmapDegree)
var filenew: File? = null
try {
if (bitmapNew != null && !TextUtils.isEmpty(path)) {
filenew = ImageSelectUtils.saveAndCoverFile_crm(bitmapNew, path)
}
} catch (e: IOException) {
e.printStackTrace()
}
val msg = Message()
msg.what = 1
val bundle = Bundle()
bundle.putSerializable("rotateFile", filenew)
msg.data = bundle
handler.sendMessage(msg)
}).start()
}
private val handler = object : Handler() {
override fun handleMessage(msg: Message) {
var handlerBundle = Bundle()
when (msg.what) {
1 -> {
handlerBundle = msg.data
if (handlerBundle != null) {
val rotateFile = handlerBundle.getSerializable("rotateFile") as File
//※※※※※,根据旋转完的File压缩图片
condensePic(this,rotateFile,picAuthDir)
}
}
}
}
}
处理图片旋转角度,与矫正工具类ImageSelectUtils:
/**
* Created by Lyq
* on 2021-04-17
*/
public class ImageSelectUtils {
/**
* 读取图片的旋转的角度
*
* @param path 图片绝对路径
* @return 图片的旋转角度
*/
public static int getBitmapDegree(String path) {
int degree = 0;
try {
// 从指定路径下读取图片,并获取其EXIF信息
if (!TextUtils.isEmpty(path)) {
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 bitmap 原始图片
* @param degrees 原始图片的角度
* @return Bitmap 旋转后的图片
*/
public static Bitmap rotateBitmapByDegree(Bitmap bitmap, int degrees) {
if (degrees == 0 || null == bitmap) {
return bitmap;
}
Matrix matrix = new Matrix();
matrix.setRotate(degrees, bitmap.getWidth() / 2, bitmap.getHeight() / 2);
Bitmap bmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
bitmap.recycle();
return bmp;
}
public static File saveAndCoverFile_crm(Bitmap bm, String path) throws IOException {//将Bitmap类型的图片转化成file类型
File dirFile = new File(path);
if (!dirFile.exists()) {
dirFile.mkdir();
}
File myCaptureFile = new File(path);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(myCaptureFile));
bm.compress(Bitmap.CompressFormat.JPEG, 80, bos);
bos.flush();
bos.close();
return myCaptureFile;
}
}
4,图片压缩
压缩图片使用的是luban;
implementation 'com.qiniu:qiniu-android-sdk:7.3.15'
/**
* 压缩
* @param context 上下文
* @param file 要压缩的文件
* @param targetDir 压缩完的目标文件夹
* @param type
* @return
*/
public void condensePic(Context context, File file, String targetDir) {
PicCompressUtils.getInstance().with(context).ignoreBy(100).setTargetDir(targetDir).load(file).setCompressListener(new OnCompressListener() {
@Override
public void onStart() {
}
@Override
public void onSuccess(File file) {
//※※※※※ 压缩成功
//压缩成功 进行上传,是传到自己服务器还是三方
}
@Override
public void onError(Throwable e) {
//※※※※※ 压缩失败
}
}).launch();
封装的压缩工具类:
/**
* Created by Lyq
* on 2021-04-13
*/
public class PicCompressUtils {
private static PicCompressUtils picCompressUtils;
private Luban.Builder builder;
public static synchronized PicCompressUtils getInstance() {
if (picCompressUtils == null) {
picCompressUtils = new PicCompressUtils();
}
return picCompressUtils;
}
public PicCompressUtils with(Context mContext) {
if (mContext != null) {
builder = Luban.with(mContext);
}
return this;
}
public PicCompressUtils load(String path) {
if (builder != null && path != null) {
builder.load(path);
}
return this;
}
public PicCompressUtils load(File file) {
if (builder != null && file != null) {
builder.load(file);
}
return this;
}
public PicCompressUtils load(List<String> list) {
if (builder != null && list != null) {
builder.load(list);
}
return this;
}
public PicCompressUtils load(InputStreamProvider inputStreamProvider) {
if (builder != null && inputStreamProvider != null) {
builder.load(inputStreamProvider);
}
return this;
}
public PicCompressUtils ignoreBy(int size) {
if (builder != null) {
builder.ignoreBy(size);
}
return this;
}
public PicCompressUtils setTargetDir(String path) {
if (builder != null && path != null) {
builder.setTargetDir(path);
}
return this;
}
public PicCompressUtils filter(CompressionPredicate compressionPredicate) {
if (builder != null && compressionPredicate != null) {
builder.filter(compressionPredicate);
}
return this;
}
public PicCompressUtils setCompressListener(OnCompressListener onCompressListener) {
if (builder != null && onCompressListener != null) {
builder.setCompressListener(onCompressListener);
}
return this;
}
public void launch() {
if (builder != null) {
builder.launch();
}
}
}