• Android Camera(二) Camera程序编写


    Android Camera 相机程序编写

      

      要自己写一个相机应用直接使用相机硬件,首先应用需要一个权限设置,在AndroidManifest.xml中加上使用设备相机的权限

    <uses-permission android:name="android.permission.CAMERA" />

     

      为你的应用创建自定义的相机,一般步骤如下:

      1.检测相机硬件并获取访问

      2.建立一个Preview类:需要一个相机预览的类,继承 SurfaceView 类,并实现SurfaceHolder接口。

      3.建立预览的布局。

      4.为拍照建立监听。

      5.拍照并且存储文件。

      6.释放相机。

      因为相机是一个共享资源,所以应该被谨慎管理,这样应用之间才不会发生冲突。

      所以使用完相机之后应该调用 Camera.release()来释放相机对象。

      如果不释放,后续的使用相机请求(其他应用或本应用)都会失败。

    检测相机硬件

      如果你的程序没有在manifest的声明中要求有相机,那么你应该在运行时检查相机的存在与否,主要用了 PackageManager.hasSystemFeature() 方法。比如:

        /** Check if this device has a camera */
        private boolean checkCameraHardware(Context context)
        {
            if (context.getPackageManager().hasSystemFeature(
                    PackageManager.FEATURE_CAMERA))
            {
                // this device has a camera
                return true;
            }
            else
            {
                // no camera on this device
                return false;
            }
        }

     

      设备上可能有多个相机,Android 2.3以后可以使用 Camera.getNumberOfCameras()来查看相机的数目。

      如下面这段程序用于检测设备中的相机,并得到默认相机的索引号:

        private int getDefaultCameraId()
        {
            int defaultId = -1;
    
            // Find the total number of cameras available
            mNumberOfCameras = Camera.getNumberOfCameras();
    
            // Find the ID of the default camera
            CameraInfo cameraInfo = new CameraInfo();
            for (int i = 0; i < mNumberOfCameras; i++)
            {
                Camera.getCameraInfo(i, cameraInfo);
                if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK)
                {
                    defaultId = i;
                }
            }
            if (-1 == defaultId)
            {
                if (mNumberOfCameras > 0)
                {
                    // 如果没有后向摄像头
                    defaultId = 0;
                }
                else
                {
                    // 没有摄像头
                    Toast.makeText(getApplicationContext(), R.string.no_camera,
                            Toast.LENGTH_LONG).show();
                }
            }
            return defaultId;
        }

      看了Camera类的代码实现后,其中不带参数的open()方法

        public static Camera open()
        {
            int numberOfCameras = getNumberOfCameras();
            CameraInfo cameraInfo = new CameraInfo();
            for (int i = 0; i < numberOfCameras; i++)
            {
                getCameraInfo(i, cameraInfo);
                if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK)
                {
                    return new Camera(i);
                }
            }
            return null;
        }

      说明open方法默认是打开第一个后向摄像头的。

     访问相机

      当检测到设备上有相机之后,必须获取其访问权,获取一个 Camera 类的对象。

      要获取主要的相机,可以使用 Camera.open() 方法,注意异常处理。

      在使用这个方法的时候一定要检查异常,如果相机正在被使用或者不存在,没有处理异常,将会使得应用被系统关闭。

      如:

        /** A safe way to get an instance of the Camera object. */
        public static Camera getCameraInstance()
        {
            Camera c = null;
            try
            {
                c = Camera.open(); // attempt to get a Camera instance
            }
            catch (Exception e)
            {
                // Camera is not available (in use or does not exist)
            }
            return c; // returns null if camera is unavailable
        }

      Android 2.3之后,可以使用Camera.open(int)来获取特定的相机。

    检查相机特性

      可以使用Camera.getParameters()方法来检查相机的特性。

      API Level 9之后,可以使用 Camera.getCameraInfo()来查看相机是在设备前面还是后面,还可以得到图像的方向。

    建立Preview类

      为了有效地拍照或录像,用户必须要看到相机能看到的图像。

      相机的preview类是一个 SurfaceView ,展示了相机正在捕捉的图像。

      下面是一个预览类的例子(来自官网):

    A basic preview class
    /** A basic Camera preview class */
    public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
        private SurfaceHolder mHolder;
        private Camera mCamera;
    
        public CameraPreview(Context context, Camera camera) {
            super(context);
            mCamera = camera;
    
            // Install a SurfaceHolder.Callback so we get notified when the
            // underlying surface is created and destroyed.
            mHolder = getHolder();
            mHolder.addCallback(this);
            // deprecated setting, but required on Android versions prior to 3.0
            mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        }
    
        public void surfaceCreated(SurfaceHolder holder) {
            // The Surface has been created, now tell the camera where to draw the preview.
            try {
                mCamera.setPreviewDisplay(holder);
                mCamera.startPreview();
            } catch (IOException e) {
                Log.d(TAG, "Error setting camera preview: " + e.getMessage());
            }
        }
    
        public void surfaceDestroyed(SurfaceHolder holder) {
            // empty. Take care of releasing the Camera preview in your activity.
        }
    
        public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
            // If your preview can change or rotate, take care of those events here.
            // Make sure to stop the preview before resizing or reformatting it.
    
            if (mHolder.getSurface() == null){
              // preview surface does not exist
              return;
            }
    
            // stop preview before making changes
            try {
                mCamera.stopPreview();
            } catch (Exception e){
              // ignore: tried to stop a non-existent preview
            }
    
            // set preview size and make any resize, rotate or
            // reformatting changes here
    
            // start preview with new settings
            try {
                mCamera.setPreviewDisplay(mHolder);
                mCamera.startPreview();
    
            } catch (Exception e){
                Log.d(TAG, "Error starting camera preview: " + e.getMessage());
            }
        }
    }

      注意要设置尺寸的话需要放在surfaceChanged()方法里,调用 setPreviewSize()方法,并且应该使用 getSupportedPreviewSizes()返回的值,而不要使用任意的尺寸。

    把Preview放在布局里面

      布局时可以使用FrameLayout,这样其他的按钮或者元素可以叠加在预览图像上。

      对于大多数设备来说,相机预览的默认方向是横放的(landscape)。

      从Android 2.2 (API Level 8)开始,可以使用 setDisplayOrientation()来设置预览图像的方向。

      如果需要在用户改变设备方向的时候改变预览图像的方向,可以在 surfaceChanged()方法中,首先用 Camera.stopPreview() 停止预览,改变方向,然后用Camera.startPreview()开启新的预览。

      当然你也可以直接在manifest中设置好方向,如下:

    <activity android:name=".CameraActivity"
              android:label="@string/app_name"
    
              android:screenOrientation="landscape">
              <!-- configure this activity to use landscape orientation -->
    
              <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    拍照

      在应用里面,必须为用户控制加上监听,来响应用户拍照的动作。

      为了得到图像,要使用 Camera.takePicture()方法。

      这个方法接收三个参数,用于从相机获取图像。

      为了接收到JPEG格式的数据,需要实现Camera.PictureCallback接口用来接收图像数据并且写入文件。

      下面的代码展示了一个最基本的实现:

    private PictureCallback mPicture = new PictureCallback() {
    
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
    
            File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
            if (pictureFile == null){
                Log.d(TAG, "Error creating media file, check storage permissions: " +
                    e.getMessage());
                return;
            }
    
            try {
                FileOutputStream fos = new FileOutputStream(pictureFile);
                fos.write(data);
                fos.close();
            } catch (FileNotFoundException e) {
                Log.d(TAG, "File not found: " + e.getMessage());
            } catch (IOException e) {
                Log.d(TAG, "Error accessing file: " + e.getMessage());
            }
        }
    };

     

      照相动作可以用按钮控制,如下:

    // Add a listener to the Capture button
    Button captureButton = (Button) findViewById(id.button_capture);
    captureButton.setOnClickListener(
        new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // get an image from the camera
                mCamera.takePicture(null, null, mPicture);
            }
        }
    );

     

    释放相机

      相机是设备资源,被所有应用共享,当应用不使用相机时应当及时释放,应当在Activity.onPause()中释放。

      如果不及时释放,后续的相机请求(包括你自己的应用和其他的应用发出的)都将失败并且导致应用退出。

    实验程序

      完整的照相程序需要考虑相机切换、预览图像的尺寸设置、焦距变换、缩放、白平衡的相机参数设置。

      请查阅文后的参考资料进行进一步学习。

      附上一个粗糙待完善的自定义相机程序(2013/4/6)

      预览图像类: 

    CameraPreview
    package com.example.hellocustomcamera;
    
    import java.io.IOException;
    import java.util.List;
    
    import android.R.integer;
    import android.content.Context;
    import android.graphics.ImageFormat;
    import android.graphics.PixelFormat;
    import android.hardware.Camera;
    import android.hardware.Camera.CameraInfo;
    import android.hardware.Camera.Size;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    
    /**
     * 相机图片预览类
     * 
     * @author
     * 
     */
    public class CameraPreview extends SurfaceView implements
            SurfaceHolder.Callback
    {
    
        private SurfaceHolder mHolder;
        private Camera mCamera;
        Size mPreviewSize;
        List<Size> mSupportedPreviewSizes;
    
        public CameraPreview(Context context, AttributeSet attrs, int defStyle)
        {
            super(context, attrs, defStyle);
            init();
        }
    
        public CameraPreview(Context context, AttributeSet attrs)
        {
            super(context, attrs);
            init();
        }
    
        public CameraPreview(Context context)
        {
            super(context);
            init();
        }
    
        /**
         * 初始化工作
         * 
         */
        private void init()
        {
            Log.d(AppConstants.LOG_TAG, "CameraPreview initialize");
    
            // Install a SurfaceHolder.Callback so we get notified when the
            // underlying surface is created and destroyed.
            mHolder = getHolder();
            mHolder.addCallback(this);
            // deprecated setting, but required on Android versions prior to 3.0
            mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    
        }
    
        public void setCamera(Camera camera)
        {
    
            mCamera = camera;
            if (mCamera != null)
            {
                mSupportedPreviewSizes = mCamera.getParameters()
                        .getSupportedPreviewSizes();
                requestLayout();
            }
        }
    
        @Override
        public void surfaceCreated(SurfaceHolder holder)
        {
            Log.d(AppConstants.LOG_TAG, "surfaceCreated");
            // The Surface has been created, now tell the camera where to draw the
            // preview.
            try
            {
                if (null != mCamera)
                {
                    mCamera.setPreviewDisplay(holder);
                }
            }
            catch (IOException e1)
            {
                e1.printStackTrace();
    
                Log.d(AppConstants.LOG_TAG,
                        "Error setting camera preview display: " + e1.getMessage());
            }
            try
            {
                if (null != mCamera)
                {
                    mCamera.startPreview();
                }
    
                Log.d(AppConstants.LOG_TAG, "surfaceCreated successfully! ");
            }
            catch (Exception e)
            {
                Log.d(AppConstants.LOG_TAG,
                        "Error setting camera preview: " + e.getMessage());
            }
        }
    
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height)
        {
    
            Log.d(AppConstants.LOG_TAG, "surface changed");
            // If your preview can change or rotate, take care of those events here.
            // Make sure to stop the preview before resizing or reformatting it.
    
            if (null == mHolder.getSurface())
            {
                // preview surface does not exist
                return;
            }
    
            // stop preview before making changes
            try
            {
                if (null != mCamera)
                {
                    mCamera.stopPreview();
                }
            }
            catch (Exception e)
            {
                // ignore: tried to stop a non-existent preview
            }
    
            // set preview size and make any resize, rotate or
            // reformatting changes here
    
            if (null != mCamera)
            {
                Camera.Parameters parameters = mCamera.getParameters();
                parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
    
                requestLayout();
    
                mCamera.setParameters(parameters);
                mCamera.setDisplayOrientation(90);
                Log.d(AppConstants.LOG_TAG, "camera set parameters successfully!: "
                        + parameters);
    
            }
            // 这里可以用来设置尺寸
    
            // start preview with new settings
            try
            {
                if (null != mCamera)
                {
    
                    mCamera.setPreviewDisplay(mHolder);
                    mCamera.startPreview();
                }
    
            }
            catch (Exception e)
            {
                Log.d(AppConstants.LOG_TAG,
                        "Error starting camera preview: " + e.getMessage());
            }
        }
    
        @Override
        public void surfaceDestroyed(SurfaceHolder holder)
        {
            Log.d(AppConstants.LOG_TAG, "surfaceDestroyed");
    
            if (null != mCamera)
            {
                mCamera.stopPreview();
            }
    
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
        {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    
            // We purposely disregard child measurements because act as a
            // wrapper to a SurfaceView that centers the camera preview instead
            // of stretching it.
            final int width = resolveSize(getSuggestedMinimumWidth(),
                    widthMeasureSpec);
            final int height = resolveSize(getSuggestedMinimumHeight(),
                    heightMeasureSpec);
            setMeasuredDimension(width, height);
    
            if (mSupportedPreviewSizes != null)
            {
                mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width,
                        height);
            }
        }
    
        private Size getOptimalPreviewSize(List<Size> sizes, int w, int h)
        {
            final double ASPECT_TOLERANCE = 0.1;
            double targetRatio = (double) w / h;
            if (sizes == null)
                return null;
    
            Size optimalSize = null;
            double minDiff = Double.MAX_VALUE;
    
            int targetHeight = h;
    
            // Try to find an size match aspect ratio and size
            for (Size size : sizes)
            {
                double ratio = (double) size.width / size.height;
                if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
                    continue;
                if (Math.abs(size.height - targetHeight) < minDiff)
                {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
    
            // Cannot find the one match the aspect ratio, ignore the requirement
            if (optimalSize == null)
            {
                minDiff = Double.MAX_VALUE;
                for (Size size : sizes)
                {
                    if (Math.abs(size.height - targetHeight) < minDiff)
                    {
                        optimalSize = size;
                        minDiff = Math.abs(size.height - targetHeight);
                    }
                }
            }
            return optimalSize;
        }
    
    }

      主要的Activity类:

    HelloCustomCameraActivity
    package com.example.hellocustomcamera;
    
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    import android.app.Activity;
    import android.content.Context;
    import android.content.pm.PackageManager;
    import android.hardware.Camera;
    import android.hardware.Camera.CameraInfo;
    import android.hardware.Camera.PictureCallback;
    import android.os.Bundle;
    import android.os.Environment;
    import android.util.Log;
    import android.view.Display;
    import android.view.View;
    import android.view.Window;
    import android.view.WindowManager;
    import android.widget.Button;
    import android.widget.FrameLayout;
    import android.widget.Toast;
    
    public class HelloCustomCameraActivity extends Activity
    {
    
        private Camera mCamera;
        private CameraPreview mPreview;
    
        int mNumberOfCameras;
        int mCameraCurrentlyLocked;
    
        // The first rear facing camera
        int mDefaultCameraId;
    
        int mScreenWidth, mScreenHeight;
    
        @Override
        public void onCreate(Bundle savedInstanceState)
        {
            Log.d(AppConstants.LOG_TAG, "onCreate");
            super.onCreate(savedInstanceState);
    
            // 无标题栏的窗口
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
    
            // 设置布局
            setContentView(R.layout.activity_hello_custom_camera);
    
            // 得到屏幕的大小
            WindowManager wManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
            Display display = wManager.getDefaultDisplay();
            mScreenHeight = display.getHeight();
            mScreenWidth = display.getWidth();
    
            // Create our Preview view and set it as the content of our activity.
            mPreview = new CameraPreview(this);
    
            FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
    
            // 将相机预览图加入帧布局里面
            preview.addView(mPreview, 0);
    
            // 使用按钮进行拍摄动作监听
            Button captureButton = (Button) findViewById(R.id.button_capture);
            captureButton.setOnClickListener(new View.OnClickListener()
            {
                @Override
                public void onClick(View v)
                {
                    // get an image from the camera
                    mCamera.takePicture(null, null, mPicture);
                }
            });
    
            // 得到默认的相机ID
            mDefaultCameraId = getDefaultCameraId();
            mCameraCurrentlyLocked = mDefaultCameraId;
    
        }
    
        @Override
        protected void onResume()
        {
            Log.d(AppConstants.LOG_TAG, "onResume");
            super.onResume();
    
            // Open the default i.e. the first rear facing camera.
            mCamera = getCameraInstance(mCameraCurrentlyLocked);
            
            mPreview.setCamera(mCamera);
        }
    
        @Override
        protected void onPause()
        {
            Log.d(AppConstants.LOG_TAG, "onPause");
            super.onPause();
    
            // Because the Camera object is a shared resource, it's very
            // important to release it when the activity is paused.
            if (mCamera != null)
            {
                mPreview.setCamera(null);
                Log.d(AppConstants.LOG_TAG, "onPause --> Realease camera");
                mCamera.release();
                mCamera = null;
            }
    
        }
    
        @Override
        protected void onDestroy()
        {
            Log.d(AppConstants.LOG_TAG, "onDestroy");
            super.onDestroy();
    
        }
    
        /**
         * 得到默认相机的ID
         * 
         * @return
         */
        private int getDefaultCameraId()
        {
            Log.d(AppConstants.LOG_TAG, "getDefaultCameraId");
            int defaultId = -1;
    
            // Find the total number of cameras available
            mNumberOfCameras = Camera.getNumberOfCameras();
    
            // Find the ID of the default camera
            CameraInfo cameraInfo = new CameraInfo();
            for (int i = 0; i < mNumberOfCameras; i++)
            {
                Camera.getCameraInfo(i, cameraInfo);
                Log.d(AppConstants.LOG_TAG, "camera info: " + cameraInfo.orientation);
                if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK)
                {
                    defaultId = i;
                }
            }
            if (-1 == defaultId)
            {
                if (mNumberOfCameras > 0)
                {
                    // 如果没有后向摄像头
                    defaultId = 0;
                }
                else
                {
                    // 没有摄像头
                    Toast.makeText(getApplicationContext(), R.string.no_camera,
                            Toast.LENGTH_LONG).show();
                }
            }
            return defaultId;
        }
    
        /** A safe way to get an instance of the Camera object. */
        public static Camera getCameraInstance(int cameraId)
        {
            Log.d(AppConstants.LOG_TAG, "getCameraInstance");
            Camera c = null;
            try
            {
                c = Camera.open(cameraId); // attempt to get a Camera instance
            }
            catch (Exception e)
            {
                // Camera is not available (in use or does not exist)
                e.printStackTrace();
                Log.e(AppConstants.LOG_TAG, "Camera is not available");
            }
            return c; // returns null if camera is unavailable
        }
    
        public static final int MEDIA_TYPE_IMAGE = 1;
        public static final int MEDIA_TYPE_VIDEO = 2;
    
        /** Create a File for saving an image or video */
        private static File getOutputMediaFile(int type)
        {
            Log.d(AppConstants.LOG_TAG, "getOutputMediaFile");
            // To be safe, you should check that the SDCard is mounted
            // using Environment.getExternalStorageState() before doing this.
    
            File mediaStorageDir = null;
            try
            {
                // This location works best if you want the created images to be
                // shared
                // between applications and persist after your app has been
                // uninstalled.
                mediaStorageDir = new File(
                        Environment
                                .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
                        "MyCameraApp");
    
                Log.d(AppConstants.LOG_TAG,
                        "Successfully created mediaStorageDir: " + mediaStorageDir);
    
            }
            catch (Exception e)
            {
                e.printStackTrace();
                Log.d(AppConstants.LOG_TAG, "Error in Creating mediaStorageDir: "
                        + mediaStorageDir);
            }
    
            // Create the storage directory if it does not exist
            if (!mediaStorageDir.exists())
            {
                if (!mediaStorageDir.mkdirs())
                {
                    // 在SD卡上创建文件夹需要权限:
                    // <uses-permission
                    // android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
                    Log.d(AppConstants.LOG_TAG,
                            "failed to create directory, check if you have the WRITE_EXTERNAL_STORAGE permission");
                    return null;
                }
            }
    
            // Create a media file name
            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
                    .format(new Date());
            File mediaFile;
            if (type == MEDIA_TYPE_IMAGE)
            {
                mediaFile = new File(mediaStorageDir.getPath() + File.separator
                        + "IMG_" + timeStamp + ".jpg");
            }
            else if (type == MEDIA_TYPE_VIDEO)
            {
                mediaFile = new File(mediaStorageDir.getPath() + File.separator
                        + "VID_" + timeStamp + ".mp4");
            }
            else
            {
                return null;
            }
    
            return mediaFile;
        }
    
        private PictureCallback mPicture = new PictureCallback()
        {
    
            @Override
            public void onPictureTaken(byte[] data, Camera camera)
            {
                Log.d(AppConstants.LOG_TAG, "onPictureTaken");
    
                File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
                if (pictureFile == null)
                {
                    Log.d(AppConstants.LOG_TAG,
                            "Error creating media file, check storage permissions: ");
                    return;
                }
    
                try
                {
                    FileOutputStream fos = new FileOutputStream(pictureFile);
                    fos.write(data);
                    fos.close();
                }
                catch (FileNotFoundException e)
                {
                    Log.d(AppConstants.LOG_TAG, "File not found: " + e.getMessage());
                }
                catch (IOException e)
                {
                    Log.d(AppConstants.LOG_TAG,
                            "Error accessing file: " + e.getMessage());
                }
    
                // 拍照后重新开始预览
                mCamera.stopPreview();
                mCamera.startPreview();
            }
        };
    
        /** Check if this device has a camera */
        private boolean checkCameraHardware(Context context)
        {
            if (context.getPackageManager().hasSystemFeature(
                    PackageManager.FEATURE_CAMERA))
            {
                // this device has a camera
                return true;
            }
            else
            {
                // no camera on this device
                return false;
            }
        }
    
    
    
    }

      布局文件:

    activity_hello_custom_camera.xml
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >
    
        <FrameLayout
            android:id="@+id/camera_preview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1" >
    
        <Button
            android:id="@+id/button_capture"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|center"
            android:text="Capture" />
    
        </FrameLayout>
    
    </LinearLayout>

      Manifest文件:

    AndroidManifest.xml
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.hellocustomcamera"
        android:versionCode="1"
        android:versionName="1.0" >
    
        <uses-sdk
            android:minSdkVersion="9"
            android:targetSdkVersion="15" />
    
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.CAMERA" />
    
        <uses-feature android:name="android.hardware.camera" />
    
        <application
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            <activity
                android:name=".HelloCustomCameraActivity"
                android:label="@string/title_activity_hello_custom_camera" >
    
                <!-- android:screenOrientation="landscape" -->
                <!-- configure this activity to use landscape orientation -->
    
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>

      三星S5660上测试可以拍照用,其他手机未知。

      

     

    参考资料

      Reference: Camera

      http://developer.android.com/reference/android/hardware/Camera.html

      相机参数:

      http://developer.android.com/reference/android/hardware/Camera.Parameters.html

      API Guides: Camera

      http://developer.android.com/guide/topics/media/camera.html

      API Demos:

      com.example.android.apis.graphics包下的CameraPreview

      实例教程:Android设备功能之Camera教程篇:

      http://www.eoeandroid.com/thread-167870-1-1.html

     

  • 相关阅读:
    20170809--JS操作Select备忘
    20160711--C# 委托的三种调用示例(同步调用 异步调用 异步回调)【转载】
    C# 内存建表备忘
    富文本编辑器 CKeditor 配置使用
    20160520—JS打分控件
    20160513--js 弹出窗口带有iframe控件 备忘
    chart 简单应用
    mvc 简单整理
    ObjectDatasourse 的绑定及显示
    GridView 详述
  • 原文地址:https://www.cnblogs.com/mengdd/p/3002975.html
Copyright © 2020-2023  润新知