Grails: displaying created image in gsp - html

I'm very new to Grails so there's probably a very simple answer to this question. I'm trying to display a dynamically created image in a gsp. The image is NOT stored in a database, it's created on the fly in the controller.
What I essentially have is one gsp that has a form which takes in a set of user inputs (requestGraph.gsp). Upon submitting the form, the parameters are sent to the a displayGraph action in the controller which queries information from a database completely outside of Grails and creates a chart using the JFreeChart library. I would like to display this image within a displayGraph.gsp or something like that.
So basically within requestGraph.gsp I have a snippet similar to:
<g:form action="displayGraph">
<!-- ... bunch of labels and boxes -->
<g:submitButton name="displayGraph" value="Display Graph" />
</g:form>
Within the controller I have something like:
def requestGraph = {}
def displayGraph = {
//... code that uses params to make an image byte array and assigns to var img
return [image : img]
}
Within displayGraph.gsp:
<body>
<h1>Graph Title</h1>
<!-- ??? How to dislpay image? -->
</body>
I tried piping the image directly to the output stream in the displayGraph action. This works, but then I lose control of all page formatting in displayGraph.gsp.
Most tutorials I've found create a dedicated action to pipe the image to an output steam then call that action using a tag. The problem is that my image isn't stored in a database and I see no way of passing the image byte array (or even the form parameters) to create/render the image. Can anybody help me with this? Thanks.

If you write the bytes to the output stream, you can treat the controller/action as the source of the image in your GSP. Here's a quick, untested example:
// controller action
def displayGraph = {
def img // byte array
//...
response.setHeader('Content-length', img.length)
response.contentType = 'image/png' // or the appropriate image content type
response.outputStream << img
response.outputStream.flush()
}
You could then access your image in the src of an <img> tag like this:
<img src="${createLink(controller: 'myController', action: 'displayGraph')}"/>
Update:
After reading your question again, this may or may not work - it looks like you might be displaying the graph as the result of a form submission. This will only work if you're storing the state on the server somewhere (instead of just getting it from the one request where the form is submitted). If you do store enough state on the server to generate the graph, then you'd have to provide some additional parameters to your controller to get the correct image, e.g. src="${g.link(controller: 'myController', action: 'displayGraph', params: ['id': 1234])}", where id is how you retrieve the graph state.

The following code works in Grails 2.x.
HomeController.groovy
class HomeController {
def index() {
}
def viewImage(){
def file = new File(params.title)
def img = file.bytes
response.contentType = 'image/png' // or the appropriate image content type
response.outputStream << img
response.outputStream.flush()
}
}
views/home/index.jsp
<%# page contentType="text/html;charset=ISO-8859-1" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
<meta name="layout" content="main"/>
<title>View Image</title>
</head>
<body>
<div class="body">
<img src="<g:createLink controller="home" action="viewImage"
params="[title: 'C:/pictures/myimage.png']"/>"/>
</div>
</body>
</html>

I believe it's not about Grails but about HTML. You could:
Make the dedicated action that pipes image accept certain parameters, and generate the image in that action;
Embed it base64-encoded into HTML, like here:
<img src="data:image/gif;base64,R0lGODlhUAAPAKIAAAsL...etc..." alt="wow" />

my suggestion actually has two parts.
1) Use the solution recommend by Rob above to generate the chart artifact, however save it to a static file with a unique identifier that is passed back as part of the response from the form submit, then rendering the chart is no different then rendering any other image.
i would suggest that the identifer be constructed from the specifif params passed in on the form submit so they can be used as a caching mechanism to render the chart again without rebuilding it
2) create a service, maybe a Quartz Service, that periodically cleans up the static charts that were created for the application

Just an improvement to #Rob's answer:
Another option which is a bit nicer, you can just render the image, straight from your controller's action:
// controller action
def displayGraph = {
def img // a byte[], File or InputStream
render(file: img, contentType: 'image/png')
}
See also: http://grails.org/doc/latest/ref/Controllers/render.html

For any reasons the above solutions does not display any image. I used:
<img src='${createLink(controller: "myController", action: "displayGraph")}' />
instead.

I used FileUploadService to save the Image file In Grails .If you getting images from directory means, try this:
<img style="height: 120px;width: 102px;"src="${resource(dir:'personImages', file: personalDetailsInstance.id + '.png')}" />

Your gsp:
<img src="${createLink(controller: "image", action: "draw")}" />
Your controller:
def draw() {
byte[] imageInBytes = imageService.getImageInBytes() //should return byte array
response.with{
setHeader('Content-length', imageInBytes.length.toString())
contentType = 'image/jpg' // or the appropriate image content type
outputStream << imageInBytes
outputStream.flush()
}
}

Related

How can I display image by href tag pointing to REST api?

I'm building some web app. On my frontend side I need to display images which are earlier uploaded to spring-boot hsqldb. Image data is stored as a BLOB type in database. I want to display them as:
<img href="/api/photos/0">
In the past I was sending GET request to my api to get image data as byte array, than encoding it to Base64, sending back as a string "data:image/jpg;base64, myData" and putting it to img src and it worked perfectly.
Now I want to check some different approach and I got stuck.
This is my vue template:
<div class="card">
<div class="card-header"><h4>Some header</h4></div>
<div class="card-body">
<img class="card-img-top" :href="url">
</div>
</div>
This is my vue method building url:
export default {
data(){
return{
url:''
}
},
mounted() {
this.makeUrl();
},
methods:{
makeUrl(){
this.url="/api/photos/0";
}
}
}
And this is my spring-boot api controller:
#GetMapping(value = "/photos/{id}")
public String readPhoto(#PathVariable Long id){
return makePhotoUrl(photosRepository.findById(id).get().getData());
}
private String makePhotoUrl(byte[] photo){
String photoUrl = "data:image/jpeg;base64," +
Base64.getEncoder().encodeToString(photo);
return photoUrl;
}
I do get image data by accessing url directly by a browser, but my card is still empty.
Please help because i have no more ideas how to make it work.
So, after another day of research I've finally figured it out. Basically I've made two mistakes.
First, href specifies link destination, but it should be used only with "a" tag:
link
If i want to specify img source I should use "src":
<img src = "www.someOtherWebsite.com">
Second, it appears that if I want to return url as a direct response from api, it must point to a physical file. I might be wrong, so please correct me.
I've changed my controller to:
public ResponseEntity<Resource> readPhotoById(Long id) {
Photo photo = photosRepository.findById(id).get();
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(photo.getType()))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + photo.getName() + "\"")
.body(new ByteArrayResource(photo.getData()));
}
Now it works as expected.
Cheers :)

Dynamically display a list of xml hotspots (for krpano) based on json list

A bit of a newbie question for xml/krpano,
I have a list of json items that I want to be dynamically loaded into XML <hotspots>. I can loop through each item in JavaScript but I have no clue how to do the same loop in XML!
Check out this picture:
Imagine that each rectangle with an image is one item in a JSON list. Each rectangle you see is a <hotspot>. Right now these three hotspots are hardcoded into the XML file, but I want to dynamically load hotspots based on how many JSON list items exist.
Here is one hotspot. If my json list has 16 items, I would expect 16 hotspots
to be loaded.
<!--* video image thumbnail *-->
<hotspot name="start" distorted="true"
url="/panorama/%$panoId%/thumb.png"
ath="0" atv="0"
ox="0" oy="36"
vr_timeout="2000"
zorder="99"
scale="0.8"
onclick="changepano( loadscene(video_scene, null, MERGE|KEEPVIEW|KEEPMOVING, BLEND(1)); );"
alpha="0.0"
onloaded="if(vr_start_done === true, removehotspot(start); start_vr(); , tween(alpha,1); );"
/>
Your question is about dynamically generating hotspots in KRPano from a JSON list.
It is not really clear to me the way you wrote your question if you want to read the JSON from KRPano XML file (let's say FROM KRPano) or if you are expecting to use Javascript to ask KRPano to produce the hotspots.
These are two completly distinct ways of doing it :)
Because I'm lazy and I suppose you want to deal with JSON in JS, I go for this solution...
Loading a JSON file from Javascript
Your KRPano project should look like a core HTML file presenting Javascript to embed the KRPano plugin.
There, you can declare a script content in your HTML in which you will parse your JSON content and you ask KRPano to generate a hotspot. This method should be called when you are sure KRPano is ready, or get it called from KRPano when it is ready, using "onready" attribute.
myHotspotList.json content:
var myHotspotList = [
{
name: "myFirstHotspot",
atv: 15.0,
ath: 56.5686,
url: "myHotspotImage.jpg"
}
];
tour.html content:
<html>
...
<script url="myHotspotList.json'></script>
<script>
function generateHotspots() {
// First, we get the KRPano plugin
var myKRPano = document.getElementById('krpanoSWFObject');
// Now we parse the JSON object
for(var idx in myHotspotList) {
// Get the current Hotspot data
var currHotspot = myHotspotList[idx];
// Ask KRPano to create a hotspot with our current name
myKRPano.call("addhotspot('"+ currHotspot.name +"');");
// Now set various attributes to this hotspot
myKRPano.call("set(hotpost['"+ currHotspot.name +"'].atv, "+currHotspot.atv+");");
myKRPano.call("set(hotpost['"+ currHotspot.name +"'].ath, "+currHotspot.ath+");");
myKRPano.call("set(hotpost['"+ currHotspot.name +"'].url, '"+currHotspot.url+"');");
}
}
</script>
...
// When you ask for pano creation, give your generation method as callback
embedpano({target:"krpanoDIV", onready:generateHotspots});
...
</html>
I hope this help and you got the trick with calling JSON object attributes and all.
Regards

Which method or tool to transform a web site into a design template?

I would like to perform web test and learning like some makes music by sampling. So, I would like to make a new design by compozing with them and add my touch.
Say I have the html, css, js, etc files from the site owner, I imagine it is possible to automatically build templates and layouts as HALM and LESS or SASS files from them. For example, a html parser may find nested common structures in pages. A css parser may find common constants and replace them by variables.
Does such tool already exists ? Or what could be the cavits to develop one ?
Exemple for CSS:
From:
h1 { background-color: #ff14a6; }
h2 { color: #ff14a6; }
To:
$primary: #ff14a6;
h1 { background-color: $primary; }
h2 { color: $primary; }
HTML is formed from: Layout + Template, where Layout is the overall structure of the HTML page. Here is a Ruby example:
File: layout.erb
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title> ... etc.
</head>
<body>
<%= yield =>
</body>
</html>
Template replaces layout's yield.
Some layout content is page-specific, while template contains frontmatter. In template (contact.html.erb):
---
title: "Contact Information"
---
In layout (layout.erb):
<title> <%= current_page.data.title %>
</title>
If you want to create a template for whatever information you want to display your best bet is a JSON container to hold the new data and your javascript + jquery to import the data to the html. This could be done with a separate js file for the new data or the same one as the app/web page constructor js file.
This way you could have a set template layout for importing your data and then just change the file if you want to use different data. Alternatively using a framework like knockoutjs or something similar could allow you to do this as well, depending ofc on what you are familiar with or like to use.
The following snippet is a demo of jQuery using data from a JSON object to place data in the HTML (this would be the script.js file):
var view = {
displayStuff: function(obj){
var HTMLwelcomeMsg = '<span class="welcome-message">%data%</span>';
var formattedWelcome = HTMLwelcomeMsg.replace("%data%", obj.welcomeMessage);
$("#header").append(formattedWelcome);
}}
The JSON data can be in a separate file loaded by the JS or the HTML:
var model = {
"dataSample1" : "Some data",
"welcomeMessage" : "Welcome to the sample website",
"dataSample2" : "Some more data",
"someNumbers" : [1,1,253,669],
"moreVars" : {
"someMoreData" : ["123 31st st", "311 2nd st"],
"phoneNums" : ["555-5555", "999-999"]
}
}
Or you can put the data inside the JS file you use to append the elements to the HTML.
Then you call your view from the controller:
var controller = function(){
view.displayStuff(model);
}
and it all just works.

Dynamic XML Template in TVML/TVJS

Does anyone know how to Dynamically generate a template in an apple tv app using TVJS/TVML? Basically I want to hit my API, get back an array of objects and then insert that data into my XML template.
I've been searching for info on how to accomplish it but have come up short. I've found many tutorials that use hard coded images, videos, etc but nothing dynamically generated.
Any help would be appreciated.
Finally, I've figured this out. It wouldn't be difficult to generate a template on-the-fly, but instead I wanted to reuse the Presenter and the ResourceLoader, and to have the template as a *.xml.js file. Here is the solution I managed to arrive at.
For the initial view, I used a catalogTemplate, as demonstrated in Ray Wenderlich's tutorial. Instead of conference talks, however, I was displaying categories of men's and women's merchandise. Once a category was selected, I wanted to display a stackTemplate with a number of options for that category. The problem was how to pass any information, the title of the category in the simplest case, to the second template.
In the first template, I had the lockups configured like so:
<lockup categoryTitle="Women: Dresses" categoryDir="w-dresses">
<img src="${this.BASEURL}images/dresses.jpg" width="230" height="288" />
<title>Dresses</title>
</lockup>
In application.js, I had a listener attached, in the same way how tutorials show:
doc.addEventListener("select", Presenter.load.bind(Presenter));
Here is the second template (Category.xml.js):
var Template = function(categoryTitle) {
return `<?xml version="1.0" encoding="UTF-8" ?>
<document>
<stackTemplate>
<banner>
<title>${categoryTitle}</title>
</banner>
</stackTemplate>
</document>`
}
This is a JavaScript, so in your case you can pass into the function, say, an array of values and then construct the template accordingly. The tricky part was to pass a value.
First, I made a couple of changes to the ResourceLoader (this can be done better, of course, it's just a proof of concept). I simply added categoryTitle as an additional parameter to the top-level function and when calling the Template:
ResourceLoader.prototype.loadResource = function(resource, callback, categoryTitle) {
var self = this;
evaluateScripts([resource], function(success) {
if(success) {
var resource = Template.call(self, categoryTitle);
callback.call(self, resource);
} else {
var title = "Resource Loader Error",
description = `Error loading resource '${resource}'. \n\n Try again later.`,
alert = createAlert(title, description);
navigationDocument.presentModal(alert);
}
});
}
Finally, in the Presenter, in the load, I am passing categoryTitle to the resourceLoader:
load: function(event) {
var self = this,
ele = event.target,
categoryTitle = ele.getAttribute("categoryTitle");
if (categoryTitle) {
resourceLoader.loadResource(`${baseURL}templates/Category.xml.js`, function(resource) {
var doc = self.makeDocument(resource);
self.pushDocument(doc);
}, categoryTitle);
}
},
This works for me.
One final note: for some categories, I had titles with an ampersand, like 'Tops & T-shirts'. Naturally, I replaced the ampersand with an XML entity: 'Tops & T-shirts'. This, however, didn't work, probably because this string was decoded twice: the first time the entity was turned into an ampersand, and on the second pass the single ampersand was flagged as an error. What worked for me was this: 'Tops &amp; T-shirts'!
It is simple if you are using atvjs.
// create your dynamic page
ATV.Page.create({
name: 'homepage',
url: 'path/to/your/json/data',
template: function(data) {
// your dynamic template
return `<document>
<alertTemplate>
<title>${data.title}</title>
<description>${data.description}</description>
</alertTemplate>
</document>`;
}
});
// later in your app you can navigate to your page by calling
ATV.Navigation.navigate('homepage');
Disclaimer: I am the creator and maintainer of atvjs and as of writing this answer, it is the only JavaScript framework available for Apple TV development using TVML and TVJS. Hence I could provide references only from this framework. The answer should not be mistaken as a biased opinion.
I'm using PHP to generate the TVML files dynamically, configuring the output as text/javascript format:
<?php
header("Content-type: application/x-javascript");
[run your PHP API calls here]
$template = '<?xml version="1.0" encoding="UTF-8" ?>
<document>
... [use PHP variables here] ...
</document>';
echo "var Template = function() { return `". $template . "`}";
?>
You can dynamically generate a template by creating a dynamic string that represents the xml in a TVML template.
Review the code in here: https://developer.apple.com/library/prerelease/tvos/samplecode/TVMLCatalog/Listings/client_js_Presenter_js.html#//apple_ref/doc/uid/TP40016505-client_js_Presenter_js-DontLinkElementID_6
This file has functions that can be used to create an XML document that can represent a view.
You can make an XMLHttpRequest (ex: consuming API JSon calls through TVJS-tvOS) bring back some JSON data and then dynamically generate an XML document that conforms to one of the TVML templates. Parse it into an XML document and then navigate to the document.

making newsletter(HTML) with SpringFramework3

I am sending newsletter like below with Springframework 3.
private void sendMail(Map<String,Object> mailInfo) throws Exception{
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost("smtp.myhost.com");
mailSender.setPort(587);
mailSender.setUsername("email#email.com");
mailSender.setPassword("12345");
MimeMessage msg = mailSender.createMimeMessage();
MimeMessageHelper mHelper = new MimeMessageHelper(msg, true, "UTF-8");
mHelper.setFrom(new InternetAddress(
mailInfo.get("send_mail").toString(), mailInfo.get("send_name").toString()));
mHelper.setTo(new InternetAddress(
mailInfo.get("recv_mail").toString(), mailInfo.get("recv_name").toString()));
mHelper.setText(mailInfo.get("mail_desc").toString(), true);
mHelper.setSubject(mailInfo.get("mail_title").toString());
mailSender.send(msg);
}
In my case value of mail_desc is an HTML(it has css and other resources). Mail goes well, but its CSS and all of images are broken.
I appended to all of src value like below in JSP
function getDomain(){
var DNS = location.href;
DNS = DNS.split('//');
DNS = 'http://' + DNS[1].substr(0,DNS[1].indexOf("/"));
return DNS;
}
So When I print this in browser console it returns localhost:8080/myApp/{image_src}.
However, When I open with gmail it looks quite different. it looks like...
<img src="https://ci5.googleusercontent.com/proxy/FVJ1IBTWmX0l0KPlNQVY_AkDsCL02O2Y_kZS7KACQlnXgfgNvNQvjBKpn9zIdPH84N_r-ulunXvzlMCVUOWsMG1WCjfYUFVX7VpjJ5OV5RdpV2ReZFjM9Yw=s0-d-e1-ft#http://localhost:8080/resources/gtl_portal/images/newsletter/ci.png" alt="ci" class="CToWUd">
Now I got questions like below :
How to implement newsletter in Normal? Where can I find some examples or references?(I think this can solve lots of problem here)
How to change value things looks like. it is quite tricky, since it is embedded in style attribute.:
<td height="50px" style="background:url('/resources/images/newsletter/top_bg.png') repeat-x 0 0;padding:15px">
Thanks a lot :D bb
You cant include your external css like you do normally , but you can prefer the way of wrapping the styles in the inline way (in <head> tag). So something like this,
<style>
.bigFont{
font-size:14px;
}
<style>
<body>
<p class='bigFont' >Hi , i am bigger </p>
</body>
so this looks separate instead adding style attribute to your tags , you can also avoid some code by resusing .
AFAIK , for adding inline images Spring framework has very good documentation. It is supported widely by mail clients, an example,
FileSystemResource res = new FileSystemResource(new File("c:/Sample.jpg"));
helper.addInline("identifier1234", res);
so that you can simply use it as <img src='cid:identifier1234'>.
For advanced templating options you can integrate your web app with Apache velocity, a templating library