使用'ui.decodeImageFromList'显示从字节列表创建的图像

时间:2018-07-12 22:44:40

标签: dart flutter

我已经搜索了一段时间,以了解如何创建一个有状态的图像,该图像可以从字节数组(或者只是十六进制颜色值列表)中创建。我在dart的ui库中遇到了这个看似有用的函数。

有人可以举例说明如何使用它吗?您可以决定每个像素多少位?

谢谢。

2 个答案:

答案 0 :(得分:4)

decodeImageFromList只是instantiateImageCodec周围的便利包装,它解码了几种受支持的图像格式(JPEG,PNG,GIF,Animated GIF,WebP,Animated 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;
  }

}

答案 1 :(得分:0)

可能对Flutter插件有帮助 我通过以下方式从指纹设备转换Java中的位图:

<div class="section">
    Click to send a request ...
</div>
<div class="section">
    <button (click)="click(1)">Server 1</button>
</div>
<div class="section">
    <button (click)="click(5)">Server 2 (Longer)</button>
</div>

然后在我刚刚使用的Flutter Dart中

ByteArrayOutputStream stream = new ByteArrayOutputStream();
fingerBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
fingerBitmap.recycle();