【问题标题】:How to resolve an ImageProvider without BuildContext如何在没有 BuildContext 的情况下解析 ImageProvider
【发布时间】:2021-04-19 03:37:06
【问题描述】:

我认为我的问题很简单,但我无法在任何地方找到答案。我将 ImageProvider 传递给我的 PixelData 类,以便能够访问单个像素颜色值,但我需要从 ImageProvider 中获取 ui.Image 和图像字节数据。我遇到了下面显示的问题,如果不将 createLocalImageConfiguration(buildContext) 与当前的 BuildContext 一起使用,我将无法访问这些值。我希望能够在 BuildContext 范围之外使用此类,因此我需要能够在没有 BuildContext 的情况下获取图像数据。

非常感谢任何有关此问题的帮助/指导。

谢谢!

class PixelData {
  ImageProvider imageProvider;
  ui.Image _image;
  ByteData _byteData;
  int _width;
  int _height;

  PixelData(this.imageProvider) : assert(imageProvider != null);

  int get width => _width;
  int get height => _height;

  Future<void> getByteData() async {
    if (imageProvider == null) throw Exception("imageProvider is null");

    // TODO here lies the problem.
    // TODO how can I provide an ImageConfiguration without BuildContext?
    // I can't use: createLocalImageConfiguration(buildContext)

    imageProvider.resolve(configuration).addListener(
      ImageStreamListener(
        (info, _) async {
          _image = info.image;
          _width = _image.width;
          _height = _image.height;
          _byteData =
              await _image.toByteData(format: ui.ImageByteFormat.rawRgba);
        },
      ),
    );
  }
  
  void getColorAt() {
    // TODO
  }
}

我尝试使用 ImageConfiguration.empty,建议在上下文不可用时使用。

这是相关的更新代码和尝试运行后出现的错误。

/// getByteData must be called before trying to access pixel data
  Future<void> getByteData() async {
    if (imageProvider == null) throw Exception("imageProvider is null");
    imageProvider.resolve(ImageConfiguration.empty).addListener(
      ImageStreamListener(
        (info, _) async {
          print("code reached");
          _image = info.image;
          _width = _image.width;
          _height = _image.height;
          _byteData =
              await _image.toByteData(format: ui.ImageByteFormat.rawRgba);
        },
      ),
    );
  }

  /// Pixel coordinates: (0,0) → (width-1, height-1).
  Color pixelColorAt(int x, int y) {
    if (_byteData == null ||
        width == null ||
        height == null ||
        x < 0 ||
        x >= width ||
        y < 0 ||
        y >= height)
      return null;
    else {
      var byteOffset = 4 * (x + (y * width));
      return _colorAtByteOffset(byteOffset);
    }
  }
test('test network image', () async {
    String url =
        "https://i0.wp.com/www.dignited.com/wp-content/uploads/2012/09/Magazine-QR-Code.jpg?fit=500%2C404&ssl=1";
    final PixelData pixelData = PixelData(imageProvider: NetworkImage(url));
    await pixelData.getByteData();
    Color a = pixelData.pixelColorAt(282, 287);
    Color b = pixelData.pixelColorAt(218, 105);
    Color c = pixelData.pixelColorAt(160, 93);
    Color d = pixelData.pixelColorAt(-1, 100);
    print(a.value);
    print(b.value);
    print(c.value);
    expect(d, null);
  });
══╡ EXCEPTION CAUGHT BY IMAGE RESOURCE SERVICE ╞════════════════════════════════════════════════════
The following _CastError was thrown while resolving an image:
Null check operator used on a null value

When the exception was thrown, this was the stack:
#0      ImageProvider.resolveStreamForKey (package:flutter/src/painting/image_provider.dart:502:69)
#1      ImageProvider.resolve.<anonymous closure> (package:flutter/src/painting/image_provider.dart:333:9)
#2      ImageProvider._createErrorHandlerAndKey.<anonymous closure>.<anonymous closure> (package:flutter/src/painting/image_provider.dart:463:26)
#3      SynchronousFuture.then (package:flutter/src/foundation/synchronous_future.dart:41:35)
#4      ImageProvider._createErrorHandlerAndKey.<anonymous closure> (package:flutter/src/painting/image_provider.dart:460:11)
#8      ImageProvider._createErrorHandlerAndKey (package:flutter/src/painting/image_provider.dart:452:16)
#9      ImageProvider.resolve (package:flutter/src/painting/image_provider.dart:330:5)
#10     PixelData.getByteData (package:pixel_data/simplifying_image_pixels.dart:26:19)
#11     main.<anonymous closure> (file:///Users/graysonharrington/Documents/Programming/Flutter/apps/pixel_data/test/pixel_data_test.dart:14:21)
#12     Declarer.test.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:175:19)
<asynchronous suspension>
#13     Declarer.test.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart)
#18     Declarer.test.<anonymous closure> (package:test_api/src/backend/declarer.dart:173:13)
#19     Invoker.waitForOutstandingCallbacks.<anonymous closure> (package:test_api/src/backend/invoker.dart:231:15)
#24     Invoker.waitForOutstandingCallbacks (package:test_api/src/backend/invoker.dart:228:5)
#25     Invoker._onRun.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/invoker.dart:383:17)
<asynchronous suspension>
#26     Invoker._onRun.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/invoker.dart)
#31     Invoker._onRun.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/invoker.dart:370:9)
#32     Invoker._guardIfGuarded (package:test_api/src/backend/invoker.dart:415:15)
#33     Invoker._onRun.<anonymous closure> (package:test_api/src/backend/invoker.dart:369:7)
#40     Invoker._onRun (package:test_api/src/backend/invoker.dart:368:11)
#41     LiveTestController.run (package:test_api/src/backend/live_test_controller.dart:153:11)
#42     RemoteListener._runLiveTest.<anonymous closure> (package:test_api/src/remote_listener.dart:256:16)
#47     RemoteListener._runLiveTest (package:test_api/src/remote_listener.dart:255:5)
#48     RemoteListener._serializeTest.<anonymous closure> (package:test_api/src/remote_listener.dart:208:7)
#66     _GuaranteeSink.add (package:stream_channel/src/guarantee_channel.dart:125:12)
#67     new _MultiChannel.<anonymous closure> (package:stream_channel/src/multi_channel.dart:159:31)
#71     CastStreamSubscription._onData (dart:_internal/async_cast.dart:85:11)
#105    new _WebSocketImpl._fromSocket.<anonymous closure> (dart:_http/websocket_impl.dart:1145:21)
#113    _WebSocketProtocolTransformer._messageFrameEnd (dart:_http/websocket_impl.dart:338:23)
#114    _WebSocketProtocolTransformer.add (dart:_http/websocket_impl.dart:232:46)
#124    _Socket._onData (dart:io-patch/socket_patch.dart:2044:41)
#133    new _RawSocket.<anonymous closure> (dart:io-patch/socket_patch.dart:1580:33)
#134    _NativeSocket.issueReadEvent.issue (dart:io-patch/socket_patch.dart:1076:14)
(elided 104 frames from dart:async and package:stack_trace)

Image provider:
  NetworkImage("https://i0.wp.com/www.dignited.com/wp-content/uploads/2012/09/Magazine-QR-Code.jpg?fit=500%2C404&ssl=1",
  scale: 1.0)
Image configuration: ImageConfiguration()
Image key:
  NetworkImage("https://i0.wp.com/www.dignited.com/wp-content/uploads/2012/09/Magazine-QR-Code.jpg?fit=500%2C404&ssl=1",
  scale: 1.0)
════════════════════════════════════════════════════════════════════════════════════════════════════

pixelColorAt() 函数之前已经使用 ui.Image 对象进行了测试,并且可以按预期工作。我只是想让该类使用 ImageProvider 构造函数变量而不是 ui.Image。

【问题讨论】:

    标签: flutter dart


    【解决方案1】:

    只看源码:

    ImageConfiguration createLocalImageConfiguration(BuildContext context, { Size size }) {
      return ImageConfiguration(
        bundle: DefaultAssetBundle.of(context),
        devicePixelRatio: MediaQuery.of(context, nullOk: true)?.devicePixelRatio ?? 1.0,
        locale: Localizations.localeOf(context, nullOk: true),
        textDirection: Directionality.of(context),
        size: size,
        platform: defaultTargetPlatform,
      );
    }
    

    因此,只要您手动提供bundledevicePixelRatio 等内容,您就可以愉快地创建ImageConfiguration

    实际上有些部分可以为空。例如,locale: Localizations.localeOf(context, nullOk: true) 具有 nullOk: true。因此你可以简单地写ImageConiguration(locale: null, ...)。其他部分类似。

    总之,写一个类似的方法:

    ImageConfiguration myOwnCreateLocalImageConfigurationWithoutBuildContext() {
      return ImageConfiguration(
        bundle: maybenullorsomething,
        devicePixelRatio: 1.0,
        locale: null,
        textDirection: Directionality.ltr, // or something you like
        size: null,
        platform: defaultTargetPlatform,
      );
    }
    

    【讨论】:

    • 我认为 MediaQuery 需要一个上下文。
    • 我使用了这种技术,最终不得不将大部分参数设置为 null,这导致我使用 ImageConfiguration.empty,建议在上下文不可用时使用它。我仍然收到错误,所以我更新了我的帖子。
    【解决方案2】:

    为什么不创建默认的?

    imageProvider.resolve(const ImageConfiguration())
    

    【讨论】:

    • 感谢您的提示!我尝试了这个并将来自它的错误消息添加到我的原始帖子中。你能理解错误信息吗?
    猜你喜欢
    • 1970-01-01
    • 2021-12-19
    • 2012-03-23
    • 2019-11-16
    • 1970-01-01
    • 1970-01-01
    • 2011-08-23
    • 1970-01-01
    相关资源
    最近更新 更多