【发布时间】:2018-09-02 10:48:31
【问题描述】:
在 Flutter 中如何将网络中的图片保存到本地目录。
我是编码和解码图像的新手。谁能指出我正确的方向?
【问题讨论】:
在 Flutter 中如何将网络中的图片保存到本地目录。
我是编码和解码图像的新手。谁能指出我正确的方向?
【问题讨论】:
如果您只想将图像(例如:.png)保存到设备,您可以通过简单的 get (http/http.dart) 和 File (dart:io) 轻松实现。
为此,您可以参考以下示例:
var response = await http.get(imgUrl);
Directory documentDirectory = await getApplicationDocumentsDirectory();
File file = new File(join(documentDirectory.path, 'imagetest.png'));
file.writeAsBytesSync(response.bodyBytes); // This is a sync operation on a real
// app you'd probably prefer to use writeAsByte and handle its Future
请注意,在上面的案例中,我使用了 dart pub 中的“path_provider”包。总体而言,您至少会导入以下项目:
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
【讨论】:
file 是一个文件对象,您可以将其用作Image.file(file, fit: BoxFit.cover),
对此有一个简单的答案和一个更复杂的答案。我会描述复杂的,然后给你简单的。
复杂的答案是您可以使用NetworkImage 手动缓存图像,解析它并获取图像流。获得图像流后,您可以使用 Flutter 的文件读写功能将其保存到文件系统(this 是了解更多信息的好资源) - 您还需要使用一个名为 PathProvider 的插件,它可以获得正确的路径适用于该链接中描述的 iOS 和 Android。您还想跟踪您下载的所有图像,并可能在一定时间后删除它们。在使用它们创建 Image 小部件之前,您还必须读回这些文件。
这给了你很多控制权,但需要一些工作(虽然不是一个疯狂的数量,但如果你是 Flutter 的新手,可能不是你现在想做的事情,这取决于你为什么要保存图像) .
简单的答案是包来救援!其他人已经遇到过这个问题,并为你写了一个插件来解决它,所以你不必考虑它! p>
有关插件的信息,请参阅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 显示它。
【讨论】:
flutter packages get 命令时失败。跨度>
cached_network_image: any(尽管这并不是真正推荐的)。您也可以尝试添加对 flutter_cache_manager 的依赖,然后看看会发生什么。
在浏览了代码和颤动文档之后。我找到了适用于 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),
],
),
);
}
}
【讨论】:
要将网络图像保存在本地系统中,您需要使用 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));
}
【讨论】:
关注此网址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();
}
}
【讨论】:
我在做这件事时遇到了很多麻烦,所以我想用一个简单的例子来解释一下上面的答案,这个例子在启动时下载一个文件,将它保存到本地目录。我用注释//%%% 标记了几行,以显示可以在应用程序第二次运行时注释掉的行。 (因为它不需要下载才能显示......它已经在设备本身上:
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
【讨论】:
您可以使用此功能从相机上传和获取 Url(download) 图像 firebase-存储
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;
});
}
【讨论】:
受 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;
}
}
【讨论】:
您可以使用image_downloader。
Environment.DIRECTORY_DOWNLOADS 或指定位置。通过调用inExternalFilesDir(),无需指定权限。callback()获取进度状态。下面是最简单的例子。它将被保存。
await ImageDownloader.downloadImage(url);
【讨论】:
【讨论】: