很多APP 都有拍照的需求 但是用户一旦多起来 问题也会比较多 因为拍照会一并跟着压缩 上传甚至会有加水印 兼容问题也随之而来
这里从头到尾讲一下,看看能不能帮到大家:
1 第一个问题是权限问题 毕竟没有权限是没办法做后面的操作的
RxPermissions.getInstance(this)
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA)
.subscribe(new Action1<Boolean>() {
@Override
public void call(Boolean granted) {
if (!granted) {
showToast("请把相机和存储权限打开");
return;
}
File sd = Environment.getExternalStorageDirectory();
String path = sd.getPath() + "/RxjavaImg"; // 在根目录创建一个文件夹来存放图片 可以自己创建
File file = new File(path);
if (!file.exists()) {
file.mkdir();
}
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//打开摄像机列表选项
intent.putExtra("return-data", false);
final Intent intent_camera = getPackageManager().getLaunchIntentForPackage("com.android.camera");
if (intent_camera != null) {
String s = GetAction_image_capture();
int index = s.indexOf("com");
if (index == -1) { //不存在的话 有一些手机 这个会有异常情况 如果没有这个需求的话 可以把setPackage这段注释掉 不影响使用
intent.setPackage("com.android.camera"); // 设置为手机自带的默认拍照软件
} else {
intent.setPackage(s); // 有些手机 并不是com.android.camera 相对比较奇特 所以我用了一个判断前缀应用包名com开头的区分一下
}
}
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(AppConfig.CAMERA_TEMP))); // 里面的AppConfig.CAMERA_TEMP 为保存的文件路径 最后是.jpg的
startActivityForResult(intent, CAMERA);
}
});
这里的操作包括了权限的请求 和最开始的拍照请求 最终图片保存到对应的目录
2 第二个问题就是拍照完后的回调
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA && resultCode == RESULT_OK) {
showLoadingDialog("加载中....");
/**
* 在这里进行回调 有大佬让我全部操作都写一个Rxjava里面 现在还在琢磨
* 这里取到用户拍完照的图片 然后进行压缩 显示
* getCompressPics()是 核心方法 下面会有写 AppConfig.CAMERA_TEMP是原图路径
* */
getCompressPics(AppConfig.CAMERA_TEMP);
}
}
3 第三个 这里应该是核心问题了 图片压缩 打水印 和最后的回传
public void getCompressPics(final String pathString) {
File file = new File(pathString);
final String paths[] = new String[2];
LubanText.get(PhotoBaseActivity3.this)
.load(file)
.putGear(LubanText.THIRD_GEAR)/** 兼容性最好*/
.asObservable()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.map(new Func1<File, File>() {
@Override
public File call(File file) {
/**加水印 这里传的是 文件地址 操作的 都是一样的东西*/
return Watermark(file.getPath(), 80);
}
})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.unsubscribeOn(Schedulers.io())
.doOnError(new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
throwable.printStackTrace();
}
})
.onErrorResumeNext(new Func1<Throwable, Observable<? extends File>>() {
@Override
public Observable<? extends File> call(Throwable throwable) {
// Toast.makeText(mContext, "由于没有读写权限导致无法正常压缩", Toast.LENGTH_SHORT).show();
dismissLoadingDialog(); //取消加载框 不写的话 注释掉就可以了
// String s = "/storage/emulated/0/RxjavaImg/image/2017-07-19/1500447991691.jpg";
onReceiveCamera1(AppConfig.CAMERA_TEMP); // onReceiveCamera1()这个方法是一个回调 把 图片路径返回 回去
return Observable.empty();
}
})
.subscribe(new Action1<File>() {
@Override
public void call(File file) {
LogUtil.e("msg", "file:" + file);
LogUtil.e("msg", file.length() / 1024 + "k");
LogUtil.e("msg",
pach = file + "";
/**处理完之后回调回去 返回给对应的类*/
dismissLoadingDialog(); //取消加载框 不写的话 注释掉就可以了
onReceiveCamera1(pach); // onReceiveCamera1()这个方法是一个回调 把 图片路径返回 回去
}
});
}
回调之后 要干嘛就干嘛了 下面是支持的方法 还有最重要的水印
4 第四个 水印
/***
* 打水印的方法
* 三次修改版
* 1 就是先缩放读取原图,
* 2 然后加水印,
* 3 再生成新的图片文件
*/
private File Watermark(String filePath, int Ratio) {
/**
* 最终保存的图片尺寸
* 宽度 高度 压缩率
* 宽高并不会固定为输入尺寸 只是参考
* 压缩率直接影响 文件大小
* 有问题 直接修改这里的数值!!
* .putGear(LubanText.CUSTOM_GEAR) 这里也有影响
* */
int Width = 720;
int Height = 1280;
int ratio = Ratio;
/**保存的图片名称 记得要创建一下 最终提交的图片 */
String PathName = AppConfig.APP_IMAGE_FOLDER + System.currentTimeMillis() + ".jpg";
File preFile = new File(PathName);
try {
/** 创建一下*/
if (!preFile.exists()) {
preFile.createNewFile();
}
/** 缩放并读取图片文件 质量问题 直接调后面两个长宽度 按照等比 缩放的 所以没问题* */
Bitmap resizedBitmap = BitmapUtilsText.getZoomImage(filePath, Width, Height);
// ImageTool.generatorContactCountIcon 这个是打水印的方法 百度一下 挺多的
if (true || true) {
LogUtil.e("msg", "打水印" + PathName);
isHasWaterMark1 = "2017年12月31日11.11.11";
s = "广州市天河区超级超级美女店!";
resizedBitmap = ImageTool.generatorContactCountIcon(resizedBitmap, this, isHasWaterMark1, s);
}
/**保存操作 这里放的是新地址*/
BufferedOutputStream bos2;
bos2 = new BufferedOutputStream(new FileOutputStream(preFile));
resizedBitmap.compress(Bitmap.CompressFormat.JPEG, ratio, bos2);
LogUtil.e("msg", "file:getWidth" + resizedBitmap.getWidth());
LogUtil.e("msg", "file:getHeight" + resizedBitmap.getHeight());
LogUtil.e("msg", "拍照后保存的图片文件大小" + preFile.length() / 1024 + "kb");
resizedBitmap.recycle();
resizedBitmap = null;
bos2.flush();
bos2.close();
} catch (Exception e) {
LogUtil.e("msg", "添加水印出现异常");
e.printStackTrace();
}
return preFile;
}
5 第5个 支撑上面运行的方法
//获取手机内部原生的应用相机包名
private String GetAction_image_capture() {
String Action_image_capture = "";
Intent infoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
ResolveInfo resolveInfo = getPackageManager().resolveActivity(infoIntent, 0);
if (resolveInfo != null) {
Log.d("PhotoBaseActivity3", "手机默认相机名称为" + resolveInfo.activityInfo.packageName);
Action_image_capture = resolveInfo.activityInfo.packageName;
}
return Action_image_capture;
}
/**
* 接收到相机拍照的图片
*/
protected abstract void onReceiveCamera1(String path);
不知道还有没有遗漏 也就仅供参考罢了 亲自测试了 华为 小米 oppo vivo 努比亚 索尼 乐视 等等几十台手机,还在提高兼容度 有不对的地方 希望大家指出 最后 感谢 浪浪大佬的耐心指导 非常感谢!