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
相关产品推荐
相关产品推荐

