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

