Flutter中如何将List<dynamic>转换为27×64像素的可查看图片?
问题描述
给定的sample.json结构如下:
[ { "id": 105399, "time": "2022-11-22 01:25:23.920", "readings": [ [ 0, 2, 3, 2, ... ] ] } ]
其中readings字段下是1728个0-100的整数列表(27×64=1728),需要将这些数值转换为27×64像素、PixelFormat.rgba8888编码的图片。
现有Flutter代码如下:
class _DemoState extends State<Demo> { Uint8List convertStringToUint8List(String str) { final List<int> codeUnits = str.codeUnits; final Uint8List uint8List = Uint8List.fromList(codeUnits); return uint8List; } fetchFileData() async { String response; responseText = await rootBundle.loadString('assets/sample.json'); setState(() { List raw = jsonDecode(responseText) as List; List readings = (raw[0]['readings']); Uint8List pixels = convertStringToUint8List(readingsStr); print(readings); print(pixels); }); }
目前遇到的问题:
print(readings)能正确输出readings里的数值列表,但变量类型是List<dynamic>print(pixels)返回的是列表内容的ASCII值,这是错误的(把列表的字符串形式转成了字节,并非有效像素数据)- 尝试过
decodeImageFromPixels但不知道如何处理ImageDecoderCallback,也试过Image.memory(pixels)但像素数据格式不符合要求
注:接触Flutter仅5天,卡了2天,第一次发帖求助。
解决步骤
1. 正确提取readings的数值列表
注意raw[0]['readings']是二维列表,需要先拿到内层的一维数值列表,并转换为List<int>类型:
List<dynamic> readingsNested = raw[0]['readings'] as List; List<int> readings = readingsNested.first.cast<int>();
2. 将0-100数值转换为RGBA8888格式的像素数据
RGBA8888每个像素占4字节(红、绿、蓝、透明度),可以把0-100的数值映射为0-255的灰度值(R=G=B),透明度设为255(不透明):
int pixelCount = readings.length; Uint8List pixelBytes = Uint8List(pixelCount * 4); for (int i = 0; i < pixelCount; i++) { int value = readings[i]; // 把0-100映射到0-255的灰度范围 int gray = (value * 2.55).round(); // 填充每个像素的RGBA四个字节 pixelBytes[i*4] = gray; // 红色通道 pixelBytes[i*4 + 1] = gray; // 绿色通道 pixelBytes[i*4 + 2] = gray; // 蓝色通道 pixelBytes[i*4 + 3] = 255; // 透明度(不透明) }
3. 使用decodeImageFromPixels生成Image对象
decodeImageFromPixels可直接将原始像素数据解码为Flutter可用的Image对象,无需转成PNG/JPG等文件格式:
// 在State类中声明变量存储生成的图片 Image? generatedImage; // 在fetchFileData中处理完pixelBytes后调用 decodeImageFromPixels( pixelBytes, 64, // 图片宽度 27, // 图片高度 PixelFormat.rgba8888, (Image image) { setState(() { generatedImage = image; }); }, // 可选:处理解码错误 onError: (error) { print('解码出错:$error'); }, );
4. 在Widget中显示生成的图片
在build方法中直接使用生成的图片:
@override Widget build(BuildContext context) { return Scaffold( body: generatedImage != null ? Image(image: generatedImage!) : const Center(child: Text('加载中...')), floatingActionButton: FloatingActionButton( onPressed: fetchFileData, child: const Icon(Icons.refresh), ), ); }
完整修正后的fetchFileData函数
fetchFileData() async { String responseText = await rootBundle.loadString('assets/sample.json'); List raw = jsonDecode(responseText) as List; List<dynamic> readingsNested = raw[0]['readings'] as List; List<int> readings = readingsNested.first.cast<int>(); int pixelCount = readings.length; Uint8List pixelBytes = Uint8List(pixelCount * 4); for (int i = 0; i < pixelCount; i++) { int value = readings[i]; int gray = (value * 2.55).round(); pixelBytes[i*4] = gray; pixelBytes[i*4 + 1] = gray; pixelBytes[i*4 + 2] = gray; pixelBytes[i*4 + 3] = 255; } decodeImageFromPixels( pixelBytes, 64, 27, PixelFormat.rgba8888, (Image image) { setState(() { generatedImage = image; }); }, onError: (error) { print('解码错误:$error'); }, ); }
内容的提问来源于stack exchange,提问作者ianjms
相关产品推荐
相关产品推荐

