Android调用摄像头拍照

这篇来学习一下如何调用摄像头拍照。

学习自《第一行代码》

以下内容皆为真机测试。

xml文件

就一个按钮和一个显示图片的。

<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:id="@+id/btnTakePhoto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Take Photo"/>

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"/>

</LinearLayout>

MainActivity中的代码

public class MainActivity extends AppCompatActivity {

    private int takePhoto = 1;
    private Uri imageUri;
    private File outputImage;

    private Button btnTakePhoto;
    private ImageView imageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnTakePhoto = findViewById(R.id.btnTakePhoto);
        imageView = findViewById(R.id.imageView);

        //  拍照按钮
        btnTakePhoto.setOnClickListener(view -> {
            //  创建File对象,用于存储拍照后的图片,命名为output_image.jdp
            //  存放在手机SD卡的应用关联缓存目录下
            outputImage = new File(getExternalCacheDir(), "output_image.jpg");
            if (outputImage.exists()) {
                outputImage.delete();
            }
            try {
                outputImage.createNewFile();
                //  如果运行设备的系统高于Android 7.0
                //  就调用FileProvider的getUriForFile()方法将File对象转换成一个封装过的Uri对象。
                //  该方法接收3个参数:Context对象, 任意唯一的字符串, 创建的File对象。
                //  这样做的原因:Android 7.0 开始,直接使用本地真实路径的Uri是被认为是不安全的,会抛出FileUriExposedException异常;
                //      而FileProvider是一种特殊的ContentProvider,他使用了和ContentProvider类似的机制对数据进行保护,可以选择性地将封装过的Uri共享给外部。
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    imageUri = FileProvider.getUriForFile(this, "com.example.permissiontest.fileprovider", outputImage);
                } else {
                    //  否则,就调用Uri的fromFile()方法将File对象转换成Uri对象
                    imageUri = Uri.fromFile(outputImage);
                }
                //  启动相机
                Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
                //  指定图片的输出地址,这样拍下的照片会被输出到output_image.jpg中。
                intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
                startActivityForResult(intent, takePhoto);
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == takePhoto) {
            if (resultCode == Activity.RESULT_OK) {
                //  将拍摄的照片显示出来
                try {
                    //  decodeStream()可以将output_image.jpg解析成Bitmap对象。
                    Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
                    imageView.setImageBitmap(rotateIfRequired(bitmap));
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 为了防止横屏照片时,返回产生的旋转,所以这里做的是将照片始终正常的竖屏显示
     * @param bitmap
     * @return
     */
    private Bitmap rotateIfRequired(Bitmap bitmap) {
        try {
            ExifInterface exifInterface = new ExifInterface(outputImage.getPath());
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            if (orientation == ExifInterface.ORIENTATION_ROTATE_90) return rotateBitmap(bitmap, 90);
            else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) return rotateBitmap(bitmap, 180);
            else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) return rotateBitmap(bitmap, 270);
            return bitmap;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private Bitmap rotateBitmap(Bitmap bitmap, int degree) {
        Matrix matrix = new Matrix();
        matrix.postRotate((float)degree);
        Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        //  将不再需要的Bitmap对象回收
        bitmap.recycle();
        return rotatedBitmap;
    }
}

注册ContentProvider

上述方法中用到了ContentProvider,所以需要去AndroidManifest.xml对它进行注册:

 <application
        ...
        <provider
            android:authorities="com.example.permissiontest.fileprovider"
            android:name="androidx.core.content.FileProvider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths"/>
        </provider>
        <activity
            ...
        </activity>
    </application>

其中android:name属性的值是固定的,android:authorities属性的值需要和刚才FileProvider.getUriForFile()方法的第二个参数相同。

这里还使用了<meta-data>标签指定Uri的共享路径,并引用了@xml/file_paths资源。现在需要去创建这个资源。

在res目录下新建文件夹xml,然后新建一个File,命名为file_paths.xml,内容如下:

<?xml version="1.0" encoding="UTF-8" ?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path
        name="my_images"
        path="/"/>
</paths>

其中, external-path是用来指定Uri共享路径的,name属性的值随便填,path值表示共享的具体路径。单斜杠表示将整个SD卡进行共享。

大功告成,现在去真机上测试时没有问题。

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
### 回答1: 要在Android Studio中打开摄像头,您需要使用Camera API。以下是一些基本步骤: 1. 在AndroidManifest.xml文件中添加相机权限: <uses-permission android:name="android.permission.CAMERA" /> 2. 在布局文件中添加SurfaceView元素: <SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="match_parent" /> 3. 在Activity中获取SurfaceView并设置它的回调: private SurfaceView surfaceView; private Camera camera; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); surfaceView = findViewById(R.id.surfaceView); surfaceView.getHolder().addCallback(surfaceCallback); } private SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { camera = Camera.open(); try { camera.setPreviewDisplay(holder); } catch (IOException e) { e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Camera.Parameters parameters = camera.getParameters(); parameters.setPreviewSize(width, height); camera.setParameters(parameters); camera.startPreview(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { camera.stopPreview(); camera.release(); } }; 4. 在AndroidManifest.xml文件中添加相机特性: <uses-feature android:name="android.hardware.camera" /> 这些是基本步骤,您可以根据需要进行更改和扩展。 ### 回答2: 要在Android Studio中打开摄像头,首先需要在AndroidManifest.xml文件中添加相机权限。在文件中添加以下代码: <uses-permission android:name="android.permission.CAMERA" /> 然后,在您的活动或碎片中添加一个SurfaceView或TextureView来显示摄像头预览。您可以在XML布局文件中添加以下代码: <SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="match_parent" /> 在Java文件中,您需要实现一些相机相关的类和接口。首先,您需要实现SurfaceHolder.Callback接口来获取SurfaceView对象。您可以在活动或碎片中的onCreate方法中添加以下代码: SurfaceView surfaceView = findViewById(R.id.surfaceView); SurfaceHolder surfaceHolder = surfaceView.getHolder(); surfaceHolder.addCallback(this); 然后,您需要实现Camera.PreviewCallback接口,以获取相机预览帧。在onCreate方法中,您可以打开相机和设置预览回调: Camera camera = Camera.open(); camera.setPreviewCallback(this); Camera.Parameters parameters = camera.getParameters(); parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); camera.setParameters(parameters); camera.setDisplayOrientation(90); camera.setPreviewDisplay(surfaceHolder); camera.startPreview(); 最后,您需要实现SurfaceHolder.Callback接口的以下方法: @Override public void surfaceCreated(SurfaceHolder holder) { } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { camera.stopPreview(); camera.release(); } 这样,您就可以在Android Studio中成功打开摄像头并显示预览画面了。当然,您还可以根据需要添加其他功能,如拍照或录制视频等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值