Flutter图片流转换插件convert_native_img_stream的使用
Flutter图片流转换插件convert_native_img_stream的使用
简介
convert_native_img_stream
是一个用于将 ImageFormatGroup.nv21
或 ImageFormatGroup.bgra8888
转换为 JPEG 文件的插件。这个插件主要适用于使用 ML Kit 或其他处理单平面原生格式(如 NV12 或 BGRA)帧的情况,并且你希望从 CameraImage
对象中保存处理后的帧。该插件可以帮助你将帧转换为内存或文件中的 JPEG 格式。
示例用法
示例代码
以下是一个完整的示例代码,展示了如何使用 convert_native_img_stream
插件从相机流中捕获帧并将其转换为 JPEG 图像。
import 'dart:io';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:convert_native_img_stream/convert_native_img_stream.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final _convertNativeImgStreamPlugin = ConvertNativeImgStream();
static List<CameraDescription> _cameras = [];
CameraController? _controller;
int _cameraIndex = -1;
bool capture = false, converting = false;
Uint8List? imageBytes;
@override
void initState() {
super.initState();
initializeCamera();
}
@override
void dispose() async {
super.dispose();
await _controller?.stopImageStream();
await _controller?.dispose();
_controller = null;
}
void initializeCamera() async {
if (_cameras.isEmpty) {
_cameras = await availableCameras();
}
for (var i = 0; i < _cameras.length; i++) {
if (_cameras[i].lensDirection == CameraLensDirection.back) {
_cameraIndex = i;
break;
}
}
if (_cameraIndex != -1) {
final camera = _cameras[_cameraIndex];
_controller = CameraController(
camera,
// 主要解决的问题,将 NV12 流转换为 JPEG 格式
ResolutionPreset.high,
enableAudio: false,
imageFormatGroup: Platform.isAndroid
? ImageFormatGroup.nv21
: ImageFormatGroup.bgra8888,
);
_controller?.initialize().then((_) {
_controller?.startImageStream((image) {
if (capture) {
setState(() {
converting = true;
});
_controller?.stopImageStream();
_controller?.pausePreview();
_convertNativeImgStreamPlugin
.convertImgToBytes(
image.planes.first.bytes,
image.width,
image.height,
)
.then((value) {
imageBytes = value;
converting = false;
setState(() {});
});
}
});
if (!mounted) {
return;
}
setState(() {});
});
}
}
Widget _body() {
if (_cameras.isEmpty) return Container();
if (_controller == null) return Container();
if (_controller?.value.isInitialized == false) return Container();
if (converting) {
return const Center(
child: CircularProgressIndicator(),
);
}
return Container(
color: Colors.black,
child: Stack(
fit: StackFit.expand,
children: <Widget>[
if (imageBytes == null)
Center(
child: CameraPreview(
_controller!,
),
)
else
Container(
color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
mainAxisSize: MainAxisSize.max,
children: [
const Expanded(
flex: 10,
child: Center(
child: Text(
"Converted image",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 22),
),
),
),
Expanded(flex: 90, child: Image.memory(imageBytes!, fit: BoxFit.cover)),
],
),
),
if (imageBytes == null)
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
ElevatedButton(
onPressed: () {
capture = true;
},
child: const Text("Pause & Convert Frame"),
),
],
),
],
),
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: _body(),
),
);
}
}
代码说明
-
初始化相机:
- 使用
availableCameras()
获取可用的摄像头列表。 - 选择后置摄像头(如果有)。
- 初始化
CameraController
并设置图像格式组为ImageFormatGroup.nv21
(Android)或ImageFormatGroup.bgra8888
(iOS)。
- 使用
-
开始图像流:
- 使用
startImageStream
方法开始从相机获取图像帧。 - 在
startImageStream
的回调中,检查是否需要捕获当前帧(通过capture
变量控制)。
- 使用
-
捕获和转换帧:
- 如果需要捕获当前帧,停止图像流并暂停预览。
- 使用
convertNativeImgStreamPlugin.convertImgToBytes
方法将帧数据转换为 JPEG 格式的字节流。 - 将转换后的字节流存储在
imageBytes
中,并更新 UI。
-
显示图像:
- 如果
imageBytes
不为空,显示转换后的图像。 - 否则,显示相机预览。
- 如果
-
按钮操作:
- 提供一个按钮,点击后设置
capture
为true
,触发帧捕获和转换。
- 提供一个按钮,点击后设置
通过以上步骤,你可以轻松地从相机流中捕获帧并将其转换为 JPEG 图像。希望这个示例对你有所帮助!
更多关于Flutter图片流转换插件convert_native_img_stream的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter图片流转换插件convert_native_img_stream的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用convert_native_img_stream
插件来处理图片流的示例代码。convert_native_img_stream
插件允许你将原生平台(如Android或iOS)的图片流数据转换为Flutter可以处理的图像格式。
首先,确保你已经在pubspec.yaml
文件中添加了convert_native_img_stream
依赖:
dependencies:
flutter:
sdk: flutter
convert_native_img_stream: ^最新版本号 # 请替换为实际的最新版本号
然后运行flutter pub get
来安装依赖。
接下来,我们将编写一个示例,展示如何从原生平台接收图片流并将其显示在Flutter应用中。由于convert_native_img_stream
插件的具体实现细节可能依赖于具体的平台(Android和iOS),这里我们假设你已经有了相应的原生代码来提供图片流。
Flutter代码部分
import 'package:flutter/material.dart';
import 'package:convert_native_img_stream/convert_native_img_stream.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Image Stream Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: ImageStreamPage(),
);
}
}
class ImageStreamPage extends StatefulWidget {
@override
_ImageStreamPageState createState() => _ImageStreamPageState();
}
class _ImageStreamPageState extends State<ImageStreamPage> {
final NativeImageStreamConverter _converter = NativeImageStreamConverter();
Uint8List? _imageBytes;
@override
void initState() {
super.initState();
// 假设你有一个方法从原生平台接收图片流
_startReceivingImageStream();
}
void _startReceivingImageStream() {
// 这里模拟从原生平台接收图片流
// 在实际使用中,这部分代码将由原生平台代码触发
Timer.periodic(Duration(seconds: 1), (timer) {
// 模拟接收到的图片数据(在实际应用中,这里将是原生平台提供的图片数据)
Uint8List imageData = Uint8List.fromList(List.generate(10000, (index) => index % 256));
// 使用convert_native_img_stream插件转换图片数据
_converter.convertNativeImageToUint8List(imageData).then((result) {
setState(() {
_imageBytes = result;
});
}).catchError((error) {
print('Error converting image: $error');
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Image Stream Example'),
),
body: Center(
child: _imageBytes != null
? Image.memory(_imageBytes!)
: CircularProgressIndicator(),
),
);
}
}
原生平台代码(示例)
由于convert_native_img_stream
的具体原生实现细节可能会依赖于插件的版本和平台,这里仅提供伪代码思路。你需要根据插件的文档和示例来编写实际的原生代码。
Android部分(伪代码)
// 在你的Activity或Service中
public void sendImageStreamToFlutter() {
// 获取图片数据(例如从相机预览回调中)
byte[] imageData = getImageDataFromCamera();
// 将图片数据发送到Flutter
MethodChannel methodChannel = new MethodChannel(getFlutterEngine().getDartExecutor().getBinaryMessenger(), "your_channel_name");
methodChannel.invokeMethod("receiveImageData", imageData);
}
iOS部分(伪代码)
// 在你的Swift或Objective-C代码中
func sendImageStreamToFlutter() {
// 获取图片数据(例如从AVCaptureVideoDataOutputSampleBufferDelegate回调中)
guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
let imageData = convertPixelBufferToData(pixelBuffer) // 自定义方法将CVPixelBuffer转换为Data
// 将图片数据发送到Flutter
let flutterEngine = (UIApplication.shared.delegate as! AppDelegate).flutterEngine
let methodChannel = FlutterMethodChannel(name: "your_channel_name", binaryMessenger: flutterEngine.binaryMessenger)
methodChannel.invokeMethod("receiveImageData", imageData)
}
在Flutter端,你需要监听从原生平台发送过来的图片数据,并调用convert_native_img_stream
插件来处理这些数据。上面的Flutter代码示例中,我们使用了Timer.periodic
来模拟接收图片流数据,但在实际应用中,你应该监听从原生平台发送过来的实际数据。
请注意,上述代码仅作为示例,并未包含完整的错误处理和资源管理逻辑。在实际开发中,请确保正确处理各种边缘情况和资源释放。