How to retrieve an image in flutter from flask api

962

You can convert the image to base64 and display it with Flutter.

On server:

import base64
...
data_object["img"] = base64.b64encode(b.read()).decode('ascii')
...

On client:

...
String imageStr = json.decode(response.data)["img"].toString();
Image.memory(base64Decode(imageStr));
...

The problem with your server-side code is it tries to coerce a bytes to str object by using function str().

However, in Python 3, bytes.__repr__ is called by str() since bytes.__str__ is not defined. This results in something like this:

str(b'\xf9\xf3') == "b'\\xf9\\xf3'"

It makes the JSON response looks like:

{"img": "b'\\xf9\\xf3'"}

Without writing a dedicated parser, you can not read this format of image data in Flutter. However, base64 is a well known format of encoding binary data and we do have a parser base64Decode in Flutter.

Share:
962
Christian Rápalo
Author by

Christian Rápalo

Updated on December 04, 2022

Comments

  • Christian Rápalo
    Christian Rápalo 11 months

    I have a post request in Flask that accepts an image file, and I want to return another image to retrieve it in Flutter and put it on screen.

    In Flutter, I can send the image through the post request, but I don't know how to retrieve an image and put it on screen.

    I know I can save the image in the static folder at Flask, and retrieve the URL from Flutter, and it works, but I think this is too inefficient for what I'm doing. So I want to send the image directly without saving it.

    This was my last attempt but didn't work.

    @app.route("/send-image", methods=['POST'])
    def send_image():
        if request.method == 'POST':
    
            user_image = request.files["image"]
            image = cv2.imdecode(np.frombuffer(
                user_image.read(), np.uint8), cv2.IMREAD_COLOR)
    
            #data is a NumPy array returned by the predict function. This numpy array it's an image
            data = predict(image)
    
            data_object = {}
            data = data.reshape(data.shape[0], data.shape[1], 1)
            data2 = array_to_img(data)
    
            b = BytesIO()
            data2.save(b, format="jpeg")
            b.seek(0)
    
            data_object["img"] = str(b.read())
            return json.dumps(data_object)
    

    Here I returned a Uint8List because I read from the internet that I can put that into an Image.memory() to put the image on the screen.

    Future<Uint8List> makePrediction(File photo) async {
        const url = "http://192.168.0.11:5000/send-image";
        try {
          FormData data = new FormData.fromMap({
            "image": await MultipartFile.fromFile(photo.path),
          });
          final response = await dio.post(url, data: data);
    
          String jsonResponse = json.decode(response.data)["img"].toString();
          List<int> bytes =
              utf8.encode(jsonResponse.substring(2, jsonResponse.length - 1));
    
          Uint8List dataResponse = Uint8List.fromList(bytes);
    
          return dataResponse;
        } catch (error) {
          print("ERRORRR: " + error.toString());
        } 
      }
    

    Sorry if what I did here doesn't make sense, but after trying a lot of things I wasn't thinking properly. I really need your help

  • Philip Tzou
    Philip Tzou about 3 years
    @Carb2750 I made some edits to the server-side code since I didn't test the code. However it seems you have already figured it out.