安卓调用手机摄像头和相册

调用摄像头和相册

调用摄像头进行拍照

  • 新建一个CameraAlbumTest项目,修改activity_main.xml中的代码
<?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:id="@+id/takePhotoBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="take photo" />

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

</LinearLayout>
  • 可以看到在布局文件当中,有一个Button和一个ImageView.Button是用于打开摄像头进行拍照的,而ImageView则是用于将拍到图片显示出来.
  • 在MainActivity中编写调用摄像头的代码逻辑
package com.zb.cameraalbumtest

import android.app.Activity
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
import android.media.ExifInterface
import android.net.Uri
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import androidx.core.content.FileProvider
import kotlinx.android.synthetic.main.activity_main.*
import java.io.File

/**
* @Description: 
* @author zb~
* @date 2022/12/21
*/
class MainActivity : AppCompatActivity() {
    val takePhoto = 1
    lateinit var imageUri: Uri
    lateinit var outputImage: File
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        takePhotoBtn.setOnClickListener {
            //创建File对象,用于存储拍照后的图片
            outputImage = File(externalCacheDir, "output_image.jpg")
            if (outputImage.exists()) {
                outputImage.delete()
            }
            outputImage.createNewFile()
            imageUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                FileProvider.getUriForFile(
                    this, "com.zb.cameraalbumtest.fileprovider",
                    outputImage
                )
            } else {
                Uri.fromFile(outputImage)
            }
            //启动相机程序
            val intent = Intent("android.media.action.IMAGE_CAPTURE")
            intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri)
            startActivityForResult(intent, takePhoto)
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        when (requestCode) {
            takePhoto -> {
                if (resultCode == Activity.RESULT_OK) {
                    //将拍摄的照片显示出来
                    Log.d("MainActivity", "进入")
                    val bitmap = BitmapFactory.decodeStream(
                        contentResolver.openInputStream(imageUri)
                    )
                    imageView.setImageBitmap(rotateIfRequire(bitmap))
                }
            }
        }
    }

    private fun rotateIfRequire(bitmap: Bitmap): Bitmap {
        val exif = ExifInterface(outputImage.path)
        val orientation = exif.getAttributeInt(
            ExifInterface.TAG_ORIENTATION,
            ExifInterface.ORIENTATION_NORMAL
        )
        return when (orientation) {
            ExifInterface.ORIENTATION_ROTATE_90 -> rotateBitmap(bitmap, 90)
            ExifInterface.ORIENTATION_ROTATE_180 -> rotateBitmap(bitmap, 180)
            ExifInterface.ORIENTATION_ROTATE_270 -> rotateBitmap(bitmap, 270)
            else -> bitmap
        }
    }

    private fun rotateBitmap(bitmap: Bitmap, degree: Int): Bitmap {
        val matrix = Matrix()
        matrix.postRotate(degree.toFloat())
        val rotateBitmap = Bitmap.createBitmap(
            bitmap, 0, 0, bitmap.width, bitmap.height,
            matrix, true
        )
        bitmap.recycle() //将不需要的Bitmap对象进行回收
        return rotateBitmap
    }
}
  • 首先创建了一个File对象,用于存储摄像头拍下的图片,这里将图片命名为output_image.jpg
  • 并且存放在手机SD卡的应用关联缓存目录下,所谓关联缓存目录就是SD卡中专门用于存放当前缓存数据的位置,调用getExternalCacheDir()方法可以得到这个目录.其具体的路径是:/sdcard/Android/data//cache
  • 至于为什么要使用这个关联缓存来存放图片是因为,从Android6.0系统开始,读写SD卡别列为了危险权限,如果将如片放在SD卡任何目录,都要进行运行时权限处理才行,而使用应用关联目录则可以跳过这一步
  • 另外,从Android10.0系统开始,公有的SD目录已经不再允许被应用程序直接访问了,而是要使用作用域存储才可以.
  • 接着会进行一个判断,如果运行设备的系统版本低于Android7.0就调用Uri的fromFile()方法将File对象转换成为Uri对象.
  • 这个Uri对象标识着output_image.jpg这张图片的本地真是路径
  • 否者就调用FileProvider的getUriForFile()方法将File对象转换成为一个封装过的Uri对象.
  • getUriForFile()方法接受三个参数:第一个参数要求传入Context对象,第二个参数可以是任意唯一的字符串,第三个参数则是我们刚刚创建的File对象
  • 之所以要进行这样一层转换是因为从Android7.0开始,直接使用本地真实的Uri被认为是不安全的,会抛出一个FileUriExposedException异常,而FileProvider则是一种特殊的ContentProvider,它使用了和ContentProvider类似的机制来对数据进行保护,可以选择性地将封装过的Uri共享给外部,从而提高应用的安全性.
  • 接下来构建了一个Intent对象,并将这个Intent得action指定为android.media.action.IMAGE_GAPTURE,在调用Intent.putExtra()方法来指定图片输出得地址,这里填入刚刚得到得Uri对象系统会找出能够响应这个Intent的Activity去启动.
  • 这样相机程序就会被打开,拍下的照片会被存放到output_image.jpg当中
  • 由于刚才使用的是startActivityForResult()启动Activity的,因此拍照完之后会有结果返回到onActivityResult()方法当中,如果发现拍照成功,就可以调用BitmapFactory的decodeStream()方法将output_image.jpg这张照片解析成为Bitmap对象,然后把它设置到ImageView中显示出来.
  • 需要注意的是,调用照相机程序去拍照可能会在一些手机上发生照片旋转的情况,这是因为这些手机认为打开摄像头进行拍摄是手机就应该是横屏的,因此回到竖屏的情况下就会发生90°旋转
  • 为此在代码当中加上了判断图片方向的代码,如果发现图片需要进行翻转,那么就先将图片旋转相应的角度,然后再显示到界面上.
  • 还没有完,因为FileProvider是一种特殊的ContentProvider,所以需要在AndroidManifest.xml当中对他进行注册才行.
<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="com.zb.cameraalbumtest.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDES_PATHS"
        android:resource="@xml/file_paths" />
</provider>
  • android:name属性的值是固定
  • android:authorities属性的值,必须和刚才FileProvider.getUriFile()方法第二参数值是一致的
  • 另外还需要在标签当中使用标签来指定Uri的共享路径,并引用了一个@xml/file_paths资源
  • 在res目录下面创建这个资源
<?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卡进行共享,当然也可以仅仅共享存放output_image.jpg这张图片的路径.

  • 这样代码就变写完了,运行项目,点击take photo就可以进行拍照了

从相册当中选取图片

  • 编辑activity_main.xml文件,在布局当中添加一个按钮用于,从相册当中选择图片
    <Button
        android:id="@+id/fromAlbumBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="from album"/>
  • 添加一个全局变量
    val takePhoto = 1
  • 编写该按钮的点击事件
        fromAlbumBtn.setOnClickListener {
            //打开文件选择器
            val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
            intent.addCategory(Intent.CATEGORY_OPENABLE)
            //指定只显示图片
            intent.type = "image/*"
            startActivityForResult(intent, fromAlbum)
        }
  • 在fromAlbum按钮的点击事件当中,先构建了一个Intent对象,并将它的action指定为Intent.ACTION_OPEN_DOCUMENT,表示打开系统的文件选择器,接着给这个Intent对象设置一些条件过滤,只允许可打开的图片显示出来,接着调用startActivityForResult()方法,我们给startActivityForResult()方法的第二个参数传入值为我们新定义的全局变量,这样当选择完图片之后会回到onActivityResult()方法是,就会进入fromAlbum的条件下处理图片
  • 编写onActivityResult()方法当中的逻辑
            fromAlbum -> {
                if (resultCode == Activity.RESULT_OK && data != null) {
                    data.data?.let { uri ->
                        //选择将图片进行显示
                        val bitmap = getBitmapFromUri(uri)
                        imageView.setImageBitmap(bitmap)
                    }
                }
            }
  • 调用了返回Intent的getData()方法来获取Uri,然后调用getBitmapFromUri()方法将Uri转换成为Bitmap对象,最终将图片显示到界面上
  • 编写getBitmapFromUri()方法
    private fun getBitmapFromUri(uri: Uri) = contentResolver.openFileDescriptor(uri, "r")?.use {
        BitmapFactory.decodeFileDescriptor(it.fileDescriptor)
    }
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android提供了方便的API来调用相册摄像头。要调用相册,我们可以使用Intent来发送一个请求给系统,打开相册应用。我们可以指定MIME类型为"image/*"来限制用户只能选择图片文件。然后,我们可以在回调中处理用户选择的图片。这样,我们就可以在我们的应用中使用用户选择的图片了。 要调用摄像头,我们也可以使用Intent来发送一个请求给系统,打开相机应用。我们可以指定MIME类型为"image/*"来限制用户只能拍摄图片。然后,我们可以在回调中处理用户拍摄的图片。这样,我们就可以在我们的应用中使用用户拍摄的照片了。 调用相册摄像头的代码示例如下: 调用相册: ```java Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); intent.setType("image/*"); startActivityForResult(intent, PICK_IMAGE_REQUEST_CODE); ``` 处理相册回调: ```java @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == PICK_IMAGE_REQUEST_CODE && resultCode == RESULT_OK && data != null) { Uri selectedImage = data.getData(); // 在这里处理用户选择的图片 } } ``` 调用摄像头: ```java Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(intent, CAPTURE_IMAGE_REQUEST_CODE); ``` 处理摄像头回调: ```java @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == CAPTURE_IMAGE_REQUEST_CODE && resultCode == RESULT_OK && data != null) { Bitmap photo = (Bitmap) data.getExtras().get("data"); // 在这里处理用户拍摄的照片 } } ``` 通过以上代码,我们可以很方便地调用相册摄像头,并在我们的应用中使用用户选择的图片或拍摄的照片。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值