You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter如何创建指定尺寸的自定义CameraPreview并保存同尺寸照片?

在Flutter中创建指定尺寸的CameraPreview并同步照片尺寸

1. 添加依赖

在pubspec.yaml中引入所需包:

dependencies:
  flutter:
    sdk: flutter
  camera: ^0.10.5+5 # 建议使用最新稳定版
  image: ^4.0.17 # 用于图片裁剪与缩放

2. 初始化相机控制器

优先选择与目标预览比例接近的相机分辨率,减少后续裁剪的变形程度:

import 'package:camera/camera.dart';
import 'package:image/image.dart' as img;

late CameraController _controller;
final Size _targetSize = const Size(400, 150); // 指定的目标尺寸

Future<void> initCamera() async {
  final cameras = await availableCameras();
  // 选择后置相机
  final targetCamera = cameras.firstWhere((cam) => cam.lensDirection == CameraLensDirection.back);

  // 匹配最接近目标比例的分辨率预设
  final targetRatio = _targetSize.width / _targetSize.height;
  ResolutionPreset bestPreset = ResolutionPreset.medium;
  double minRatioDiff = double.infinity;

  for (final preset in ResolutionPreset.values) {
    final res = await targetCamera.getResolutionPreset(preset);
    final ratio = res.width / res.height;
    final diff = (ratio - targetRatio).abs();
    if (diff < minRatioDiff) {
      minRatioDiff = diff;
      bestPreset = preset;
    }
  }

  _controller = CameraController(
    targetCamera,
    bestPreset,
    enableAudio: false,
  );
  await _controller.initialize();
}

3. 构建指定尺寸的CameraPreview

用固定尺寸容器包裹预览组件,通过FittedBox保证预览内容比例正确:

Widget buildCustomPreview() {
  if (!_controller.value.isInitialized) {
    return const SizedBox.shrink();
  }

  return Container(
    width: _targetSize.width,
    height: _targetSize.height,
    child: FittedBox(
      fit: BoxFit.cover, // 按比例填充容器,超出部分自动裁剪
      child: SizedBox(
        width: _controller.value.previewSize!.width,
        height: _controller.value.previewSize!.height,
        child: CameraPreview(_controller),
      ),
    ),
  );
}

4. 拍摄并裁剪照片到目标尺寸

先拍摄原始照片,再根据预览比例计算裁剪区域,最终缩放到目标尺寸:

Future<File?> captureAndProcessImage() async {
  if (!_controller.value.isInitialized) return null;

  // 拍摄原始照片
  final XFile rawFile = await _controller.takePicture();
  final img.Image rawImage = img.decodeImage(await rawFile.readAsBytes())!;

  // 计算裁剪区域,匹配预览的显示比例
  final previewRatio = _targetSize.width / _targetSize.height;
  final imageRatio = rawImage.width / rawImage.height;

  int cropW, cropH;
  int startX = 0, startY = 0;

  if (imageRatio > previewRatio) {
    // 原图更宽,裁剪左右两侧
    cropH = rawImage.height;
    cropW = (rawImage.height * previewRatio).round();
    startX = (rawImage.width - cropW) ~/ 2;
  } else {
    // 原图更高,裁剪上下两侧
    cropW = rawImage.width;
    cropH = (rawImage.width / previewRatio).round();
    startY = (rawImage.height - cropH) ~/ 2;
  }

  // 裁剪+缩放至目标尺寸
  final cropped = img.copyCrop(rawImage, x: startX, y: startY, width: cropW, height: cropH);
  final resized = img.copyResize(cropped, width: _targetSize.width.round(), height: _targetSize.height.round());

  // 保存处理后的图片
  final outputPath = rawFile.path.replaceAll('.jpg', '_target.jpg');
  final outputFile = File(outputPath);
  await outputFile.writeAsBytes(img.encodeJpg(resized));

  return outputFile;
}

5. 关键注意事项

  • 权限配置:在Android的AndroidManifest.xml和iOS的Info.plist中添加相机、存储权限声明
  • 生命周期管理:页面销毁时调用await _controller.dispose();释放相机资源
  • 性能优化:目标尺寸较小时,选择低分辨率预设可降低图片处理的资源消耗

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 00:44:57