Android摄像头基础——第二阶段 自定义简单的相机
2016-01-20 22:25
666 查看
一、
1.布局文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/startCamera" android:text="Start Camera"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/startCamera2" android:text="Start Camera2"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/customCamera" android:text="Custom Camera"/> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/imageView" /> </LinearLayout>
增加了一个按钮,点击之后进入自定义相机界面
2.MainActivity.java
public class MainActivity extends Activity { private Button startCamera; private Button startCamera2; private Button customCamera; private ImageView imageView; private String photoFilePath;// 照片存放路径 private static final int REQ_1 = 1; private static final int REQ_2 = 2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); startCamera = (Button) findViewById(R.id.startCamera); startCamera2 = (Button) findViewById(R.id.startCamera2); customCamera=(Button) findViewById(R.id.customCamera); imageView = (ImageView) findViewById(R.id.imageView); photoFilePath = Environment.getExternalStorageDirectory().getPath();// 获取sd卡目录的路径 photoFilePath += "/test.jpg"; startCamera.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);// 指定action,隐式Intent startActivityForResult(intent, REQ_1);// 在指定的新的Activity结束后返回此Activity中,并且返回了数据 // REQ_1相当于一个标记,当时指定的Activity结束后会返回REQ_1给onActivityResult中的requestCode // 表明是需要的Activity返回的数据 } }); startCamera2.setOnClickListener(new OnClickListener() { // 从照片存储的系统目录中去获取原图 @Override public void onClick(View v) { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); Uri photoUri = Uri.fromFile(new File(photoFilePath));// 这里包含两步 // 首先根据指定路径创建一个文件对象 // 然后根据这个文件对象获得Uri intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);// 根据EXTRA_OUTPUT参数,系统相机将会在获取照片后根据相应的Uri存储照片 // 一定要注意,是uri,不是文件的路径字符串!!!!!!!!!! startActivityForResult(intent, REQ_2); } }); customCamera.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //注意:这儿不能直接用intent(this,XXX.class),因为这是在一个匿名类中,如果直接this就是指的当前的匿名类,而非MainActivity.this startActivity(new Intent(MainActivity.this,CustomCamera.class)); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) {// 判断新启动的Activity是否顺利结束 if (requestCode == REQ_1) { Bundle bundle = data.getExtras();// Bundle类是一个key-value对,两个activity之间的通讯可以通过bundle类来实现 // data中的图片数据是缩略图,而不是原图(因此imageView中显示的图片不会像原图那样清晰) // 因为如果返回原图可能会数据量太大导致数据溢出 // Bitmap是Android系统中的图像处理的最重要类之一 Bitmap bitmap = (Bitmap) bundle.get("data");// 将得到的图片数据存储在bitmap中 if(bitmap!=null) startCamera.setText(""+bitmap.getWidth()+" "+bitmap.getHeight()); else startCamera.setText("null"); imageView.setImageBitmap(bitmap); } else if (requestCode == REQ_2) { FileInputStream fis = null;// 局部变量需要初始化 try { fis = new FileInputStream(photoFilePath); Bitmap bitmap = BitmapFactory.decodeStream(fis); //在第一阶段中,有提过关于图片尺寸过大而引起的问题,需要注意一下 if(bitmap!=null) startCamera2.setText(""+bitmap.getWidth()+" "+bitmap.getHeight()); else startCamera2.setText("null"); imageView.setImageBitmap(bitmap); } catch (FileNotFoundException e) { e.printStackTrace(); } finally { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } } }
二、实现自定义的相机
1.布局文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/customButton" android:text="CAPTURE"/> <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" > <!-- SurfaceView用来预览相机的取景 --> <SurfaceView android:id="@+id/preview" android:layout_width="match_parent" android:layout_height="match_parent" /> <!-- 在预览界面上增加水印 --> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:text="Welcome to my camera" android:textColor="#ea3826" android:textSize="20sp" android:layout_marginBottom="72dp" /> </RelativeLayout> </LinearLayout>
2.CustomCamera.java
/** * 实现自定义相机的核心类 * 1 实现相机的三个生命周期方法getCamera、setStartPreview、releaseCamera(这三个方法基本是固定的), * 并且与之和Activity的生命周期绑定起来 * 2 实现SurfaceHolder.Callback接口(因为在布局文件中使用了SurfaceView), * 注意要在getCamera和releaseCamera方法中分别将Camera对象与布局文件中的SurfaceView进行绑定与取消绑定 * (以上两布都是对相机的生命周期进行管理) * 3 实现点击按钮进行拍照的功能,设置拍照时的参数以及实现AutoFocusCallback接口中onAutoFocus方法的第三个参数(一个回调接口) * */ public class CustomCamera extends Activity implements SurfaceHolder.Callback { private Button customButton; private Camera mCamera; private SurfaceView mPreview;//用来预览相机的取景 private SurfaceHolder mHolder; private PictureCallback mPictureCallback = new PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { //data保存了拍照之后整个照片完整的数据(而非缩略图的数据) // File tempFile=new File("/sdcard/temp.png");//创建一个临时文件用来保存照片,可以自定义其路径 File tempFile=new File("/storage/emulated/0/temp.png"); try { FileOutputStream fos=new FileOutputStream(tempFile); fos.write(data); fos.close(); Intent intent=new Intent(CustomCamera.this,Result.class); intent.putExtra("picPath", tempFile.getAbsolutePath()); startActivity(intent); CustomCamera.this.finish(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.custom); customButton = (Button) findViewById(R.id.customButton); mPreview = (SurfaceView) findViewById(R.id.preview); mPreview.setOnClickListener(new OnClickListener() { // 实现点击SurfaceView范围内的屏幕时自动对焦 @Override public void onClick(View v) { mCamera.autoFocus(null); } }); customButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //首先需要设置相机的一些参数 Camera.Parameters parameters=mCamera.getParameters(); parameters.setPictureFormat(ImageFormat.JPEG);//设置拍照的格式 parameters.setPictureSize(800, 400);//设置拍得的图片的大小 parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);//在预览时自动对焦(前提是相机支持自动对焦的) mCamera.autoFocus(new Camera.AutoFocusCallback() {//开始相机的自动对焦 @Override public void onAutoFocus(boolean success, Camera camera) { //success代表当前对焦是否已经完全准确 if(success) { //如果对焦准确就进行拍照 mCamera.takePicture(null, null, mPictureCallback);//最后一个参数是一个回调 } } });//获取最清晰的焦距之后再进行拍照 } }); mHolder = mPreview.getHolder(); mHolder.addCallback(this);// 将当前的Activity作为回调设置给mHolder(因为实现了Callback接口) } @Override protected void onResume() { super.onResume(); if (mCamera == null) { mCamera = getCamera();// 将mCamera的生命周期与此Activity的生命周期进行绑定,保证Camera使用的资源能正确的初始化 if (mHolder != null) { setStartPreview(mCamera, mHolder); } } } @Override protected void onPause() { super.onPause(); releaseCamera();// 将mCamera的生命周期与此Activity的生命周期进行绑定,保证Camera使用的资源能正确的释放 } /** * 获取系统的Camera对象 * * @return */ private Camera getCamera() { // 注意:package android.graphics中的Camera是用来实现3D图形变换的 // android.hardware.Camera才是需要导入的,使用系统硬件的系统相机 Camera camera = null; try { camera = Camera.open();//初始化操作 } catch (Exception e) { camera = null;// 释放掉原来的对象引用,使之变成可回收的 e.printStackTrace(); } return camera; } /** * 开始预览相机内容 */ private void setStartPreview(Camera camera, SurfaceHolder holder) { // 需要将Camera对象与SurfaceView进行绑定,使得Camera实时预览的效果直接展现在SurfaceView上 try { camera.setPreviewDisplay(holder); // 需要注意,系统默认的Camera是横屏的,其预览的图像也是横屏的,因此需要将Camera预览角度进行转换 camera.setDisplayOrientation(90);// 将整个Camera旋转90° camera.startPreview(); } catch (IOException e) { e.printStackTrace(); } } /** * 释放相机占用的资源,解除相关的绑定 */ private void releaseCamera() { if(mCamera!=null) { mCamera.setPreviewCallback(null);//将相机的回调置空,取消mPreview与mCamera的关联操作 mCamera.stopPreview(); //停止相机的取景功能 mCamera.release(); mCamera = null; } } @Override public void surfaceCreated(SurfaceHolder holder) { setStartPreview(mCamera, mHolder);//将surfaceCreated与setStartPreview进行绑定 } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { mCamera.stopPreview();//将相机进行关闭 //然后重启预览功能 setStartPreview(mCamera, mHolder); } @Override public void surfaceDestroyed(SurfaceHolder holder) { releaseCamera(); } }
三、显示拍得的照片
1.布局文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Capture result" android:gravity="center" android:textSize="30sp"/> <ImageView android:id="@+id/resultImageView" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
2.Result .java
public class Result extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.result); ImageView iv =(ImageView) findViewById(R.id.resultImageView); String path=getIntent().getStringExtra("picPath"); // Bitmap bitmap = BitmapFactory.decodeFile(path); // iv.setImageBitmap(bitmap); //直接从指定路径获得图片,但是由于在CameraCuston中改变了预览的角度,但是拍照得到的照片依旧是横置的 //所以在这里如果不加处理,显示的照片就会是横置的,以下为处理方法 FileInputStream fis = null; try { fis = new FileInputStream(path); Bitmap bitmap = BitmapFactory.decodeStream(fis); Matrix matrix = new Matrix(); matrix.setRotate(90);//选择90° bitmap = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix, true);//通过变换矩阵得到新的bitmap //根据的实际的手机,还是需要考录是否缩小图片 // BitmapFactory.Options options=new BitmapFactory.Options(); // options.inJustDecodeBounds=false;//如果为true,bitmap将会为null // options.inSampleSize=2;//把图片的尺寸缩小一半 // Bitmap bitmap = BitmapFactory.decodeStream(fis,null,options); //在CustomCamera已经设置过照片的大小 iv.setImageBitmap(bitmap); } catch (FileNotFoundException e) { e.printStackTrace(); } finally { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } }
四、修改AndroidManifest.xml文件,添加相应权限,注册新增的Activity
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.cameratest" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.CAMERA" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".CustomCamera"> </activity> <activity android:name=".Result"> </activity> </application> </manifest>
相关文章推荐
- ubntu获取android源码的方法
- android 动画-Tween Animation(一)动画体系简介,涉及到的核心类、核心接口讲解(下)
- android 动画整理概述
- 【读书笔记】【Android开发艺术探索】第10章 Android 的消息机制
- android 动画-Tween Animation(一)动画体系简介,涉及到的核心类、核心接口讲解(上)
- Android Design Support Library(一)--TextInputLayout简析
- android Volley框架学习一
- Android学习路线
- 【Android】获取控件的宽和高
- 通过Android keyevent 向系统发送命令
- Android基础之Intent
- Android几种layout(布局)的区别
- 手机常见干扰问题分析与解决方法
- Android自助餐之内容提供者ContentProvider使用
- Android图片内存的计算
- 转载关于通过判断浏览器的userAgent,用正则来判断是否是ios和Android客户端
- Android中给LineayLayout加边框
- android:scaleType属性
- 【Android】intent action 跳转到系统使用,调用系统功能
- Android应用启动速度优化