Friday, December 17, 2010

Provide custom validation messages using setCustomValidity in HTML 5 pages

If you have come through my other note on "Form validations on HTML 5", you already know that HTML 5 is promising enough to make validations better and native. Just set the right properties for the INPUT elements and HTML 5 gives you on-the-fly validations with less code. But, in some scenarios, we might have to include additional logical validations, in which case, setCustomValidity() function can be used to logically decide and set your own validation messages.

Below is a simple sample code that will demonstrate the usage of setCustomValidity() functionality.
<!DOCTYPE html>
<html>
<head><meta charset="utf-8">
<title>HTML5 Sample Validation Page</title>
<style type="text/css">
body
{
    font-family:Arial;
    font-size:12px;
}
.valid
{
    color:#000000;
}
.invalid
{
    color:#FF0000;
}
</style>
</head>
<body>
<form id="form1" method="post">
<label>Age: <input type="number" required="true" value="50" min="18" max="60" step="1" oninput="validate(this)"> (between 18 and 60)</label><br /><br />
<div id="validateMsg"></div><br />
<div id="validity"></div>
<script>
function validate(input) {
    //logically decide and set custom validation message
    if (input.value == "20" || input.value == "30") {
        // set custom validation message
        input.setCustomValidity('Your Age (' + input.value + ') is in a transition phase.');
    } else {
        // reset the validation message - makes it valid for checkValidity function
        input.setCustomValidity('');
    }
    document.getElementById('validateMsg').innerHTML = 'Validation Message: "' + input.validationMessage + '"';
    document.getElementById('validity').innerHTML = 'checkValidity function output: "' + input.checkValidity() + '"';
}
</script>
</form>
</body>
</html>
Concept:
In this example, Age input is expected to accept only values between 18 and 60. Additionally, 20 and 30 ages are also treated as Invalid (of course, unusual scenario). This is done by using setCustomValidity() function which will internally set the validationMessage property of the input control. The HTML 5 form validation function checkValidity() takes the validationMessage in to account and provides output as shown below, in Google Chrome.

Valid Input:

Invalid Input:

Custom In-valid Input: (20 and 30 are not accepted):

In valid scenarios, validationMessage is an empty string and checkValidity function returns true. In In-valid scenarios, including our custom invalid scenarios, checkValidity function returns false and validationMessage is returned based on the custom message set.

Form Validation using checkValidity and Validity in HTML 5 using JavaScript- Sample Code

The next major version of the HTML standards (HTML 5) seem to have numerous improvements over the current standards. Most of the functionalities, for which the developers has to write extensive custom code, will get reduced to a certain extend by the launch of new standards.

The below sample shows how to perform a FORM validation for an HTML 5 input element using the newly introduced "Validity" property associated to an input element. This will also demonstrate the usage of checkValidity() function which can be used to identify whether the the form elements are all validated to proceed with the server communication.

Skill level: For Beginners

Sample Code:
<!DOCTYPE html>
<html>
<head><meta charset="utf-8">
<title>HTML5 Sample Validation Page</title>
<style type="text/css">
body
{
    font-family:Arial;
    font-size:12px;
}
.valid
{
    color:#000000;
}
.invalid
{
    color:#FF0000;
}
</style>
</head>
<body>
<form id="form1" method="post">

<label>Age: <input type="number" required="true" value="50" min="18" max="60" step="1" oninput="validate(this)"> (between 18 and 60)</label><br /><br />
<div id="validateMsg"></div><br />
<div id="validity"></div>
<script>
    function validate(input) {
        var out = document.getElementById('validateMsg');
        if (input.validity) {
            if (input.validity.valid === true) {
                out.innerHTML = "<span class='valid'>" + input.value +
                            " is a valid age.</span>";
            } else {
                out.innerHTML = "<span class='invalid'>" + input.value +
                            " is not valid age.</span>";
            }
        }
        document.getElementById('validity').innerHTML = "checkValidity() output: <span class='invalid'>" + input.checkValidity() + "</span>";
    }
</script> 
</form>
</body>
</html>

Concept:
The input element is a number element (that accepts "Age") in this example, with maximum and minimum values set in the design mode. [If more information is needed on the Input elements, refer here.] During the user input event, a JavaScript function validate() is called. This function validates the input value using the input.validity.valid property and provides appropriate message, after checking for the support of this functionality.

checkValidity() function is called to check and understand the value that it returns for the successful and unsuccessful validation scenarios.

Here are the output screens:

Valid Input:

Invalid Input:

As you can see, the checkValidity() always seems to return false. It returns true for values less than 10. It is being suspected that the inadequate browser support is one reason behind this weird behavior OR i'm missing something. However, as per the documentation here, this function will help us to check and trigger functions based on the invalid/valid state of one/multiple elements, thereby assisting us in form validations.

In the above code, the script tag is provided inside the body tag, for the sake of easy understanding. Keep it inside the HEAD tag, as it is usually done.

Sunday, December 12, 2010

HTML 5 Sample page with sample code for newly introduced INPUT elements

Here is a sample code for an HTML 5 page with the new input elements, which has the minimum set of properties defined so as to get a feel of how the new HTML standards are coming up. This will also give us an idea on how these changes are going to affect the user experience once they gets implemented in web pages.

Let us start by specifying the HTML 5 doc-type as shown below.
<!DOCTYPE html>
At the time of this writing, below are the type of input elements that are available. Most of these new element types are being supported in Google Chrome.

Keyword State Usage
search Search <input type="search">
number Number <input type="number">
range Range <input type="range">
color Color <input type="color">
tel Telephone <input type="tel">
url URL <input type="url">
email E-mail <input type="email">
date Date <input type="date">
month Month <input type="month">
week Week <input type="week">
time Time <input type="time">
datetime Date and Time <input type="datetime">
datetime-local Local Date and Time <input type="datetime-local">

Here is the sample HTML code showing the basic features of the newly introduced input controls. For sake of simplicity, the properties are kept to a minimum. Even the layout beautification is ignored.

Simple Sample Code:
<!DOCTYPE html>
<html>
<head><meta charset="utf-8">
<title>HTML5 Sample Page</title>
<style type="text/css">
body
{
    font-family:Arial;
    font-size:12px;
}
</style>
</head>
<body>
<form id="form1" method="post">
Search:
<input type="search" placeholder="Search text here"><br />
Number:
<input type="number" value="50" min="40" max="60" step="5" autofocus="true"><br />
Range:
<input type="range" value="50" min="40" max="60" step="5"><br />
Color:
<input type="color" value="#000000"><br />
Telephone:
<input type="tel" placeholder="999" pattern="[0-9][A-Z]{3}" title="A part number is a digit followed by three uppercase letters."><br />
URL:
<input type="url" value="http://www.google.com"><br />
Email:
<input type="email" multiple value="me@somewhere.com"><br />
Date:
<input type="date" max="2050-12-31" min="2000-01-01" value="2010-01-01"><br />
Date Time (Time zone information included):
<input type="datetime" value="2000-12-31T00:00+05:30"><br />
Local Date Time (No Time Zone information):
<input type="datetime-local" value="2000-12-1T00:00"><br />
Month:
<input type="month" max="2000-10" min="2000-02" value="2000-04" step="2"><br />
Week:
<input type="week" max="2000-W50" min="2000-W05" value="2000-W06" step="2"><br />
Time:
<input type="time" max="23:00:00" min="01:00:00" value="04:30:00" step="5"><br />
File Upload:
<input type="file" accept="image/*" name="image" multiple onchange="updateFilename(this.value)"><br />
<input type="submit" value="Submit"/>
</form>
</body>
</html>

The above sample code also includes the usage of new properties like multiple, pattern, placeholder, autofocus, min, max, step etc.

Here is how it looks in Google Chrome.

Yes, it looks ugly (though it serves the purpose)! Feel free to copy the code and beautify/change it as needed. Let me know whether there is any changes, since the specification is fairly new.

References:
http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary
http://www.whatwg.org/specs/web-apps/current-work/multipage/common-input-element-attributes.html#the-multiple-attribute

Sunday, November 21, 2010

Port forwarding through a modem and router to expose and enable communications to local services - How to?


I’ve been trying to expose few ports on my machine to the public, for the past few days. I started off assuming that this will be a simple task to do. Even after trying different configuration settings found from Googling, I was not successful. As I’m not a networking guy, I was missing few basic things which were crucial for this to work. Combining all these learning, here are the steps that you will have to take to successfully forward ports to your desired local machine.

The purpose:
This might vary from person to person; sometimes you might want to locally deploy a web site and expose it for testing to your friends OR you might want to open up your MySQL or utorrent Web UI so that it is publicly accessible. From a networking perspective, all of these scenarios lands up in opening up ports in your router to the PC in which these services resides. By default, most of these ports are closed.

Network Structure:
Assuming that the following is your existing network structure, let’s see the steps involved.


Initial Steps:
Here are basic information needed to start with
  • The port to be opened up; in my case, this is 61799
  • The local IP address of the system which will be running the target service; Ex: 192.168.1.3
  • IP address of the router and your public IP; the IP address that represents you in the world.
Make sure that the IP addresses are static.
Before starting with the steps involved, we need to make sure that all these addresses does not get altered over time. This is important because most routers assigns IP addresses dynamically to each of the PC/clients using DHCP, as and when they initialize a connection with the router. Based on the Lease time (the time for next renewal), the IP assigned to one client-PC might get changed later.

So, let’s first give your PC a static IP first. if your PC is already on static IP, skip this step.
Conceptually, what you are going to do is to understand the preferred network settings and set them to your network adapter-card. You will also disable dynamic IP address renewal in your PC. Based on the OS that you have, static IP assignment process can vary. Here is one site that explains this. A typical settings can look like this.


One most important thing here is that, even though you have told your PC to have a static address, you should tell your router you assign the same. Otherwise router will still try to dynamically renew the PC’s IP which will lead to conflicts. To accomplish this, set the router in such a way that the router’s DHCP does not include this address. However, care should be taken that the existing clients can still run on dyncamic IP assignment process. In order to do this, the best step is to set a range for DHCP an assign an IP out of this range to the PC. It is always better to limit from the top range so that you are not touching the router/modem IP settings, which are usually on the lower range. From my settings below, i freed up IP addresses above 192.168.1.100


So, now the
  • Local PC is set with the IP 192.168.1.101
  • The port to be opened up is 61799
  • The router IP is 192.168.1.2 (usually this is 192.168.1.1). this is the IP at which the router’s web console resides. 
Port forwarding:
Now, let’s welcome and guide the requests from the outside world to the local PC. This is done using port forwarding. For beginners, let’s assume that port forwarding is like guiding a guest from one door to the destination room in your house. Some time, this can involve going through multiple doors(ports) OR just a single door. This is a very limited or primitive way of looking at it. From networking perspective, there is more to it. Just like your house to be secure, most of these doors are closed, by default. That’s why you need to open this up.

Port forwarding is sometimes called Virtual Servers. The trick is to access the router’s configuration page and find the page for this setting. Basic information, the page will ask for is
  • the service name (just for your identification)
  • the incoming port (when some one comes to this door)
  • the local PC (route to which computer)
  • the target port (to which door; the port at which your service is keep listening to so that it can accept the request). 
Here are the screenshots as per my router.



Allow access for the Port in Local PC - Firewall changes:
The final step is to make sure that the port is opened for access in your local PC. To open the port in your local PC, access the advanced settings of your firewall in your local PC and add a port exception. Most windows OS handles this section seamlessly. Basically we are trying to tell the firewall that if any request comes through 61799 door, let it come through.if you are looking for Step-by-step instruction for this, googling will help! Below are the major parts in this process, in screenshots.







Public IP Address:
Let’s identify the public IP of your’s . Most of the ISP( internet service provider) will assign an IP for your network, each time you connect to it. if you have a static IP bought from your ISP, ignore this section. Otherwise, you can have to find out your piblic IP using websites like whatismyip.org

That's it. You’re done. Use any of the online port check tool to confirm whether the port is open. canyousee.org is one such site. Make sure that your service is running at your local PC while checking. Once this is confirmed, you should be able to access the service at [public IP]:[port]. For example, an http service can be requested by http://ppp.ppp.ppp.ppp:61799/ where ppp.ppp.ppp.ppp is your public IP.

Tip:
There are FREE tools available that can give you a domain name for your IP, even if changes dynamically. You can register with them that will get you and address like http://you.theirname.com. You might have to download few apps to refresh thier records as and when your IP changes. These changes will be done automatically and you will now have a public address by using this. With this, your address for the service will be http://you.thiername.com:61799. Few free sites are http://www.dyndns.com/http://www.no-ip.com/,  http://asus.freeddns.com (free for ASUS products)


Multiple Router Scenario:
For most common network structures, the process is now complete. But tragically, my network structure were slightly different. It is something like this.



Here, the modem that i was having, the one that my ISP gave me, was not really a modem; that was also a router. In this case, i had two routers in my network and all the clients were connected to my second router.

The ideal way is to make the second router work as a Access Point and make the above explained changes in the primary router. This is possible, if your secondary router is capable to work as an Access Point. Even though my router ASUS RT-N14U is capable to do so, i tried to make it work without any changes to the existing system, keeping the secondary router as a router itself.

Primary router changes - Port Forwarding to secondary router:
Here are the steps involved to make this happen:
Connect the primary router directly to your local PC.
Access the administrative module which might be residing at http://192.168.1.1. In my case this was a Beetel 220bx modem. so, by default, it will not show you the advanced options. Little bit of googling showed that http://192.168.1.1/main.html and http://192.168.1.1/index.html are the two pages that exposes the options. Accessing main.html provided me the options to configure a virtual server in my primary modem.

The virtual server in my primary modem was set as
  • Incoming port: 61799
  • Target IP: IP address of the secondary router (192.168.1.2)
  • Target port: 61799
What i told here is to route all the requests from public at 61799 to the same port at 61799 to my second router, which is already set to route the request to my local PC.

Once the settings are done, turn off the machines and get back to your original network structure. This was the final step i have to do and get this working.

If there are other ways to achieve the same, let me know as comments.

Sunday, February 21, 2010

Solve absolute URL – relative URL issue without code changes using BASE tag (Google AJAX Feed API)


The Application


I was trying out a sample application using Google AJAX Feed API. The feeds were requested from a C# windows application and the responses (feed’s HTML content) were shown in a WebBrowser control.

The Problem

The weird problem was that the HTML snippet for some feed has relative URLs and they failed to display in the WebBrowser control. [For those, who are wondering what a relative and absolute URL is, see below.]

<!-- absolute URL -->
<img src="http://www.mywebsite.com/images/image.gif" />

<!-- relative URL -->
<img src="images/image.gif" />

When i searched for it, few were trying to do a content search and to replace the relative URLs with absolute URLs. Well, this might be needed in some scenarios, but, not in my case, since the content gets rendered in a WebBrowser control.

The Solution

The BASE tag can help us here. For me, I just put the feed content inside an HTML header section with BASE tag as shown below and now my feed renders fine; added the BASE-Target option also to make it better.


<html>
<head>
<base href="http://www.mywebsite.com/images/" />
<!-- in the case of Google API, this was feed's link -->
<base target="_blank" />
<!-- Provided this so that the links will open in new window -->
</head>

<body>
<!-- in the case of Google API, body has feed content -->
<img src="image.gif" />
<a href="http://www.mynewwebsite.com">New Website</a>
</body>
</html>

The Conclusion

Hope this solves the problem for few and the logic (use of BASE tag) will be useful in other scenarios too. As for the Google AJAX Feed API, I'm hoping that Google will fix this in the upcoming versions.

Saturday, February 13, 2010

Create simple and reusable objects for AJAX in JavaScript – ajaxRequest

Well, there are similar ones out there. jQuery, YUI and AjaxObject are just to name a few, which has their own implementations along with other in-built functionalities. Then there is mine, which is done in a much simpler way with the cost of flexibility. If you’re just looking for a simple reusable JavaScript class for making AJAX calls (and AJAX calls only), you're at the right place.

For Beginners:
For the sake of the simplicity of this article, i will not be going in much detail about the basics of HTTP calls, the different modes (POST, GET) of communications and their related topics. Let’s just say that, an HTTP call or an AJAX call can be made to a URL (Ex: http://www.mywebsite.com) using either GET (where URL has all the information like http://www.mywebsite.com?name=john&age=25) or POST (where the form data is submitted as key-value pair like key1=value1&key2=value2 with appropriate header information on the request). Oops! did i just said everything about HTTP calls in one sentence? No, there is more.

The ajaxRequest Snippet
Here is the ajaxRequest’s code. The code is pretty straightforward and is designed in such a way that it works with minimum arguments. There are comments embedded in the code (download from below) and sample usage code provided below to make it’s use seamless.

function ajaxRequest(url, method, postData) {
//validation start
if (url == undefined) return false;
this.method = method == undefined ? "GET" : method.toUpperCase();
if (this.method != "GET" && this.method != "POST") return false;
if (url == undefined || url == "") return false;
//validation end
this.url = url + ((url.indexOf('?') > 0) ? "&ajts" : "?ajts") + new Date().getTime();
var mainCls = this;
this.inProgress = false;
this.xmlHttpObj = null;
this.postData = postData;
this.toString = function() { return "Ajax by Sanal"; }
this.abort = function() {
if (mainCls.inProgress) {
mainCls.xmlHttpObj.abort();
mainCls.inProgress = false;
mainCls.xmlHttpObj = null;
}
}
this.execute = function(statusChangeFunction) {
try {
// Firefox, Opera 8.0+, Safari
mainCls.xmlHttpObj = new XMLHttpRequest();
}
catch (e) {
// Internet Explorer
try {
mainCls.xmlHttpObj = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e) {
try {
mainCls.xmlHttpObj = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {

return false; //No support for AJAX
}
}
}

mainCls.xmlHttpObj.onreadystatechange = function() {
if (statusChangeFunction) {
statusChangeFunction(mainCls.xmlHttpObj.readyState, typeof (mainCls.xmlHttpObj.responseText) == "unknown" ? null : mainCls.xmlHttpObj.responseText, typeof (mainCls.xmlHttpObj.responseXML) == "unknown" ? null : mainCls.xmlHttpObj.responseXML, mainCls.xmlHttpObj.readyState==4 ? mainCls.xmlHttpObj.status : null);
}
if (mainCls.xmlHttpObj.readyState == 4) {
mainCls.inProgress = false;
mainCls.xmlHttpObj = null;
}
}

mainCls.xmlHttpObj.open(mainCls.method, mainCls.url, true);
if (mainCls.method == "POST") {
mainCls.xmlHttpObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
mainCls.xmlHttpObj.setRequestHeader("Content-Length", mainCls.postData.length);
}
mainCls.inProgress = true;
mainCls.xmlHttpObj.send(mainCls.method == "POST" ? mainCls.postData : null);
return true;
}
}

Code Download
The above code with embedded comments, along with the minified version, can be downloaded from here. [In case, if you don't know, minified version will not have the comments and spaces, to keep the file size to a minimum possible, making the server-browser communication faster.]

Sample usage:
Provide a reference

First, let the browser know that it needs to load the script.

If you're using the minified version, change the file name appropriately.

Create an Object
Then, in another scripting place, create an object for ajaxRequest as shown below. In the example below, the testAjax function will be the function that triggers the AJAX call to the server url “ajaxprocessor.aspx” which in turn processes the aynschronous requests. Since there are no other arguments passed, the call is defaulted to a GET call and the URL is expected to have input parameters for server processing.

function testAjax() {
var myAjaxRequest = new ajaxRequest("ajaxprocessor.aspx?name=john");
myAjaxRequest.execute(processMyRequest);
myAjaxRequest = null;
}

One minor point to note here. Among the query strings that are being passed to the URL, it is not recommended to use the key "ajts" (AJAX timestamp) since that is being used by the ajaxRequest to make every AJAX call unique to the browser. This is applicable to both GET and POST requests.

Track your AJAX call
The “processMyRequest” function in the above code is the callback method, that gets executed when for every state change of your AJAX call. A simple implementation of the “processMyRequest” can be something like this. I’m assuming that you have a DIV with the id “myDIV” placed in your web page. [Beginners, you might want to know more about readyState and status for asynchronous calls]

function processMyRequest(readyState, responseText) {            
if (readyState == 1)//loaded
document.getElementById("myDIV").innerHTML = "Loading...";
else if (readyState == 4)//complete
document.getElementById("myDIV").innerHTML = responseText;
}

The callback function can be created with any number of arguments depending on the need. The arguments are in the order as specified in the main ajaxRequest code comments.

The sample approach can be used to make a POST call by changing the object creation as

var myAjaxRequest = new ajaxRequest("ajaxprocessor.aspx","POST","key1=value1&key2=value2”);

Refer the downloaded ajaxRequest code for more technical details on each of these methods and variables.

Browser Compatibility
This code has been tested with IE, Firefox and Chrome and is expected to be working in most of the browsers. If problems are found, share them so that everyone will know.

Enhancements
Well, as mentioned at the beginning of this article, this might not be flexible enough. if you dig deep enough, you might find functionalities that could’ve included to make it better. Feel free to change the code for your usage and let me know what was missing.

Thursday, February 4, 2010

Retrieve an element's width or height using JavaScript

Even though, not 100% browser independent, the following JavaScript code will get you an element's current/rendered width or height. The code is pretty simple and self-explanatory.

Code to retrieve element's width:
function getWidth(element){

    if (typeof element.clip !== "undefined") //netscape
    {
        return element.clip.width;
    }
    else {
        if (element.style.pixelWidth)//opera 
        {
            return element.style.pixelWidth;
        }
        else //IE and firefox
        {
            return element.offsetWidth;
        }
    }
}
Code to retrieve element's height:
function getHeight(element){

    if (typeof element.clip !== "undefined")    //netscape
    {
        return element.clip.height;
    }
    else {
        if (element.style.pixelHeight) //opera
        {
            return element.style.pixelHeight;
        }
        else //IE and firefox
        {
            return element.offsetHeight;
        }
    }
}
Sample Usage:
function usage(){
 alert(getWidth(document.getElementById("yourElementId")));
}
This code works for most of the input (dropdown/select-one/Select-multiple, textbox, textarea) elements in an HTML form. Feel free to share any better solutions.

Thursday, January 7, 2010

Picasa Vs Windows Live Photo Gallery - A quick comparison

If you're someone who went out to choose between Picasa and Windows Live Photo Gallery, don't look further. Picasa is the clear winner. At this instant, there are not even comparable. Read ahead for more information.

User Interface - Intuitiveness and simplicity
    Live photo gallery is simple and easy. The UI is not much congested as Picasa; may be because of the less visible features of Live gallery. Gallery is easy to play with. Picasa's UI has more options with various view modes and sliders all around providing greater flexibility. If your priority is for simplicity, Live Gallery wins here. But if you prefer flexibility, Picasa is the one.

Face Recognition
    This is one place where Picasa rocks! Picasa has the easiest workflow (to assign the names for the detected faces in photos) available. As soon as the photos are added, Picasa scans them and groups them for you to name them. Each naming seems to improve Picasa's intelligence and face detection becomes more reliable and less error-prone. Live Gallery needs more manual activity to add people tags, making the workflow more cumbersome. Both the tools sometimes detects some part of the images as faces, while actually they are not. Live Gallery needs to improve a lot on this aspect.

Image Editing
    Again, Picasa is much better here. You will love the one touch abilities to fix your images and the ability to provide watermark or captions.

Sharing, Syncing, Email and Printing
    Both of them inherently supports their own photo sharing services online. Live Gallery supports adding Plug-ins too for sharing to other sites. Sync is much customizable and powerful operation in Picasa when compared to Live Gallery.

Export
    Picasa allows you to export photos in bulk to the desired quality and size while Live gallery just provides a rename and resize facility for single images. Just in case, if you ended having some raw images for conversion, Picasa does this job much easier. You can even export them with watermarks. Common raw formats are supported by default in Picasa. Windows Live Gallery asks us to install plug-in for this.

Multiple format support for image and video
    Well, this one may vary per user. Based on the formats that i had, Picasa handled all my videos and images without the need of any additional codec installs. Live Gallery did asked me to install additional plug-in.

Tagging
    Picasa has the leading edge here due to the availability of Quick tags and it seems to support all the standard tagging mechanisms like IPTC and EXIF.

Search
    They both performed good here since they all searched based on tags and file names and provided the results.

Additional Features
    Live Gallery provides the facility to make a blog post and to create a Data CD with the images. Picasa goes much further in this aspect with Blogging, Collage, Geo-Tagging, Places association, multiple-image Screensaver, Movie Creation, Poster creation and list goes on...

Conclude Now
    This comparison can go further covering more minute details which doesn’t seem to be necessary for inferring the result. Picasa provides much more flexibility and features in all those individual modules implemented when compared to Windows Live Gallery. Hopefully, we can expect more from Windows Live Gallery in the near future.

If you’re in the lookout for similar tools with comparable capabilities, search for iPhoto (Mac) and Adobe Lightroom.