dart - 绘制从远程服务器下载的图像

标签 dart flutter

我需要做以下事情:

  1. 从服务器下载 PNG 资源
  2. 根据状态在该图像上绘制几个不同颜色的矩形
  3. 在可缩放 ImageView 中显示该图像

我在使用 Canvas 的 Android 应用程序中有一个工作代码,但我不知道如何使用 Flutter 来实现。

这是下载资源的代码:

static Future<File> getImageFromUrl(String url) async {
final directory = await getApplicationDocumentsDirectory();
final file = File("$directory/${_getSHA(url)}.png");

if (await file.exists()) {
  // Returns the cached file
} else {
  final response = await http.get(url);

  if (response.statusCode >= 200 && response.statusCode < 300) {
    await file.writeAsBytes(response.bodyBytes);
  } else {
    return null;
  }
}
return file;
}

接下来我该做什么?我尝试使用 PictureRecorder 和 Canvas,但我找不到从这些 Canvas 上的文件绘制图像然后将其转换为图像的方法,因为我无法从文件中提取宽度和高度。

编辑: 下面是我想在 Flutter 中实现的等效 Android 代码。

// Here we have a bitmap from a file
    Bitmap mapBitmap = getBitmap();

    Canvas mapCanvas = new Canvas(mapBitmap);

    mapDrawable.setBounds(0, 0, mapCanvas.getWidth(), mapCanvas.getHeight());
    mapDrawable.draw(mapCanvas);

    canvasWidth = mapCanvas.getWidth();
    canvasHeight = mapCanvas.getHeight();

    Paint paint = new Paint();
    for (java.util.Map.Entry<String, MapObject> entry : this.mapObjects.entrySet()) {
        MapObject mapObject = entry.getValue();
        paint.setColor(getContext().getResources().getColor(mapObject.getBackgroundColor()));
        paint.setAlpha(100);
        mapCanvas.drawRect((int) (mapObject.getPosX() * scaleX),
                (int) (mapObject.getPosY() * scaleY),
                (int) ((mapObject.getPosX() + mapObject.getWidth()) * scaleX),
                (int) ((mapObject.getPosY() + mapObject.getHeight()) * scaleY),
                paint);
    }

    photoView.setImageBitmap(mapBitmap);

最佳答案

我终于设法解决了这个问题!

我创建了一个渲染器来创建合成图像(来自远程资源的背景并在前景中添加矩形)。

渲染器:

class MapRenderer {
  ui.Image _mapBackgroundImage;

  Future<ui.Codec> renderMap(String url, List<Sensor> sensors) async {
    await _loadMapBackground(url);
    var renderedMapImage = await _updateSensors(sensors);
    var byteD = await renderedMapImage.toByteData(
        format: ui.ImageByteFormat.png);
    return ui.instantiateImageCodec(Uint8List.view(byteD.buffer));
  }


  Future<ui.Image> _updateSensors(List<Sensor> sensors) async {
    ui.PictureRecorder recorder = ui.PictureRecorder();
    Canvas c = Canvas(recorder);

    var paint = ui.Paint();
    c.drawImage(_mapBackgroundImage, ui.Offset(0.0, 0.0), paint);

    for (Sensor s in sensors) {
      paint.color = (s.availability ? CustomColors.npSensorFree : CustomColors
          .npSensorOccupied);
      c.drawRect(
        ui.Rect.fromPoints(ui.Offset(s.posX, s.posY),
            ui.Offset(s.posX + s.width, s.posY + s.height)),
        paint,
      );
    }

    return recorder
        .endRecording()
        .toImage(_mapBackgroundImage.width, _mapBackgroundImage.height);
  }

  Future<void> _loadMapBackground(String url) async {
    var imageBytes = await _getLocalCopyOrLoadFromUrl(url);

    if (imageBytes != null) {
      _mapBackgroundImage = await _getImageFromBytes(imageBytes);
    } else {
      return null;
    }
  }

  Future<ui.Image> _getImageFromBytes(Uint8List bytes) async {
    var imageCodec = await ui.instantiateImageCodec(bytes);
    var frame = await imageCodec.getNextFrame();
    return frame.image;
  }

  Future<Uint8List> _getLocalCopyOrLoadFromUrl(String url) async {
    final directory = await getApplicationDocumentsDirectory();
    final file = File("${directory.path}/${_getSHA(url)}.png");

    if (await file.exists()) {
      return await file.readAsBytes();
    } else {
      Uint8List resourceBytes = await _loadFromUrl(url);

      if (resourceBytes != null) {
        await file.writeAsBytes(resourceBytes);
        return resourceBytes;
      } else {
        return null;
      }
    }
  }

  Future<Uint8List> _loadFromUrl(String url) async {
    final response = await http.get(url);

    if (response.statusCode >= 200 && response.statusCode < 300) {
      return response.bodyBytes;
    } else {
      return null;
    }
  }

  String _getSHA(String sth) {
    var bytes = utf8.encode(sth);
    var digest = sha1.convert(bytes);

    return digest.toString();
  }

  void dispose() {
    _mapBackgroundImage.dispose();
  }
}

为了向 ZoomableImage 提供图像,我创建了一个自定义 ImageProvider:

class MapImageProvider extends ImageProvider<MapImageProvider> {
  final String url;
  final List<Sensor> sensors;

  final MapRenderer mapRenderer = MapRenderer();

  MapImageProvider(this.url, this.sensors);

  @override
  ImageStreamCompleter load(MapImageProvider key) {   
    return MultiFrameImageStreamCompleter(
        codec: _loadAsync(key),
        scale: 1.0,
        informationCollector: (StringBuffer information) {
          information.writeln('Image provider: $this');
          information.write('Image key: $key');
        });
  }

  Future<ui.Codec> _loadAsync(MapImageProvider key) async {
    assert(key == this);

    return await mapRenderer.renderMap(url, sensors);
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is MapImageProvider &&
          runtimeType == other.runtimeType &&
          url == other.url;

  @override
  int get hashCode => url.hashCode;

  @override
  String toString() => '$runtimeType("$url")';  

  @override
  Future<MapImageProvider> obtainKey(ImageConfiguration configuration) {
    return SynchronousFuture<MapImageProvider>(this);
  }
}

如果有人知道将图像转换为编解码器或什至跳过此步骤的更好方法,请发表评论(MapRenderer.renderMap 函数)。

关于dart - 绘制从远程服务器下载的图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53203904/

相关文章:

android - Flutter:我怎样才能提高该应用程序的性能?

dart - 使用 WidgetsApp 的应用导航示例

flutter - 命令 “flutter create”如何工作?

database - 错误状态 : PostgreSQLSeverity. 错误:指定的参数类型与查询 SELECT to_regclass(@tableName:text) 中的列参数类型不匹配

android - 什么时候在 Flutter 中使用 setState?

dart - 数字大,精度损失

javascript - ShadowRoot 的 getSelection().getRangeAt(0) 在 Google Chrome 35 中返回不正确的 Range 对象

android - 如何更改 Flutter DevTools 默认浏览器?

带有圆形图像图标的 Flutter 布局

Dart:无法推断函数文字的类型,因为文字有一个 block 作为它的主体