vaadinvaadin-flowvaadin14vaadin-gridvaadin23

How do I dynamically render an image using LitRenderer and StreamResource in Vaadin Flow?


I'm trying to create a LitRenderer for dynamically generated images that can be either gif/jpg/png files using a StreamResource in Vaadin. I also have the byte[] and so on but I figure using a StreamResource is the better way to do this. That being said I'm not sure how to display the StreamResource in the LitRenderer code. Below is my code:

private Renderer<CustomImageData> createImageRenderer() {
    return LitRenderer.<CustomImageData>of("""
                            <vaadin-horizontal-layout>
                                <div><img src=\"${item.imageStreamResource}\"/></div>
                            </vaadin-horizontal-layout>""")
            .withProperty("imageStreamResource", CustomImageData::getThumbnailAsStreamResource);
}

Clearer I can't just pass the imageStreamResource as a src as it's not a URL. It manages URL's but it's not a URL. My CustomImageData also has methods like getByteData(), getMimeType(), and so on but as mentioned above using a StreamResource seems like the better implementation.

My question is how edit the code above so that it will display the image for <img>? The only examples I can find including such as this one and this one only seem to show images that are pre-defined, nothing dynamically generated.

And in case this helps the calling code is:

grid.addColumn(createImageRenderer())
        .setKey(THUMBNAIL)
        .setHeader(THUMBNAIL);

Solution

  • StreamResource is not a good alternative in combination with LitRenderer. The reason for this is that each StreamResource instance needs to be registered to generate a URL and route requests for that URL to that particular instance. This would cause a memory leak unless carefully managed. With typical usage, the resource is associated with a component instance: when the component is detached, then the StreamResource instance and its corresponding URL are also unregistered.

    With LitRenderer, there isn't any directly accessible trigger available for reacting when the resource instance for a given row can be unregistered. This means that you'd have to associate the resource with the entire grid component, which in turn means that if the user scrolls through all of the rows in that grid, then you'd end up with all those StreamResource instances in memory, along with any byte[] or such that they reference.

    I would instead recommend that you define your own URL scheme and implement a servlet (or e.g. a Spring RestController) to handle requests to those URLs to on-demand fetch the corresponding data and return it directly in the response. As an alternative, you could also replace your LitRenderer with a ComponentRenderer since that would give something for the StreamResource to be associated with. Yet another way could be to pass the image data as a base64 encoded data URI, as shown in this example.