在 Flutter/Dart 中从字节加载图像的问题

Posted

技术标签:

【中文标题】在 Flutter/Dart 中从字节加载图像的问题【英文标题】:Problems loading images from bytes in Flutter/Dart 【发布时间】:2020-01-08 10:00:24 【问题描述】:

我正在使用 Flutter 构建一个应用程序。我正在使用多种我正在努力拼凑起来的新技术。

我的实际问题是使用以下方法时无法在应用中加载图像:

    使用 Mongoengine 将测试数据插入 MongoDB,使用 this method 将图像插入 GridFS。 查询 GraphQL 服务器以获取数据和检索数据,并以 bytes 的形式从 GridFS 接收图像,但采用 string - 例如“b'/9j/4AAQSkZJRgABAQEASABIAAD/4V0X ....'” 使用该字节字符串在应用程序中加载图像,例如Image.memory()

但图片无法加载并出现错误:type String is not a subtype of type Uint8List。所以我尝试通过执行以下操作将字节字符串从 String 转换为原始字节:

List<int> bytesList = imageData['image']['data'].codeUnits;
Uint8List thumbImageBytes = Uint8List.fromList(bytesList);

我得到以下异常:

I/flutter ( 4303): ══╡ EXCEPTION CAUGHT BY IMAGE RESOURCE SERVICE ╞══════
I/flutter ( 4303): The following _Exception was thrown while resolving an image:
I/flutter ( 4303): Exception: Could not instantiate image codec.

我不知道我能做些什么来解决这个问题,我似乎无法通过谷歌搜索等找到任何东西。除了this S.O question 这是我试图做的事情之外,似乎没有可用于此确切情况的信息.我还尝试了 cmets 中建议的所有方法,按照建议的链接并尝试了所有可用的答案组合、cmets 以及所有内容。

我的设置如下;

主应用:Flutter/Dart API 服务器:基于 Python/Flask/Mongoengine 的 GraphQL/Graphene API 后端数据库:MongoDB

Python 方面;

Mongoengine 文档模型:

class Product(Document):
    meta = 'collection': 'product'
    name = StringField(unique=True)
    price = FloatField()
    sale_price = FloatField()
    description = StringField()
    image = FileField()
    thumb = FileField()
    created_at = DateTimeField(default=datetime.utcnow)
    edited_at = DateTimeField()
    # user = ReferenceField(User)

    def __repr__(self):
        return f'<Product Model::name: self.name>'

模型的石墨烯模式:

class ProductAttribute:
    name = graphene.String()
    price = graphene.Float()
    sale_price = graphene.Float()
    description = graphene.String()
    image = Upload()
    thumb = graphene.String()
    created_at = graphene.DateTime()
    edited_at = graphene.DateTime()

class Product(MongoengineObjectType):
    """Product node."""

    class Meta:
        model = ProductModel
        interfaces = (graphene.relay.Node,)

class CreateProductInput(graphene.InputObjectType, ProductAttribute):
    """Arguments to create a product."""
    pass

class CreateProduct(graphene.Mutation):
    """Create a product."""
    product = graphene.Field(lambda: Product, description="Product created by this mutation.")

    class Arguments:
        input = CreateProductInput()
        image = Upload(required=True)

    def mutate(self, info, image, input):
        data = utils.input_to_dictionary(input)
        data['created_at'] = datetime.utcnow()
        data['edited_at'] = datetime.utcnow()
        print(data)

        product = ProductModel(**data)
        product.save()

        return CreateProduct(product=product)

我的基本石墨烯架构:

class Query(graphene.ObjectType):
    """Query objects for GraphQL API."""

    node = graphene.relay.Node.Field()
    single_product = graphene.relay.Node.Field(schema_product.Product)
    all_products = MongoengineConnectionField(schema_product.Product)

class Mutations(graphene.ObjectType):
    createProduct = schema_product.CreateProduct.Field()


schema = graphene.Schema(query=Query, types=[schema_product.Product], mutation=Mutations)

【问题讨论】:

您确定您的图像没有使用 base64 编码为字符串吗?如果您得到的字符串完全由可打印字符组成,这似乎相当可疑。 【参考方案1】:

这是非常可疑的:

    您的二进制数据存储在String 中(这通常是错误的)。 您的String 恰好完全由可打印字符组成。

因此,您可能会将已编码 的二进制数据返回为可打印的字符串。一种常见的编码是 base64,果然,当我尝试对几种不同类型的图像进行 base64 编码时,我看到 base64 编码的 JPEG 文件会生成一个以/9j/4AAQSk 开头的字符串,就像你得到的字符串一样。

您肯定会返回 base64 编码的数据。如果您不自己进行编码,那么某些东西会自动为您进行编码,并且可能有一种对称机制可以为您解码。如果没有,您需要显式地对您的String 进行base64 解码以取回二进制数据。您可以使用dart:convert 为您解码。

【讨论】:

嘿,谢谢,我应该意识到它实际上是base64!所以基本上字节来自pythonopen(file, 'rb'),它给出了b'&lt;STRING&gt;'字节表示,然后用mongodb就可以了,但是当石墨烯将数据传回时,它是一个像"b'&lt;STRING&gt;'"这样的字符串,所以字节表示变成了一个字符串。我只是将字符串“切片”String byteString = allProductsItem['thumb']['data']; Uint8List thumbImage = base64.decode(byteString.substring(2, byteString.length - 1));

以上是关于在 Flutter/Dart 中从字节加载图像的问题的主要内容,如果未能解决你的问题,请参考以下文章

在 Flutter/Dart 中从 JSON 数组中提取数据

如何在我的 Flutter 应用程序中从 JWT 获取声明

如何在视频/图像上添加图像或文本(水印) - Flutter/Dart

是否可以用Dart / Flutter绘制图像?

Flutter/Dart - 如何在其他屏幕上的图像选择器后更新图像

Flutter/Dart:将图像文件保存到“/storage/emulated/0/Picture/AppFolder/”