Android development-calling camera

Android open camera

Add camera permissions under manifest in AndroidManifest.xml file
<!-- 相机 -->
    <uses-permission android:name="android.permission.CAMERA" />
    <!-- 录音 -->
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <!-- 存储卡读写 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
    <!-- 获取网络状态 -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <!-- 互联网 -->
    <uses-permission android:name="android.permission.INTERNET" />

The setting interface includes a button Button and an ImageView. Button is used to display the button, and ImageView is used to place the taken photos. The entire code is as follows:

Interface code:

<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 code:

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 && 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 file code:

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();
        }
    }

}

Detailed description of MainActivity code

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

private static final int REQUEST_CAMERA_PERMISSION = 100;It is used to define the request code for requesting camera permission. In Android, when we request permissions, we need to assign a unique request code to each permission request.

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

ActivityResultLauncher launcherOriginalIs an activity result launcher for registering and processing the original image returned after taking a photo.

ActivityResultLauncherIt is a component in the Android Jetpack library that provides a convenient way to handle activity results (such as the results returned after starting the camera to take a picture).

In the code, we use registerForActivityResult()the method to create an ActivityResultLauncherobject and specify the use ActivityResultContracts.TakePicture()as activity result contract. This contract defines the data types and operations we wish to receive from the activity results.

By registering ActivityResultLauncher, we can use in the button click event launcherOriginal.launch(mImageUri)to start the camera to take pictures, and receive and process the returned results after the camera takes pictures.

In launcherOriginalthe callback of , we can perform logical processing based on the results. For example, in the code, if the result is true, it means that the photo was taken successfully. We can call BitmapUtil.getAutoZoomImage()the method to obtain and process the Bitmap object of the original photo and display it in the image view.

By using it ActivityResultLauncher, we can handle activity results more conveniently and encapsulate the logic in callbacks, making the code clearer and easier to maintain.

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

resultIt is the result returned after the photo operation is completed. When using ActivityResultContracts.TakePicture()the contract to start the camera to take a photo, it will return a Boolean result indicating whether the photo-taking operation was successful.

When the user completes the photo taking operation and returns, the system will pass the result to resultthe parameter, and then we can perform logical processing based on the result in the callback.

If result, trueit means the photo was taken successfully. In this case we can continue with the logic of the original photo. In the code, it calls BitmapUtil.getAutoZoomImage()the method to obtain and process the Bitmap object of the original photo, and set it to be ImageViewdisplayed in .

Note that depending on the specific implementation, resultthe type may vary. In ActivityResultContracts.TakePicture()the contract, it specifies that the returned result type is Boolean, so in the callback, resultthe type of will be Boolean.

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

findViewById(R.id.btn_original)R.id.btn_originalUsed to find the button control with ID in the layout file . This is a click event listener. When the button is clicked, the corresponding logic will be executed.

The logic is as follows:

  • First, checkCameraPermission()check if the camera permission has been granted via the method.
  • If the camera permission has been granted, call takeOriginalPhoto()the method to start the photo taking operation.
  • If camera permission has not been granted, requestCameraPermission()the method is called to request camera permission.

The purpose of this code is to check the camera permission status when the user clicks the "btn_original" button, and perform corresponding operations based on the permission status. If the permission has been granted, start the photo taking operation; if the permission has not been granted, request the camera permission. This ensures that you obtain the necessary permissions before taking a photo to avoid permission issues.

where vis a parameter name used to represent the clicked View (i.e. button) object. When setting a click event, the Android system will automatically pass the clicked View object to this parameter.

In the callback function of the click event, we can vreference and operate the clicked View object through parameters. For example, you can call v.getId()the method to get the ID of the clicked View, or call v.setVisibility(View.GONE)to hide the View.

In the above code, vthe function is to perform corresponding operations based on the button click status, such as checking permissions, requesting permissions, or performing photo operations, etc.

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

checkCameraPermission(), used to check whether camera permission has been granted.

In Android, using sensitive permissions (such as camera permissions) requires dynamically requesting user authorization at runtime. The purpose of this method is to check whether the application has been granted camera permission.

The specific explanation is as follows:

  1. checkSelfPermission(this, Manifest.permission.CAMERA): ContextCompat.checkSelfPermission()Check whether the application has been granted camera permission by calling the method. It receives two parameters, the first parameter is the current context ( thispointing to the current Activityor Contextobject), and the second parameter is the permission to check (here, the camera permission).
  2. PackageManager.PERMISSION_GRANTED: This is a constant indicating the status that permission has been granted.
  3. ==: Comparison operator, used to compare whether two values ​​are equal.
  4. Return value: If the camera permission has been granted, then checkSelfPermission()the return value will be equal to PackageManager.PERMISSION_GRANTED, so the method returns true. Otherwise, return falseindicating that camera permission has not been granted yet.

By calling this method, we can check the status of the camera permission before needing to use the camera function to ensure that the application has the required permissions, thereby avoiding performing camera-related operations without permission.

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): Check whether the permission description dialog should be displayed by calling ActivityCompat.shouldShowRequestPermissionRationale()the method. It receives two parameters, the first parameter is the current context ( thispointing to the current Activityor Contextobject), and the second parameter is the permission to be requested (here, the camera permission).
    • If returned true, it means that the permission description dialog box should be displayed to the user at this time. You can use a dialog box or other means to explain to the user why camera permission is required, and request permission again after the user agrees.
    • If returned false, it means that the permission description dialog box should not be displayed at this time, and permission can be requested directly.
  2. requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION): ActivityCompat.requestPermissions()Request camera permission by calling the method. It receives three parameters. The first parameter is the current context ( thispointing to the current Activityor Contextobject), the second parameter is the permission array to be requested (only camera permissions are included here), and the third parameter is the request code for requesting permissions ( Constants are used here REQUEST_CAMERA_PERMISSION).
    • When this method is called, the system will display a permission request dialog box to the user, and the user can choose to grant or deny permission.
    • The result will onRequestPermissionsResult()be called back to the current through the method Activity, where the user's permission grant result can be processed.

By calling this method, we can request permission from the user when camera permission is needed so that the application can use the camera function. If the user has previously rejected the permission request, you can also explain the necessity of the permission to the user and request the permission again when needed.

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

This is a callback method onRequestPermissionsResult()that is called when the user responds to a permission request.

The specific explanation is as follows:

  1. requestCode == REQUEST_CAMERA_PERMISSION: First, check whether the request code matches the request code of the camera permission request. This is to ensure that camera permission callbacks are handled correctly in the event of multiple permission requests.
  2. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED): Check whether the length of the authorization result array grantResultsis greater than 0, and whether the authorization result of the first permission is PackageManager.PERMISSION_GRANTED.
    • If the conditions are met, it means that the user has granted camera permission.
    • If the conditions are not met, it means the user has denied camera permission.
  3. If the user has granted camera permission, takeOriginalPhoto()the method can be called to perform the photo taking operation.
    • In this method, camera permissions are obtained and the camera logic is executed.
  4. If the user denies camera permission, you can elseperform other actions in the code block, such as displaying a message telling the user that camera permission is denied, or performing other logic.

By implementing this method, the camera permission grant or denial can be handled based on the user's response to the permission request, and corresponding processing operations can be performed.

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. Create an ContentValuesobject valuesto store information about the photo taken.
  2. Use put()the method to valuesadd key-value pairs to :
    • MediaStore.Images.Media.DISPLAY_NAME: Specify the name of the image file, using the current date and time as part of the file name.
    • MediaStore.Images.Media.MIME_TYPE: Specify the MIME type of the image, here set to "image/jpeg", indicating that the image type is JPEG.
  3. getContentResolver().insert()Insert the path information of the picture into the MediaStore database of the external memory through the content parser method, and return a Uri object representing the picture mImageUri.
    • MediaStore.Images.Media.EXTERNAL_CONTENT_URIIs a Uri representing a collection of pictures in external storage.
  4. Finally, use to launcherOriginal.launch(mImageUri)start the photo taking activity and pass the Uri object of the image mImageUri.
    • launcherOriginalregisterForActivityResult()It is an activity result launcher previously registered through and is used to process the results of photo-taking activities.

Overall, what this code does is create a Uri for taking photos and pass it to the launcherOriginallauncher to start the photo taking activity.

Detailed description of BitmapUtil.java file code

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();
    }
}

Method signature:public static void saveImage(String path, Bitmap bitmap)

  • pathIs the path to save the image file, which is a string type.
  • bitmapIs the bitmap object to be saved.

Inside the method, FileOutputStreamthe bitmap data is written to the file at the specified path by constructing a file output stream object.

  1. try (FileOutputStream fos = new FileOutputStream(path)) {
          
          
        bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos);
    } catch (Exception e) {
          
          
        e.printStackTrace();
    }
    
    • FileOutputStreamIs the output stream used to write data to a file.
    • compress()Method used to compress bitmap data into a file output stream.
    • Bitmap.CompressFormat.JPEGIndicates that the bitmap is compressed in JPEG format.
    • 80It is a parameter of compression quality, with a value range of 0-100. The larger the value, the better the quality and the larger the file size.
    • fosIs a file output stream object created through the constructor method.

bitmapGenerally speaking, the function of this code is to compress and save the data of the bitmap object to paththe image file at the specified 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);
}

Method signature:public static Bitmap getRotateBitmap(Bitmap bitmap, float rotateDegree)

  • bitmapIs the bitmap object to be rotated.
  • rotateDegreeis the angle of rotation, with clockwise direction being the positive value.

Inside the method, first create a matrix object for operating pictures Matrix.

Matrix matrix = new Matrix();

Use matrix.postRotate(rotateDegree)the method to perform image rotation. Here rotateDegreeis the angle of rotation.

Finally, use Bitmap.createBitmap()the method to create and return the rotated bitmap object.

return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
  • Bitmap.createBitmap()Method used to create a new bitmap based on the given source bitmap and matrix.
  • Parameter explanation:
    • bitmap: Source bitmap object.
    • (0, 0): The starting point coordinates of cropping, which means cropping starts from the upper left corner of the original bitmap.
    • bitmap.getWidth(): Cropping width, here means cropping the entire width.
    • bitmap.getHeight(): The height of cropping, here means cropping the entire height.
    • matrix: Matrix object used to operate on the source bitmap.
    • false: Whether to modify the source bitmap in-situ. Set here falseto mean creating a new bitmap object.

bitmapTherefore, the function of this code is to rotate the given bitmap object by the rotation angle rotateDegreespecified by the parameter and return the rotated bitmap object.

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);
}

Method signature:public static Bitmap getScaleBitmap(Bitmap bitmap, double scaleRatio)

  • bitmapIs the bitmap object to be scaled.
  • scaleRatioIs the scaling ratio, greater than 1 means zooming in, and less than 1 means zooming out.

Inside the method, first calculate the new width and height after scaling.

int new_width = (int) (bitmap.getWidth() * scaleRatio);
int new_height = (int) (bitmap.getHeight() * scaleRatio);
  • bitmap.getWidth()Gets the width of the source bitmap.
  • bitmap.getHeight()Get the height of the source bitmap.
  • scaleRatiois the scaling ratio.

Use Bitmap.createScaledBitmap()the method to create and return a scaled bitmap object.

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

Bitmap.createScaledBitmap()Method used to create a new bitmap based on the given source bitmap and target width and height.

  • Parameter explanation:
    • bitmap: Source bitmap object.
    • new_width: The width of the target bitmap.
    • new_height: The height of the target bitmap.
    • false: Whether to modify the source bitmap in-situ. Set here falseto mean creating a new bitmap object.

bitmapTherefore, the function of this code is to scale the given bitmap object . The scaling ratio scaleRatiois specified by the parameter and return the scaled bitmap object.

Guess you like

Origin blog.csdn.net/A4545156/article/details/131156128