Flutter轻量级相机功能插件flutter_lite_camera的使用

Flutter轻量级相机功能插件flutter_lite_camera的使用

Flutter Lite Camera 是一个专为在 Windows、Linux 和 macOS 平台上以固定分辨率为 640x480 捕获 RGB888 格式帧的轻量级 Flutter 插件。该插件非常适合用于构建相机预览应用和进行图像处理任务。

特性

  • 跨平台:兼容 Windows、Linux 和 macOS。
  • RGB888 帧格式:捕获未压缩的 RGB888 帧,便于图像处理。
  • 简单集成:提供易于使用的 API,方便与 Flutter 集成。

要求

  • Flutter SDK: 版本 3.0.0 或以上
  • 权限: 在 macOS 上确保授予相机访问权限。在 DebugProfile.entitlementsRelease.entitlements 中添加:
    <key>com.apple.security.device.camera</key>
    <true/>
    

API

方法 描述
getDeviceList() 返回可用摄像头设备列表。
open(int index) 打开指定索引的摄像头。
captureFrame() 捕获单个 RGB888 图像帧。
release() 释放摄像头资源。

示例代码

import 'package:flutter/material.dart';
import 'dart:async';

import 'package:flutter/services.dart';
import 'package:flutter_lite_camera/flutter_lite_camera.dart';
import 'dart:ui' as ui;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CameraApp(),
    );
  }
}

class CameraApp extends StatefulWidget {
  [@override](/user/override)
  State<CameraApp> createState() => _CameraAppState();
}

class _CameraAppState extends State<CameraApp> {
  final FlutterLiteCamera _flutterLiteCameraPlugin = FlutterLiteCamera();
  bool _isCameraOpened = false;
  bool _isCapturing = false;
  int _width = 640;
  int _height = 480;
  ui.Image? _latestFrame;
  bool _shouldCapture = false;

  [@override](/user/override)
  void initState() {
    super.initState();
    _handleWindowClose();
  }

  Future<void> _startCamera() async {
    try {
      List<String> devices = await _flutterLiteCameraPlugin.getDeviceList();
      if (devices.isNotEmpty) {
        print("Available Devices: $devices");
        print("Opening camera 0");
        bool opened = await _flutterLiteCameraPlugin.open(0);
        if (opened) {
          setState(() {
            _isCameraOpened = true;
            _shouldCapture = true;
          });

          // 开始捕获帧
          _isCapturing = true;
          _captureFrames();
        } else {
          print("Failed to open the camera.");
        }
      }
    } catch (e) {
      // print("Error initializing camera: $e");
    }
  }

  Future<void> _captureFrames() async {
    if (!_isCameraOpened || !_shouldCapture) return;

    try {
      Map<String, dynamic> frame = await _flutterLiteCameraPlugin.captureFrame();
      if (frame.containsKey('data')) {
        Uint8List rgbBuffer = frame['data'];
        await _convertBufferToImage(rgbBuffer, frame['width'], frame['height']);
      }
    } catch (e) {
      // print("Error capturing frame: $e");
    }

    // 安排下一次帧捕获
    if (_shouldCapture) {
      Future.delayed(const Duration(milliseconds: 30), _captureFrames);
    }
  }

  Future<void> _convertBufferToImage(Uint8List rgbBuffer, int width, int height) async {
    final pixels = Uint8List(width * height * 4); // RGBA 缓冲区

    for (int i = 0; i < width * height; i++) {
      int r = rgbBuffer[i * 3];
      int g = rgbBuffer[i * 3 + 1];
      int b = rgbBuffer[i * 3 + 2];

      // 填充 RGBA 缓冲区
      pixels[i * 4] = b;
      pixels[i * 4 + 1] = g;
      pixels[i * 4 + 2] = r;
      pixels[i * 4 + 3] = 255; // Alpha 通道
    }

    final completer = Completer<ui.Image>();
    ui.decodeImageFromPixels(
      pixels,
      width,
      height,
      ui.PixelFormat.rgba8888,
      completer.complete,
    );

    final image = await completer.future;
    setState(() {
      _latestFrame = image;
    });
  }

  Future<void> _stopCamera() async {
    setState(() {
      _shouldCapture = false;
    });

    if (_isCameraOpened) {
      await _flutterLiteCameraPlugin.release();
      setState(() {
        _isCameraOpened = false;
        _latestFrame = null;
      });
    }

    _isCapturing = false;
  }

  void _handleWindowClose() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      SystemChannels.lifecycle.setMessageHandler((message) async {
        if (message == AppLifecycleState.detached.toString()) {
          await _stopCamera();
        }
        return null;
      });
    });
  }

  [@override](/user/override)
  void dispose() {
    _stopCamera();
    super.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          if (_latestFrame != null)
            LayoutBuilder(
              builder: (context, constraints) {
                final screenWidth = constraints.maxWidth;
                final screenHeight = constraints.maxHeight;
                final imageAspectRatio = _width / _height;
                final screenAspectRatio = screenWidth / screenHeight;

                double drawWidth, drawHeight;
                if (imageAspectRatio > screenAspectRatio) {
                  drawWidth = screenWidth;
                  drawHeight = screenWidth / imageAspectRatio;
                } else {
                  drawHeight = screenHeight;
                  drawWidth = screenHeight * imageAspectRatio;
                }

                return Center(
                  child: CustomPaint(
                    painter: FramePainter(_latestFrame!),
                    child: SizedBox(
                      width: drawWidth,
                      height: drawHeight,
                    ),
                  ),
                );
              },
            )
          else
            Center(
              child: Text('Camera not initialized or no frame captured'),
            ),
          Positioned(
            bottom: 20,
            left: 20,
            right: 20,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                // 开始按钮
                ElevatedButton(
                  onPressed: _isCapturing ? null : () => _startCamera(),
                  child: const Text('Start'),
                ),
                // 停止按钮
                ElevatedButton(
                  onPressed: !_isCapturing ? null : () => _stopCamera(),
                  child: const Text('Stop'),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

class FramePainter extends CustomPainter {
  final ui.Image image;

  FramePainter(this.image);

  [@override](/user/override)
  void paint(Canvas canvas, Size size) {
    final paint = Paint();
    canvas.drawImageRect(
      image,
      Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble()),
      Rect.fromLTWH(0, 0, size.width, size.height),
      paint,
    );
  }

  [@override](/user/override)
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}

更多关于Flutter轻量级相机功能插件flutter_lite_camera的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter轻量级相机功能插件flutter_lite_camera的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


flutter_lite_camera 是一个轻量级的 Flutter 插件,用于在 Flutter 应用中快速集成相机功能。它提供了简单的 API,允许开发者轻松地访问设备的摄像头,并捕获照片或视频。以下是如何使用 flutter_lite_camera 插件的详细步骤:

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 flutter_lite_camera 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_lite_camera: ^1.0.0  # 请使用最新的版本号

然后运行 flutter pub get 来获取依赖。

2. 导入插件

在你的 Dart 文件中导入 flutter_lite_camera 插件:

import 'package:flutter_lite_camera/flutter_lite_camera.dart';

3. 使用相机

flutter_lite_camera 提供了一个 LiteCamera 小部件,你可以直接将它添加到你的应用界面中。

基本使用

以下是一个简单的例子,展示如何在 Flutter 应用中使用 LiteCamera 来显示相机预览并捕获照片:

import 'package:flutter/material.dart';
import 'package:flutter_lite_camera/flutter_lite_camera.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Lite Camera Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: CameraScreen(),
    );
  }
}

class CameraScreen extends StatefulWidget {
  @override
  _CameraScreenState createState() => _CameraScreenState();
}

class _CameraScreenState extends State<CameraScreen> {
  LiteCameraController? _cameraController;

  @override
  void initState() {
    super.initState();
    _cameraController = LiteCameraController();
  }

  @override
  void dispose() {
    _cameraController?.dispose();
    super.dispose();
  }

  Future<void> _takePicture() async {
    try {
      final image = await _cameraController?.takePicture();
      if (image != null) {
        // 处理捕获的照片,比如保存到相册或显示在界面上
        print('Picture taken: ${image.path}');
      }
    } catch (e) {
      print('Error taking picture: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Lite Camera'),
      ),
      body: LiteCamera(
        controller: _cameraController,
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _takePicture,
        child: Icon(Icons.camera),
      ),
    );
  }
}

4. 处理捕获的照片

在上面的例子中,_takePicture 方法用于捕获照片。捕获的照片以 XFile 对象的形式返回,你可以使用 image.path 获取照片的文件路径,并进行进一步的处理,比如保存到相册或显示在界面上。

5. 其他功能

flutter_lite_camera 还支持其他功能,比如切换相机、设置闪光灯模式等。你可以通过 LiteCameraController 来访问这些功能。

例如,切换相机的代码可能如下:

Future<void> _switchCamera() async {
  await _cameraController?.switchCamera();
}
回到顶部