45_拍照
------------------------------------------------------------------- 在main.xml布局文件添加用于显示取景画面的SurfaceView 控件: <SurfaceView android:layout_width="fill_parent" android:layout_height="240dip" android:id="@+id/surfaceView" /> SurfaceView surfaceView = (SurfaceView)this.findViewById(R.id.surfaceView); surfaceView.getHolder().setFixedSize(176, 144); //设置分辨率 /*下面设置Surface不维护自己的缓冲区,而是等待屏幕的渲染引擎将内容推送到用户面前*/ surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); Camera camera = Camera.open(); WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); Camera.Parameters parameters = camera.getParameters(); parameters.setPreviewSize(display.getWidth(), display.getHeight());//设置预览照片的大小 parameters.setPreviewFrameRate(3);//每秒3帧 parameters.setPictureFormat(PixelFormat.JPEG);//设置照片的输出格式 parameters.set("jpeg-quality", 85);//照片质量 parameters.setPictureSize(display.getWidth(), display.getHeight());//设置照片的大小 camera.setParameters(parameters); camera.setPreviewDisplay(surfaceView.getHolder());//通过SurfaceView显示取景画面 camera.startPreview();//开始预览 camera.autoFocus(null);//自动对焦 camera.takePicture(null, null, null, jpegCallback);//拍照片 camera.stopPreview();//停止预览 camera.release();//释放摄像头 ------------------------------------------------------------------------- <uses-permission android:name="android.permission.CAMERA"/>
package cn.itcast.picture;
import java.io.File;
import java.io.FileOutputStream;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.graphics.Bitmap.CompressFormat;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Display;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
import android.view.WindowManager;
public class TakePictureActivity extends Activity {
private static final String TAG = "TakePictureActivity";
private SurfaceView surfaceView;
private Camera camera;
private boolean preview;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Window window = getWindow();
requestWindowFeature(Window.FEATURE_NO_TITLE);//没有标题
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);// 设置全屏
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);//高亮
setContentView(R.layout.main);
surfaceView = (SurfaceView) this.findViewById(R.id.surfaceView);
surfaceView.getHolder().addCallback(new SufaceListener());
/*下面设置Surface不维护自己的缓冲区,而是等待屏幕的渲染引擎将内容推送到用户面前*/
surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceView.getHolder().setFixedSize(176, 144); //设置分辨率
}
private final class SufaceListener implements SurfaceHolder.Callback{
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
camera = Camera.open();//打开摄像头
Camera.Parameters parameters = camera.getParameters();
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
parameters.setPreviewSize(display.getWidth(), display.getHeight());//设置预览照片的大小
parameters.setPreviewFrameRate(3);//每秒3帧
parameters.setPictureFormat(PixelFormat.JPEG);//设置照片的输出格式
parameters.set("jpeg-quality", 85);//照片质量
parameters.setPictureSize(display.getWidth(), display.getHeight());//设置照片的大小
camera.setParameters(parameters);
camera.setPreviewDisplay(surfaceView.getHolder());//通过SurfaceView显示取景画面
camera.startPreview();
preview = true;
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if(camera!=null){
if(preview) camera.stopPreview();
camera.release();
camera = null;
}
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(camera!=null && event.getRepeatCount()==0){
switch (keyCode) {
case KeyEvent.KEYCODE_SEARCH:
camera.autoFocus(null);//自动对焦
break;
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_CAMERA:
//拍照
camera.takePicture(null, null, new PictureCallbackListener());
break;
}
}
return true;
}
private final class PictureCallbackListener implements Camera.PictureCallback{
@Override
public void onPictureTaken(byte[] data, Camera camera) {
try {
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
File file = new File(Environment.getExternalStorageDirectory(), "itcast.jpg");
FileOutputStream outStream = new FileOutputStream(file);
bitmap.compress(CompressFormat.JPEG, 100, outStream);
outStream.close();
//重新浏览
camera.stopPreview();
camera.startPreview();
preview = true;
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
}
}
-------------------------------------------------------------------------------------------------
1.拍照应用的界面:
---------------------
a.横向,全屏
b.--------------------------
拍照区域
---------------------------
c.右下角: 对焦 拍照
-------------------------------------------------
1.要求当用户触摸屏幕的时候显示:对焦 拍照
2.这两个按钮是显示在之上的.
----------------------------------------------------
3.所以这时候用的是帧布局.一层在一层之上.
4.也用到了相对布局
---------------------------------------------
下面是拍照的所有源码:
------------------------------
新建android项目:
1./takepicture/src/com/credream/camer/TakepictureActivity.java
package com.credream.camer; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import android.app.Activity; import android.hardware.Camera; import android.hardware.Camera.PictureCallback; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; public class TakepictureActivity extends Activity { private View layout;//布局 private Camera camera;//摄像头 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE);//设置activity没有标题栏 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);//设置activity全屏显示 setContentView(R.layout.main); //获取这个相对布局 layout = this.findViewById(R.id.buttonlayout); //这里可以使用surfaceView来显示视频画面。 SurfaceView surfaceView = (SurfaceView) this.findViewById(R.id.surfaceView); //直接将画面显示到屏幕上,不再使用缓冲区 surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); //设置画面的分辨率 surfaceView.getHolder().setFixedSize(176, 144); //保持屏幕的高亮,不要锁定屏幕 surfaceView.getHolder().setKeepScreenOn(true); //当surfaceView被创建的时候就会调用 surfaceView.getHolder().addCallback(new SurfaceCallback()); } public void takepicture(View v){ if(camera!=null){//拍照前判断,照相机对象不允许为null switch (v.getId()) {//当id为takepicture时候, case R.id.takepicture: camera.takePicture(null, null, new MyPictureCallback()); //camera.startPreview();//拍完照调用这个方法继续预览,这样是不可以的 //camera.takePicture这个方法内部采用了异步保存照片,当camera.takePicture方法执行完后,摄像头可能还没有处理完照片 //所以直接在camera.takePicture方法后面调用camera.startPreview();方法是不对的 //这个方法开始拍照,这三个参数是:快门按下去后 /* * null,第一个当快门按下去之后,会调用这个对象中的回调方法 * null,第二个参数是当摄像头拍完后,照片数据分为照片的原始数据,和照片经过压缩后的数据,第二个参数就是指照片的原始数据 * 第三个参数就是照片经过压缩后的数据 * new MyPictureCallback()这个方法就是得到摄像头拍摄完,并压缩后的数据 * * */ break; //摄像头拍照的时候是不可以预览的,因为摄像头在某一个时刻只能做一件事情,当拍完照后就没有预览画面了。 case R.id.autofocus: camera.autoFocus(null); //这里的输入参数是:得到对焦成功之后的事件。,不想得到这个事件可以设为null break; } } } private final class MyPictureCallback implements PictureCallback{ public void onPictureTaken(byte[] data, Camera camera) { //byte[] data, Camera camera这个是压缩后的数据和摄像头 try { //保存照片文件 Environment.getExternalStorageDirectory()这个是sd卡的根目录 File jpgFile = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis()+".jpg"); //文件输出流 FileOutputStream outStream = new FileOutputStream(jpgFile); //把照片写到sd卡的根目录 outStream.write(data); outStream.close(); //截止到这里摄像头已经把照片处理完了,这时候在调用camera.startPreview();进入画面预览界面,才可以 camera.startPreview();//写完数据后继续 } catch (Exception e) { e.printStackTrace(); } } } private final class SurfaceCallback implements Callback{ //当surfaceView被创建的时候执行这个方法 public void surfaceCreated(SurfaceHolder holder) { try{ camera = Camera.open();//打开摄像头,Camera这里Camera类,有两个这里用硬件中的那个import android.hardware.Camera; Camera.Parameters parameters = camera.getParameters();//不同厂商的摄像头,他们的参数是不同的。 //注意这里需要真实的手机进行测试,因为这样才可以得到摄像头的各项参数 //Log.i("TakepictureActivity", parameters.flatten()); //可以通过Log.i("TakepictureActivity", parameters.flatten());来查看该摄像头的各项参数 //parameters.flatten()这个方法用来查看,摄像头可以设置的各项参数 //这些参数根据摄像头不同时不一样的 parameters.setPreviewSize(800, 480);//摄像头捕获的照片大小 parameters.setPreviewFrameRate(5);//每秒中摄像头捕获的画面 parameters.setPictureSize(1024,768);//设置照片大小 parameters.setJpegQuality(80);//设置照片的质量,100是最好的 camera.setParameters(parameters);//设置完摄像头的参数后把参数再给摄像头 camera.setPreviewDisplay(holder);//把摄像头捕获的数据给surfaceView camera.startPreview();//开始预览 }catch (Exception e) { e.printStackTrace(); } } public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) { } //当应用不在前台的时候调用这个方法 public void surfaceDestroyed(SurfaceHolder holder) { if(camera!=null){ camera.release();//释放摄像头 camera = null; } } } @Override public boolean onTouchEvent(MotionEvent event) { //判断如果当前的事件是,触摸按下的事件的话。 if(event.getAction() == MotionEvent.ACTION_DOWN){ layout.setVisibility(ViewGroup.VISIBLE);//这时候就显示按钮。相对布局, //return true的时候就是把这个事件消费掉。不在往下传递。 return true; } return super.onTouchEvent(event); } }
-------------------------------------------------------------------
2./takepicture/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.credream.camer" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" /> <!-- android:screenOrientation="landscape"这句的作用是控制屏幕为横屏。 全屏,没有标题栏,和状态栏。 --> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:label="@string/app_name" android:name=".TakepictureActivity" android:screenOrientation="landscape" > <intent-filter > <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <!--这个是访问摄像头的权限 --> <uses-permission android:name="android.permission.CAMERA"/> <!-- 在SDCard中创建与删除文件权限 --> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <!-- 往SDCard写入数据权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> </manifest>
--------------------------------------------------------------------------------------
3./takepicture/res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?> <!-- 这里用了帧布局 --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <!-- 拍照用到了SurfaceView控件 --> <SurfaceView android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/surfaceView" /> <!-- 用到了相对布局 --> <RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:visibility="gone" android:id="@+id/buttonlayout" > <!-- android:onClick="takepicture"指定点击后执行的方法, android:layout_alignParentRight="true"指定在相对布局(也就是button按钮的父元素的右边) android:layout_alignParentBottom="true"指定在相对布局(也就是button按钮的父元素的下边) android:layout_marginRight="5dp"指的是右边距离相对布局(也就是button按钮的父元素为5个像素) --> <!-- 拍照按钮 --> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_alignParentBottom="true" android:layout_marginRight="5dp" android:text="@string/takepicture" android:onClick="takepicture" android:id="@+id/takepicture" /> <!-- android:layout_toLeftOf="@id/takepicture"指的是这个按钮在id为takepicture的组件的左边。 android:layout_alignTop="@id/takepicture"指的是这个按钮和id为takepicture的组件的顶部对其。 android:layout_marginRight="20dp"指的是这个按钮距离相对布局右边20个像素 --> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toLeftOf="@id/takepicture" android:layout_alignTop="@id/takepicture" android:layout_marginRight="20dp" android:text="@string/autofocus" android:onClick="takepicture" android:id="@+id/autofocus" /> </RelativeLayout> </FrameLayout>
------------------------------------------------------------------------------------------------------------------------
4. /takepicture/res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello World, TakepictureActivity!</string> <string name="app_name">拍照</string> <string name="takepicture">拍照</string> <string name="autofocus">对焦</string> </resources>