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