如何在flutter中使用rootBundle加载图片?

Posted

技术标签:

【中文标题】如何在flutter中使用rootBundle加载图片?【英文标题】:How to use rootBundle in flutter to load images? 【发布时间】:2019-01-07 14:47:35 【问题描述】:

我使用图像插件 (image: ^2.0.4),所以我可以在图像上写一些东西,然后将新图像保存到设备或通过邮件发送。我尝试使用“new File”加载图像,但在 Flutter 上出现错误。我询问并搜索并得到提示,我可以使用 rootBundle 在 Flutter 中加载图像。我做到了,我得到了以下错误。

[ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] 未处理的异常: 无法加载资产:packages/myAppName/assets/images/ReceiptRaw_1.jpg

当我创建一个简单的 dart 控制台应用程序时,该插件可以工作,但无法使用颤振加载。请帮忙,

这是 Flutter 代码:

    Future<bool> makeReceiptImage() async 

// UPDATE ****************************************

      // load the receipt jpeg
  var imageData = await rootBundle.load('packages/myAppName/dekonts/ReceiptRaw_1.jpg');
  print("imageData: $imageData"); // Prints as imageData: Instance of 
'_ByteDataView'

// UPDATE ****************************************

  Image _receiptImage = await decodeImage(new File(imageData).readAsBytesSync());

      drawString(_receiptImage, arial_48, 440, 30, “Customer Name”, color: 0xFF000000); 

      // Write it to disk as a different jpeg 
      var new_jpeg = await encodeJpg(_receiptImage); 
      String newImagePath = await rootBundle.loadString('packages/myAppName/assets/images/ReceiptRaw_2.jpg'); 
      await new File(‘$newImagePath’).writeAsBytesSync(new_jpeg); 
    

这是 Dart 控制台代码:

import 'dart:io';
import 'dart:convert';
import 'dart:async';
import 'package:image/image.dart';

void main() async 
  // load the receipt jpeg
  String mImagePath = 'images/ReceiptRaw_1.jpg';
  Image _receiptImage = decodeImage(new File(mImagePath).readAsBytesSync());
  drawString(_receiptImage, arial_48, 440, 30, “Customer Name”, color: 0xFF000000);

  // Write it to disk as a different jpeg
  var new_jpeg = encodeJpg(_receiptImage);
  new File('images/ReceiptRaw_1.jpg').writeAsBytesSync(new_jpeg);

更新 1: 当我使用下面的代码时,我收到以下错误:

在 pubspec.yaml 中检测到错误: 找不到资产的文件或变体:packages/myAppName/assets/images/ReceiptRaw_1.jpg

 String imageData = await rootBundle.loadString('packages/myAppName/assets/images/ReceiptRaw_1.jpg');
  Image _receiptImage = await decodeImage(new File(imageData).readAsBytesSync());

更新 2: 如果我使用rootBundle.load,则会出现以下错误。

错误:“dart.typed_data::ByteData”类型的值无法分配给“dart.core::String”类型的变量。

var imageData = await rootBundle.load('packages/myAppName/assets/images/ReceiptRaw_1.jpg');
  Image _receiptImage = await decodeImage(new File(imageData).readAsBytesSync());

新更新:

第 1 步: 移动到ReceiptRaw_1.jpg 进入lib/dekonts/ 文件夹

改为:

assets:
  - packages/myAppName/dekonts/ReceiptRaw_1.jpg

改为:

var imageData = await rootBundle.load('packages/myAppName/dekonts/ReceiptRaw_1.jpg');
print("imageData: $imageData"); 

结果: 打印为

imageData:“_ByteDataView”的实例

第 2 步: 移动到 /lib/assets/images/ReceiptRaw_1.jpg 文件夹

改为:

assets:
  - packages/myAppName/lib/assets/images/ReceiptRaw_1.jpg

改为:

var imageData = await rootBundle.load('packages/myAppName/lib/assets/images/ReceiptRaw_1.jpg');
print("imageData: $imageData"); 

结果:错误如下:

解决依赖关系... 运行“gradlew assembleDebug”... 在 pubspec.yaml 中检测到错误: 未找到资产的文件或变体:packages/myAppName/lib/assets/images/ReceiptRaw_1.jpg

更新:

/// 要包括第一张图片,应用程序的pubspec.yaml 应该 /// 在资产部分指定它: /// /// 资产: /// - 包/fancy_backgrounds/backgrounds/background1.png /// /// lib/ 是隐含的,因此它不应包含在资产路径中。

【问题讨论】:

imageData 已经是图像数据。 new File(...).readAsBytesSync() 是多余的。 “找不到资产的文件或变体:packages/capitalbankmobile/assets/images/ReceiptRaw_1.jpg”你在哪里有这个文件? 【参考方案1】:

pub 依赖的文件不能作为文件使用。它们包含在存档文件中。

将图片添加到pubspec.yaml中的资产

flutter:
  assets:
    - packages/myAppName/assets/images/ReceiptRaw_1.jpg

然后加载它

var imageData = await rootBundle.load('packages/myAppName/assets/images/ReceiptRaw_1.jpg');

为此,文件ReceiptRaw_1.jpg 需要在

myAppName/lib/assets/images/ReceiptRaw_1.jpg

lib/ 部分是强制性的。

【讨论】:

非常感谢,一旦我完成了整个项目,我会将工作代码作为更新发布。 听起来不错:) 我使用 path_provider 写入设备。但我无法使用读取我的图像 @Günther // 显示写入的图像 if (_dekontExist == true) setState(() newDekontImage = _appDocumentsDirectory + "/" + widget._currentUserReceiptNo + ".jpg"; ); body: new Column( children: [ new Padding( padding: E​​dgeInsets.fromLTRB(10.0, 10.0, 10.0, 10.0), child: Image.network("$newDekontImage"+ "?raw=true"), ), ], ),【参考方案2】:

在@Günter Zöchbauer 的帮助下,我终于成功了。我对 Stack Overflow 成员的小小贡献。

// TODO: 1 - 加载所有内容

  Future _loadEverything() async 
    await _requestAppDocumentsDirectory();   // TODO: 2 - GET APP DOCUMENTS DIRECTORY
    _dekontExist = await makeReceiptImage(); // TODO: 3 - MAKE A RECEIPT

    // Show the writen image
    if (_dekontExist == true) 
      setState(() 
        newDekontImage = _appDocumentsDirectory + "/" + widget._currentUserReceiptNo + ".jpg";
        imageOkay = true; // FOR - 4 - MAIN WIDGET BUILD
      );
    
  

// TODO: 2 - 获取应用文档目录

Future _requestAppDocumentsDirectory() async 
  // I choose temp dir because I don’t want to write twice same Receipt
  // Also when user close the app it will destroys the images
  final _directory =
      await getTemporaryDirectory(); //getApplicationDocumentsDirectory();
  setState(() 
    _appDocumentsDirectory = _directory.path;
  );

// TODO: 3 - 制作收据

Future<bool> makeReceiptImage() async 

  // I use this as a template:
  // 'packages/mayApp/assets/images/CapitalReceipt.jpg'  

  ByteData imageData = await rootBundle.load('packages/mayApp/assets/images/CapitalReceipt.jpg');
  List<int> bytes = Uint8List.view(imageData.buffer);
  Image _receiptImage = decodeImage(bytes);

  // TODO: WRITE ON TO THE IMAGE
  drawString(_receiptImage, arial_48, 440, 30, “Customer Receipt - Customer Name”, color: 0xFF000000);


  // Write it to disk as a different jpeg
    var new_jpeg = await encodeJpg(_receiptImage);
    String newDekontImage = _appDocumentsDirectory + "/" + "$_currentUserReceiptNo" + ".jpg";
    await new File(newDekontImage).writeAsBytesSync(new_jpeg);

  return true;

// TODO: 4 - 主要小部件构建

  @override
  Widget build(BuildContext context) 
    capitalHeight = MediaQuery.of(context).size.height;
    capitalWidth = MediaQuery.of(context).size.width;

    if (imageOkay == true) 
      return new Scaffold(
        resizeToAvoidBottomPadding: true,
        appBar: new AppBar(
          title: new Text("Customer Receipt"),
          backgroundColor: const Color(0xFF7CB342),
          elevation: 0.0,
          actions: <Widget>[
            new Container(
              padding: EdgeInsets.only(right: 10.0),
              child: new Icon(Icons.mail),
            )
          ],
        ),
        body: new Column(
          children: <Widget>[
            new Padding(
              padding: EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 0.0),
              child: new Center(
                child: new Container(
                  width: capitalWidth,
                  height: capitalHeight / 2.3,
                  color: Colors.black54, //capitalLightGreen,
                  child: new Container(
                    width: capitalWidth - 20.0,
                    height: capitalHeight / 2.3,
                    child: Image.file(File('$newDekontImage')),
                  )
                ),
              )
            ),
          ],
        ),
      );
     else 
      return new Scaffold(
          resizeToAvoidBottomPadding: true,
          appBar: new AppBar(
            title: new Text("Customer Receipt"),
            backgroundColor: const Color(0xFF7CB342),
            elevation: 0.0,
            actions: <Widget>[
              new Container(
                padding: EdgeInsets.only(right: 10.0),
                child: new Icon(Icons.mail),
              )
            ],
          ),
          body: new Center(
            child: new CircularProgressIndicator(),
          ));
    
  

【讨论】:

乍一看,这看起来很有帮助,但是当我尝试重现这项工作时,我得到了很多错误(45 个错误)。是的,我们都希望有一种简单的方法来使用 jsFiddle 来测试 Flutter 代码概念。与此同时,我们在构建和测试代码中将 sn-ps 提交到“hello world + button indicator”示例中。从那时起,您的代码(如当前编写的)是失败的。也许您可以添加一点(甚至发布在你的 github repo 上创建一个功能示例?) 嗨,@zipzit 我使用图片插件(图片:^2.0.4)。插件示例中所需的一切。我刚刚修改了上面的代码,所以它可以在 Flutter 中工作。但我会尝试在 GitHub 中制作工作示例,以便每个人都可以分享。谢谢

以上是关于如何在flutter中使用rootBundle加载图片?的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 如何模拟对 rootBundle.loadString(...) 的调用,然后重置模拟的行为?

为啥我在 Flutter 测试期间使用 rootBundle.load 得到“对空值使用空检查运算符”?

如何在主方法 Flutter 中加载 json?

在颤振单元测试中访问 rootBundle

Flutter:如何在不阻塞 UI 的情况下异步地从资产中读取文件

如何在 Flutter 中重新加载 webview?