Search code examples
javascriptjavaimagefrontendspark-java

Rendering an image on a Java-Backend then displaying it in the Frontend


My goal is to have a node-editor in the frontend which passes information on how data is supposed to be rendered as an image to the backend, where the heavy lifting is done, resulting in an image which is then displayed in the browser again.

To achieve this, I have a Java Spark-Route looking like this:

    post("/render", (req, res) -> {

      Gson gson = new GsonBuilder().setPrettyPrinting().create();
      ResponsePojo response = gson.fromJson(req.body(), ResponsePojo.class);

      BufferedImage bi = render(response);


      // Write the image data to the response output stream
      try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
        ImageIO.write(bi, "jpeg", baos);
        res.raw().getOutputStream().write(baos.toByteArray());
        res.raw().getOutputStream().flush();
      } catch (IOException e) {
        e.printStackTrace();
      }


      res.type("image/jpeg");
      res.status(200);

      return res;
    });

Calling this route looks like this:

  // Send the request using the fetch() method
  fetch(RENDER_URL, requestOptions)
    .then(response => {
      //const blob = streamToBlob(response.body, 'jpeg');

      let data;
      let url;

      response.blob().then(blobResponse => {
        data = blobResponse;
      })

      url = URL.createObjectURL(data);
    })

This call results in the following error:

Error occurred during request: TypeError: URL.createObjectURL: Argument 1 is not valid for any of the 1-argument overloads.

I've also taken a look at the following npm module: https://github.com/feross/stream-to-blob

Which results in the following error:

Uncaught (in promise) TypeError: stream.on is not a function
    streamToBlob2 index.js:13
    streamToBlob2 index.js:10
    sendRenderRequest index.js:95

What's confusing to me is that the errors suggest to me that I'm not in fact working with a ReadableStream, however if I console.log() the response.body I do get:

Response.body received: ReadableStream { locked: false }

Looking forward to any and all help, thanks in advance for your time and sorry for any obvious oversights, I'm still learning!


Solution

  • You're going to at the very least need to fix that JS, because if you're using then on a promise, all the code that has to subsequently kick in has to either be inside that then handler, or be in function(s) that are called from inside that then handler, or be somewhere in the subsequent then chain. The following code does not work:

    let data;
    
    response.blob().then(blobResponse => {
      data = blobResponse;
    })
    
    url = URL.createObjectURL(data);
    

    because your url = ... doesn't wait for anything: response.blob() is a promise, and so we immediately move on to url = ... without waiting, and at some unknown time in the future, that then handler will kick in.

    So: give the MDN "Using Promises" a read, and move all the code that depends on the result of that then into the handler. Or, alternatively, mark your context as async so that you can use the await keyword instead of having to chain then handlers.