Flutter将网络映像保存到本地目录

时间:2018-03-23 17:09:34

标签: dart flutter

在Flutter中如何将图像从网络保存到本地目录。

我是编码和解码图像的新手。有人能指出我正确的方向吗?

10 个答案:

答案 0 :(得分:7)

有一个简单的答案和一个更复杂的答案。我将描述复杂的一个,然后给你一个简单的。

复杂的答案是,您可以使用NetworkImage手动缓存图像,解析图像并获取图像流。获得图像流后,可以使用flutter的文件读取和保存将其保存到文件系统中。编写功能(this是一个很好的资源来了解更多信息) - 你还需要使用一个名为PathProvider的插件,它为iOS和Android提供了正确的路径,该路径在该链接中有所描述。您还需要跟踪您下载的所有图像,并可能在一定时间后删除它们。在使用它们创建Image小部件之前,您还必须先阅读这些文件。

这给了你很多控制权,但是有点工作(虽然不是一个疯狂的数量,但如果你是新手,可能不是你想要做的事情,这取决于你想要保存图像的原因)

简单的答案是救援套件!其他人已经遇到过这个问题并编写了一个插件来解决它,所以你不必考虑它!

有关该插件的信息,请参阅cached_network_image package

您需要在pubspec.yaml

中添加依赖项
dependencies:
  cached_network_image: "^0.3.0"

导入它:

import 'package:cached_network_image/cached_network_image.dart';

并使用它!

new CachedNetworkImage(
   imageUrl: "http://imageurl.png",
   placeholder: new CircularProgressIndicator(),
   errorWidget: new Icon(Icons.error),
),

请注意,此下载&显示图片 - 如果您想单独执行这些操作,可以使用new CachedNetworkImageProvider(url)并使用new Image进行显示。

答案 1 :(得分:6)

徘徊在代码和文档之后。我找到了适用于iOS和Android的方法和类,而且一切顺利。

帮助程序类

import 'dart:async';
import 'dart:io' as Io;
import 'package:image/image.dart';

import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:path_provider/path_provider.dart';
class SaveFile {

  Future<String> get _localPath async {
    final directory = await getApplicationDocumentsDirectory();

    return directory.path;
  }
   Future<Io.File> getImageFromNetwork(String url) async {

     var cacheManager = await CacheManager.getInstance();
     Io.File file = await cacheManager.getFile(url);
     return file;
   }

   Future<Io.File> saveImage(String url) async {

    final file = await getImageFromNetwork(url);
    //retrieve local path for device
    var path = await _localPath;
    Image image = decodeImage(file.readAsBytesSync());

    Image thumbnail = copyResize(image, 120);

    // Save the thumbnail as a PNG.
    return new Io.File('$path/${DateTime.now().toUtc().toIso8601String()}.png')
      ..writeAsBytesSync(encodePng(thumbnail));
  }
}

课程的使用

class HomePageState extends State<HomePage>{

Future<Null> _launched ;

  Widget _showResult(BuildContext context, AsyncSnapshot<Null> snapshot){
    if(!snapshot.hasError){
      return Text('Image is saved');
    }
    else{
      return const Text('Unable to save image');
    }
  }

  Future<Null> _saveNetworkImage(String url) async{
    try{
       await SaveFile().saveImage(url);
    }
    on Error catch(e){
      throw 'Error has occured while saving';
    }
  }
   @override
   Widget Build(BuildContext context){
       return new Scaffold(
            key: _scaffoldKey,
            appBar: new AppBar(
                title: new Text('Image'),
            ),
            body: Column(
                  children: <Widget>[
                       IconButton(icon: Icon(Icons.save), onPressed: (){
                     setState(() {
                       _launched =_saveNetworkImage(url);
                     });
                    }),
                      new FutureBuilder<Null>(future: _launched ,builder: _showResult),
                  ],
            ),
          );
   }
}

答案 2 :(得分:2)

如果您只想将图像(例如:.png)保存到设备,则可以通过简单的get(http / http.dart)和File(dart:io)轻松实现。

为此,您可以根据以下示例进行操作:

var response = await get(imgUrl);
documentDirectory = await getApplicationDocumentsDirectory();

File file = new File(
  join(documentDirectory.path, 'imagetest.png')
);

file.writeAsBytesSync(response.bodyBytes);

请注意,在上述情况下,我使用了来自dart pub的“ path_provider”包。总体而言,您的导入中至少应包含以下项目:

import 'dart:io';
import 'package:http/http.dart' show get;
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';

答案 3 :(得分:1)

要将网络映像保存在本地系统中,您需要使用ImagePickerSave dart插件。在pub.yaml文件中添加dart插件: image_picker_saver:^ 0.1.0 ,然后调用以下代码以保存图像。 URL是网络图像的图像URL

void _onImageSaveButtonPressed(String url) async {
  print("_onImageSaveButtonPressed");
  var response = await http
      .get(url);

  debugPrint(response.statusCode.toString());

  var filePath = await ImagePickerSaver.saveFile(
      fileData: response.bodyBytes);
  var savedFile= File.fromUri(Uri.file(filePath));
}

答案 4 :(得分:0)

您可以使用image_downloader

  • 对于ios,图像保存在照片库中。
  • 对于Android,图像保存在Environment.DIRECTORY_DOWNLOADS或指定位置。通过调用inExternalFilesDir(),不需要指定权限。
  • 通过callback(),您可以获取进度状态。

以下是最简单的示例。它将被保存。

await ImageDownloader.downloadImage(url);

答案 5 :(得分:0)

我在执行此操作时遇到很多麻烦,因此我想通过一个简单的示例来详细说明上述答案,该示例在启动时下载文件,然后将其保存到本地目录中。我用注释//%%%标记了几行,以显示可以在应用程序第二次运行时被注释掉的行。 (因为它不需要下载即可显示...它已经在设备本身上:

import 'package:flutter/material.dart';
import 'package:http/http.dart' show get;
import 'dart:io';
import 'package:path_provider/path_provider.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Test Image',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Test Image'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  initState() {
    _downloadAndSavePhoto();
    super.initState();
  }

  _downloadAndSavePhoto() async {
    // Get file from internet
    var url = "https://www.tottus.cl/static/img/productos/20104355_2.jpg"; //%%%
    var response = await get(url); //%%%
    // documentDirectory is the unique device path to the area you'll be saving in
    var documentDirectory = await getApplicationDocumentsDirectory();
    var firstPath = documentDirectory.path + "/images"; //%%%
    //You'll have to manually create subdirectories
    await Directory(firstPath).create(recursive: true); //%%%
    // Name the file, create the file, and save in byte form.
    var filePathAndName = documentDirectory.path + '/images/pic.jpg';
    File file2 = new File(filePathAndName); //%%%
    file2.writeAsBytesSync(response.bodyBytes); //%%%
    setState(() {
      // When the data is available, display it
      imageData = filePathAndName;
      dataLoaded = true;
    });
  }

  String imageData;
  bool dataLoaded = false;

  @override
  Widget build(BuildContext context) {
    if (dataLoaded) {
      return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              // imageData holds the path AND the name of the picture.
              Image.file(File(imageData), width: 600.0, height: 290.0)
            ],
          ),
        ),
      );
    } else {
      return CircularProgressIndicator(
        backgroundColor: Colors.cyan,
        strokeWidth: 5,
      );
    }
  }
}

这是我的pubspec.yaml文件:

http: ^0.12.0+2
  path_provider: 1.5.0

答案 6 :(得分:0)

您可以使用此功能从相机上载并获取Url(下载)图像 firebase-storage

 Future _upIm()async {
      final StorageReference firebaseStorageRef =
      FirebaseStorage.instance.ref().child(DateTime.now().toString());
      final StorageUploadTask task =
      firebaseStorageRef.putFile(_storedImage);

      var downUrl=await (await task.onComplete).ref.getDownloadURL();
      var url =downUrl.toString();
      print(url);

      setState(() {
        uploadImage=url;
      });

    }

答案 7 :(得分:0)

受Paras启发,CacheManager.getInstance()已弃用

final DefaultCacheManager defaultCacheManager = DefaultCacheManager();
final fileInfo = await defaultCacheManager.getFileFromCache(imageUrl);
ImageGallerySaver.saveImage(image);

下面是saveImage函数

// save raw data to gallery with permission
static Future<void> saveImage(Uint8List image) async {
  try {
    if (Platform.isIOS) {
      await PermissionHandler().requestPermissions([PermissionGroup.photos]);
      PermissionStatus permission = await PermissionHandler().checkPermissionStatus(PermissionGroup.photos);
      if (permission == PermissionStatus.granted) {
      } else {
        throw 'denied';
      }
    } else if (Platform.isAndroid) {
      await PermissionHandler().requestPermissions([PermissionGroup.storage]);
      PermissionStatus permission = await PermissionHandler().checkPermissionStatus(PermissionGroup.storage);
      if (permission == PermissionStatus.granted) {
      } else {
        throw 'denied';
      }
    }
    await ImageGallerySaver.saveImage(image);
  } catch (e) {
    throw e;
  }
}

答案 8 :(得分:-1)

关注此网址flutter save network image

代码段

import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:http/http.dart' as http;

class NetworkToLocalImage extends StatefulWidget{
 String url;

 NetworkToLocalImage(this.url);

 @override
 _LoadImages createState() => new _LoadImages(url);
 }

class _LoadImages extends State<NetworkToLocalImage>{

 String url;
 String filename;
 var dataBytes;

 _LoadImages(this.url){
 filename = Uri.parse(url).pathSegments.last;
 downloadImage().then((bytes){
  setState(() {
    dataBytes = bytes;
  });
});
}

Future<dynamic> downloadImage() async {
String dir = (await getApplicationDocumentsDirectory()).path;
File file = new File('$dir/$filename');

if (file.existsSync()) {
  print('file already exist');
  var image = await file.readAsBytes();
  return image;
} else {
  print('file not found downloading from server');
  var request = await http.get(url,);
  var bytes = await request.bodyBytes;//close();
  await file.writeAsBytes(bytes);
  print(file.path);
  return bytes;
}
}

 @override
 Widget build(BuildContext context) {
 // TODO: implement build
 if(dataBytes!=null)
 return new Image.memory(dataBytes);
 else return new CircularProgressIndicator();
}
}

答案 9 :(得分:-3)