安卓打开相机

在AndroidManifest.xml文件manifest添加相机权限
<!-- 相机 -->
    <uses-permission android:name="android.permission.CAMERA" /&gt;
    <!-- 录音 --&gt;
    <uses-permission android:name="android.permission.RECORD_AUDIO" /&gt;
    <!-- 存储读写 --&gt;
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /&gt;
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /&gt;
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /&gt;
    <!-- 获取网络状态 --&gt;
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /&gt;
    <!-- 互联网 -->
    <uses-permission android:name="android.permission.INTERNET" />

设置界面包含一个按钮Button一个ImageView,Button用来显示按钮,ImageView用来放置拍摄后的照片,全部代码如下

界面代码

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:id="@+id/btn_original"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="打开相机"
            android:textColor="@color/black"
            android:textSize="17sp"/>
    </LinearLayout>
    <ImageView
        android:id="@+id/iv_photo"
        android:layout_width="match_parent"
        android:layout_height="360dp"
        android:scaleType="fitCenter"/>
</LinearLayout>

MainActivity代码:

package com.example.ocr;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.content.ContentValues;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.widget.ImageView;

import com.example.ocr.util.BitmapUtil;
import com.example.ocr.util.DateUtil;

public class MainActivity extends AppCompatActivity {
    private static final int REQUEST_CAMERA_PERMISSION = 100;
    private ImageView iv_photo; // 声明一个图像视图对象
    private Uri mImageUri;// 图片路径对象
    private ActivityResultLauncher launcherOriginal; // 声明一个活动结果启动器对象

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        iv_photo = findViewById(R.id.iv_photo);
        // 注册一个善后工作的活动结果启动器准备打开拍照界面返回原始图)
        launcherOriginal = registerForActivityResult(
                new ActivityResultContracts.TakePicture(), result -> {
                    if (result) {
                        Bitmap bitmap = BitmapUtil.getAutoZoomImage(this, mImageUri);
                        iv_photo.setImageBitmap(bitmap);
                        // 在这里处理原始照片逻辑
                    }
                });
        findViewById(R.id.btn_original).setOnClickListener(v -> {
            if (checkCameraPermission()) {
                takeOriginalPhoto();
            } else {
                requestCameraPermission();
            }
        });
    }

    private boolean checkCameraPermission() {
        return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
                == PackageManager.PERMISSION_GRANTED;
    }

    private void requestCameraPermission() {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
            // 显示权限说明对话框
            // 可以使用一个对话框或其他方式用户解释为什么需要相机权限,并在用户同意后请求权限
        } else {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
                    REQUEST_CAMERA_PERMISSION);
        }
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CAMERA_PERMISSION) {
            if (grantResults.length > 0 &amp;&amp; grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                takeOriginalPhoto();
            } else {
                // 相机权限被拒绝可以显示一条消息执行其他操作
            }
        }
    }
    // 拍照获取原始图片
    private void takeOriginalPhoto() {
        // Android10开始必须由系统自动分配路径,同时该方式也能自动刷新相册
        ContentValues values = new ContentValues();
        // 指定图片文件名称
        values.put(MediaStore.Images.Media.DISPLAY_NAME, "photo_" + DateUtil.getNowDateTime());
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");// 类型图像
        // 通过内容解析器插入一条外部内容的路径信息
        mImageUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

        launcherOriginal.launch(mImageUri);
    }
}

BitmapUtil.java 文件代码:

package com.example.ocr.util;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.net.Uri;
import android.provider.MediaStore;
import android.util.Log;

import java.io.FileOutputStream;
import java.io.InputStream;

public class BitmapUtil {
    private final static String TAG = "BitmapUtil";

    // 把位图数据保存指定路径的图片文件
    public static void saveImage(String path, Bitmap bitmap) {
        // 根据指定文件路径构建文件输出流对象
        try (FileOutputStream fos = new FileOutputStream(path)) {
            // 把位图数据压缩到文件输出流中
            bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 获得旋转角度之后的位图对象
    public static Bitmap getRotateBitmap(Bitmap bitmap, float rotateDegree) {
        Matrix matrix = new Matrix(); // 创建作图片用的矩阵对象
        matrix.postRotate(rotateDegree); // 执行图片旋转动作
        // 创建返回旋转后的位图对象
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
                bitmap.getHeight(), matrix, false);
    }

    // 获得比例缩放之后的位图对象
    public static Bitmap getScaleBitmap(Bitmap bitmap, double scaleRatio) {
        int new_width = (int) (bitmap.getWidth() * scaleRatio);
        int new_height = (int) (bitmap.getHeight() * scaleRatio);
        // 创建返回缩放后的位图对象
        return Bitmap.createScaledBitmap(bitmap, new_width, new_height, false);
    }

    // 获得自动缩小后的位图对象
    public static Bitmap getAutoZoomImage(Context ctx, Uri uri) {
        Log.d(TAG, "getAutoZoomImage uri="+uri.toString());
        Bitmap zoomBitmap = null;
        // 打开指定uri获得输入流对象
        try (InputStream is = ctx.getContentResolver().openInputStream(uri)) {
            // 从输入解码得到原始的位图对象
            Bitmap originBitmap = BitmapFactory.decodeStream(is);
            int ratio = originBitmap.getWidth()/2000+1;
            // 获得比例缩放之后的位图对象
            zoomBitmap = BitmapUtil.getScaleBitmap(originBitmap, 1.0/ratio);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return zoomBitmap;
    }

    // 获得自动缩小后的位图对象
    public static Bitmap getAutoZoomImage(Bitmap origin) {
        int ratio = origin.getWidth()/2000+1;
        // 获得比例缩放之后的位图对象
        Bitmap zoomBitmap = getScaleBitmap(origin, 1.0/ratio);
        return zoomBitmap;
    }

    // 通知相册来了张新图片
    public static void notifyPhotoAlbum(Context ctx, String filePath) {
        try {
            String fileName = filePath.substring(filePath.lastIndexOf("/")+1);
            MediaStore.Images.Media.insertImage(ctx.getContentResolver(),
                    filePath, fileName, null);
            Uri uri = Uri.parse("file://" + filePath);
            Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri);
            ctx.sendBroadcast(intent);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

详细说明MainActivity代码

private static final int REQUEST_CAMERA_PERMISSION = 100;
private ImageView iv_photo; // 声明一个图像视图对象
    private Uri mImageUri;// 图片的路径对象

private static final int REQUEST_CAMERA_PERMISSION = 100;用来定义请求相机权限的请求码。在Android中,当我们请求权限时,需要为每个权限请求分配一个唯一的请求码。

private ActivityResultLauncher launcherOriginal; // 声明一个活动结果启动器对象

ActivityResultLauncher launcherOriginal用于注册处理拍照返回的原始图片的活动结果启动器

ActivityResultLauncher 是 Android Jetpack 库中的一个组件,它提供了一种方便的方式来处理活动结果(如启动相机拍照返回的结果)。

在代码中,我们使用 registerForActivityResult() 方法创建一个 ActivityResultLauncher 对象,并指定使用 ActivityResultContracts.TakePicture() 作为活动结果合同这个合同定义我们希望从活动结果中接收数据类型操作

通过注册 ActivityResultLauncher我们可以按钮点击事件使用 launcherOriginal.launch(mImageUri)启动相机拍照,并在相机拍照完成后接收和处理返回的结果。

launcherOriginal回调中,我们可以根据结果进行逻辑处理例如,在代码中,如果结果为 true,则表示拍照成功我们可以调用 BitmapUtil.getAutoZoomImage() 方法获取处理原始照片的 Bitmap 对象,并将其显示图像视图中。

通过使用 ActivityResultLauncher我们可以更方便地处理活动结果,并将逻辑封装回调中,使代码更加清晰和易于维护

new ActivityResultContracts.TakePicture(), result -> {
    if (result) {
        Bitmap bitmap = BitmapUtil.getAutoZoomImage(this, mImageUri);
        iv_photo.setImageBitmap(bitmap);
        // 在这里处理原始照片逻辑
    }
});

result 是拍照操作完成返回的结果。在使用 ActivityResultContracts.TakePicture() 合同启动相机拍照时,它将返回一个布尔值结果,表示拍照操作是否成功

用户完成拍照操作并返回时,系统会将结果传递result 参数然后我们可以在回调中根据结果进行逻辑处理。

如果 resulttrue表示拍照成功。在这种情况下,我们可以继续处理原始照片逻辑。在代码中,它调用BitmapUtil.getAutoZoomImage() 方法获取并处理原始照片的 Bitmap 对象,并将其设置ImageView显示

需要注意的是,根据具体的实现result类型可能会有所不同。在 ActivityResultContracts.TakePicture() 合同中,它指定了返回的结果类型为 Boolean,因此在回调中,result 的类型将是 Boolean

findViewById(R.id.btn_original).setOnClickListener(v -> {
    if (checkCameraPermission()) {
        takeOriginalPhoto();
    } else {
        requestCameraPermission();
    }
});

findViewById(R.id.btn_original) 用于查找布局文件中具有 R.id.btn_original ID 的按钮控件。这是一个点事件监听器,当按钮点击时,会执行相应的逻辑

逻辑如下

  • 首先,通过 checkCameraPermission() 方法检查是否已经授予相机权限。
  • 如果相机权限已经授予,则调用 takeOriginalPhoto() 方法开始拍照操作。
  • 如果相机权限尚未授予,则调用 requestCameraPermission() 方法来请求相机权限。

这段代码的目的是在用户点击btn_original” 按钮时,检查相机权限状态,并根据权限状态执行相应的操作。如果权限已经授予,则启动拍照操作;如果权限尚未授予,则请求相机权限。这样可以确保在拍照之前获取必要的权限,以避免出现权限问题

其中v 是一个参数名,用于表示点击的 View(即按钮)对象。在设置点击事件时候,Android 系统会自动将被点击的 View 对象传递这个参数

在点击事件回调函数中,我们可以通过 v 参数引用和操作被点击的 View 对象。例如,可以调用 v.getId() 方法获取被点击的 View 的 ID,或者调用 v.setVisibility(View.GONE)隐藏该 View。

上述代码中,v作用用来执行根据按钮点击状态执行相应的操作,如检查权限、请求权限或执行拍照操作等。

private boolean checkCameraPermission() {
    return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
            == PackageManager.PERMISSION_GRANTED;
}

checkCameraPermission()用于检查是否已经授予相机权限。

在 Android 中,要使用敏感权限(如相机权限),需要在运行动态请求用户授权这个方法的作用检查应用程序是否已经被授予了相机权限。

具体解释如下

  1. checkSelfPermission(this, Manifest.permission.CAMERA):通过调用 ContextCompat.checkSelfPermission() 方法,检查应用程序是否已经被授予了相机权限。它接收两个参数,第一个参数是当前上下文this 指向当前ActivityContext 对象),第二个参数是要检查的权限(这里是相机权限)。
  2. PackageManager.PERMISSION_GRANTED:这是一个常量表示权限已经被授予的状态。
  3. ==比较操作符用于比较两个是否相等
  4. 返回值:如果相机权限已经被授予,那么 checkSelfPermission() 返回值等于 PackageManager.PERMISSION_GRANTED,因此方法返回 true。否则,返回 false表示相机权限尚未被授予。

通过调用这个方法,我们可以在需要使用相机功能之前检查相机权限的状态,以确保应用程序具备所需的权限,从而避免在没有权限的情况下执行相机相关的操作。

private void requestCameraPermission() {
    if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
        // 显示权限说明对话框
        // 可以使用一个对话框或其他方式向用户解释为什么需要相机权限,并在用户同意后请求权限
    } else {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
                REQUEST_CAMERA_PERMISSION);
    }
}
  1. shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA):通过调用 ActivityCompat.shouldShowRequestPermissionRationale() 方法,检查是否应该显示权限说明对话框。它接收两个参数,第一个参数是当前上下文(this 指向当前ActivityContext 对象),第二个参数是要请求的权限(这里是相机权限)。
  2. requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION):通过调用 ActivityCompat.requestPermissions() 方法,请求相机权限。它接收三个参数,第一个参数是当前上下文(this 指向当前ActivityContext 对象),第二个参数是要请求的权限数组这里包含相机权限),第三个参数是请求权限的请求码(这里使用常量 REQUEST_CAMERA_PERMISSION)。
    • 当调用这个方法后,系统会显示一个权限请求对话框给用户,用户可以选择授予或拒绝权限。
    • 结果将通过 onRequestPermissionsResult() 方法回调当前 Activity,可以在该方法中处理用户的权限授予结果。

通过调用这个方法,我们可以在需要相机权限的时候向用户请求权限,以便应用程序能够使用相机功能。如果用户之前拒绝了权限请求,还可以在需要的时候向用户解释权限的必要性,并再次请求权限。

public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_CAMERA_PERMISSION) {
        if (grantResults.length > 0 &amp;&amp; grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            takeOriginalPhoto();
        } else {
            // 相机权限被拒绝,可以显示一条消息或执行其他操作
        }
    }
}

这是一个回调方法 onRequestPermissionsResult(),当用户对权限请求作出响应时,系统会调用该方法。

具体解释如下

  1. requestCode == REQUEST_CAMERA_PERMISSION:首先,检查请求码是否与相机权限请求的请求码匹配。这是为了确保多个权限请求的情况下,正确处理相机权限的回调
  2. if (grantResults.length > 0 &amp;&amp; grantResults[0] == PackageManager.PERMISSION_GRANTED):检查授权结果数组 grantResults长度是否大于0,并且第一个权限的授权结果是否为 PackageManager.PERMISSION_GRANTED
    • 如果条件满足,表示用户授予了相机权限。
    • 如果条件不满足,表示用户拒绝了相机权限。
  3. 如果用户授予了相机权限,可以调用 takeOriginalPhoto() 方法来执行拍照操作。
    • 在该方法中,会获取相机权限并执行拍照逻辑。
  4. 如果用户拒绝了相机权限,可以在 else 代码块中执行其他操作,比如显示一条消息告知用户相机权限被拒绝,或者执行其他逻辑。

通过实现这个方法,可以根据用户对权限请求的响应,来处理相机权限授予或拒绝的情况,并做出相应的处理操作。

private void takeOriginalPhoto() {
    // Android10开始必须由系统自动分配路径,同时该方式也能自动刷新相册
    ContentValues values = new ContentValues();
    // 指定图片文件的名称
    values.put(MediaStore.Images.Media.DISPLAY_NAME, "photo_" + DateUtil.getNowDateTime());
    values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");// 类型为图像
    // 通过内容解析器插入一条外部内容的路径信息
    mImageUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

    launcherOriginal.launch(mImageUri);
}
  1. 创建一个 ContentValues 对象 values用于存储拍照图片的相关信息
  2. 使用 put() 方法向 values添加键值对:
  3. 通过内容解析器 getContentResolver().insert()法将图片的路径信息插入外部存储器的 MediaStore 数据库中,返回一个表示图片的 Uri 对象 mImageUri
  4. 最后,使用 launcherOriginal.launch(mImageUri) 启动拍照活动,并传递图片的 Uri 对象 mImageUri

总体来说,这段代码的作用创建一个用于拍照的 Uri,并将其传递launcherOriginal 启动器以便启动拍照活动。

详细说明BitmapUtil.java 文件代码

public static void saveImage(String path, Bitmap bitmap) {
    // 根据指定的文件路径构建文件输出流对象
    try (FileOutputStream fos = new FileOutputStream(path)) {
        // 把位图数据压缩到文件输出流中
        bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

方法签名public static void saveImage(String path, Bitmap bitmap)

在方法内部,通过构建文件输出流对象 FileOutputStream,将位图数据写入到指定路径的文件中。

  1. try (FileOutputStream fos = new FileOutputStream(path)) {
        bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos);
    } catch (Exception e) {
        e.printStackTrace();
    }
    

总体来说,这段代码的作用是将位图对象 bitmap数据压缩保存到指定路径 path 的图片文件中。

public static Bitmap getRotateBitmap(Bitmap bitmap, float rotateDegree) {
    Matrix matrix = new Matrix(); // 创建操作图片用的矩阵对象
    matrix.postRotate(rotateDegree); // 执行图片的旋转动作
    // 创建并返回旋转后的位图对象
    return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
            bitmap.getHeight(), matrix, false);
}

方法签名public static Bitmap getRotateBitmap(Bitmap bitmap, float rotateDegree)

在方法内部,首先创建一个用于操作图片的矩阵对象 Matrix

Matrix matrix = new Matrix();

使用 matrix.postRotate(rotateDegree) 方法来执行图片的旋转动作这里rotateDegree 是旋转的角度

最后,使用 Bitmap.createBitmap() 方法创建并返回旋转后的位图对象。

return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);

因此,这段代码的作用是将给定的位图对象 bitmap 进行旋转,旋转角度rotateDegree 参数指定,并返回旋转后的位图对象。

public static Bitmap getScaleBitmap(Bitmap bitmap, double scaleRatio) {
    int new_width = (int) (bitmap.getWidth() * scaleRatio);
    int new_height = (int) (bitmap.getHeight() * scaleRatio);
    // 创建并返回缩放后的位图对象
    return Bitmap.createScaledBitmap(bitmap, new_width, new_height, false);
}

方法签名public static Bitmap getScaleBitmap(Bitmap bitmap, double scaleRatio)

  • bitmap 是要进行缩放的位图对象。
  • scaleRatio 是缩放比例,大于1表示放大,小于1表示缩小。

在方法内部,首先计算缩放后的新宽度和新高度

int new_width = (int) (bitmap.getWidth() * scaleRatio);
int new_height = (int) (bitmap.getHeight() * scaleRatio);
  • bitmap.getWidth() 获取源位图的宽度
  • bitmap.getHeight() 获取源位图的高度
  • scaleRatio 是缩放比例。

使用 Bitmap.createScaledBitmap() 方法创建并返回缩放后的位图对象。

return Bitmap.createScaledBitmap(bitmap, new_width, new_height, false);

Bitmap.createScaledBitmap()方法用于根据给定的源位图和目标宽高创建新的位图。

  • 参数解释:
    • bitmap:源位图对象。
    • new_width目标位图的宽度。
    • new_height:目标位图的高度。
    • false:是否对源位图进行原位修改。这里设置为 false,表示创建新的位图对象。

因此,这段代码的作用是将给定的位图对象 bitmap 进行缩放操作,缩放比例由 scaleRatio 参数指定,并返回缩放后的位图对象

原文地址:https://blog.csdn.net/A4545156/article/details/131156128

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_48504.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注