79

I'm converting images saved in my Firebase database to Base64 and would like to decode and encode. I've researched similar questions, but am still getting errors. Here is what I have so far?

var image1 = String;

var pic = event.snapshot.value['image'];
var photo = BASE64.decode(pic);
image1 = photo;

I'm getting the following error...

A value of type "List<int>" cannot be assigned to a variable of type "Type"

If you could please provide a reverse process for encoding an image into Base64 so they may be saved back to Firebase, that would be appreciated.

*** UPDATE

Here is my updated code that's still throwing an error.

image1 = event.snapshot.value['image'];
var image = BASE64.decode(image1.toString());
new Image.memory(image),

The error is...

FormatException: Invalid Length must be a multiple of 4

Charles Jr
  • 8,333
  • 15
  • 53
  • 74

9 Answers9

101

There's a simpler way using 'dart:convert' package

Image.memory(base64Decode(base64String));

Implementation and some useful methods :

import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/widgets.dart';


Image imageFromBase64String(String base64String) {
  return Image.memory(base64Decode(base64String));
}

Uint8List dataFromBase64String(String base64String) {
  return base64Decode(base64String);
}

String base64String(Uint8List data) {
  return base64Encode(data);
}
Amir.n3t
  • 2,859
  • 3
  • 21
  • 28
  • `The method 'memory' isn't defined for the type 'Image'. Try correcting the name to the name of an existing method, or defining a method named 'memory'.` ... I'm finding references to `Image.memory` when searching on the web, but not of this error, nor of it being deprecated. How do I get the `Image.memory` method?? – kris May 15 '23 at 23:42
52

You can convert a Uint8List to a Flutter Image widget using the Image.memory constructor. (Use the Uint8List.fromList constructor to convert a List to Uint8List if necessary.) You can use BASE64.encode to go the other way.

Here's some sample code.

screenshot

import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      theme: new ThemeData.dark(),
      home: new MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  State createState() => new MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {
  String _base64;

  @override
  void initState() {
    super.initState();
    (() async {
      http.Response response = await http.get(
        'https://flutter.io/images/flutter-mark-square-100.png',
      );
      if (mounted) {
        setState(() {
          _base64 = BASE64.encode(response.bodyBytes);
        });
      }
    })();
  }

  @override
  Widget build(BuildContext context) {
    if (_base64 == null)
      return new Container();
    Uint8List bytes = BASE64.decode(_base64);
    return new Scaffold(
      appBar: new AppBar(title: new Text('Example App')),
      body: new ListTile(
        leading: new Image.memory(bytes),
        title: new Text(_base64),
      ),
    );
  }
}

However, it's generally a bad idea to store large blobs of binary data in your database. It's not playing to the strengths of Firebase realtime database and you will end up wasting bandwidth transmitting data you don't need as well as unnecessary encoding and decoding. You should use the firebase_storage plugin instead, storing the path or download URL of the image in the database.

Collin Jackson
  • 110,240
  • 31
  • 221
  • 152
  • Got it. Now its says `Uint8ClampedList cannot be assigned to variable Uint8List`? Please explain – Charles Jr Sep 11 '17 at 03:35
  • When I run this `new Image.memory(photo.toList()),` My app breaks and I get the following error `Format Exception: Invalid Length, must be multiple of 4` Please help – Charles Jr Sep 11 '17 at 03:47
  • Please update your question with the code you're using, because I don't see a call to `toList()`. It sounds like you're directly calling `toList()` on a `String`, which will produce a `List` of base64 characters. This list isn't a binary representation of the decoded image, so that's probably why you're running into an error when it can't be rendered. Convert the decoded image (the output of `decode()`) to a Uint8List using `new Uint8List.fromList()`. – Collin Jackson Sep 11 '17 at 15:43
  • That said, I would strongly suggest you try firebase_storage, it is a much better approach than storing base64 encoded images in a database. – Collin Jackson Sep 11 '17 at 15:43
  • Thanks @CollinJackson , The problem is that I currently have an iOS Swift app that I'm updating where I've saved user photos with Base64. There's only a few users but I would like to allow them to access their photos and if they change them then save them and new ones to `FirebaseStorage`. I've updated the question with my new results. – Charles Jr Sep 11 '17 at 23:48
  • I updated my answer with sample code. The base64 encoding and decoding seems to work fine, so I think something is wrong with the database handling code. Can you print out the value of `image1.toString()` and put it in your question so that I can test with the same image? – Collin Jackson Sep 12 '17 at 01:30
  • Collin I'm having trouble again. See if you can turn this BASE64 string into an image. It's just a placeholder until my user uploads a photo `SW1hZ2UoaW1hZ2U6IEFzc2V0SW1hZ2UoYnVuZGxlOiBudWxsLCBuYW1lOiAiYXNzZXRzL3BsYWNlaG9sZGVyLnBuZyIpLCBhbGlnbm1lbnQ6IEFsaWdubWVudC5jZW50ZXIp` – Charles Jr Oct 26 '17 at 03:44
  • Is this possible to save gif in sqflite with this way? – Mo Meshkani Dec 29 '18 at 13:38
  • Converted successfully but image not getting proper when I decoded base64 to image online? any idea how can I get proper image – iPatel Mar 08 '19 at 14:53
  • You can also use Uint8List bytes = Base64Decoder().convert(base64Text); if you get an error while trying to use BASE64.decode() – Chidi Sep 28 '21 at 23:40
26
Uint8List _bytesImage;

String _imgString = 'iVBORw0KGgoAAAANSUhEUg.....';

_bytesImage = Base64Decoder().convert(_imgString);

Image.memory(_bytesImage)
Jeferson Rivera
  • 494
  • 6
  • 4
  • How do I use this on a CircleAvatar background Image? I have tried several things including `backgroundImage: Image.memory(_bytesImage);` – Michael May 06 '20 at 16:42
  • 3
    Nevermind, I found that I could just add `.image` to the end there and it worked: `backgroundImage: Image.memory(_bytesImage).image;` – Michael May 06 '20 at 16:46
12

To open a camera photo (temporary folder), editing a file and then turning it into Base64:

Code:

import 'dart:convert';
import 'package:image/image.dart' as ImageProcess;

File file = File(imagePath);
final _imageFile = ImageProcess.decodeImage(
  file.readAsBytesSync(),
);

...edit file...

String base64Image = base64Encode(ImageProcess.encodePng(_imageFile));

Decode and show:

import 'dart:convert';
import 'package:image/image.dart' as ImageProcess;

final _byteImage = Base64Decoder().convert(base64Image);
Widget image = Image.memory(_byteImage)
luisdemarchi
  • 1,402
  • 19
  • 29
9

import

import 'dart:convert';
import 'dart:typed_data';

from screen load the data and assign to this variable

    Uint8List _bytes;
  _bytes = Base64Decoder().convert("iVBORw0KGgoAAAANSUhEUgAAANgAAA......");

In code tree structure widget

Image.memory(_bytes)
abhijith k
  • 369
  • 4
  • 4
4

With this simple method i could set an image in flutter. The image attribute is the base64 image as string, example:

TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb2

Try the next:

Widget getImagenBase64(String imagen) {
    _imageBase64 = imagen;
    const Base64Codec base64 = Base64Codec();
    if (_imageBase64 == null) return new Container();
    bytes = base64.decode(_imageBase64);
    return Image.memory(
          bytes,
          width: 200,
          fit: BoxFit.fitWidth,
       
    );
  }

I hope this work for you. Happy coding.

Pedro Molina
  • 1,101
  • 12
  • 12
  • This is a bad practice to create a widget and return it in a function. Create a stateless widget which take your 'String imagen' as attributes and return your Image.memory – 0xPunt Apr 18 '23 at 09:01
1

this worked for me

ClipRRect(
                borderRadius: BorderRadius.circular(100),
                child: Image.memory(
                  base64Decode(widget.imgBase64 ?? ''),
                  gaplessPlayback: true,
                  fit: BoxFit.cover,
                )),
ANUSREE P
  • 101
  • 1
  • 2
0

Do check the type using runtimeType, In my case it was String. My function was returning Future<<U'intList>> i changed it to Future<<s'tring>> and used Image.Memory like this: Image.memory(base64Decode(_imageBytes!)

Here is my full code:

import 'dart:convert';
import 'dart:typed_data';

import 'package:flutter/material.dart';

import 'getResponseFromNodeApi.dart';
import 'getResponseFromStabilityAi.dart';

class MyImageWidget extends StatefulWidget {
  const MyImageWidget({Key? key}) : super(key: key);

  @override
  _MyImageWidgetState createState() => _MyImageWidgetState();
}

class _MyImageWidgetState extends State<MyImageWidget> {
  String? _imageBytes;
  String? _errorMessage;

  @override
  void initState() {
    super.initState();

    _generateImage();
  }

  Future<void> _generateImage() async {
    setState(() {
      _imageBytes = null;
      _errorMessage = null;
    });

    try {
      // final bytes = await getResponseFromStabilityAi();
      final bytes = await getResponseFromNodeApi(textPrompt: 'light House');
      // List<int> bytes2 = utf8.encode(bytes as String);
      setState(() {
        _imageBytes = bytes;
      });
    } catch (e) {
      setState(() {
        print(e);
        _errorMessage = 'Failed to generate image: $e';
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Generated Image'),
      ),
      body: Center(
        child: _imageBytes != null
            ? Image.memory(base64Decode(_imageBytes!))
            : _errorMessage != null
            ? Text(_errorMessage!)
            : const CircularProgressIndicator(),
      ),
    );
  }
}

I hope this helps

0

Supposing we have a DataURL stored in a String of a format similar to the following:

String dataUrl = "data:image/jpeg;base64,/9j/4AAQSk...";

A simple solution exists to render this as an Image via Uri:

Image.memory(
    Uri.parse(dataUrl).data?.contentAsBytes()
    ?? Uint8List(0),
)

This is a null-safe solution, and can be easily modified into the following for older versions of Dart:

Image.memory(Uri.parse(dataUrl).data.contentAsBytes())