Android摄像头基础——第二阶段 自定义简单的相机

这里写图片描述


一、
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>
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!感谢您的提问。 以下是一个简单Android 计数器的基础编码示例: 1. 在 activity_main.xml 文件中添加以下代码: ``` <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/counterTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="0" android:textSize="50dp" android:layout_gravity="center_horizontal"/> <Button android:id="@+id/incrementButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Increment" android:layout_gravity="center_horizontal" android:onClick="incrementCounter"/> <Button android:id="@+id/resetButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Reset" android:layout_gravity="center_horizontal" android:onClick="resetCounter"/> </LinearLayout> ``` 2. 在 MainActivity.java 文件中添加以下代码: ``` public class MainActivity extends AppCompatActivity { private int counter = 0; private TextView counterTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); counterTextView = findViewById(R.id.counterTextView); } public void incrementCounter(View view) { counter++; counterTextView.setText(Integer.toString(counter)); } public void resetCounter(View view) { counter = 0; counterTextView.setText(Integer.toString(counter)); } } ``` 3. 运行应用程序,您将看到一个显示当前计数器值的 TextView 和两个按钮:Increment 和 Reset。单击 Increment 按钮将增加计数器值,单击 Reset 按钮将将计数器值重置为零。 希望这可以帮助您入门 Android 编程!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值