很多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 努比亞 索尼 樂視 等等幾十臺手機,還在提高兼容度 有不對的地方 希望大家指出 最后 感謝 浪浪大佬的耐心指導 非常感謝!