如何在Flutter中保存图像文件?使用Image_picker插件选择的文件

时间:2018-07-14 11:28:57

标签: dart flutter

我真的很困惑。颤抖真棒,但有些时间被困住了

所有代码均已完成。所选文件也显示在预览中,但我尝试将该文件保存在本地android存储中。我无法在

中获得成功
  Future getImage(ImageSource imageSource) async {
    var image = await ImagePicker.pickImage(source: imageSource);

    setState(() {
      _image = image;
    });
  } 

使用此代码选择文件,然后将文件保存在_image中,现在我尝试使用path_provider和dart.io进行存储,但无法获得保存方法。

6 个答案:

答案 0 :(得分:7)

使用await ImagePicker.pickImage(...),您已经在正确的轨道上,因为该函数返回了File

File类具有一个copy method,您可以使用它来复制文件(该文件已经通过相机或放在图库中保存在磁盘上)并放入了您的应用程序文档中目录:

// using your method of getting an image
final File image = await ImagePicker.pickImage(source: imageSource);

// getting a directory path for saving
final String path = await getApplicationDocumentsDirectory().path;

// copy the file to a new path
final File newImage = await image.copy('$path/image1.png');

setState(() {
  _image = newImage;
});

您还应该注意,您可以使用ImagePickerimage.path获取图像文件的路径,该路径还将包含您可能要提取的文件结尾,并且可以保存图像路径通过使用newImage.path

答案 1 :(得分:5)

自image_picker 0.6.7起

pickImagepickVideoretrieveLostData已被弃用
https://pub.dev/packages/image_picker#-changelog-tab-

这些方法必须替换为

  • getImage
  • getVideo
  • getLostData

getImage()方法的用法示例:

...
File _storedImage;
...

void _takePicture() async {
  // 1. Create an ImagePicker instance.
  final ImagePicker _picker = ImagePicker();

  // 2. Use the new method.
  //
  // getImage now returns a PickedFile instead of a File (form dart:io)
  final PickedFile pickedImage = await _picker.getImage(...)

  // 3. Check if an image has been picked or take with the camera.
  if (pickedImage == null) {
    return;
  }

  // 4. Create a File from PickedFile so you can save the file locally
  // This is a new/additional step.
  File tmpFile = File(pickedFile.path);

  // 5. Get the path to the apps directory so we can save the file to it.
  final String path = await getApplicationDocumentsDirectory().path;
  final String fileName = basename(pickedFile.path); // Filename without extension
  final String fileExtension = extension(pickedFile.path); // e.g. '.jpg'

  // 6. Save the file by copying it to the new location on the device.
  tmpFile = await tmpFile.copy('$path/$fileName$fileExtension');

  // 7. Optionally, if you want to display the taken picture we need to update the state
  // Note: Copying and awaiting the file needs to be done outside the setState function.
  setState(() => _storedImage = tmpFile);
}

一个更紧凑的示例

File _image;
final picker = ImagePicker();

Future getImage() async {
  final File pickedImage = await picker.getImage(source: ImageSource.camera);

  if (pickedImage == null) return;

  File tmpFile = File(pickedImage.path);
  tmpFile = await tmpFile.copy(tmpFile.path);

  setState(() {
    _image = tmpFile;
  });
}

答案 2 :(得分:3)

希望能帮助和见到别人。给个喜欢。

RepaintBoundary将为您提供帮助。

final GlobalKey _repaintKey = new GlobalKey();


//  Image Widget


Widget _buildQrImage() {
_avatar = RepaintBoundary(
  key: _repaintKey,
  child: Image.asset('assets/ifredom.jpg')
);

return Column(
  children: <Widget>[
    _avatar,
    (imageFile == null)
        ? Image.asset('assets/default.jpg')
        : Image.file(imageFile),
    FlatButton(
      child: Text("save"),
      onPressed: () {
        _saveScreenShot(context);
      },
    ),

  ],
);
}



void _saveScreenShot(BuildContext context) {
RenderRepaintBoundary boundary = _repaintKey.currentContext.findRenderObject();

// ScreenShot and save
saveScreenShot(boundary, success: () {
  saveScreenShot2SDCard(boundary, success: () {
    showToast('save ok');
  }, fail: () {
    showToast('save ok');
  });
}, fail: () {
  showToast('save fail!');
});
}

此文件为utils。

Flutter提供了一个RepaintBoundaryWidget来实现屏幕截图功能。

RepaintBoundary用于包装需要截取的部分。

RenderRepaintBoundary可用于截取由RepaintBoundary包装的部分。

然后通过使用boundary.toImage()方法将其转换为ui.Image对象,然后使用image.toByteData()将图像转换为byteData;

最后通过File()将其存储为文件对象。 WriteAsBytes():

import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'dart:ui' as ui;

import 'package:flutter/rendering.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';

import 'package:oktoast/oktoast.dart';

final String scrawlImagePath = '/screen_shot_scraw.png';


Future<File> getScreenShotFile() async {
  Directory tempDir = await getTemporaryDirectory();
  String tempPath = '${tempDir.path}$scrawlImagePath';
  File image = File(tempPath);
  bool isExist = await image.exists();
  return isExist ? image : null;
}

Future saveScreenShot2SDCard(RenderRepaintBoundary boundary,
    {Function success, Function fail}) async {
  // check storage permission.
  PermissionHandler().requestPermissions([PermissionGroup.storage]).then((map) {
    if (map[PermissionGroup.storage] == PermissionStatus.granted) {
      capturePng2List(boundary).then((uint8List) async {
        if (uint8List == null || uint8List.length == 0) {
          if (fail != null) fail();
          return;
        }
        Directory tempDir = await getExternalStorageDirectory();
        _saveImage(uint8List, Directory('${tempDir.path}/flutter_ui'),
            '/screen_shot_scraw_${DateTime.now()}.png',
            success: success, fail: fail);
      });
    } else {
      showToast('请打开SD卡存储权限!');
//      if (fail != null) fail();
      return;
    }
  });
}

void saveScreenShot(RenderRepaintBoundary boundary,
    {Function success, Function fail}) {
  capturePng2List(boundary).then((uint8List) async {
    if (uint8List == null || uint8List.length == 0) {
      if (fail != null) fail();
      return;
    }
    Directory tempDir = await getTemporaryDirectory();
    _saveImage(uint8List, tempDir, scrawlImagePath,
        success: success, fail: fail);
  });
}

void _saveImage(Uint8List uint8List, Directory dir, String fileName,
    {Function success, Function fail}) async {
  bool isDirExist = await Directory(dir.path).exists();
  if (!isDirExist) Directory(dir.path).create();
  String tempPath = '${dir.path}$fileName';
  File image = File(tempPath);
  bool isExist = await image.exists();
  if (isExist) await image.delete();
  File(tempPath).writeAsBytes(uint8List).then((_) {
    if (success != null) success();
  });
}

Future<Uint8List> capturePng2List(RenderRepaintBoundary boundary) async {
  ui.Image image =
      await boundary.toImage(pixelRatio: ui.window.devicePixelRatio);
  ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png);
  Uint8List pngBytes = byteData.buffer.asUint8List();
  return pngBytes;
}

答案 3 :(得分:2)

@creativecreatoror可能没有真正的帮助,但它错过了一个重要的部分,即检索图像供以后使用。

保存图像

// Step 1: Retrieve image from picker 
final File image = await ImagePicker.pickImage(source: imageSource);

// Step 2: Check for valid file
if (image == null) return;

// Step 3: Get directory where we can duplicate selected file.
final String path = await getApplicationDocumentsDirectory().path;

// Step 4: Copy the file to a application document directory. 
final var fileName = basename(file.path);
final File localImage = await image.copy('$path/$fileName');
  

提示:您可以使用 basename(file.path)从原始文件中检索文件名。确保您导入“ package:path / path.dart”;

检索/加载图像

// Step 1: Save image/file path as string either db or shared pref
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('test_image', localImage.path)

// Step 2: Loading image by using the path that we saved earlier. We can create a file using path 
//         and can use FileImage provider for loading image from file.
CircleAvatar(
          backgroundImage: FileImage(File(prefs.getString('test_image')),
          radius: 50,
          backgroundColor: Colors.white)

答案 4 :(得分:0)

要在本地保存文件,我们需要添加一些依赖

dependencies:
  flutter:
    sdk: flutter
  path_provider:
  path:

path_provider

找到存储图像的正确路径。

路径

创建适用于任何平台的路径。


示例:

final pickedFile = await picker.getImage(source: ImageSource.camera);
_image = File(pickedFile.path);

// getting a directory path for saving
final Directory extDir = await getApplicationDocumentsDirectory();
String dirPath = extDir.path;
final String filePath = '$dirPath/image.png';

// copy the file to a new path
final File newImage = await _image.copy(filePath);
setState(() {
  if (pickedFile != null) {
    _image = newImage;
  } else {
    print('No image selected.');
  }
});

答案 5 :(得分:0)

以下代码是空安全的,并将图像存储在设备的外部存储设备中,该设备可在 /storage/emulated/0/Android/data/<your-package>/files/name.png 中找到。

创建此方法:

Future<File?> captureAndSaveImage() async {
  final pickedImage = await ImagePicker().getImage(source: ImageSource.camera);
  if (pickedImage == null) return null;
  
  try {
    final directory = await getExternalStorageDirectory();
    if (directory != null) return File(pickedImage.path).copy('${directory.path}/name.png');
  } catch (e) {
    return null;
  }
}

用法:

File? file = await captureAndSaveImage();