关于自定义水印相机(watercamera)的一点心得
本文为原创,转载请声明!
网上有很多自定义相机,但是跟我需要的项目真心不符,所以最后还是只能找了一个(git上面的例子:原本想链接地址的,结果没找到了,是个外国朋友的项目,所以还是用我的吧)过来修改了,还是我一贯的作风,代码中注释说明!
两个类:
第一个类CameraDialog相机
是关于相机的,从调用相机到设计相机参数等,这个类可以随意更改继承fragment或者dialog,关键在于你运用的地方需求了
对了,这个类中有运用了(事件分发),如果需要详细了解的话,请点击郭霖大神的链接
首先,权限声明:
由于我们项目版本支持要求,不能使用camera2, 因此继续沿用camera这个过时的api,第一个是用户使用相机权限,第二个是硬件请求权限,第三个是相机自动对焦权限,第四个是写入SD卡权限。
<!--相机相关权限-->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="true"/>
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
其次,讲讲水印相机的所涉及的一般问题:
一. 水印的添加:关于水印的添加,我主要是以下这种思路,1. 通过方法
mCamera.takePicture(null, null, mPicture);
拍出图片。
我并不想直接利用intent这个方法
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 1);
然后再去处理
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
}
而是采取以Camera.PictureCallback回调方法传回的图片数据(byte[] data)进行转化(转成bitmap)
Camera.PictureCallback mPicture = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
//处理图片数据data
}
再来,就是看几个重要的方法了,输出图片路径方法getOutputMediaFile()
/**
* 设置相片储存目录
* FileUtils 顾名思义是一个用来处理文件的常用工具类,自己定义的
* getStringToday()也是常用时间工具类里面的一个自定义方法
*/
private File getOutputMediaFile() {
File file = FileUtils.setPictureDirectory(mContext);
path = file.getAbsolutePath() + File.separator
+ getStringToday() + ".jpg";
File mediaFile = new File(path);
return mediaFile;
}
/**
* 设置相片目录
* @param context
* @param
* @return
*/
public static File setPictureDirectory(Context context) {
String filePath = setPicturePath(context);
File destDir = new File(filePath);
if (!destDir.exists()) {
boolean isCreate = destDir.mkdirs();
log(filePath + " has created. " + isCreate);
}
return destDir;
}
/**
* 设置图片路径
*
* @param context
* @param
* @return
*/
public static String setPicturePath(Context context) {
String filePath;
// 如SD卡已存在,则存储;反之存在data目录下
if (hasSdcard()) {
// SD卡路径:SD\Picture\AutoCapture 目录下
filePath = Environment.getExternalStorageDirectory() + File.separator +"Picture" + File.separator +"AutoCapture"
// + dirName
;
} else {
filePath = context.getCacheDir().getPath() + File.separator
// + dirName
;
}
/**
* 得到现在时间
* 格式化时间格式为yyyyMMdd_HHmmss
* @return 字符串 yyyyMMdd_HHmmss
*/
public static String getStringToday() {
Date currentTime = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmssSSS");
String dateString = formatter.format(currentTime);
return dateString;
}
然后,就是看另一个重要问题,拍照时,预览界面跟拍照后相片不能正摆问题,有些会倒90度,有些则是-90度,总之就是角度调整方法 setOrientations()
/**
* 解决预览界面跟拍照后相片不能正摆问题
*
*/
private void setOrientations() {
if (mCamera != null) {
Camera.Parameters cameraParameter = mCamera.getParameters();
cameraParameter.setRotation(90);
cameraParameter.set("rotation", 90);
if ((orientations >= 45) && (orientations < 135)) {
cameraParameter.setRotation(180);
cameraParameter.set("rotation", 180);
}
if ((orientations >= 135) && (orientations < 225)) {
cameraParameter.setRotation(270);
cameraParameter.set("rotation", 270);
}
if ((orientations >= 225) && (orientations < 315)) {
cameraParameter.setRotation(0);
cameraParameter.set("rotation", 0);
}
mCamera.setParameters(cameraParameter);
}
}
//当然,在预览界面CameraPreview类中可以通过调用
//mCamera.setDisplayOrientation(90)来改变
//(根据横屏竖屏需求来处理)
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.getParameters().setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
mCamera.setDisplayOrientation(90);
mCamera.startPreview();
} catch (Exception e) {
e.printStackTrace();
}
}
最后就说一说Bitmap.compress(CompressFormat format, int quality, OutputStream stream)这个方法了,通过API源码我们可以知道CompressFormat 一共有三种储存格式
public enum CompressFormat {
JPEG (0),
PNG (1),
WEBP (2);
CompressFormat(int nativeInt) {
this.nativeInt = nativeInt;
}
final int nativeInt;
}
其中 PNG 和WEBP我了解不多,时间需要,也没去深究,但是查阅了很多相关资料才知道:只有Bitmap.CompressFormat格式为JPEG,第二个参数quality才能起作用!这是令我多么悲痛的领悟啊…第三个参数也是很重要的,但是必须通过 ByteArrayOutputStream stream = new ByteArrayOutputStream()来作容器,原理大概是这么讲:Bitmap.compress方法即将数据以jpeg格式压缩,压缩比例为quality,压缩后的数据存入stream。
Camera.PictureCallback mPicture = new Camera.PictureCallback() {
@Override
public