Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/dart/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/flutter/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Dart 绘制从远程服务器下载的图像_Dart_Flutter - Fatal编程技术网

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

Dart 绘制从远程服务器下载的图像,dart,flutter,Dart,Flutter,我需要做以下工作: 从服务器下载PNG资源 在该图像上绘制几个矩形,根据状态使用不同的颜色 在可缩放图像视图中显示该图像 我在一个使用Canvas的Android应用程序中有一个工作代码,但我不知道如何使用Flutter来实现这一点 以下是下载资源的代码: static Future<File> getImageFromUrl(String url) async { final directory = await getApplicationDocumentsDirectory();

我需要做以下工作:

  • 从服务器下载PNG资源
  • 在该图像上绘制几个矩形,根据状态使用不同的颜色
  • 在可缩放图像视图中显示该图像
  • 我在一个使用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;
    }
    
    静态未来getImageFromUrl(字符串url)异步{
    最终目录=等待getApplicationDocumentsDirectory();
    final file=file(“$directory/${{u getSHA(url)}.png”);
    if(wait file.exists()){
    //返回缓存文件
    }否则{
    最终响应=等待http.get(url);
    如果(response.statusCode>=200&&response.statusCode<300){
    wait file.writeAsBytes(response.bodyBytes);
    }否则{
    返回null;
    }
    }
    返回文件;
    }
    
    接下来我该怎么办?我尝试使用PictureRecorder和Canvas,但我找不到一种方法从这些画布上的文件中绘制图像,然后将其转换为图像,因为我无法从文件中提取宽度和高度

    编辑: 下面是我想在flifter中实现的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);
    
    //这里有一个文件中的位图
    位图mapBitmap=getBitmap();
    Canvas mapCanvas=新画布(mapBitmap);
    mapDrawable.setBounds(0,0,mapCanvas.getWidth(),mapCanvas.getHeight());
    mapDrawable.draw(mapCanvas);
    canvasWidth=mapCanvas.getWidth();
    canvasHeight=mapCanvas.getHeight();
    油漆=新油漆();
    for(java.util.Map.Entry:this.mapObjects.entrySet()){
    MapObject MapObject=entry.getValue();
    setColor(getContext().getResources().getColor(mapObject.getBackgroundColor());
    油漆。setAlpha(100);
    mapCanvas.drawRect((int)(mapObject.getPosX()*scaleX),
    (int)(mapObject.getPosY()*scaleY),
    (int)((mapObject.getPosX()+mapObject.getWidth())*scaleX),
    (int)((mapObject.getPosY()+mapObject.getHeight())*scaleY),
    油漆);
    }
    设置图像位图(mapBitmap);
    
    通常,要简单地显示来自internet的图像,可以使用构造函数。如果要进一步自定义交互,例如根据加载状态显示矩形,可以使用该类并将a传递给其构造函数。
    NetworkImage
    允许您监听加载和错误事件

    要在图像上方绘制,我只建议使用小部件

    如果您想在图像中添加缩放功能,您应该考虑使用OR包替换下面代码中的<代码>图像<代码>。 此外,如果需要缓存,您可以使用软件包中的

    CachedNetworkImageProvider

    下面的示例显示加载图像上的黄色矩形、完全加载图像上的绿色矩形以及加载崩溃时的红色矩形。这是一个完整的应用程序,您可以复制并粘贴到IDE中,然后试用

    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Network Image Download',
          theme: ThemeData(),
          home: MainPage(),
        );
      }
    }
    
    class MainPage extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => MainPageState();
    }
    
    class MainPageState extends State<MainPage> {
      ImageProvider provider;
      bool loaded;
      bool error;
    
      @override
      void initState() {
        super.initState();
    
        loaded = false;
        error = false;
        provider = NetworkImage('https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png');
    
        provider.resolve(ImageConfiguration()).addListener((_, __) {
          setState(() {
            loaded = true;
          });
        }, onError: (_, __) {
          setState(() {
            error = true;
          });
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: Stack(
              alignment: Alignment.center,
              children: <Widget>[
                Image(image: provider),
                Container(
                  width: 75.0,
                  height: 75.0,
                  color: colorByState(),
                )
              ],
            ),
          ),
        );
      }
    
      Color colorByState() {
        if (error) {
          return Colors.red;
        } else if (loaded) {
          return Colors.green;
        } else {
          return Colors.yellow;
        }
      }
    }
    
    导入“包装:颤振/材料.省道”;
    void main()=>runApp(MyApp());
    类MyApp扩展了无状态小部件{
    @凌驾
    小部件构建(构建上下文){
    返回材料PP(
    标题:“网络图像下载”,
    主题:主题数据(),
    主页:主页(),
    );
    }
    }
    类MainPage扩展了StatefulWidget{
    @凌驾
    State createState()=>MainPageState();
    }
    类MainPageState扩展状态{
    图像提供者;
    bool-loaded;
    布尔误差;
    @凌驾
    void initState(){
    super.initState();
    加载=错误;
    错误=错误;
    提供者=网络映像('https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png');
    provider.resolve(ImageConfiguration()).addListener((){
    设置状态(){
    加载=真;
    });
    },一个错误:(u,uu){
    设置状态(){
    错误=真;
    });
    });
    }
    @凌驾
    小部件构建(构建上下文){
    返回脚手架(
    正文:中(
    子:堆栈(
    对齐:对齐.center,
    儿童:[
    图像(图像:提供者),
    容器(
    宽度:75.0,
    身高:75.0,
    颜色:colorByState(),
    )
    ],
    ),
    ),
    );
    }
    Color colorByState(){
    如果(错误){
    返回颜色。红色;
    }否则,如果(已加载){
    返回颜色。绿色;
    }否则{
    返回颜色。黄色;
    }
    }
    }
    
    我终于解决了这个问题

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

    渲染器:

    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();
      }
    }
    
    类映射渲染器{
    ui.Image\u映射背景图像;
    未来的renderMap(字符串url,列表传感器)异步{
    wait_loadMapBackground(url);
    var renderedMapImage=等待更新传感器(传感器);
    var byteD=wait renderedMapImage.toByteData(
    格式:ui.ImageByteFormat.png);
    返回ui.instantialeimagecodec(Uint8List.view(byteD.buffer));
    }
    未来更新传感器(列表传感器)异步{
    ui.PictureRecorder记录器=ui.PictureRecorder();
    画布c=画布(记录器);
    var paint=ui.paint();
    c、 drawImage(_mapBackgroundImage,ui.Offset(0.0,0.0),绘制);
    用于(传感器中的传感器){
    paint.color=(s.availability?CustomColor.npSensorFree:CustomColor)
    .1(已占用);
    c、 drawRect(
    ui.Rect.fromPoints(ui.Offset(s.posX,s.posY),
    ui.偏移量(s.posX+s.width,s.posY+s.height)),
    油漆,
    );
    }
    回程记录器
    .endRecording()
    .toImage(_-mapBackgroundImage.width,_-mapBackgroundImage.height);
    }
    Future\u loadMapBackground(字符串url)异步{
    var imageBytes=wait_getLocalCopyOrLoadFromUrl(url);
    if(imageBytes!=null){
    _mapBackgroundImage=Wait_getImageFromBytes(imageBytes);
    }否则{
    返回null;
    }
    }
    傅
    
    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);
      }
    }