You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android强制竖屏拍照功能实现遇阻,求助适配不同平板摄像头布局

解决Android强制竖屏拍照并统一照片方向的问题

我来帮你搞定这个困扰!你之前的代码里用MediaStore.EXTRA_SCREEN_ORIENTATION来强制相机竖屏,但这个参数的兼容性极差——大部分第三方相机APP都会直接忽略它,尤其是平板设备因为摄像头位置差异,拍摄出来的照片方向根本没法保证统一。

下面给你一套靠谱的解决方案,核心思路是:不依赖相机APP的方向设置,而是通过读取照片的Exif信息(记录拍摄时的设备方向),手动把照片旋转为竖屏。

步骤1:修正相机启动代码

先去掉不靠谱的EXTRA_SCREEN_ORIENTATION,同时确保我们自己的Activity在拍照前后的方向处理,还要兼容Android 7.0+的FileUri限制:

// 先保存当前Activity的屏幕方向,拍完照后恢复
private int mCurrentOrientation;
private File mPhotoFile;

// 启动相机的方法
private void launchCamera(int idRow) {
    // 保存当前方向
    mCurrentOrientation = getResources().getConfiguration().orientation;
    // 临时锁定当前Activity为竖屏
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

    Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if (cameraIntent.resolveActivity(getPackageManager()) != null) {
        try {
            // 创建照片存储目录
            File storageDir = new File(Environment.getExternalStorageDirectory() + PDF_FOLDER_C);
            if (!storageDir.exists()) {
                storageDir.mkdirs();
            }
            // 创建临时照片文件
            mPhotoFile = File.createTempFile("capture_photo", ".jpg", storageDir);

            // Android 7.0+用FileProvider生成安全Uri
            Uri photoUri;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                photoUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", mPhotoFile);
                cameraIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            } else {
                photoUri = Uri.fromFile(mPhotoFile);
            }

            cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
            startActivityForResult(cameraIntent, idRow);
        } catch (IOException e) {
            e.printStackTrace();
            // 恢复方向
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
        }
    }
}

步骤2:添加FileProvider配置(Android 7.0+必需)

AndroidManifest.xml中注册FileProvider:

<application>
    <!-- 其他配置 -->
    <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="${applicationId}.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>
</application>

然后在res/xml目录下创建file_paths.xml

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

步骤3:处理拍照结果,修正照片方向

onActivityResult中读取照片的Exif方向,然后旋转为竖屏:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    // 先恢复原来的屏幕方向
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

    if (requestCode == idRow && resultCode == RESULT_OK && mPhotoFile != null && mPhotoFile.exists()) {
        // 1. 获取照片的Exif拍摄方向
        int exifOrientation = getExifOrientation(mPhotoFile);
        // 2. 读取原图并旋转为竖屏
        Bitmap originalBitmap = BitmapFactory.decodeFile(mPhotoFile.getAbsolutePath());
        Bitmap rotatedBitmap = rotateBitmapToPortrait(originalBitmap, exifOrientation);
        // 3. 保存旋转后的照片(覆盖原文件)
        saveRotatedBitmap(rotatedBitmap, mPhotoFile);

        // 这里可以继续处理照片,比如显示到ImageView
        // imageView.setImageBitmap(rotatedBitmap);

        // 回收Bitmap避免内存泄漏
        originalBitmap.recycle();
        rotatedBitmap.recycle();
    }
}

// 读取照片的Exif方向信息
private int getExifOrientation(File imageFile) {
    try {
        ExifInterface exif = new ExifInterface(imageFile.getAbsolutePath());
        return exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
    } catch (IOException e) {
        e.printStackTrace();
        return ExifInterface.ORIENTATION_NORMAL;
    }
}

// 根据Exif方向旋转照片为竖屏
private Bitmap rotateBitmapToPortrait(Bitmap bitmap, int exifOrientation) {
    Matrix matrix = new Matrix();
    switch (exifOrientation) {
        case ExifInterface.ORIENTATION_ROTATE_90:
            matrix.postRotate(90);
            break;
        case ExifInterface.ORIENTATION_ROTATE_180:
            matrix.postRotate(180);
            break;
        case ExifInterface.ORIENTATION_ROTATE_270:
            matrix.postRotate(270);
            break;
        // 其他情况不需要旋转
        default:
            return bitmap;
    }
    return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}

// 保存旋转后的Bitmap到文件
private void saveRotatedBitmap(Bitmap bitmap, File targetFile) {
    try {
        FileOutputStream fos = new FileOutputStream(targetFile);
        bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);
        fos.flush();
        fos.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

关键说明

  1. 为什么不用EXTRA_SCREEN_ORIENTATION?
    这个参数是系统相机的私有约定,第三方相机APP完全可以不遵守,所以靠它强制方向根本不可靠。
  2. Exif信息的作用?
    不管设备摄像头在顶部还是侧面,相机拍摄时都会把设备的旋转角度记录到Exif中,我们只需要根据这个角度修正照片,就能保证最终输出都是竖屏。
  3. 权限注意事项
    别忘了在Manifest中添加权限,Android 6.0+还要动态申请:
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    

内容的提问来源于stack exchange,提问作者Mattia

火山引擎 最新活动