秋天来了
今年的冬天会比往年冷吗
也许要看棉被的厚度
需求来了
(1)自定义拍照界面。预览相机,并在上面添加其他操作的组件。如切换相机,拍照按钮,手电筒。
(2)拍好照片后直接裁剪指定范围。拍照的时候获取到照片为指定尺寸的全屏照片,如480p或720p或1080p。拍好照片后,上传到服务器为了减少识别压力,则裁剪照片获取中间部分。
实现的效果
省流-> 编写的DEMO地址
一、自定义拍照
1. 集成
官网提供了使用教程使用 Camera 插件实现拍照功能,按完整样例可以实现。
方便在页面中使用,则将
java
void _initializeCamera() async {
// Ensure that plugin services are initialized so that `availableCameras()`
// can be called before `runApp()`
WidgetsFlutterBinding.ensureInitialized();
// Obtain a list of the available cameras on the device.
final cameras = await availableCameras();
// Get a specific camera from the list of available cameras.
firstCamera = cameras.first;
// To display the current output from the Camera,
// create a CameraController.
_controller = CameraController(
// Get a specific camera from the list of available cameras.
cameras.first,
// Define the resolution to use.
ResolutionPreset.high,
enableAudio: false,
imageFormatGroup: ImageFormatGroup.jpeg);
// Next, initialize the controller. This returns a Future.
_initializeControllerFuture = _controller.initialize();
_valueNotifier.value = true;
}
放到initState
中进行初始化。
2. 提速
另一个需要注意点:final image = await _controller.takePicture();
执行时间在3-4秒的处理时间,比常规的拍照慢了好多。
多次测试和验证后,确认原因为: "对焦" 。
解决方法:在拍照前,锁定聚焦。
csharp
// 设置对焦,提高拍照效率
await _controller.setFocusMode(FocusMode.locked);
await _controller.setExposureMode(ExposureMode.locked);
二、裁剪
自定义拍照后返回一个XFile
可获取照片保存的路径。在上传之前,不需要用户手动裁剪,直接截取照片的指定位置(demo中为获取中间部分)。
1. 文件转ui.Image
类型
读取文件转为ui.Image
如下:
scss
//通过 文件读取Image
static Future<ui.Image> loadImageByFile(String path) async {
var list = await File(path).readAsBytes();
return loadImageByUint8List(list);
}
//通过[Uint8List]获取图片
static Future<ui.Image> loadImageByUint8List(Uint8List list) async {
ui.Codec codec = await ui.instantiateImageCodec(list);
ui.FrameInfo frame = await codec.getNextFrame();
return frame.image;
}
2. 裁剪
获取到ui.Image
后,使用PictureRecorder
后将图片绘制需要的部分,并保存为ui.Image
。
ini
double width = background.width.toDouble();
double height = background.height.toDouble();
PictureRecorder recorder = PictureRecorder();
Canvas canvas = Canvas(recorder);
Rect rect = Rect.fromLTWH(0, height / 3, width, height / 3);
Rect dstRect = Rect.fromLTWH(0, 0, width, height / 3);
canvas.drawImageRect(background, rect, dstRect, Paint());
Picture picture = recorder.endRecording();
ui.Image image = await picture.toImage(width.toInt(), height ~/ 3);
3. 保存到临时文件
裁剪好图片后,写入到文件,或展示。
ini
// 写入到文件夹中
ByteData? byteData = await image.toByteData(format: ImageByteFormat.png);
if (null != byteData) {
try {
final Directory appCache = await getApplicationCacheDirectory();
var filePath = "${appCache.path}/test${DateTime.now().millisecondsSinceEpoch}.png";
File file = File(filePath);
file = await file.writeAsBytes(byteData.buffer.asUint8List());
setState(() {
_croppedImagePath = file.path;
});
} on MissingPlatformDirectoryException catch (e) {
debugPrint("保存图片失败,${e.message}");
}
}
保存到data/data/包名/cache/的目录下,可以自行切换。
三、 完成
搜索了很久没有找到flutter来实现裁剪图片的,有一个库image_cropper,主要还是需要用户参与,然后移动框进行裁剪,不是很符合我们的要求。
参考了Flutter 绘制番外 | 将你的 Canvas 绘制保存为图片提供的方法。此方法太好用了,不知道还真想不到。