在flutter / dart-ui中将UInt8List转换为Image

我有这种情况下,我必须从这样的图像中获取UInt8List:

List stuff = image.toByteData().buffer.asUInt8List()

做一些操作,然后返回到Image。

我尝试了以下方法:

List stuff = image.toByteData().buffer.asUInt8List()

ui.decodeImageFromList(stuff, (image){

// do stuff with image

});

但是我一直收到这个异常:

E/flutter (10201): [ERROR:flutter/lib/ui/painting/codec.cc(97)] Failed decoding image. Data is either invalid, or it is encoded using an unsupported format.

E/flutter (10201): [ERROR:flutter/shell/common/shell.cc(186)] Dart Error: Unhandled exception:

...

请注意,即使列表中没有任何更改,也会引发异常。如何使列表具有可编码的格式?

回答:

ui.Image可以将自身转换为RGBA位图(或PNG),但不能将其自身从位图转换回去。(这样做的原因是,无法以任何方式告诉图像编解码器诸如颜色深度,几何形状等的信息。)解决方案是在位图的前面添加一个BMP文件头,您可以在其中描述这些内容丢失的东西,然后将其传递给instantiateImageCodec。请参见此答案,但请注意,在这种情况下,所讨论的位图具有奇怪的压缩颜色图。在您使用32位RGBA的情况下,标头会更简单。

decodeImageFromList只是一个便利包装器,instantiateImageCodec用于解码几种受支持的图像格式(JPEG,PNG,GIF,动画GIF,WebP,动画WebP,BMP和WBMP)之一。令人惊讶的是,还没有一种方法可以传递原始位图。但是,BMP文件格式基本上是粘贴在位图前面的简单标头(可以是RGB,RGBA或使用索引色图)。标头字段告诉解码器诸如宽度,高度,每像素位数,像素格式等信息

在内存中构造BMP标头,添加位图并将其传递给以上任一函数都非常容易。

这是一个完整的例子。请注意,从RGB332到ARGB的映射有点偏离。确实,您应该使用256个成员查找表。循环为RGB322字节的256个可能值产生256个近似ARGB值。

如果你喜欢画在画布的使用instantiateImageCodec,而不是Image.memory部件。

import 'dart:math';

import 'dart:typed_data';

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {

@override

Widget build(BuildContext context) {

return new MaterialApp(

title: 'BMP Demo',

home: new MyHomePage(),

);

}

}

class MyHomePage extends StatefulWidget {

@override

_MyHomePageState createState() => new _MyHomePageState();

}

class _MyHomePageState extends State<MyHomePage> {

Uint8List bmp;

BMP332Header header;

Random r = Random();

@override

void initState() {

super.initState();

header = BMP332Header(100, 100);

bmp = header.appendBitmap(

Uint8List.fromList(List<int>.generate(10000, (i) => r.nextInt(255))));

}

@override

Widget build(BuildContext context) {

return new Scaffold(

appBar: new AppBar(

title: new Text('Bitmap'),

),

body: Center(

child: Image.memory(bmp),

),

);

}

}

class BMP332Header {

int _width; // NOTE: width must be multiple of 4 as no account is made for bitmap padding

int _height;

Uint8List _bmp;

int _totalHeaderSize;

BMP332Header(this._width, this._height) : assert(_width & 3 == 0) {

int baseHeaderSize = 54;

_totalHeaderSize = baseHeaderSize + 1024; // base + color map

int fileLength = _totalHeaderSize + _width * _height; // header + bitmap

_bmp = new Uint8List(fileLength);

ByteData bd = _bmp.buffer.asByteData();

bd.setUint8(0, 0x42);

bd.setUint8(1, 0x4d);

bd.setUint32(2, fileLength, Endian.little); // file length

bd.setUint32(10, _totalHeaderSize, Endian.little); // start of the bitmap

bd.setUint32(14, 40, Endian.little); // info header size

bd.setUint32(18, _width, Endian.little);

bd.setUint32(22, _height, Endian.little);

bd.setUint16(26, 1, Endian.little); // planes

bd.setUint32(28, 8, Endian.little); // bpp

bd.setUint32(30, 0, Endian.little); // compression

bd.setUint32(34, _width * _height, Endian.little); // bitmap size

// leave everything else as zero

// there are 256 possible variations of pixel

// build the indexed color map that maps from packed byte to RGBA32

// better still, create a lookup table see: http://unwind.se/bgr233/

for (int rgb = 0; rgb < 256; rgb++) {

int offset = baseHeaderSize + rgb * 4;

int red = rgb & 0xe0;

int green = rgb << 3 & 0xe0;

int blue = rgb & 6 & 0xc0;

bd.setUint8(offset + 3, 255); // A

bd.setUint8(offset + 2, red); // R

bd.setUint8(offset + 1, green); // G

bd.setUint8(offset, blue); // B

}

}

/// Insert the provided bitmap after the header and return the whole BMP

Uint8List appendBitmap(Uint8List bitmap) {

int size = _width * _height;

assert(bitmap.length == size);

_bmp.setRange(_totalHeaderSize, _totalHeaderSize + size, bitmap);

return _bmp;

}

}

以上是 在flutter / dart-ui中将UInt8List转换为Image 的全部内容, 来源链接: utcz.com/qa/436186.html

回到顶部