android之利用surfaceView实现自定义水印相机

知识点

1、自定义相机+预览相机

2、截屏拍照加水印

3、关于不使用intent来传输图片

4、关于大家说要demo的,因为这里是项目里头的,不方便弄出来,大家可以直接复制代码过去,就差不多的了。

俗话说,有图有真相。很多人都是喜欢直接看图,不像我,比较喜欢文字多点,经常看看散文什么的陶冶一下情操。

好了,说到这里,就引出我们今天要做的这个功能,那就是水印相机。水印相机说白了,就是在拍照的图片上面加上自己想要的各种信息,包括文字,图片或者其它你想要的信息。

在这里,我自己定义了一个类WaterCameraActivity,是自定义的相机的,然后还有一个类ViewPhoto,是用来查看你拍照后的图片的,有使用图片和取消/重新拍照功能。

3、关于不使用intent来传输图片

因为intent最大的传输数据为1m,一张图片随便都有3,4m,再加之读取到内存中,就可能变成2倍3倍大了,很容易造成oom。所以我们还是利用本地储存来进行,只要传输一个路径就OK了,这样做的问题就是,老是要读取本地图片,性能不是很好呢。关于这个,如果各位有好的建议可以提出来一起探讨。

下面我们直接上代码,毕竟还是代码说事比较清楚,代码里面都注释好了,各位可以认真去看。

WaterCameraActivity的布局:布局很简单,就是一个SurfaceView+需要加入的水印信息,如下图

布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><!--这是用来预览相机的空间,大家可以去好好了解一下,这里我就不详细讲了--><SurfaceViewandroid:id="@+id/sfv_camera"android:layout_width="match_parent"android:layout_height="match_parent" /><!--想要的信息放在surfaceview之上就OK了,下面是我想要加入的信息--><RelativeLayoutandroid:id="@+id/rl_setting"android:layout_width="match_parent"android:layout_height="60dp"android:background="@null"android:gravity="center_vertical"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:layout_marginLeft="5dp"android:orientation="vertical"><TextViewandroid:id="@+id/tv_time"android:layout_width="wrap_content"android:layout_height="wrap_content"android:shadowColor="#000"android:shadowDx="3"android:shadowDy="3"android:shadowRadius="2"android:text="08:27"android:textColor="#fff"android:textSize="25sp" /><TextViewandroid:id="@+id/tv_date"android:layout_width="wrap_content"android:layout_height="wrap_content"android:shadowColor="#000"android:shadowDx="3"android:shadowDy="3"android:shadowRadius="2"android:text="2016/07/24"android:textColor="#fff"android:textSize="15sp" /></LinearLayout><ImageButtonandroid:id="@+id/imgvBtn_switchFlash"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_marginRight="20dp"android:background="@null"android:paddingLeft="10dp"android:paddingRight="10dp" /><ImageButtonandroid:id="@+id/imgvBtn_switchCamera"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_marginRight="20dp"android:background="@null"android:paddingLeft="10dp"android:paddingRight="10dp"android:visibility="gone" /></RelativeLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:layout_marginBottom="75dp"android:layout_marginRight="3dp"android:gravity="right"android:orientation="vertical"><TextViewandroid:id="@+id/tv_operation"style="@style/textView_water"android:drawableLeft="@drawable/operation"android:text="点击操作" /><TextViewandroid:id="@+id/tv_username"style="@style/textView_water"android:drawableLeft="@drawable/user_icon"android:text="钓鱼的小木匠" /><TextViewandroid:id="@+id/tv_address"style="@style/textView_water"android:drawableLeft="@drawable/address"android:text="广东省惠州市惠城区鹅岭南路6号TCL工业大厦" /></LinearLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="75dp"android:layout_alignParentBottom="true"android:layout_gravity="center_vertical"><!--android:background="@drawable/take_photo_selector"定义一个根据点击状态改变的xml文件--><ImageButtonandroid:id="@+id/btn_takePic"android:layout_width="64dp"android:layout_height="64dp"android:layout_centerInParent="true"android:background="@drawable/take_photo_selector" /><Buttonandroid:id="@+id/imgvBtn_back"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_marginLeft="20dp"android:background="@null"android:text="取 消"android:textColor="#0f0"android:textSize="20sp" /></RelativeLayout></RelativeLayout></RelativeLayout>

WaterCameraActivity类

/*** 启动自定义水印相机** Created by tanksu on 16/6/28.*/
public class WaterCameraActivity extends BaseActivity implements SurfaceHolder.Callback {private Context mContext;private SurfaceView mSurfaceView;private ImageButton imgvBtn_takePic, imgvBtn_switchFlash, imgvBtn_switchCamera;private Button btn_back;private TextView tv_time, tv_username, tv_address, tv_date, tv_operation;private SurfaceHolder mSurfaceHolder;private Camera mCamera;private String curDate = "", curTime = "", curAddress = "", userName = "", userOperation = "";private final int REQUEST_CODE = 1001;private Camera.CameraInfo cameraInfo = new Camera.CameraInfo();private int mCameraId;private long currentTimeMillis = 0;private Intent waterIntent;/*** 这是点击surfaceview聚焦所调用的方法*/private Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback(){@Overridepublic void onAutoFocus(boolean success, Camera camera) {//success = true,聚焦成功,否则聚焦失败//在这里我们可以在点击相机后是否聚焦成功,然后做我们的一些操作,这里我就省略了,大家自行根据需要添加}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.watercamera_layout);initViews();initData();initListener();}/*** 初始化控件*/private void initViews() {mSurfaceView = (SurfaceView) findViewById(R.id.sfv_camera);imgvBtn_takePic = (ImageButton) findViewById(R.id.btn_takePic);tv_time = (TextView) findViewById(R.id.tv_time);tv_username = (TextView) findViewById(R.id.tv_username);tv_address = (TextView) findViewById(R.id.tv_address);tv_date = (TextView) findViewById(R.id.tv_date);tv_operation = (TextView) findViewById(R.id.tv_operation);imgvBtn_switchFlash = (ImageButton) findViewById(R.id.imgvBtn_switchFlash);imgvBtn_switchFlash.setImageResource(R.drawable.camera_setting_flash_off_normal);imgvBtn_switchCamera = (ImageButton) findViewById(R.id.imgvBtn_switchCamera);imgvBtn_switchCamera.setImageResource(R.drawable.changing_camera_normal);btn_back = (Button) findViewById(R.id.imgvBtn_back);mContext = this;}/*** 初始化数据*/private void initData() {mSurfaceView.setFocusable(true);mSurfaceHolder = mSurfaceView.getHolder();mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);mSurfaceHolder.setKeepScreenOn(true);mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);mSurfaceHolder.addCallback(this);SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd"); //获取当前时间,作为图片的命名,再转换为常用时间格式currentTimeMillis = System.currentTimeMillis();curDate = formatter.format(currentTimeMillis);tv_date.setText(curDate);SimpleDateFormat format = new SimpleDateFormat("HH:mm", Locale.getDefault()); //获取24小时制的时间curTime = format.format(currentTimeMillis);tv_time.setText(curTime);Intent intent = getIntent(); //我写的这个类,是要用startActivityForResult来启动的,传入的参数可以根据自己需求来定,我这里传过来的信息有//地址CUR_ADDRESS,用户名USER_NAME,用户操作USER_OPERATION,然后把信息设置到空间里面去,同时还要保存intent。//而时间和日期,则是在本类中自己获取,同样设置入控件里面去if (intent != null) {waterIntent = intent;curAddress = intent.getStringExtra(StaticParam.CUR_ADDRESS);userName = intent.getStringExtra(StaticParam.USER_NAME);userOperation = intent.getStringExtra(StaticParam.USER_OPERATION);tv_operation.setText(userOperation);tv_address.setText(curAddress);tv_username.setText(userName);}else {toast("intent equals null,please try again!");}mCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;}/*** 初始化监听器*/private void initListener() {//这个方法是点击拍照的方法imgvBtn_takePic.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mCamera.takePicture(null, null, new PicCallBacKImpl(WaterCameraActivity.this));}});//设置闪光灯的模式,有禁止,自动和打开闪光灯三种模式imgvBtn_switchFlash.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {CameraUtil.setFlashMode(mCamera, imgvBtn_switchFlash);}});//这个是切换前后摄像头的操作,因为时间关系没有做imgvBtn_switchCamera.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {}});//取消按钮,finish本页面btn_back.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {WaterCameraActivity.this.finish();}});mSurfaceView.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {mCamera.autoFocus(autoFocusCallback); //设置相机为自动对焦模式,就不用认为去点击了return false;}});}/*** 我们在此周期方法里面打开摄像头*/@Overrideprotected void onStart() {if (this.checkCameraHardware(this) && (mCamera == null)) {openCamera();//打开后置摄像头}super.onStart();}/*** 拍照回调类*/class PicCallBacKImpl implements Camera.PictureCallback {private Activity mActivity;public PicCallBacKImpl(Activity activity) {this.mActivity = activity;}@Overridepublic void onPictureTaken(byte[] data, Camera camera) {Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);bitmap = ImageUtil.matrixImageView(bitmap, 90);String path = ImageUtil.saveBitmap(null, String.valueOf(currentTimeMillis), bitmap);if (path != null && path.length() > 0) {waterIntent.setClass(mActivity, ViewPhoto.class);waterIntent.putExtra(StaticParam.PIC_PATH, path);waterIntent.putExtra(StaticParam.CUR_DATE, curDate);waterIntent.putExtra(StaticParam.CUR_TIME, curTime);waterIntent.putExtra(StaticParam.CUR_TIME_MILLIS, currentTimeMillis);mActivity.startActivityForResult(waterIntent, REQUEST_CODE);} else {toast("can't save the picture");camera.stopPreview();camera.release();camera = null;}}}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {if(RESULT_OK == resultCode){switch (requestCode){case REQUEST_CODE: //处理返回结果setResult(RESULT_OK, data); //将结果直接给设置为,启动水印相机的返回结果break;default:break;}WaterCameraActivity.this.finish();//结束本页面,就会将结果返回到调用本页的那个activity了}super.onActivityResult(requestCode, resultCode, data);}@Overridepublic void surfaceCreated(SurfaceHolder holder) {try {mCamera = Camera.open(mCameraId);Camera.getCameraInfo(mCameraId, cameraInfo);} catch (Exception e) {e.printStackTrace();}}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {startPreview(mCamera, mSurfaceHolder);}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {if (mCamera != null) {mCamera.stopPreview();mCamera.release();mCamera = null;}}/*** 检查设备是否有摄像头** @param context context* @return boolean*/private boolean checkCameraHardware(Context context) {if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {return true;}return false;}/*** 打开后置摄像头*/private void openCamera() {Camera.CameraInfo cameraInfo = new Camera.CameraInfo();Camera.getCameraInfo(mCameraId, cameraInfo);this.cameraInfo = cameraInfo;if (mCameraId == Camera.CameraInfo.CAMERA_FACING_BACK) { //后置摄像头 CAMERA_FACING_FRONTmCamera = Camera.open();mCamera.startPreview();//开始预览相机}}/*** 开始预览相机** @param camera        camera* @param surfaceHolder surfaceHolder*/private void startPreview(Camera camera, SurfaceHolder surfaceHolder) {camera.setDisplayOrientation(CameraUtil.getPreviewDegree(WaterCameraActivity.this));try {camera.setPreviewDisplay(surfaceHolder);} catch (IOException e) {e.printStackTrace();} finally {}camera.startPreview();//调用此方法,然后真正的预览相机}/*** 停止相机预览*/private void stopPreview() {if (mCamera != null) {mCamera.release();mCamera.release();mCamera = null;}}@Overrideprotected void onDestroy() {if (mCamera != null) {mCamera.stopPreview();mCamera.release();mCamera = null;}super.onDestroy();}}

下面是察看图片的类

ViewPhoto类的布局,布局入下图所示

<span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><RelativeLayoutandroid:id="@+id/rl_layout"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_margin="0dp"android:padding="0dp"><ImageViewandroid:id="@+id/imgv_photo"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#000000" /><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="12dp"android:layout_marginTop="65dp"android:orientation="vertical"><TextViewandroid:id="@+id/tv_time"android:layout_width="wrap_content"android:layout_height="wrap_content"android:shadowColor="#000"android:shadowDx="3"android:shadowDy="3"android:shadowRadius="2"android:text="08:27"android:textColor="#fff"android:textSize="25sp" /><TextViewandroid:id="@+id/tv_date"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@+id/tv_time"android:shadowColor="#000"android:shadowDx="3"android:shadowDy="3"android:shadowRadius="2"android:text="2016/07/24"android:textColor="#fff"android:textSize="15sp" /></RelativeLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:layout_marginBottom="70dp"android:layout_marginRight="1dp"android:gravity="right"android:orientation="vertical"><TextViewandroid:id="@+id/tv_operation"style="@style/textView_water"android:drawableLeft="@drawable/operation"android:text="点击操作" /><TextViewandroid:id="@+id/tv_userName"style="@style/textView_water"android:drawableLeft="@drawable/user_icon"android:text="钓鱼的小木匠" /><TextViewandroid:id="@+id/tv_address"style="@style/textView_water"android:drawableLeft="@drawable/address"android:text="广东省惠州市惠城区鹅岭南路6号TCL工业大厦" /></LinearLayout></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:layout_marginBottom="10dp"android:background="#000"android:gravity="center_vertical"><TextViewandroid:id="@+id/tv_cancel"style="@style/textView_common"android:layout_marginLeft="20dp"android:text="重 拍" /><TextViewandroid:id="@+id/tv_ok"style="@style/textView_common"android:layout_alignParentRight="true"android:layout_marginRight="20dp"android:text="使用图片" /><CheckBoxandroid:id="@+id/cb_savePic"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:checked="true"android:text="保存"android:textColor="#4fe19f" /></RelativeLayout>
</RelativeLayout>
</span>

ViewPhoto类代码

<span style="font-size:12px;">/*** 查看拍照的类* <p/>* Created by tanksu on 16/6/29.*/
public class ViewPhoto extends BaseActivity {private ImageView imgv_photo;private TextView tv_cancel, tv_ok;private int width, height;private RelativeLayout rl_layout;private String picPath = "", curDate = "", curTime = "", curAddress = "", userName = "", userOperation = "";private TextView tv_time, tv_date, tv_userName, tv_address, tv_operation;private CheckBox cb_savePic;private long currentTimeMillis;private String signal;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);//去掉标题栏setContentView(R.layout.viewphoto_layout);initViews();initData();initListener();}/*** 初始化控件*/private void initViews() {imgv_photo = (ImageView) findViewById(R.id.imgv_photo);tv_cancel = (TextView) findViewById(R.id.tv_cancel);tv_ok = (TextView) findViewById(R.id.tv_ok);rl_layout = (RelativeLayout) findViewById(R.id.rl_layout);tv_time = (TextView) findViewById(R.id.tv_time);tv_date = (TextView) findViewById(R.id.tv_date);tv_userName = (TextView) findViewById(R.id.tv_userName);tv_address = (TextView) findViewById(R.id.tv_address);cb_savePic = (CheckBox) findViewById(R.id.cb_savePic);tv_operation = (TextView) findViewById(R.id.tv_operation);}/*** 初始化数据*/private void initData() {WindowManager windowManager = getWindowManager();Display display = windowManager.getDefaultDisplay();width = display.getWidth();height = display.getHeight();Intent intent = getIntent();if (intent != null) {//这里的目标是,将所有传过来的的信息都去取出来,设置到每个相应的空间里面去//有人会问我为什么要这样做,其实我在拍照的时候,还没有真正的拿到一张具有水印的照片//我这里采用的是截屏的方式,所以呢,就要重新吧信息展现出来//其实还有很多的方法可以做水印相机,例如用位图来“画”信息等,但是有简单的方法,为什么不用呢,非要去弄一些很复杂的方法?!picPath = intent.getStringExtra(StaticParam.PIC_PATH);curDate = intent.getStringExtra(StaticParam.CUR_DATE);curTime = intent.getStringExtra(StaticParam.CUR_TIME);userName = intent.getStringExtra(StaticParam.USER_NAME);curAddress = intent.getStringExtra(StaticParam.CUR_ADDRESS);userOperation = intent.getStringExtra(StaticParam.USER_OPERATION);signal = intent.getStringExtra(StaticParam.TS_HUB_OP_SIGNAL);currentTimeMillis = intent.getLongExtra(StaticParam.CUR_TIME_MILLIS, System.currentTimeMillis());tv_time.setText(curTime);tv_date.setText(curDate);tv_userName.setText(userName);tv_address.setText(curAddress);tv_operation.setText(userOperation);BitmapFactory.Options options = new BitmapFactory.Options();options.outWidth = width;options.outHeight = height;Bitmap bitmap = ImageUtil.getPressedBitmap(picPath, width, height);//方法在下面,根据路径,获取第一步拍照存本地的图片/***** 根据图片路径,得到压缩过的位图** @param path* @param width* @param height* @return returnBitmappublic static Bitmap getPressedBitmap(String path, int width, int height) {BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;Bitmap bitmap = BitmapFactory.decodeFile(path, options);options.inSampleSize = getBitmapSampleSize(options, width, height);//getBitmapSampleSize(options, width, height)options.inJustDecodeBounds = false;Bitmap returnBitmap = BitmapFactory.decodeFile(path, options);return returnBitmap;}* 根据要去的宽高,压缩图片** @param options   options* @param reqWidth  reqWidth* @param reqHeight reqHeight* @return inSimpleSizepublic static int getBitmapSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {int imgWidth = options.outWidth;int imgHeight = options.outHeight;int inSimpleSize = 1;if (imgWidth > imgHeight || imgWidth < imgHeight) {final int heightRatio = imgWidth / reqWidth;final int widthRatio = imgHeight / reqHeight;inSimpleSize = widthRatio < heightRatio ? widthRatio : heightRatio;}return inSimpleSize;}*/imgv_photo.setImageBitmap(bitmap);} else {toast("intent equals null,please try again!");}}/*** 初始化监听器*/private void initListener() {//点击使用图片按钮,就可以在启动水印相机的onactivityresult回调里面,获取到图片的路径,然后获取图片即可使用了tv_ok.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {final Bitmap bitmap = getScreenPhoto(rl_layout);ImageUtil.saveBitmap(picPath, String.valueOf(currentTimeMillis), bitmap);//根据路径保存图片/*** 根据路径和名字保存图片** @param path    path* @param imgName imgName* @param bitmap  bitmap* @return createPathpublic static String saveBitmap(String path, String imgName, Bitmap bitmap) {String savePath = null;if (path == null) { //if path is nullFile fileSDCardDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);String imgPath = fileSDCardDir.getAbsolutePath() + "/s/waterCamera/";File fileDir = new File(imgPath);if (!fileDir.exists()) {fileDir.mkdirs();}String photoName = imgName + ".JPG";imgPath = imgPath + photoName;File fileIphoto = new File(imgPath);if (!fileIphoto.exists()) {try {fileIphoto.createNewFile();} catch (IOException e) {e.printStackTrace();}}savePath = fileIphoto.getPath();saveBitmap(bitmap, fileIphoto);return savePath;} else { //if path isn't null, override the photoFile oldFile = new File(path);if (oldFile.exists()) {oldFile.delete();}File newFile = new File(path);if (!newFile.exists()) {try {newFile.createNewFile();} catch (IOException e) {e.printStackTrace();}}saveBitmap(bitmap, newFile);savePath = newFile.getPath();return savePath;}}*/Intent intent = new Intent(ViewPhoto.this, TsDrActivity.class);intent.putExtra(StaticParam.PIC_PATH, picPath);//这里最主要的,就是将储存在本地的图片的路径作为结果返回intent.putExtra(StaticParam.IS_SAVE_PIC, cb_savePic.isChecked());//这里就是是否用户要保存这张图片的选项intent.putExtra(StaticParam.TS_HUB_OP_SIGNAL, signal);setResult(RESULT_OK, intent); //如果是OK,就设置为OK结果ViewPhoto.this.finish();}});tv_cancel.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {new Thread(new Runnable() {@Overridepublic void run() {ImageUtil.deleteImageFromSDCard(picPath);//重新拍照,就将本地的图片给删除掉,然后重新拍照}}).start();ViewPhoto.this.finish();}});}/*** 截屏,这里就是截屏的地方了,我这里是截屏RelativeLayout,* 只要你将需要的信息放到这个RelativeLayout里面去就可以截取下来了** @param waterPhoto waterPhoto* @return Bitmap*/public Bitmap getScreenPhoto(RelativeLayout waterPhoto) {View view = waterPhoto;view.setDrawingCacheEnabled(true);view.buildDrawingCache();Bitmap bitmap = view.getDrawingCache();int width = view.getWidth();int height = view.getHeight();Bitmap bitmap1 = Bitmap.createBitmap(bitmap, 0, 0, width, height);view.destroyDrawingCache();bitmap = null;return bitmap1;}
</span>

使用

<span style="font-size:12px;">//例如:启动水印相机的代码
Intent intent = new Intent(TsHubActivity.this, WaterCameraActivity.class);intent.putExtra(StaticParam.CUR_ADDRESS, curAddress);intent.putExtra(StaticParam.USER_NAME, stationName);Button btn_recv = (Button) findViewById(R.id.batchRecv);intent.putExtra(StaticParam.USER_OPERATION, btn_recv.getText().toString());startActivityForResult(intent, JustOneOrder);
</span>

回调

<span style="font-size:12px;">//拍照回调方法
@Overridepublic void onActivityResult(int requestCode, int resultCode, Intent data) {//以下是需要拍照的图片参数final String imgPath = data.getStringExtra(StaticParam.PIC_PATH);//图片路径Bitmap bitmap = BitmapFactory.decodeFile(imgPath);//获取到图片了
}</span>

上面这两个类,直接复制来就可以用了,可以根据你的需求进行修改,不难,很简单。关于前后摄像头切换的,因为时间紧任务重,就没有时间去做了。

如有任何问题,请及时与我联系,谢谢。

android之利用surfaceView实现自定义水印相机相关推荐

  1. 自定义水印相机(watercamera)

    关于自定义水印相机(watercamera)的一点心得 本文为原创,转载请声明! 网上有很多自定义相机,但是跟我需要的项目真心不符,所以最后还是只能找了一个(git上面的例子:原本想链接地址的,结果没 ...

  2. Android中利用shape属性自定义设置Button按钮

    博主前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住也分享一下给大家,

  3. IOS 自定义相机, 使用 AVFoundation(附实现部分腾讯水印相机功能 demo)

    原文链接:http://www.jianshu.com/p/c64bf543f16a 这是一款使用 AVFoundation 自定义的相机,与系统原生相机有一样的外观但比系统的相机更好.更符合实际的开 ...

  4. Android利用SurfaceView 实现水印相机,仿钉钉

    最近项目中要求增加拍照打卡功能.模仿钉钉的样子,于是就网上找了些资源.功能虽然实现了,却难以看懂,参考了各位大神的代码.加以整理整合.再做出一番梳理.以供各位参考.希望对阅读者有帮助. 主要来源于:主 ...

  5. Android水印相机

    本篇文章实现的水印相机,类似于qq空间中的水印相机功能,因之前看过一个demo上实现了一个简陋的水印相机功能,觉得挺有意思,就在此基础上进行了修改,优化和完善,并增加了部分功能,使之更接近于qq水印相 ...

  6. android水印相机,Android 水印相机开发

    水印相机是自定义相机的一种,实现方法有很多,我看了很多别人的做的很漂亮,我做的就很普通了,不过总算是实现了拍照加水印的功能. 我这边用到了SurfaceView,有人没用这个也做出来水印相机,个人觉得 ...

  7. Android自定义camera相机 系列(一)

    该文章 主要使用 自定义 surfaceview 及 camera 知识点,来实现一个自定义的拍照 .切换闪光灯 和 前后摄像头的功能.阅读需要消耗时间 :15分钟+ .内容比较简单算是 开发相机的过 ...

  8. Android 自定义相机 身份证拍照 自定义身份证相机

    项目中需要用到拍摄身份证,拍完照片后直接拿到和身份证比例一致的图片,做成功的结果如下:    拍完照后直接拿到裁剪好的图本文的核心技术来自: https://yq.aliyun.com/article ...

  9. Android自定义Camera2相机

    转载请标明出处:https://blog.csdn.net/ZhijunHong/article/details/115730693,谢谢~ 写在前面 Google从Android 5.0 L(API ...

最新文章

  1. 摄像头ISP系统原理(下)
  2. 斯洛文尼亚接受BCH支付的商家达343家,日本和北昆士兰州对BCH接受度增长迅速
  3. 字符指针+结构体排序(后缀子串排序)
  4. FTP和TCP、UDP
  5. [转]编程的首要原则(s)是什么?
  6. 【转】一些 SQLite技巧
  7. 第129天:node.js安装方法
  8. 使用lua脚本开发wow插件(魔兽世界插件开发)
  9. Softmax和关于它的交叉熵损失函数详细求导过程
  10. 使用chkconfig管理开机自启动
  11. Java利用公式求自然对数的底e
  12. C# dll注入(指定进程注入指定dll)
  13. CD19药物|适应症|市场销售-上市药品前景分析
  14. 0318复利计算器4.0
  15. Mybatis如何进行分页的
  16. [1]无线通信--介绍基本概念
  17. MATLAB打开代码,中文注释乱码的解决方法
  18. 【线上研讨会】多位重磅嘉宾莅临RT-Thread 嵌入式人工智能教学研讨会
  19. ELKStack简介
  20. 飞机场100个常见公共标志英文单词(zt)

热门文章

  1. Latex 表格整体居中
  2. android 分辨率显示不全,手机分辨率太高软件显示不全?教你瞬间让任意软件变全屏...
  3. php的四大特性八大优势
  4. jQuery简单体验及jQuery中文手册下载
  5. MATLAB 亮度与对比度调整
  6. 【小程序源码】王者荣耀改重复名,空白名最低战力查询助手
  7. oracle bi enterprise edition,Oracle BI Publisher 企业版在WIN7下的装配(BI Publisher Enterprise Edition)...
  8. Intellij IDEA 出现“Usage of API documented as @since 1.7+”的解决办法
  9. 降成本设计,刻不“容”缓
  10. CDH 6.3.2 离线安装部署详细教程 (亲妈级别教学,有手就行)