18

I'm trying to load image from server using networkimage() and I want to download the same once it is loaded.. can anyone suggest me some ideas.

CircleAvatar(
      backgroundImage: NetworkImage(url),
      maxRadius: 15.0,
              ); 

Here I'm loading image from my server. I want to save to the image to particular path after the image is loaded.

Jones Stephen
  • 473
  • 1
  • 5
  • 17
  • You can to get a file out of network image and store it – Dinesh Balasubramanian Sep 12 '18 at 17:43
  • Possible duplicate, you can find the answer here -[https://stackoverflow.com/questions/49455079/flutter-save-a-network-image-to-local-directory](https://stackoverflow.com/questions/49455079/flutter-save-a-network-image-to-local-directory) – F-1 Sep 13 '18 at 11:05

7 Answers7

52

I recently battled this, and decided to solve it without plugins. I hope it helps someone.

The below program downloads a picture from the web, stores it in the device's local path, and then displays it when run. (note, it does not work for flutter web because you don't have access to the local file storage on that platform. Instead you would have to save the image to a local database using a plugin like sqflite, or hive from pub.dev.) Here's the code:

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 {
  // This widget is the root of your application.
  @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() {
    _asyncMethod();
    super.initState();
  }

  _asyncMethod() async {
    //comment out the next two lines to prevent the device from getting
    // the image from the web in order to prove that the picture is 
    // coming from the device instead of the web.
    var url = "https://www.tottus.cl/static/img/productos/20104355_2.jpg"; // <-- 1
    var response = await get(url); // <--2
    var documentDirectory = await getApplicationDocumentsDirectory();
    var firstPath = documentDirectory.path + "/images";
    var filePathAndName = documentDirectory.path + '/images/pic.jpg'; 
    //comment out the next three lines to prevent the image from being saved
    //to the device to show that it's coming from the internet
    await Directory(firstPath).create(recursive: true); // <-- 1
    File file2 = new File(filePathAndName);             // <-- 2
    file2.writeAsBytesSync(response.bodyBytes);         // <-- 3
    setState(() {
      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>[
              Image.file(File(imageData), width: 600.0, height: 290.0)
            ],
          ),
        ),
      );
    } else {
      return CircularProgressIndicator(
        backgroundColor: Colors.cyan,
        strokeWidth: 5,
      );
    }
  }
}

pubspec.yaml file: http: ^0.12.1 path_provider: ^1.6.5

flutter version: 1.20.0-3.0.pre.112 dart version 2.9.0-19.0.dev

William Terrill
  • 3,484
  • 4
  • 31
  • 41
  • 1
    So, this works for a specific file, since you give the file specific name and hence can call it without downloading it again. I wonder if one can write something more general, so that I can deal with multiple images. Let's say a chat app. I would not want to download an image more than once. Furthermore, it must be stateless, because I don't want to download the images again after closing the app. – FrontMobe Aug 08 '21 at 12:20
  • for the naming piece, since it's a string, you can make it whatever you want it to be. (numeric, random, whatever) I'm not sure what you mean by being stateless since I only made it stateful in order to call the real 'meat' of the widget, which is the _asyncMethod(). This method finds and downloads the files and stores them with the documentDirectory.path, which means that it is stored on the device. Therefore, to show those files, you can just point a widget (stateless or otherwise) at that directory to show desired files. I hope that helps... let me know if doesn't – William Terrill May 31 '22 at 16:35
5

I recommend image_downloader.

  • For ios, image is saved in Photo Library.
  • For Android, image is saved in Environment.DIRECTORY_DOWNLOADS or specified location. By calling inExternalFilesDir(), specification of permission becomes unnecessary.
  • By callback(), you can get progress status.

The following is the simplest example. It will be saved.

await ImageDownloader.downloadImage(url);
ko2ic
  • 1,977
  • 14
  • 20
  • Is the iOS photos library private? Or would photos there spam up the user's gallery app? – Sam Apr 05 '20 at 15:21
4

I used image_downloader.
Use await ImageDownloader.downloadImage("url") of image_downloader package's method to download image using it's url.

Note : above method will return value as follows :-

  • imageId of the saved image if saving succeeded.

  • null if not been granted permission. for this you have to ask for storage permission, just add following line into android manifest file :

uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"

  • Otherwise it is a PlatformException.
Asad Patel
  • 111
  • 5
2

I tried many solution, but this is simplest solution for my... Just try it

STEP - 1
Add this package in your pubspec.yaml file

dependencies:
 image_downloader: ^0.20.1

STEP - 2
Add this in your dart file

import 'package:image_downloader/image_downloader.dart';  

STEP - 3
Write this code on press download button

ColButton(
   title: 'Download',
   icon: Icons.file_download,
   onTap: () async {
     try {
       showLoadingDialog(context);
       // Saved with this method.
       var imageId =
           await ImageDownloader.downloadImage("https://raw.githubusercontent.com/wiki/ko2ic/image_downloader/images/bigsize.jpg");
       if (imageId == null) {
          return;
       }
       // Below is a method of obtaining saved image information.
       var fileName = await ImageDownloader.findName(imageId);
       var path = await ImageDownloader.findPath(imageId);
       var size = await ImageDownloader.findByteSize(imageId);
       var mimeType = await ImageDownloader.findMimeType(imageId);
       Navigator.pop(context);
       showToast('Image downloaded.');
      } on PlatformException catch (error) {
          print(error);
        }
     },
   ),
Rohit Tagadiya
  • 3,373
  • 1
  • 25
  • 25
1

I use this plugin to save image in the phone using an URL https://pub.dartlang.org/packages/image_picker_saver

Pigna
  • 66
  • 6
0

For more advanced handling of Image/File downloads, you can consider the flutter_downloader package.

Some of the features that I like are :

  • Shows OS level download progress
  • can track all downloads
  • Has notification
Purus
  • 5,701
  • 9
  • 50
  • 89
0

While using image_downloader if any one is getting this

Error : (No implementation found for method downloadImage on channel plugins.ko2ic.com/image_downloader)

than follow below steps

Note: in the case of android, to use this feature, the following settings are required.

Add the following within tag in AndroidManifest.xml .

<provider
        android:name="com.ko2ic.imagedownloader.FileProvider"
        android:authorities="${applicationId}.image_downloader.provider"
        android:exported="false"
        android:grantUriPermissions="true">
    <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths"/>
</provider>

Add provider_paths.xml in android/app/src/main/res/xml/

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>