【问题标题】:How to use an ui.Image as an ImageProvider data source如何使用 ui.Image 作为 ImageProvider 数据源
【发布时间】:2020-03-21 11:01:21
【问题描述】:

我可以从内存或文件中设置标准颤振图像,但不能像 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;
  }
}

【问题讨论】:

    标签: image flutter dart photoviewer


    【解决方案1】:

    PhotoView 作者在这里,该小部件适用于所有 ImageProvider(内存和文件扩展 ImageProvider)。

    问题在于您如何创建提供程序。 image.buffer.asUint8List() 打印无头位图,使其无法显示。 位图的头部包含信息,例如每个像素的大小(以位为单位)和图像的大小(以像素为单位)。 我实际上已经围绕它创建了一个完整的包。

    使用bitmap package,您可以从ui.Image 实例中检索头部文件:

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

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

    然后,恢复最终的位图:

    Uint8List headedIntList = bitmap.buildHeaded();
    

    现在您可以将它传递给 PhotoView:

    PhotoView(imageProvider: headedIntList)
    

    【讨论】:

    • 感谢您的帮助。我发现了问题。它实际上一直在工作,但图像被调整大小并在黑色背景下丢失。无论如何,我都会尝试您建议的代码,它给出了一个错误: Uint8List headedIntList = bitmap.buildHeaded(); ////发生异常。 -> StateError(坏状态:元素太少)
    • 只是因为你足够关心来回答 - 并激励我自己解决我自己的问题。
    【解决方案2】:

    编辑您的新代码运行良好,但您看不到这个圆圈,因为 paint.strokeWidth 为 1 请更改为 10
    在新的完整代码中,我还将PhotoView 包装为Container 并设置height

    代码 sn-p 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;
      }
    }
    

    照片视图可以与MemoryImage一起正常工作,您可以在下面复制粘贴运行完整代码
    您遇到的错误可能是 Image is not ready when display
    你可以检查pngBytes == null return Container()
    代码sn-p

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

    工作演示动画 gif

    完整代码

    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.
        );
      }
    }
    

    【讨论】:

    • 我到处玩,看看能否在没有运气的情况下模仿你的方法。可能它与图像类型有关。我正在检索生成的 png 图像。我用完整的代码更新了这个问题,包括图像是如何生成的。
    • 您的新代码运行良好,但您看不到此图像,因为 paint.strokeWidth 为 1 ,请更改为 10
    猜你喜欢
    • 2022-12-04
    • 1970-01-01
    • 2021-05-18
    • 1970-01-01
    • 2012-10-29
    • 1970-01-01
    • 1970-01-01
    • 2017-01-30
    • 1970-01-01
    相关资源
    最近更新 更多