You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Android Studio开发相机APP拍照画质过低及图库显示问题求助

解决相机APP低分辨率问题 + 图库显示实现方案

嘿,作为刚入坑Android开发的新手,碰到相机拍出来的照片分辨率只有177×144、远低于手机支持的3MP的问题,肯定超头疼吧!我来帮你一步步搞定这两个需求——提升照片画质,还有让拍摄的照片在图库中显示~

一、先搞定低分辨率的核心问题

你拍出来的照片尺寸这么小,大概率是没给相机指定合适的拍照/预览分辨率,默认用了系统提供的最小尺寸。下面是具体的修复步骤:

1. 获取并设置相机支持的最佳分辨率

不管你用的是旧的Camera API还是新的CameraX,都不能依赖默认的分辨率,得手动挑选合适的尺寸。这里先以新手常用的旧Camera API为例:

  • 先获取相机支持的所有拍照尺寸列表,然后挑最大的(或者最接近3MP的,3MP大概对应2048×1536左右):
// 假设你已经获取到了Camera实例camera
Camera.Parameters params = camera.getParameters();
List<Camera.Size> pictureSizes = params.getSupportedPictureSizes();

// 筛选出分辨率最大的拍照尺寸
Camera.Size bestPicSize = pictureSizes.get(0);
for (Camera.Size size : pictureSizes) {
    if (size.width * size.height > bestPicSize.width * bestPicSize.height) {
        bestPicSize = size;
    }
}

// 同时要设置预览尺寸,最好和拍照尺寸比例一致,避免画面拉伸
List<Camera.Size> previewSizes = params.getSupportedPreviewSizes();
Camera.Size bestPreviewSize = findMatchingPreviewSize(previewSizes, bestPicSize);

// 把选中的尺寸应用到相机参数
params.setPictureSize(bestPicSize.width, bestPicSize.height);
params.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height);
camera.setParameters(params);
  • 上面用到的findMatchingPreviewSize方法,用来匹配和拍照尺寸比例最接近的预览尺寸,避免画面变形:
private Camera.Size findMatchingPreviewSize(List<Camera.Size> previewSizes, Camera.Size picSize) {
    float picRatio = (float) picSize.width / picSize.height;
    Camera.Size bestMatch = previewSizes.get(0);
    float minRatioDiff = Float.MAX_VALUE;

    for (Camera.Size size : previewSizes) {
        float previewRatio = (float) size.width / size.height;
        float diff = Math.abs(previewRatio - picRatio);
        if (diff < minRatioDiff) {
            minRatioDiff = diff;
            bestMatch = size;
        }
    }
    return bestMatch;
}

2. 检查JPEG压缩质量

有时候即使分辨率设置对了,过度压缩也会让画质看起来很差,记得设置JPEG质量:

params.setJpegQuality(90); // 范围0-100,数值越高画质越好,文件也会稍大

3. 别用缩略图保存!

很多新手会犯的错误:用takePicture回调里的byte[] data直接保存,这个data其实是缩略图!要保存全尺寸图片,得写入到文件里:

camera.takePicture(null, null, new Camera.PictureCallback() {
    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        File picFile = getOutputMediaFile();
        if (picFile != null) {
            savePictureToFile(data, picFile);
            // 这里后面再加图库更新的代码
        }
    }
});

// 获取图片存储的路径
private File getOutputMediaFile() {
    File mediaDir = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), "MyCameraApp");
    if (!mediaDir.exists() && !mediaDir.mkdirs()) {
        Toast.makeText(this, "创建存储目录失败", Toast.LENGTH_SHORT).show();
        return null;
    }
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
    return new File(mediaDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
}

// 把图片写入文件
private void savePictureToFile(byte[] data, File file) {
    try (FileOutputStream fos = new FileOutputStream(file)) {
        fos.write(data);
    } catch (IOException e) {
        e.printStackTrace();
        Toast.makeText(this, "保存图片失败", Toast.LENGTH_SHORT).show();
    }
}

二、让照片在图库中显示

拍完照后,系统图库不会自动扫描到新文件,得手动通知媒体库更新:
savePictureToFile执行完成后,添加以下代码:

// 通知媒体库扫描新图片
MediaScannerConnection.scanFile(this,
        new String[]{file.getAbsolutePath()},
        new String[]{"image/jpeg"},
        new MediaScannerConnection.OnScanCompletedListener() {
            @Override
            public void onScanCompleted(String path, Uri uri) {
                Toast.makeText(MyCameraActivity.this, "照片已保存到图库", Toast.LENGTH_SHORT).show();
            }
        });

新手必看的权限提示

别忘了在AndroidManifest.xml里加必要的权限,而且Android 6.0以上还要动态申请:

<!-- 相机权限 -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<!-- 存储权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

动态申请权限的代码可以放在Activity的onCreate里:

if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED ||
        ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this,
            new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE},
            100); // 请求码随便设,只要唯一就行
}

额外小建议

如果你是刚学Android,非常推荐用CameraX来开发相机功能,它比旧的Camera API更简单,兼容性也更好。设置分辨率只需要几行代码:

ImageCapture imageCapture = new ImageCapture.Builder()
        .setTargetResolution(new Size(2048, 1536)) // 直接指定3MP左右的分辨率
        .setJpegQuality(90)
        .build();

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

火山引擎 最新活动