In this post I am going to show how we can enrich an ADF application with features like taking pictures with a Web camera. In order to get an access to the camera's stream and in an effort to show taken pictures we will use HTML5 tags video and canvas. Basically, my html code looks like the following:
On the left side we are going to show a video stream, captured from a Web camera, and on the right side we are going to show taken pictures. In order to get it all working we need some java script:
Since the ADF framework gets confused about mixing pure html tags with ADF components, we're going to access to the html page, containing video and canvas tags via af:inlineFrame. An ADF page fragment should look like this:
That's it!
<table border="1" width="900" align="center"> <tr align="center"> <td> Web Camera <div id="camera" style="height:300px; width:400px; border-style:solid;"> <video id="video" width="400" height="300"></video> </div> </td> <td> Photo Frame <div id="frame" style="height:300px; width:400px; border-style:solid;"> <canvas id="canvas" width="400" height="300" ></canvas> </div> </td> </tr> <tr align="center"> <td colspan="2"> <button id="snap" onclick="snap()">Snap Photo</button> </td> </tr> </table>And it looks like this:
On the left side we are going to show a video stream, captured from a Web camera, and on the right side we are going to show taken pictures. In order to get it all working we need some java script:
<script type="text/javascript">
var video = document.getElementById("video");
videoObj = { "video": true },
canvas = document.getElementById("canvas"),
context = canvas.getContext("2d"),
frame = document.getElementById("frame");
errorBack = function (error) {
alert(error);
};
//This function is going to be invoked on page load
function setupCamera()
{
if(navigator.getUserMedia) {
navigator.getUserMedia(videoObj, standardVideo, errorBack);
} else if(navigator.webkitGetUserMedia) {
navigator.webkitGetUserMedia(videoObj, webkitVideo, errorBack);
}
else if(navigator.mozGetUserMedia) {
navigator.mozGetUserMedia(videoObj, mozillaVideo, errorBack);
}
}
//Different functions for different browsers
standardVideo = function(stream) {
video.src = stream;
video.play(); }
webkitVideo = function(stream){
video.src = window.webkitURL.createObjectURL(stream);
video.play(); }
mozillaVideo = function(stream){
video.src = window.URL.createObjectURL(stream);
video.play(); }
//onClick for the snap button
function snap()
{
//Take a picture from video stream
context.drawImage(video,0,0,400,300);
//Add a css3 class style to get a "sliding" effect
canvas.className="animated";
//Add s listener to remove "animating" class style
//at the end of animation
canvas.addEventListener("animationend", animationEnd, false);
}
function animationEnd(e)
{//Finish the animation
canvas.className="normal";
//Set up taken picture as div's background
frame.style.backgroundImage='url('+canvas.toDataURL("image/png")+')';
}
//on load
window.addEventListener("DOMContentLoaded",setupCamera(), false);
</script>
We use some CSS3 animation in order to get a "slide" effect. So, the picture is going to slide from the video stream to the Photo Frame: <style type="text/css">
@keyframes slide
{
from {left:-440px;}
to {left:0px;}
}
.animated
{
position:relative;
animation:slide 0.5s ease-in;
-webkit-animation: slide 0.5s ease-in;
}
.normal
{
}
</style>
So, you can play with the result of our work here.Since the ADF framework gets confused about mixing pure html tags with ADF components, we're going to access to the html page, containing video and canvas tags via af:inlineFrame. An ADF page fragment should look like this:
<af:panelStretchLayout id="psl1">
<f:facet name="bottom">
<af:panelGroupLayout layout="horizontal" id="pgl1">
<af:commandButton text="Submit" id="cb1" action="submit">
<af:clientListener type="action" method="takePicture"/>
<af:serverListener type="takePicture"
method="#{TakePictureBean.takePicture}" />
</af:commandButton>
<af:commandButton text="Cancel" id="cb2" action="cancel"/>
</af:panelGroupLayout>
</f:facet>
<f:facet name="center">
<af:inlineFrame id="iframe"
source="Snapshot.html"
styleClass="AFStretchWidth"
/>
</f:facet>
</af:panelStretchLayout>
Let's pay attention to the Submit button. Actually, when we click this button, we're going to grab taken picture, send the image to the server and set it as a value of a BLOB entity attribute. So, let's look at the client side first. The code of the button's client listener:function takePicture(actionEvent)
{ //We are doing all this stuff just in order
// to get access to the inlineFrame's content
var source = actionEvent.getSource();
var ADFiframe = source.findComponent("iframe");
var iframe = document.getElementById(ADFiframe.getClientId()).firstChild;
var innerDoc = (iframe.contentDocument) ?
iframe.contentDocument :
iframe.contentWindow.document;
//Finally we can work with our canvas,
//containing taken picture
var canvas = innerDoc.getElementById("canvas");
//Convert the image into the DataURL string and
//send it to the server with a custom event
AdfCustomEvent.queue(source, "takePicture",
{picture : canvas.toDataURL("image/png")}, true);
}
On the server side we're going to listen to the takePicture event. So, the code of the server listener:public void takePicture(ClientEvent clientEvent)
throws SQLException
{
//Convert the image into an array of bytes
String picture = (String) clientEvent.getParameters().get("picture");
String prefix = "base64,";
int startIndex = picture.indexOf(prefix) + prefix.length();
byte[] imageData = Base64.decodeBase64(picture.substring(startIndex).getBytes());
//Find an attribute binding pointing to a BLOB entity attribute
BindingContext bc = BindingContext.getCurrent();
DCBindingContainer dcb = (DCBindingContainer) bc.getCurrentBindingsEntry();
AttributeBinding attr = (AttributeBinding)dcb.getControlBinding("Image");
//And set an attribute's value
attr.setInputValue(new BlobDomain(imageData));
}
You can download a sample application for this post. It requires JDeveloper 11gR2. That's it!

What's uρ, yes this post is trulу pleasant and I have learnеd
ReplyDeleteloot of things from it about blogging. thanks.
Κijk oоk op mijn webpagina ... voorbeeldbrief incassobureau
That was enjoyable to read, thanks for posting it.
ReplyDeleteHere is my website :: Bing (bing.com)