Thursday, 23 March 2017

Deal with script error while using Google Map in Iinternet Explorer.

Script error in IE is very frustrating as it comes frequently and with some error and it doesn't get closed and pops up again and again. I got the same error while using the  google map and unable to pan the map, either zoom in or zoom out. Got the error like: (see screen shot).             








While exploring the issue i got that the issue was coming from onion.js file which is a javascript library file. This file gets included automatically when you use Google Map API file (https://maps.googleapis.com/maps/api/js/v=3&sensor=false).

I got the exact problem why we usually get the script error in onion.js. Onion.js is a javascript file and there is a java script function called JSON.pasre() used in that particular file and some of IE browsers(Ex- IE7) don't support the JSON.parse method and it shows a script error.

To reproduce this issue you have to check/uncheck some of the functionalities in Internet option.

- Open IE,  goto settings and click on Internet Options.
- Goto Advanced tab and see Browsing.
- Uncheck 'Disable script debugging(Internet Explorer)'.
- Uncheck 'Disable script debugging (Other)'.
- Check 'Display a notification about every script error.'


 Inorder to resolve the issue i added below java script code in the same page where the Google map API is being called and it worked.

 <script type="text/javascript">
        window.onerror = function() {
            return true;
        };
</script>


Defining the onerror event with a function that returns a value of true at the very top of your page suppresses all scripting errors on the page .

Important Notes:

Be careful while using this event, since it only suppresses errors, but doesn't fix them. Whenever you test codes in your browser, make sure to first turn off the error suppressor.

Thursday, 28 April 2016

Auto Image rotation functionality using ColdFusion.

Generally we use our mobile phones to take picture and then send it to computer for various uses. We can take a picture from mobile with any angle we want then the phone has the ability to preview the image with proper orientation. Now the problem is when we have taken a picture with up side down and send the same picture to computer, it will preview the images with upside down as the system doesn't change the orientation automatically. Now the real issue is, we have couple of images and we want to create a profile picture for each users by manipulating the same images that we have. We can't use a up side down image as a profile picture. In order to resolve this issue we have the mechanism in ColdFusion to read the image and we can find if the image is proper oriented or not.

Let's take a look to the below code:

Set an image path to a varibale.

<cfset VARIABLES.imageName = "IMG_111.JPG">

Read the image property.
   
<cfset VARIABLES.theImage = ImageRead(VARIABLES.imageName)>
Then get the orientation of that image.
<cfset VARIABLES.orientation  = ImageGetEXIFTag(VARIABLES.theImage, 'orientation')>

Use ImageGetEXIFMetadata and then check if the structKeyExists.

<cfif (NOT isNull(orientation))>   
    <!---Find the rotation degree from below string if needed--->
    <cfset VAR hasRotate = findNoCase('rotate',orientation)>       
    <cfif hasRotate>       
        <!---strip out all text in the orientation value to get the degree of orientation--->
        <cfset rotateValue =reReplace(orientation,'[^0-9]','','all')>       
        <!---Rotate and write the image if needed for the particular image if needed.--->
        <cfimage   
            action = "rotate"
            angle = "#rotateValue#"
            source = "#
VARIABLES.imgPath#"  
            destination = "#
VARIABLES.imgPath#"
            isBase64= "no"
            name = "cfimage"
            overwrite = "yes">   
    </cfif>
</cfif>  
 

Now the above snippet will query for the given image, check if the orientation is right or not, if not, then it will proper oriented.
Now try to show the same image on the UI and you can find the proper oriented image.

We can also get below information form an image by reading the EXIF data of an image:

- The date/time the pic was shoot
- Image height
- Image weight
- ISO speed rating
- Make and model of the camera
- X resolution
- Y resolution
- GPS Latitude
- GPS Latitude Ref
- GPS Longitude
- GPS Longitude Ref etc.

 

Tuesday, 19 April 2016

Ingetration of Facebook and Google in ColdFusion

If we are working with some sign in functionality, we can use log in using Facebook or Google. We can get all the required info like user name, email address, phone number, address, date of birth, gender etc with out entering manually in the sign in form and it will just auto populate all the above info on the sign in form. Only we need to fetch the data from FB/Google server.

Let's start with the Facebook integration.

We have to include all the API files first.

 <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
   <script src=" //ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
 

<!-- facebook button -->
        <div style="margin:5px 0;"><a  onclick="_login();" id="fbBtn" style="padding:20px;"> Log In Using Facebook</a></div>
       
        <!-- google button -->
        <div style="margin:5px 0;"><a  id="authorize-button" onclick="handleClientLoad();" >Log In Using Google</a></div>

 
Facebook java script Code starts here.

<script type="text/javascript">
    var flag = 0;       
    $("#fbBtn").click(function(){
        flag = 1;
    });   
  // Load the SDK asynchronously
  (function(thisdocument, scriptelement, id) {
    var js, fjs = thisdocument.getElementsByTagName(scriptelement)[0];
    if (thisdocument.getElementById(id)) return;
   
    js = thisdocument.createElement(scriptelement); js.id = id;
    js.src = "//connect.facebook.net/en_US/sdk.js"; //you can use
    fjs.parentNode.insertBefore(js, fjs);
  }(document, 'script', 'facebook-jssdk'));
   
  window.fbAsyncInit = function() {
  FB.init({
    appId      : '*****07300******', //Change this APP ID to yours
    cookie     : true,  // enable cookies to allow the server to access
                        // the session
    xfbml      : true,  // parse social plugins on this page
    version    : 'v2.1' // use version 2.1
  });

  // These three cases are handled in the callback function.
  FB.getLoginStatus(function(response) {
 // $("#fbBtn").trigger("click");
    statusChangeCallback(response);
  });

  };
   
  // This is called with the results from from FB.getLoginStatus().
  function statusChangeCallback(response) {
     
    if (response.status === 'connected') {
       
      // Logged into your app and Facebook.
      _i();
    } else if (response.status === 'not_authorized') {
       
      // The person is logged into Facebook, but not your app.
      document.getElementById('status').innerHTML = 'Please log ' +
        'into this app.';
    }
  } 
 
  function _login() {
    FB.login(function(response) {
       // handle the response
       if(response.status==='connected') {
        _i();
       }
     }, {scope: 'public_profile,email'});
 }

 function _i(){
     FB.api('/me', function(response) {
         //console.log(response);           
    });
 }

</script>

Google java script code starts here.

<script type="text/javascript">
var flag=0;
$("#authorize-button").click(function(){
    flag=1;
});
var clientId = '**4876******.apps.googleusercontent.com'; // Change the Client ID to yours.
// To use in your own application, replace this API key with your own.

var apiKey = 'AI**************1L1****************F-g';

// To enter one or more authentication scopes, refer to the documentation for the API.

var scopes = 'https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email';

// Use a button to handle authentication the first time.

function handleClientLoad() {
    gapi.client.setApiKey(apiKey);
    window.setTimeout(checkAuth,1);
}

function checkAuth() {
    gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: true}, handleAuthResult);
}

function handleAuthResult(authResult) {
    var authorizeButton = document.getElementById('authorize-button');
    if (authResult && !authResult.error) {
        //authorizeButton.style.visibility = 'hidden';
        makeApiCall();
    } else {
        //authorizeButton.style.visibility = '';
        authorizeButton.onclick = handleAuthClick;
        }
    }
   
function handleAuthClick(event) {
    gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: false}, handleAuthResult);
    return false;
}

// Load the API and make an API call.  Display the results on the screen.

function makeApiCall() {
    gapi.client.load('plus', 'v1', function() {
        var request = gapi.client.plus.people.get({
        'userId': 'me'
        });
   
        var request = gapi.client.plus.people.get( {'userId' : 'me'} );
        request.execute( function(profile) {
            var email = profile['emails'].filter(function(v) {
                return v.type === 'account'; // Filter out the primary email
            })[0].value;
            var fName = profile.displayName;
        });

        request.execute(function(resp) {
            //console.log(resp);         
        });
    });
}
</script>

<script src="https://apis.google.com/js/client.js"></script>


 

Thursday, 14 April 2016

Converting videos to different format/resolution and creating thumbnails using FFMPEG in ColdFusion

If we are going to create a video player application in ColdFusion, then we have to work on different aspects of the video files to upload,play and store in server.

We have different formatted video files that we can upload to our application to play, but we have to make a default format file for all so that the video player will play that particular file easily.
So, the first process would be, we have to convert all uploaded files to a .mp4 file for example. If the user uploads an .AVI file or .DAT file, then we have to convert that file to .mp4 file for better
resolution and better picture quality.

So for converting a video file to .mp4 file we can use FFMPEG plug in. Below code we can use to do that.

<cfset argString = '/c #ARGUMENTS.serverPath#\manage\ffmpeg.exe -i "#fsVideoFile#" -ar 22050 "#ARGUMENTS.serverDirPath#\#dltSpaceServerFileName#.mp4" 2>&1'>

<cfexecute name="#ARGUMENTS.name#"
    arguments="#ARGUMENTS.argument#"
    timeout="3000"
    variable="jsonInfo"
    errorVariable="errorOut"
/>

ARGUMENTS.serverPath = The path wehere you store the ffmpeg.exe file(You can download this file form FFMPEG site).
fsVideoFile = The original file uploaded by the user.
ARGUMENTS.serverDirPath = The path where you can store the new converted video file.
dltSpaceServerFileName = The new video file name.


By using the above code you can convert the video files to .mp4. You can actually convert to any of the video format by changing the .ext to the new video file name.

If it necessary, then we can also get the length of the video file using the same API. For that, we can use below code.

<cfexecute name="#ARGUMENTS.serverPath#\manage\ffprobe.exe"
    arguments="#fsVideoFile# -v quiet -print_format json -show_format -show_streams"
    timeout="3000"
    variable="jsonInfo"
    errorVariable="errorOut"
/>

This above code is responsible for getting the length or duration of the video file. We can also get the resolution of that particular video file.
We would need the resolution of the video file to know whether it is a high resolution file or not. High resolution files need more internet speed to play. We can play the video by
depending upon our internet speed. If the internet is fast then we can play the high resolution or hd video files, if not the the medium or low resolution file would be played.

We can also create different resolution files by using this API. If the user upload a high resolution video file then, we can convert it to two different resolution files.


<cfexecute name="#ARGUMENTS.serverPath#\manage\ffmpeg.exe#"
    arguments="/c #ARGUMENTS.serverPath#\manage\ffmpeg.exe -i "#fsVideoFile#" -s 800x600 -ar 22050 "#fsVideoFileLarge#" 2>&1"
    timeout="3000"
    variable="jsonInfo"
    errorVariable="errorOut"
/>


<cfexecute name="#ARGUMENTS.serverPath#\manage\ffmpeg.exe#"
    arguments="/c #ARGUMENTS.serverPath#\manage\ffmpeg.exe -i "#fsVideoFile#" -s 480x320 -ar 22050 "#fsVideoFileLarge#" 2>&1"
    timeout="3000"
    variable="jsonInfo"
    errorVariable="errorOut"
/>


Here we are creating two different resolutions files with a resolution of 800x600 and 480x320. We can dynamically switch to the different resolution files depending upon the bandwidth.

There is also a mechanism we can extract the images from the video to show as a thumbnail.

<cfexecute name="#ARGUMENTS.serverPath#\manage\ffmpeg.exe#"
    arguments="-itsoffset -4  -i #fsVideoFile# -vcodec mjpeg -vframes 1 -an -f rawvideo -s 500x300 #ARGUMENTS.serverDirPath#\images\posters\poster_#dltSpaceServerFileName#.png"
    timeout="3000"
    variable="jsonInfo"
    errorVariable="errorOut"
/>

Monday, 31 August 2015

Google map API integration(Marker management and clustering) using ColdFusion

We can embedded google map in our ColdFusion project and  create an interactive Google Map application which will dynamically fetch markers and marker information
from database and ColdFusion server.


If we have tens of thousands of markers we want to place on a Google map to provide our users with various information and to do this, the best method would be to have the Google Map make a call to the database for map markers that are within the bounds of the map view port. When the user changes the map (pans, zooms in/out) the view port bounds of the map change and a new database call would be made to fetch all visible markers. Thus only markers that would actually be visible on the current view port would be displayed.

The steps we can follow:

We have to Place the map code on any page at any map size and then make a call to the database for marker info and display it. When the user clicks on the marker another call would be made to the ColdFusion server to dynamically create the content of the info window. Need to handle the query request the map application would make to the server and return the results back to the map application in JSON format. Again we have to create a ".cfm" file to load into the marker info window when the user clicks on the marker.Due to the number of markers that can potentially be displayed on the map Marker Clustering should be utilized to keep things clean and not slow the performance down.

Please find the code base here.

<div id="map-canvas"></div>

//initilize the gmap function here.  
        function initialize() {
        var center = new google.maps.LatLng(4.184, 8.4158)//the map will be shown this latLng on the first load.

        var map = new google.maps.Map(document.getElementById('map-canvas'), {
          zoom: 7,
          center: center,
          mapTypeId: google.maps.MapTypeId.ROADMAP
        });

            google.maps.event.addListener(map, 'idle', showMarkers);
          
            // Below function is used to set the zoom and call the server for markers.
            function showMarkers(){              
              
                var bounds = map.getBounds();
                var dat = new Date();
                zoomLevel1 = map.getZoom();              
                //Below code to mark the map zoom wheather will change or not.
                google.maps.event.addListener(map, 'zoom_changed', function() {
                        zoomLevel = map.getZoom();
                    if (zoomLevel >= zoomLevel1) {
                        zoomStatus = 'zoom in';
                    } else {
                        zoomStatus ='zoom out';
                    }
                });
              
                //set the zoomStatus as zoom out to show the markers on the first load of gmap.
                if(typeof(zoomStatus) == 'undefined'){
                    zoomStatus = 'zoom out';
                }              
                $("#light").show();
                $("#fade").show();
              
                $.ajax({
                    // call the  server to fetch the bound for different regions.
                    url: "getMarker.cfc?method=pullMarkers&returnformat=json&center="+bounds+"&dat=" + dat,
                    type: "GET",
                    data: {zoomStatus:zoomStatus},
                    dataType:"json",
                    success: function(data){  
                        //validate the data as per the required data type.
                        var rawData = (data)[0];
                        var splitData = (rawData[0].DATA);
                      
                        markers = [];
                        for (i = 0; i < splitData.length; i++) {
                            var latLng = new google.maps.LatLng(splitData[i][0],splitData[i][1]);
                            plmarker(latLng,splitData[i][3],splitData[i][6],splitData[i][5],splitData[i][4]);
                          }
                      
                        //Show all the markers in the clustering method.                  
                        var markerCluster = new MarkerClusterer(map, markers);                      
                                         },
                    error:function(){                        
                                             }
                });  
            }          
            //Function to place the markers in map location after being fetched from server.
            function plmarker(latLng,title,url,mrkrColor,mrkrIcon){
              
                //delete the extra spaces from the icon label.
                markerLabel = $.trim(title);              
                var marker = new google.maps.Marker({
                       position: latLng,
                    map:map,
                    title:markerLabel,
                    draggable:false,
                    url:url,
                    icon:markerIcon
                 });
              
                //Function to show the marker info in info window once a marker is clicked.
                 google.maps.event.addListener(marker, 'click', function(){
                     var boatLaunchURL = this.url;
                     var dat = new Date();
                      $.ajax({
                    // call the server to fetch marker information for a particular marker.
                        url: "getMarker.cfc?method=fetchURLContent&returnformat=json&dat=" + dat,
                        type: "GET",
                        data: {url:boatLaunchURL},
                        dataType:"json",
                        success: function(data){
                                    infoWindow.setContent('<div class="scrollFix">'+data+'</div>');// set the size of the info window.
                                    infoWindow.open(map, marker);
                                    }
                    });
                });
                markers.push(marker);
            }
        }
        google.maps.event.addDomListener(window, 'load', initialize);
        infoWindow = new google.maps.InfoWindow();

Monday, 3 November 2014

Select and upload multiple files to the server in ColdFusion using jQuery without refreshing the page.

In web application, we frequently need to attach/upload files or photos to the server as per the requirement. It's a common thing now to send or receive pictures or files from different users. There are different ways to do this in different languages  but it's a bit easy task if we consider to do it with ColdFusion.

We have some predefined tags to do it. If we want to upload some file to the server, The code snippet is like:

'<cffile action="upload" path="D:\upload\#getToUserID.peopleID#" filefield="#key#">'


We just need to put the code in a <form></form> tag. The data will be uploaded to the server once we submit the form.


Now if we want to upload a file/pic in ColdFusion, but we don't want to submit the page, because the page will be refreshed and load again if the form is submitted.

So we can upload a file to the server with out refreshing or submitting a page with the help of jQuery.

for that we need two jQuery frame works. We also need to include the parent jQuery frame over here.
a) jquery-ui.js
b) jquery.MultiFile.js
c) malsup.github.com/jquery.form.js.


The jQuery multiple file selection plugin helps users to select multiple files easily for upload. It has some basic restrictions and validation so that easily we can check whether two same files are selected or not.

Below is the HTML code:

<form action="abc.cfc?method=attahFile method="post" id=myForm>
<input id="Avatar" type="file" name="Avatar"/>         
<input type="submit" value="Send Message" class="btn btn-primary btn-sm" id="replyMessage">   
</form>


So above is the HTML code to select the file we want to upload. First we need to include the multiple file upload framework to the template so that it will allow to select multiple files to select one by one.

Below is the snippet to include the multiple file select frame work.

<script src="js/jquery.MultiFile.js"></script>

<script>
$('#avatar').MultiFile({
         STRING: { remove:'Remove',
         selected:'Selected: $file',
         denied:'Invalid file $ext!',       
         }
    });
</scrpit>

So this code will help to add multiple files to upload into the server.

Now we need to add the code to submit the form using jQuery so that the form will be submitted , but it will not get refreshed and not get loaded again.

For that we need to add another jQuery framework called jquery.form.js.
the source code is:

<script src="http://malsup.github.com/jquery.form.js"></script>

Above Plugin allow us to easily update HTML forms to use AJAX. The two methods, ajaxForm and ajaxSubmit, gather required information from the form field to determine how to manage the submit process. The two methods support all of the options which allows the control over the data is being submitted.

The JS code will be:

$('#myForm').ajaxForm({
        beforeSubmit: function() {
                            },
        success: function(data){
            alert("Thank you");
        }
    });


 Note: One thing we need to do along with this,we need to differentiate the multifiles by their id(s) so that while uploading the different files, we can easily handle them.

 Below code will work as per our requirement:

 $('body').on('change','input.MultiFile-applied',
      function(e){console.log(this);
          $(this).attr('name',$(this).attr('id'));
      }
    )