flutteruint8list

JsonDecoded Uint8List image is not displaying Flutter


In my e-commerce app I have a ProductsScreen which has a button that pushes NewEditProductScreen for creating a new product sheet or editing an existing one.

I use ImagePicker and ImagePickerWeb to select the picture for the product sheet and as I needed a common format both for web and device app versions I use Uint8List for the picked image. It gets then uploaded to Firebase Storage (all working) which returns the downloadUrl. Then the product gets saved both to sembast (for local inventory) and to firebase for e-commerce product searches.

To save the Uint8List picked to sembast I use jsonEncode in toMap() and jsonDecode in fromMap() model's methods. Now the problem is that while displaying the picked image on NewEditProductScreen with Image.memory(imageData) works as expected, when loading the product in ProductScreen, image displayed with Image.memory(productImage) is not showing. As before the encoding the image displays as expected but after encoding/decoding it it doesn't I guess that jsonEncode and jsonDecode are not working well with Uint8List ? What else can I try to save Uint8List to sembast? I tried not to decode/encode it to sembast but it doesn't help.

NewEditProductScreen receiving picked image state:

if (state is PickedImage) {
              setState(() {
                imageData = state.imageData;
                print('  ###### Uint8List picked image is: ${state.imageData}');
              });
            }

NewEditProductScreen displaying it:

Container(
                        color: Colors.lightBlueAccent,
                        child: Stack(children: [
                          Center(
                            child: Image.memory(imageData), //productImage),
                          ),
                          GestureDetector(
                            onTap: () {
                              BlocProvider.of<ProductBloc>(context)
                                  .add(PickImage());
                            },
                            child: Center(
                              child: AutoSizeText(
                                AppLocalizations.instance.text('Choose image'),
                                textAlign: TextAlign.center,
                                style: TextStyle(
                                    color: Colors.white,
                                    fontSize: 15,
                                    fontWeight: FontWeight.w500),
                                minFontSize: 8,
                                maxLines: 1,
                                group: autoSizeGroup,
                              ),
                            ),
                          ),
                        ]),
                      ),

ProductsScreen loaded selected product state :

                  setState(() {
                    productId = state.product.productId;
                    productName = state.product.productName;
                    brand = state.product.brand;
                    price = state.product.price;
                    productDescription = state.product.productDescription;
                    category = state.product.category;
                    isPromotion = state.product.isPromotion;
                    vendor = state.product.vendor;
                    barcode = state.product.barcode;
                    productImage = state.product.productImage;
                    imageUrl = state.product.imageUrl;
                    minimumStock = state.product.minimumStock;
                    availableQuantity = state.product.availableQuantity;
                    soldQuantity = state.product.soldQuantity;
                    print(
                        '  ###### Uint8List image is: ${state.product.productImage}');
                  });
                }

and image display:

Container(
                                    color: Colors.lightBlueAccent,
                                    child: Center(
                                      child: Image.memory(
                                          productImage), //productImage),
                                    ),
                                  ),

This is the Product model:

class Product {
  final String productId;
  final String productName;
  final String brand;
  final String price;
  final String productDescription;
  final String category;
  final bool isPromotion;
  final String vendor;
  final String barcode;
  String imageUrl;
  final Uint8List productImage;
  int minimumStock;
  int availableQuantity;
  int soldQuantity;

  Product(
      {@required this.productId,
      @required this.productName,
      @required this.brand,
      @required this.price,
      @required this.productDescription,
      @required this.category,
      @required this.isPromotion,
      @required this.vendor,
      @required this.barcode,
      @required this.imageUrl,
      @required this.productImage,
      @required this.minimumStock,
      @required this.availableQuantity,
      @required this.soldQuantity});

  Map<String, dynamic> toMap() {
    return {
      'productId': productId,
      'productName': productName,
      'brand': brand,
      'price': price,
      'productDescription': productDescription,
      'category': category,
      'isPromotion': isPromotion,
      'vendor': vendor,
      'barcode': barcode,
      'imageUrl': imageUrl,
      'productImage': jsonEncode(productImage),
      'minimumStock': minimumStock,
      'availableQuantity': availableQuantity,
      'soldQuantity': soldQuantity,
    };
  }

  static Product fromMap(Map<String, dynamic> map) {
    return Product(
      productId: map['productId'],
      productName: map['productName'],
      brand: map['brand'],
      price: map['price'],
      productDescription: map['productDescription'],
      category: map['category'],
      isPromotion: map['isPromotion'],
      vendor: map['vendor'],
      barcode: map['barcode'],
      imageUrl: map['imageUrl'],
      productImage: jsonDecode(map['productImage']),
      minimumStock: map['minimumStock'],
      availableQuantity: map['availableQuantity'],
      soldQuantity: map['soldQuantity'],
    );
  }

  Map<String, dynamic> toFirebase() {
    return {
      'Product Id': productId,
      'Product Name': productName,
      'Brand': brand,
      'Product Price': price,
      'Product Description': productDescription,
      'Product Category': category,
      'isPromotion': isPromotion,
      'Product Vendor': vendor,
      'Code': barcode,
      'Product Picture Url': imageUrl,
      'Minimum Stock': minimumStock,
      'Available Quantity': availableQuantity,
      'SoldQuantity': soldQuantity,
    };
  }

  static Product fromFirebase(Map<String, dynamic> map) {
    return Product(
      productId: map['Product Id'],
      productName: map['Product Name'],
      brand: map['Brand'],
      price: map['Price'],
      productDescription: map['Product Description'],
      category: map['Product Category'],
      isPromotion: map['isPromotion'],
      vendor: map['Product Vendor'],
      barcode: map['Code'],
      imageUrl: map['Product Picture Url'],
      minimumStock: map['Minimum Stock'],
      availableQuantity: map['Available Quantity'],
      soldQuantity: map['Sold Quantity'],
    );
  }

}

Solution

  • The problem was that Sembast does json encoding/decoding automatically and json doesn't support Uint8list. I actually thought that being a List it would support it. Printing the Uint8List value when receiving the state reading the db, as well as printing the Uint8List value when receiving the state with picked image led me to thing everything was fine in that sense as the were identical..no error messages when reading or saving to db also made me thing everything worked.. SO To write/read Uint8List to/from Sembast they need to be base64 coded/decoded..

    Changed model's toMap() as:

    'productImage': base64Encode(productImage),
    //      'productImage': jsonEncode(productImage),
    

    and model's fromMap as:

    productImage: base64Decode(map['productImage']),
    //      productImage: jsonDecode(map['productImage']),
    

    and everything is working fine. Hope this will help others just starting out in Flutter. Cheers