I am working with a web application in which there is a Java Applet that captures an image from a wacom device into a RenderedImage object. The applet itself is embedded into a JSF 2.0 page.
I need to pass the created RenderedImage from Applet to a JSF backing bean so that it would be a part of a User object. My backing bean is view scoped.
I'm really lost with this. I've been searching for a good example on how this goal can be achieved. Should I use JSObject, or should I send an image to a servlet?
Can you offer some advice on how to solve this problem?
You problem can be divided into the following sub-steps:
Create a byte array from your BufferedImage that is holding its data;
Encode the data properly so that it won't be damaged/modified while it is being sent to the server as a string, for example by using Apache Commons Base64 codec;
Save the data as a hidden form field via Applet-to-JavaScript communication;
Send POST request to the server by, for example, triggering <h:commandButton>'s onclick;
Write encoded string to a java bean property in a standard JSF way;
Decode the string to get the byte array representing the image;
Recreate the image from the byte array and inject it in your view scoped bean.
That said, let's move on to implementing that agenda.
In your applet you'll have a method that will do points (1) - (4). Call it in a usual way, after you obtain the image:
Java Applet method:
public void processImage() throws IOException, JSException {
BufferedImage image = createBufferedImage();//the way you get the image
/* point 1 */
ByteArrayOutputStream bs = new ByteArrayOutputStream();
ImageIO.write(image, "png", bs);
bs.flush();
byte[] imageByteArray = bs.toByteArray();
bs.close();
/* point 1 */
String imageAsString = Base64.encodeBase64String(imageByteArray);//point 2
/* points 3-4 */
JSObject window = JSObject.getWindow(this);
window.call("writeImageValue", new Object[] {imageAsString});
/* points 3-4 */
}
JSF page (form and JavaScript):
<script>
function writeImageValue(imageValue) {
document.getElementById('image').value = imageValue;//point 3
document.getElementById('image-form:submit').click();//point 4
}
</script>
<h:form id="image-form">
<input type="hidden" id="image" name="image" />
<h:commandButton id="submit" action="#{imageSubmitBean.submitImage}" style="display:none" />
</h:form>
JSF managed bean:
#ManagedBean
#RequestScoped
public class ImageSubmitBean {
#ManagedProperty("#{param.image}")//point 5
private String imageAsString;//getter+setter
#ManagedProperty("#{userBean}")//your view scoped bean
private UserBean userBean;//getter+setter
public String submitImage() throws IOException {
byte[] imageByteArray = Base64.decodeBase64(imageAsString);//point 6
/* point 7 */
InputStream is = new ByteArrayInputStream(imageByteArray);
BufferedImage image = ImageIO.read(is);
is.close();
userBean.setUserImage(image);//update your view scoped bean
/* point 7 */
return null;
}
}
Related
I am attempting to load a custom component(descending from UIInput). I then encode an html input back to the client. My component loader is thus:
#FacesComponent("TomsWidgetComponent")
#SessionScoped
public class TomsWidgetComponent {
public TomsInput getNewInput(UIComponent parent)
{
ExpressionFactory factory = getFacesContext().getApplication().getExpressionFactory();
TomsInput newComponent = (TomsInput) getFacesContext().getApplication().createComponent(getFacesContext(), "org.tom.example.toms.TomsInput", "org.tom.example.toms.TomsInput");
String newId = FacesContext.getCurrentInstance().getViewRoot().createUniqueId();
newComponent.setId(newId);
elements.put(newId, newComponent);
newComponent.setInputData(new InputData());
ValueExpression valueExpression = factory.createValueExpression(getFacesContext().getELContext(),"#{tomsInput.string}",String.class);
newComponent.setValueExpression("value", valueExpression);
getChildren().add(newComponent);
pushComponentToEL(getFacesContext(), newComponent);
return newComponent;
}
html:
<"input type="tel" id="j_id2" oninput="mojarra.ab(this,event,0,'execute',0)" /input >"
The input shows up just fine, but ajax event never seems show up in my component. I've tried several permutations, with the key on setValueExpression, and adding behavior listeners.
...
Ive gotten passed the exceptions but the Ajax now coming back from the form is causing my component to reload. It's content is:
tomswidgetform=tomswidgetform&j_id2=fffdsdfgbg&javax.faces.ViewState=-6270730402975544133%3A7227399941332846704&javax.faces.source=j_id2&javax.faces.partial.event=input&javax.faces.partial.execute=j_id2%20j_id2&javax.faces.behavior.event=change&AJAX%3AEVENTS_COUNT=1&javax.faces.partial.ajax=true
Any idea what might be wrong? Thanks.
I am using Primefaces/JSF in combination with pure javascript tools in order to implement an image viewer & annotator. Image viewer is built upon the OpenLayers framework.
When the user annotates (draws shapes) on the canvas, a JSON object is created and upon Save action passed to the back bean. Back bean retrieves the object (deserialized) and stores it in to a file.
Here is the relevant code:
OpenLayers javascript (image-viewer.js):
function initialiseMap(){'
...
map = new OpenLayers.Map(imageEditorID, options);
imageLayer = new OpenLayers.Layer.TMS(imgURL, "", {
...
});
map.addLayer(imageLayer);
var vlayer = new OpenLayers.Layer.Vector("Editable");
map.addLayer(vlayer);
//draw controls and shape tools
...
//then define save action
var save = new OpenLayers.Control.Button({
...
var GEOJSON_PARSER = new OpenLayers.Format.GeoJSON();
var vectorLayerAsJson = GEOJSON_PARSER.write(vlayer.features);
//and finally post to server layer with drawn shapes
sendJSONToServer([{name:'param', value:vectorLayerAsJson}]);
...
The above Image Viewer/Map tool, is loaded via an p:outputPanel component of primefaces and uses sendJSONToServer remoteCommand to get JSON layer:
<h:head>
<script src="#{facesContext.externalContext.requestContextPath}/js/image-viewer.js" />
...
<h:body>
<h:form id="imageEditor">
<p:fieldset legend="Viewer">
...
// inoutHidden does not have on* events? how am i going to post to image-viewer.js?
<h:inputHidden value="#{imageAnnotations.fetchJsonString()}" />
...
<p:outputPanel layout="block" styleClass="imageEditorImagePanel" />
<p:remoteCommand immediate="true" name="sendJSONToServer" action="#{imageAnnotations.actionOnString}" />
</p:fieldset>
....
Finally in the backbean the JSON object is fetched and stored in a file (implementation is raw):
#ManagedBean(name="imageAnnotations")
public class ImageAnnotations {
//actionOnString fetches and saves the JSON string - this is a raw impementation
public String actionOnString() {
//Do the job and get and save JSON string
}
public String fetchJsonString(){
//Do the job and get JSON string
return jsonString;
}
}
The question is How am i going to use a JSF or primefaces element to make available the imageAnnotations.fetchJsonString() value for fetching from within js?
Even I can't give all answers, for me the filling of your hiddenInput should be managed as following:
#ManagedBean(name="imageAnnotations")
public class ImageAnnotations {
private String jsonString;
public void anyMethodFillingOrInitializingTheJSONString() {
this.jsonString = resultOfYourWork();
}
public String getJsonString(){
return this.jsonString();
}
public void setJsonString(String item) {
this.jsonString = item;
}
}
When you reload this hidden input field, just be sure to trigger a javascript parsing the String and updating your client-side Model. This can be done via the on* - events you can connect with Primefaces buttons.
Guys, can anybody help with the other parts?
I'm using JSF with primefaces and want to display an image from java code.
I already saw the tutorial on http://www.primefaces.org/showcase/ui/dynamicImage.jsf
But I'm not clear on how I can get the path to my image file correctly:
Code:
Bean:
#ManagedBean
public class ABean {
private StreamedContent bStatus;
public ABean() {
try {
Boolean connected = false;
if (connected == true) {
bStatus = new DefaultStreamedContent(new FileInputStream(new File("/images/greendot.png")), "image/jpeg");
} else {
bStatus = new DefaultStreamedContent(new FileInputStream(new File("/images/reddot.png")), "image/jpeg");
}
} catch(Exception e) {
e.printStackTrace();
}
}
public StreamedContent getBStatus() {
return bStatus;
}
public void setBStatus(StreamedContent bStatus) {
this.bStatus = bStatus;
}
}
xhtml:
<p:graphicImage value="#{ABean.bStatus}" />
returns:
java.io.FileNotFoundException: \images\reddot.png
I would appreciate best practices on where to store my image when displaying it form code and how to do it.
Since your images are in your web folder, you don't really need to use DefaultStreamedContent. I'd leave that only for images generated on the fly.
For your case, I'd just create a simple method that returns the image path (in your web folder) based on the boolean variable. Something like this:
public String getImagePath(){
return connected ? "/images/greendot.png" : "/images/reddot.png";
}
And on the graphicImage, you can just reference that:
<p:graphicImage value="#{yourBean.imagePath}"/>
Note that you might have to adjust the graphicImage tag if your web context is not root.
EDIT
You can actually make this even simpler:
<p:graphicImage value="#{yourBean.connected ? '/images/greendot.png' : '/images/reddot.png'}"/>
Just make sure to have a getter for the connected property.
Create your StreamedContent as follows:
bStatus = new DefaultStreamedContent(FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream("/images/greendot.png"), "image/jpeg");
When you are creating new File() this will be absolute path in your disk, not just in your application.
I need the URL for a component in wicket. When I use a page it works properly, but when using panel it does not work.
public final class ImageP extends Panel {
public ImageP(String id) {
super(id);
List<Mapp> list = Mapp.loadall(); //load image from database
final Mapp asr = list.get(0);
ByteArrayResource resource = new ByteArrayResource("image/jpeg", asr.getImage());
Image image = new Image("img", resource);
add(image);
System.out.println(getRequestCycle().urlFor(image, IResourceListener.INTERFACE));
}
}
This code does not work and throws an exception, but when I use page instead of panel getRequestCycle().urlFor(image, IResourceListener.INTERFACE) it works properly.
I bet you've got the following exception:
java.lang.IllegalStateException: No Page found for component [Component id = img]
It's because RequestCycle object internally calls getPage() method of the component that's first parameter of the urlFor() method with the following signature:
urlFor(Component component, RequestListenerInterface interface)
In case of calling method urlFor() in the constructor of a panel it's impossible to get page of a panel's child because panel isn't attached to page yet. So Wicket throws "a nice exception".
To fix that problem you just can move your code to the onBeforeRender() method of the panel. Something like that:
#Override
protected void onBeforeRender() {
//
// ... init resource ...
//
Image image = new Image("img", resource);
addOrReplace(image);
System.out.println(getRequestCycle().urlFor(image, IResourceListener.INTERFACE));
super.onBeforeRender();
}
P.S. I also assume that you're using Wicket 1.4 or earlier because there's no RequestCycle.urlFor(component, listener) method in Wicket 1.5 and later. So I think neither your question nor my answer doesn't make sense in that case.
I want to rescale an image and return it to the client, and am running into some trouble with sending the image back to the client.
My serverside controller:
#RequestMapping(value = {"/fw/ajax/submit_profileimage.do"})
public void submitFile(HttpServletRequest request, HttpServletResponse response, #RequestParam("file") MultipartFile f) {
try {
InputStream in = new ByteArrayInputStream(f.getBytes());
BufferedImage originalImage = ImageIO.read(in);
BufferedImage newImage = new BufferedImage(MAX_HEIGHT, MAX_WIDTH, BufferedImage.TYPE_INT_RGB);
paintComponent(newImage.getGraphics(), originalImage, getRatio(originalImage));
ImageIO.write(newImage, "png", response.getOutputStream());
response.setContentType("image/png");
response.getOutputStream().flush();
response.getOutputStream().close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
Clientside Jquery code:
uploadButton.click(function(){
$('#imagePreview').addClass('loading');
form.ajaxSubmit(function(data){
alert(data); //this is where I'd like to handle the image!
});
});
the data that is returned by the ajaxSubmit is:
"<body style="margin: 0px;"><img style="-webkit-user-select: none" src="http://localhost:8080/fairview/ajax/submit_profileimage.do"></body>"
Clearly not an image file.
But when I check the debugger, I can see that the submit_profileimage.do request has succeded, and allegedly returned an image! I have no idea if I've done something wrong on the clientside, or on the serverside.
So the question is: How can I display the image on the clientside?
I would simply save the resized image on the server and return back to jquery simpy a URL to where the resized image has been saved. Then simply set the src attribute of the image to that URL. The browser will than take care of downloading the image.
uploadButton.click(function(){
$('#imagePreview').addClass('loading');
form.ajaxSubmit(function(data){
//Assuming data is the URL to the resized image.
$("#myimage").attr("src", data);
});
});
I went with the approach described as the accepted answer here: Help getting image from Servlet to JSP page
Which pretty much means I didn't really answer the initial question, I still can't handle a raw image clientside. Rather, I use one service to store the image, return the id of where the image is stored, and set the src attr of the image to a service that will return the image.