Home > Software design >  How to display a BufferedImage in Thymeleaf
How to display a BufferedImage in Thymeleaf

Time:09-23

I'm currently trying to teach myself Spring Boot by writing a simple tabletop simulator for the popular card game Magic the Gathering. So what I want to do first is retrieve card images from the Scryfall API and display them in Thymeleaf. I know how to do this for static images, but I can't seem to find a way to display images retrieved dynamically. My current workaround is to provide Thymeleaf with the Scryfall URI, but what I really want to do is to display a BufferedImage in Thymeleaf. So here's my current code for the controller.

package mtg;

import java.util.Map;

import org.springframework.boot.json.BasicJsonParser;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

@Controller
@RequestMapping("/sample")
public class SampleCardController {

@ModelAttribute
public void addCardToModel(Model model) {
    RestTemplate rest = new RestTemplate();
    String jsonString = rest.getForObject(
            "https://api.scryfall.com/cards/random", String.class);
    BasicJsonParser parser = new BasicJsonParser();
    Map<String, Object> map = parser.parseMap(jsonString);
    String name = (String) map.get("name");
    String uri = (String) map.get("uri");
    model.addAttribute("cardName", name);
    model.addAttribute("imageURI", uri   "?format=image");
}

@GetMapping
public String showSampleCard() {
    return "sample";
}
}

And this is the Thymeleaf template sample.html:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Sample</title>
  </head>
  <body>
    <h1>Here's a sample card!</h1>
    <h3 th:text="${cardName}"></h3>
    <img th:src="${imageURI}"/>
  </body>
</html>

What I really want to be doing in the controller, is something like this:

package mtg;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;

import javax.imageio.ImageIO;

import org.springframework.boot.json.BasicJsonParser;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

@Controller
@RequestMapping("/sample")
public class SampleCardController2 {

    @ModelAttribute
    public void addCardToModel(Model model) {
        RestTemplate rest = new RestTemplate();
        String jsonString = rest.getForObject(
                "https://api.scryfall.com/cards/random", String.class);
        BasicJsonParser parser = new BasicJsonParser();
        Map<String, Object> map = parser.parseMap(jsonString);
        String name = (String) map.get("name");
        String imageURI = (String) map.get("uri");
        BufferedImage image = null;
        try {
            image = ImageIO.read(new URL(imageURI   "?format=image"));
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        model.addAttribute("cardName", name);
        model.addAttribute("image", image);
    }

    @GetMapping
    public String showSampleCard() {
        return "sample";
    }

}

But I don't know how to get Thymeleaf to display the image. It seems that for the img tag`you can only provide a th:src attribute which needs an URL. Is there something similar to th:text="${cardName}" for images where you can use the name of the model attribute?

EDIT: See @Lee Greiner 's comment below for how to fix the template.

CodePudding user response:

You can insert more than just an URL in the img tag. In this case, you can insert the base64 representation of the image you are loading by doing this:

<div>
  <p>Taken from wikpedia</p>
  <img src="data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAUA
    AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
        9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" />
</div>

And from your code, get the base64 from the BefferedImage object like this:

public static String imgToBase64String(final RenderedImage img, final String formatName)
{
  final ByteArrayOutputStream os = new ByteArrayOutputStream();

  try
  {
    ImageIO.write(img, formatName, os);
    return Base64.getEncoder().encodeToString(os.toByteArray());
  }
  catch (final IOException ioe)
  {
    throw new UncheckedIOException(ioe);
  }
}

And pass it to the view.

Links IMG tag base64 src

BufferedImage to base64

  • Related