如何将ui.Image用作ImageProvider数据源

时间:2019-11-26 04:49:34

标签: image flutter dart photoviewer

我可以从内存或文件中设置标准的抖动图像,但不能按PhotoView框架的要求设置ImageProvider。

PhotoView框架接受AssetImage作为提供程序的一种类型,但不接受任何其他ImageProvider类型(文件和内存)。

可能是一种解决方法?我认为该框架将支持图像资源,而不是项目资产

import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:photo_view/photo_view.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'dart:convert';

import 'dart:ui' as ui;
import 'dart:typed_data';
import 'dart:async';
import 'dart:io';


class TestImageDraw extends StatefulWidget {
  TestImageDraw({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _TestImageDrawState createState() => _TestImageDrawState();
}

class _TestImageDrawState extends State<TestImageDraw> {
  ImageProvider _imageProvider;

  @override
  void initState() {
    super.initState();

    _imageProvider = NetworkImage(
        "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png");
  }

  _generateImage() {
    GenImage.generateImage().then((generatedImage) async {
      ByteData image =
          await generatedImage.toByteData(format: ui.ImageByteFormat.png);

      // String base64 = base64Encode(image.buffer.asInt64List());
      // print(base64);
      // Uint8List bytes = base64Decode(base64);
      // _imageProvider = MemoryImage(bytes);

      _imageProvider = MemoryImage(image.buffer.asUint8List());

      setState(() {});
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: Container(
          child: Column(children: <Widget>[
        //Image will display
        Image(image: _imageProvider),
        Container(
            child: _imageProvider != null
                ? PhotoView(imageProvider: _imageProvider)
                : Container()),
      ])),
      floatingActionButton: new FloatingActionButton(
        onPressed: _generateImage,
        tooltip: 'Generate',
        child: new Icon(Icons.add),
      ),
    );
  }
}

class GenImage {
  static Future<ui.Image> generateImage() async {
    ui.PictureRecorder recorder = new ui.PictureRecorder();
    Canvas c = new Canvas(recorder);
    var rect = new Rect.fromLTWH(0.0, 0.0, 200.0, 200.0);
    c.clipRect(rect);

    final paint = new Paint();
    paint.strokeWidth = 1;
    paint.color = const Color(0xFF0000FF);
    paint.style = PaintingStyle.stroke;

    final offset = new Offset(100.0, 100.0);
    c.drawCircle(offset, 50.0, paint);
    var picture = recorder.endRecording();
    final image = await picture.toImage(500, 500);
    return image;
  }
}

2 个答案:

答案 0 :(得分:1)

PhotoView作者,此小部件可与所有ImageProvider(内存和文件扩展ImageProvider)配合使用。

问题在于您如何创建提供程序。 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> <img id="narwhalId" src="http://placekitten.com/100/100" />打印出无头的位图,使其无法显示。 位图的头部包含信息,例如每个像素的大小(以位为单位)和图像的大小(以像素为单位)。 我实际上已经围绕它创建了一个完整的程序包。

使用bitmap package,您可以从image.buffer.asUint8List()实例中检索一个头文件:

首先,创建一个位图实例:

ui.Image

然后,恢复最终的位图:

ByteData bytedata = await image.toByteData();
Bitmap bitmap = Bitmap.fromHeadless(imageWidth, imageHeight, bytedata.buffer.asUint8List());

现在您可以将其传递到PhotoView:

Uint8List headedIntList = bitmap.buildHeaded();

答案 1 :(得分:0)

编辑新代码效果很好,但由于paint.strokeWidth为1,因此您看不到此圆圈,请更改为10
在新的完整代码中,我还用PhotoView包装Container并设置height

代码段paint.strokeWidth = 10

final paint = new Paint();
paint.strokeWidth = 10;
paint.color = const Color(0xFF0000FF);
paint.style = PaintingStyle.stroke;

新的完整代码

import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:photo_view/photo_view.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'dart:convert';

import 'dart:ui' as ui;
import 'dart:typed_data';
import 'dart:async';
import 'dart:io';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: TestImageDraw(
        title: "test",
      ),
    );
  }
}

class TestImageDraw extends StatefulWidget {
  TestImageDraw({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _TestImageDrawState createState() => _TestImageDrawState();
}

class _TestImageDrawState extends State<TestImageDraw> {
  ImageProvider _imageProvider;

  @override
  void initState() {
    super.initState();

    _imageProvider = NetworkImage(
        "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png");
  }

  _generateImage() {
    GenImage.generateImage().then((generatedImage) async {
      ByteData image =
      await generatedImage.toByteData(format: ui.ImageByteFormat.png);

      // String base64 = base64Encode(image.buffer.asInt64List());
      // print(base64);
      // Uint8List bytes = base64Decode(base64);
      // _imageProvider = MemoryImage(bytes);

      _imageProvider = MemoryImage(image.buffer.asUint8List());

      setState(() {});
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: SingleChildScrollView(
        child: Container(
            child: Column(children: <Widget>[
              //Image will display
              //Image(image: _imageProvider),
              Container(
                  height: 300,
                  child: _imageProvider != null
                      ? PhotoView(imageProvider: _imageProvider)
                      : Container()),
            ])),
      ),
      floatingActionButton: new FloatingActionButton(
        onPressed: _generateImage,
        tooltip: 'Generate',
        child: new Icon(Icons.add),
      ),
    );
  }
}

class GenImage {
  static Future<ui.Image> generateImage() async {
    ui.PictureRecorder recorder = new ui.PictureRecorder();
    Canvas c = new Canvas(recorder);
    var rect = new Rect.fromLTWH(0.0, 0.0, 200.0, 200.0);
    c.clipRect(rect);

    final paint = new Paint();
    paint.strokeWidth = 10;
    paint.color = const Color(0xFF0000FF);
    paint.style = PaintingStyle.stroke;

    final offset = new Offset(100.0, 100.0);
    c.drawCircle(offset, 50.0, paint);
    var picture = recorder.endRecording();
    final image = await picture.toImage(500, 500);
    return image;
  }
}

enter image description here

照片视图可以与MemoryImage配合使用,您可以在下面复制粘贴完整运行代码
您遇到的错误可能是显示
时图像未准备好 您可以检查是否pngBytes == null return Container()
代码段

 children: <Widget>[
            bytes == null
                ? Container()
                : Expanded(
                    flex: 1,
                    child: PhotoView(
                      imageProvider: MemoryImage(bytes),
                    ),
                  ),

动态演示gif动画

enter image description here

完整代码

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:photo_view/photo_view.dart';
import 'package:http/http.dart' as http;
import 'dart:typed_data';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.

  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  String _base64;
  Uint8List bytes;

  void _incrementCounter() {
    (() async {
      http.Response response = await http.get(
        'https://picsum.photos/250?image=9',
      );
      if (mounted) {
        setState(() {
          _base64 = base64Encode(response.bodyBytes);
          print(_base64);
          bytes = base64Decode(_base64);
        });
      }
    })();
  }

  @override
  void initState() {
    super.initState();
   /* (() async {
      http.Response response = await http.get(
        'https://picsum.photos/250?image=9',
      );
      if (mounted) {
        setState(() {
          _base64 = base64Encode(response.bodyBytes);
          print(_base64);
          bytes = base64Decode(_base64);
        });
      }
    })();*/
  }


  @override
  Widget build(BuildContext context) {
    // This method is rerun every time setState is called, for instance as done
    // by the _incrementCounter method above.
    //
    // The Flutter framework has been optimized to make rerunning build methods
    // fast, so that you can just rebuild anything that needs updating rather
    // than having to individually change instances of widgets.
    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text(widget.title),
      ),
      body: Center(
        // Center is a layout widget. It takes a single child and positions it
        // in the middle of the parent.
        child: Column(
          // Column is also a layout widget. It takes a list of children and
          // arranges them vertically. By default, it sizes itself to fit its
          // children horizontally, and tries to be as tall as its parent.
          //
          // Invoke "debug painting" (press "p" in the console, choose the
          // "Toggle Debug Paint" action from the Flutter Inspector in Android
          // Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
          // to see the wireframe for each widget.
          //
          // Column has various properties to control how it sizes itself and
          // how it positions its children. Here we use mainAxisAlignment to
          // center the children vertically; the main axis here is the vertical
          // axis because Columns are vertical (the cross axis would be
          // horizontal).
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            bytes == null
                ? Container()
                : Expanded(
                    flex: 1,
                    child: PhotoView(
                      imageProvider: MemoryImage(bytes),
                    ),
                  ),
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}