草庐IT

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

coder 2023-07-22 原文

我需要做以下事情:

  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/

有关dart - 绘制从远程服务器下载的图像的更多相关文章

  1. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  2. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  3. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

  4. ruby-on-rails - 启动 Rails 服务器时 ImageMagick 的警告 - 2

    最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru

  5. ruby-on-rails - s3_direct_upload 在生产服务器中不工作 - 2

    在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo

  6. ruby - 安装 Ruby 时遇到问题(无法下载资源 "readline--patch") - 2

    当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub

  7. ruby - 用 Ruby 编写一个简单的网络服务器 - 2

    我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b

  8. ruby-on-rails - 在 Rails 中调试生产服务器 - 2

    您如何在Rails中的实时服务器上进行有效调试,无论是在测试版/生产服务器上?我试过直接在服务器上修改文件,然后重启应用,但是修改好像没有生效,或者需要很长时间(缓存?)我也试过在本地做“脚本/服务器生产”,但是那很慢另一种选择是编码和部署,但效率很低。有人对他们如何有效地做到这一点有任何见解吗? 最佳答案 我会回答你的问题,即使我不同意这种热修补服务器代码的方式:)首先,你真的确定你已经重启了服务器吗?您可以通过跟踪日志文件来检查它。您更改的代码显示的View可能会被缓存。缓存页面位于tmp/cache文件夹下。您可以尝试手动删除

  9. ruby-on-rails - 添加回形针新样式不影响旧上传的图像 - 2

    我有带有Logo图像的公司模型has_attached_file:logo我用他们的Logo创建了许多公司。现在,我需要添加新样式has_attached_file:logo,:styles=>{:small=>"30x15>",:medium=>"155x85>"}我是否应该重新上传所有旧数据以重新生成新样式?我不这么认为……或者有什么rake任务可以重新生成样式吗? 最佳答案 参见Thumbnail-Generation.如果rake任务不适合你,你应该能够在控制台中使用一个片段来调用重新处理!关于相关公司

  10. Unity 热更新技术 | (三) Lua语言基本介绍及下载安装 - 2

    ?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------

随机推荐