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

iOS端Flutter如何将BGRA8888格式CameraImage转为Image?

CameraImage转image包Image格式的解决方法

CameraImage是相机输出的原始图像数据(大多是YUV或RGBA格式),而Image.decodeBytes()只能解码JPG、PNG这类已经编码好的图片字节流,直接传CameraImage的原始数据自然会返回null,得换个方式处理。

针对最常见的YUV_420_888格式

1. 把YUV数据转成RGBA字节数组

CameraImage的YUV_420_888包含Y、U、V三个像素平面,需要手动转成RGBA格式的字节数组,再用image包的Image.fromBytes()创建Image对象,代码示例:

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

img.Image convertCameraImageToImage(CameraImage cameraImage) {
  final format = cameraImage.format;
  // 优先处理YUV420格式
  if (format.group == ImageFormatGroup.yuv420) {
    final yPlane = cameraImage.planes[0];
    final uPlane = cameraImage.planes[1];
    final vPlane = cameraImage.planes[2];

    final yBytes = yPlane.bytes;
    final uBytes = uPlane.bytes;
    final vBytes = vPlane.bytes;

    final width = cameraImage.width;
    final height = cameraImage.height;

    final yRowStride = yPlane.bytesPerRow;
    final uvRowStride = uPlane.bytesPerRow;
    final uvPixelStride = uPlane.bytesPerPixel!;

    // 创建RGBA字节容器
    final rgbaBytes = Uint8List(width * height * 4);

    for (int y = 0; y < height; y++) {
      for (int x = 0; x < width; x++) {
        // 计算当前Y像素的索引
        final yIndex = y * yRowStride + x;
        // YUV420是4个Y对应1个UV,所以取整计算UV索引
        final uvIndex = (y ~/ 2) * uvRowStride + (x ~/ 2) * uvPixelStride;

        final yValue = yBytes[yIndex];
        final uValue = uBytes[uvIndex];
        final vValue = vBytes[uvIndex];

        // 用标准BT.601公式把YUV转成RGBA
        int r = (yValue + 1.370705 * (vValue - 128)).round();
        int g = (yValue - 0.698001 * (vValue - 128) - 0.337633 * (uValue - 128)).round();
        int b = (yValue + 1.732446 * (uValue - 128)).round();

        // 确保颜色值在0-255范围内
        r = r.clamp(0, 255);
        g = g.clamp(0, 255);
        b = b.clamp(0, 255);

        // 填充RGBA数据(A设为255,完全不透明)
        final rgbaIndex = (y * width + x) * 4;
        rgbaBytes[rgbaIndex] = r;
        rgbaBytes[rgbaIndex + 1] = g;
        rgbaBytes[rgbaIndex + 2] = b;
        rgbaBytes[rgbaIndex + 3] = 255;
      }
    }

    // 从RGBA字节生成image包的Image对象
    return img.Image.fromBytes(width, height, rgbaBytes, format: img.Format.rgba);
  } else {
    // 处理RGBA格式的CameraImage
    final plane = cameraImage.planes[0];
    return img.Image.fromBytes(
      cameraImage.width,
      cameraImage.height,
      plane.bytes,
      format: img.Format.rgba,
      bytesPerRow: plane.bytesPerRow,
    );
  }
}

2. 用转换后的Image做处理

拿到img.Image对象后,就能用image包的API做旋转、裁剪等操作了,比如旋转90度:

final rotatedImage = img.copyRotate(convertedImage, 90);

关键说明

  • 别再用Image.decodeBytes()了,它只认编码好的图片文件字节,不认相机输出的原始像素数据。
  • 如果你的CameraImage是RGBA格式,可以直接取第一个平面的字节,用Image.fromBytes()创建对象,记得传bytesPerRow参数保证像素排列正确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 10:46:11