Tuesday, May 7, 2013

AngularJS Directives - building a DSL with your HTML

I will admit in advance - this content trades off of a great little screencast by Brian Ford from CODEShow on AngularJS directives. Go watch that if you have a little knowledge of AngularJS and 45 minutes to kill... But if not...

What is AngularJS?

Google built AngularJS, a Javascript MVC (well, MV VM, more later) to write single-page web applications. It provides an application framework, which lets you define view templates for your HTML content, register MVC controllers (for handling activities, listening for events and initializing views), build services (stateful or stateless Javascript code for handling integration to outside data sources and sinks), and several other components, including directives.
As I mentioned before, we'll get to directives in a bit. But first, the 5 minute AngularJS sample.

AngularJS in a nutshell

AngularJS provides a bridge between your HTML and Javascript via a nice two-way data-binding mechanism. Angular uses a view model object, which can be set within your controllers, to send data to a page. A one-way example:
To play with this, just click on the various headings (Javascript, HTML, Result). I'm using JSFiddle, an incredibly useful playground where you can quickly cook up snippets of whatever you wish and share them online, even associate them with your GitHub account.

Breakdown - the Module

you can see that we've defined an module named 'demo' (ignore those square brackets for now):
var demo = angular.module('demo', []);
This module defines an application for us. We can eventually register a number of elements in this application, but for now, we'll just set up the application itself so it can be bound to a portion of our page.

The Controller and 'ViewModel'

We then defined a controller called 'MyCtrl':
function MyCtrl($scope) {
...
}
which will automatically inject the magically named 'scope' variable - $scope. Just like Spring or other dependency injection systems, provided you know the service you're injecting, you specify it by name. Built-in and add-on services from Angular generally use the '$' prefix. Yours will not. That's a way of distinguishing user code from system-built code.
The '$scope' variable is a ViewModel - meaning a model specific to display of a template or view. To demystify the whole 'MVVM' term you may have heard, consider the ViewModel is simply the model that is given to the view, so that you can decouple it from your application's internal model, some of which you may not want to share with the page at a given time. Those darn terms...

The View

Now we come to the view. In our case, we've decided to make this view static - meaning that it's embedded into the page. We can certainly set up external views in another post, but for now, let's just focus on the content. You'll notice in the HTML we've defined two special tag attributes that you won't recognize, 'ng-app' and 'ng-controller'.

Greeting

Hi, it's Ken. The current time is {{time}}.
The ng-controller attribute is easy - it tells the page to watch for any data exported from our controller, named MyCtrl, and inject data stored in the $scope variable by its name. You'll notice above we left out our controller implementation. Let's look at it now:
function MyCtrl ($scope) {
    $scope.time = new Date().toTimeString();
}
Now, you can see the linkage - the $scope.time variable becomes {{time}} in the page. But what about the ng-app attribute?

The ng-app attribute defines what the scope of a given application might be on a given page. Like the controller, this limits the exposure of the application to a given area of the page. An application may be composed of elements such as controllers, services, views, directives, etc., and you may have need of Angular on several completely unrelated places on a given page. That's OK, you can create two applications, or an outer application and two related inner applications, all by defining modules. Further, once you start building components you'll likely want to set up more than one controller on a given view page, rather than one monolithic controller and view.

A sample directive

Ok, so let's bring it home. Maybe we want to think of the time as a 'feature' - something we'd use on the page in a few places. What if we wanted it to be referred to by a 'display-current-time' HTML tag? Something like this:
Hi, it's Ken. The current time is
to define a tag like that, you use a directive - a Javascript component that provides an HTML tag, attribute or CSS class with YOUR defined name, that then behaves like a DSL language element in the page.

Defining a directive

Let's begin with what we want our HTML to look like. This is a completely trivial and silly example, but it gives you an idea of what you can do.

Greeting

Hi, it's {{name}}. The current time is .
I didn't want to remove the controller, so I used it to bind the name to 'Ken'. Here's the controller now:
function MyCtrl ($scope) {
    $scope.name = 'Ken';       
}
Ok, our manager is going to freak out. Maybe later we'll externalize this into a form field, and show you that nifty two-way binding.

The directive

Now for the directive. We'll add it to the javascript sample file, and since we've defined our application (demo) above, we simply add the directive to it.
demo.directive('displayCurrentTime', function() {
    return {
        restrict: 'E',
        template: '12:00:03'
    };
});
The directive is given a camel-cased name - displayCurrentTime and in the inimitable Javascript way, we provide the implementation as an inlined anonymous function. The directive must return at least a template to render, and optionally a narrowed-down 'restrict' variable which tells Angular to activate the directive for HTML tags/elements (E), HTML tag attributes (A), or CSS classes 'C'. In the example above, we're going to only activate it for tags.
Angular expects that camel-cased name to turn into a lower-cased, dash-separated name in the HTML. Hence why our tags above are called 'display-current-time'.

Getting dynamic

Now let's get a bit more code-driven and dynamically generate the time.
demo.directive('displayTime', function($parse) {
    return {
        restrict: 'E',
        replace: true,
        transclude: false,
        template: '',
        link: function (scope, element, attrs, controller) {
            var currentDate = new Date();
            element.text(currentDate.toTimeString());
        }
    }});
One key function of a directive is to link the content in the model to DOM elements on the page. We supply a link function definition, and AngularJS injects the element as the second parameter. We then create a Javascript date with an empty constructor (current time) and use the element's text method to send it to the content of the span itself. In more advanced cases, we can supply a compile method, which is more powerful, but for simple cases like this the link method will suffice. Play with this snippet: By the way, if you begin trying to troubleshoot issues with your AngularJS or other framework app, some developers insist you reproduce the core problem in a tool like JSFiddle. It's a good way to play with a sandbox with zero setup.

Marco... Polo!

Let's take this one step further, and implement another directive to provide a business-level component. Perhaps you need to provide a list of user roles in a drop-down element, and you want to notify the rest of the application when you've changed the current one. In AngularJS, a typical way to do this is via a controller and view:

Play around with the values, and open Firebug or your Chrome developer tools (sorry IE users, I'm sure there's a way but I've been a mac user for too long). You'll see the console writing the change as we make it. Note the name of the attributes all begin with ng-. That's short for Angular. These are built-in attributes of the various supported widgets. Read up on the various ngXXX API attributes/elements to learn how to control text boxes, buttons, text areas, and other objects.

The DSL for groups

Let's say you want to set up a widget for group selection, with its own styling and form elements. You might start by coding it directly using a controller/view combination. First, we're using a simple form, with some AngularJS decoration here. From the HTML:
    <form class="userGroup">
        <label for="userGroupSelect">Select a Group</label>
        <select 
            ng-model="currentGroup"
            ng-options="o.value as o.label for o in myGroups"></select>        
        <input type="button" ng-click="applyNewGroup(currentGroup)" value="Switch Group"/>
    </form> 
Now, we'll bring in the AngularJS controller. We'll break this down step-by-step. First, we provide the application and a controller:
var demo = angular.module('demo', []);

function MyCtrl ($scope, $rootScope) {
    $scope.myGroups = [
        {label:'Admin', value:1},
        {label:'Users', value:2},
        {label:'Public', value:3}
    ];
    ...
}
The group list is arbitrary here - we could easily use Angular's $http component or even a RESTful resource to fetch the values. Note that the myGroups scope variable lines up with the curious expression in the ng-options attribute of our select tag. Let's explain that:
o.value as o.label for o in myGroups
What? Ok, this is almost like a select statement. It's one of the things in Angular you have to read through a few times to get it right. This expression assumes we are passing it an array of JS objects (myGroups) and that we're providing both a display and an option for the option tag it generates. Reading the fragments from the right, we first assign an alias 'o' to myGroups (o in myGroups). Then, we provide an optional label in the middle (o.label), and the data value (o.value). Hence, 'o.value as o.label for o in myGroups'. Easy, peasy? Well, nope but it does work. See the select directive and the cries for better documentation in the comments to make sure you're not the only crazy one.

Handling the change event

Rather than immediately changing the group for our application, we want to do it once the user clicks the button. So in that way, our currentGroup model element is transient. To do that, we'll define a function that takes the immediately bound model element currentGroup and broadcasts it to the rest of the application:
$scope.applyNewGroup = function (currentGroup) {
    $rootScope.$broadcast("new group", currentGroup);
};

// this could be anywhere in our application...
$scope.$on("new group", function(obj, value) {
    console.log("Global group switched to " + JSON.stringify(value));
});
You may not have noticed but in our controller, we not only requested $scope, but $rootScope. The root scope is a scope that all controllers in our application can see. If we wanted our controllers to be notified when the user changes groups, we simply call the root scope's $broadcast method, passing it a message and optionally, data to send. We've done that by passing the group id along. To subscribe to a message, in any sub-scope of the application (any controller), we just use the local scope's $on method. The scope is passed the object generating the event and the value passed. Since the value is our group, we accept it.

Put it all together

Now we'll put in the magic sauce. Let's externalize the form into a template string (yes, this can be an URL instead and loaded as a view file) and use the directive function to set it up:
demo.directive('userGroupSwitcher', function() {
    return {
        restrict: 'E',
        replace: true,
        transclude: false,
        template: '<form class="userGroup">
         <label for="userGroupSelect">Select a Group</label>
         <select ng-model="currentGroup" 
           ng-options="o.value as o.label for o in myGroups" />
         <input type="button" 
            ng-click="applyNewGroup(currentGroup)" 
            value="Switch Group"/>
         </form>'
    };
});
Then, to place the tag on the screen, we use:
    <user-group-switcher />
Play around with it here:

Summary

AngularJS is a powerful client-side Javascript application platform. You can use as little or as much of it as you wish. There are tons of samples online about building Angular web applications with simple controllers and forms, but I wanted to show you how to write directives - a way of liberating your domain-specific features from DOM elements, and allowing you to assemble views using business-specific building blocks. You can use directives for anything from menus, to re-use of forms, to wrapping other JS component libraries and widgets, to anything you can think of. Combining directives with Angular's message passing, easy REST/Ajax support, two-way data binding, support for templates and dependency injection, it's hard to pick a better framework (in my opinion) that can get you started quicker or provide you more flexibility without forcing you to build your own skeleton.

Resources

For finding more AngularJS component libraries based on directives, see ngmodules.org. A few of my favorites: Angular Bootstrap, for wrapping / encapsulating Twitter bootstrap features using directive tags and attributes, Angular UI, a set of widgets based on jQuery UI, and one I'm hacking with right now, jQuery Mobile Angular Adapter which tries to settle the score between Angular's dynamic views and jQuery Mobile's jump-link based dialog switching. For hacking around with Angular, please DO use JS Fiddle and search around for some good ones to start from. Feel free to fork any of mine to get going. In my next article, I'll show you more of the inner workings of Angular directives. If you want to learn that beforehand, go to the above-mentioned projects' github pages and start reading. Marco!

Thursday, April 25, 2013

Setting Realistic Expectations For Mobile App Development

This article was originally seen in the May issue of SmartCEO. It was written by Mike Rappaport, CEO of Chariot Solutions.

One common misconception about mobile application development is that it's much easier and less expensive than traditional software creation.  We've all heard stories about an app that was developed overnight, released in the app store, with the app quickly becoming a big success. This is usually not the case.  In reality, developing a mobile solution is sometimes more costly and difficult to implement for most businesses.

Since mobile applications are delivered on smaller screens and tend to have a more focused purpose, the thought is that they should be less expensive to develop than traditional applications. So why isn't that the case?

The main reason is that mobile application development still needs to adhere to the same processes as traditional software development. All software development should include planning, requirements definition, design, development, testing, delivery and support.  Along with an effective development process, delivering a quality solution requires having the right people in the right roles.

Since mobile applications have a more focused purpose than traditional applications, it is even more important that business, creative and development resources work together to clearly define and deliver a successful application.

Moreover, mobile development faces additional challenges that most traditional applications may not experience.  The most significant challenges include: variety of devices, user interface paradigm shifts, network connectivity, testing and distribution.

Mobile devices come in a variety of sizes, shapes, and platforms.  The type of devices to be supported will have a direct impact on the cost of development.  The major platforms are iOS (iPhone and iPad) and Android. But what if the user base includes Windows Phone or BlackBerry? What about tablets versus phones? Even within tablets or phones, device sizes can vary from a design, development and testing perspective.

User interfaces on mobile devices rely on the user touching a small screen with their finger or thumb.  This is a very different experience from traditional applications.  This not only forces designers to rethink how users interact with applications, but it requires a design that is intuitive.  These designs also need to adapt to varying screen sizes and take into account the size of a finger as opposed to the point of a cursor.  A poorly designed (yet typical) web form in a traditional application might include 15 or more fields with descriptions on what acceptable values might be.

How does that fit on a 3.5 inch screen?  Challenges like this require more creative solutions, which subsequently have a direct impact on cost.

Imagine entering 15 fiels of data using thumbs, only to find that the network suddenly became unavailable during the submission.  How does the application handle that? As with traditional applications, data integrity and security are a major concern on mobile devices. However, network availability is much more variable on mobile devices.  Also, data can be more vulnerable on mobile devices, simply due to the fact that devices are mobile. Accessing and handling mobile data introduces additional complexity into the design and implementation of mobile applications.

As features are developed, testing of mobile applications becomes even more important.  How a touch-based application looks, feels and reacts can vary significantly from device to device.  It is critical to get the applications deployed onto devices and in the hands of users early and often.  Depending on the size of the application, this can lead to longer testing cycles.

Finally, once development is complete, it must be distributed.  This process varies from platform to platform.  There may be additional effort required to prepare the application for submission to an App Store. The time for submission and potential rejection need to be accounted for when planning the project.

The bottom line is that developing mobile applications is much like developing software for other platforms, with some additional complexities.  But the recipe for success is the same: It takes the right people and an effective process to be successful.  When all of this is done properly, it has been proven that mobile applications have the ability to dramatically improve, and in some cases transform businesses.  Business leaders need to understand that though the cost of mobile application development may be high, the ROI can be much higher.

Tuesday, April 9, 2013

The Pivotal Initiative - the future of Spring and open source at VMware/EMC



EMC and VMware have poured their open source software development workforce into a new wholly-owned subsidiary, dubbed "The Pivotal Initiative". This organization will focus on data science consulting and tooling from GreenPlum, including SpringSource/vFabric development teams.

It is being girded by a team of forward-looking developers at Pivotal, a recent EMC purchase and well known for their work with Ruby tools and testing software.

Until now, Pivotal has not yet discussed their strategy for the SpringSource teams. Adrian Colyer, one of SpringSource's spiritual leaders, here outlays what the future will hold, including support for Java 8 Lambdas (closures) in Spring 4, Groovy, Grails, and Cloud Foundry. 

Monday, March 18, 2013

Training Courses on Tap for Spring 2013

It's that time again. Flowers are sprouting, pollen is flowing, and, lo and behold, Chariot is running more training...

We have some exciting additions to our courses this quarter, including a guest course by Neosoft, our usual Spring training courses, a Groovy and Grails offering, and more. Here's our lineup:

  • March 26-28 - Comprehensive Maven 3 and Nexus training - We are running a 3 day maven intro, intermediate and advanced course starting on March 26. You'll learn how to build Java application with Maven, including JARs, WARs, and multi-module projects.
  • April 9-12 - Core Spring Developer Training/Certification - Recently updated, this course covers Spring 3.1 and above, all three styles of dependency injection (XML, annotations, JavaConfig), JDBC, Hibernate/JPA, an introduction to Spring Web MVC, Security, JMX and more. A deep discussion of the Spring lifecycle and features such as proxying, interface-driven development, JUnit-based testing and Aspect Oriented Programming provides a strong foundation for new Spring developers.
  • April 17-19 - Neo4j Tutorial by Neo Technology - We are featuring a guest training course by NeoSoft, discussing their NoSQL Graph database, Neo4J. This is a two-day course to get developers up to speed in using Neo4J.
  • April 30-May 3 - Groovy and Grails v2.0 - new for Chariot training, we're featuring a four-day Groovy and Grails training course, written by the developers of Grails at VMware. This course begins with a heavy introduction to the Groovy programming language, and then dives into Grails, the convention-driven Spring-and-Hibernate application framework. Configuration, controllers, services, scaffolding, testing, writing plugins, and GSP tags are covered.
  • May 9-10 - Advanced Scala - This Typesafe course, taught by Michael Pigg, takes our Scala training even further than Fast Track to Scala, and includes a deep dive into functional programming concepts, internal DSLs, custom Scala collections, and details on the Scala type system.
As usual, we offer discounts for Chariot training alumni. Contact us for information on obtaining a discount code - please provide your name, course, and estimated training date. We also provide private training and can offer courses in Hadoop, Java, Tomcat, and other technologies. Check our course catalog for more information.

Friday, March 15, 2013

Recap - Chariot Day 2013 - Our internal conference...

One thing Chariot people love to do is learn new technologies and techniques. Being consultants constantly challenged in the field, keeping our blades sharp is key to doing battle. Every year or so we get together and run our own internal conference to see what each of our current passions are. We call it Chariot Day.

Earlier this month, on a Saturday, we had two rooms going from 9-5PM, each with 45-minute sessions on subjects such as:
  • Becoming a better programmer, Mythbusters Style
  • Async networking for Android w/Robospice
  • A great session on zsh
  • Data Mining - it's not just for kids
  • Universal EventBus with Vert.x
  • Functional programming with Scala
  • Single-page Javascript with AngularJS
  • Billions of Things (you can imagine scalability and performance on a large scale)
  • Having fun with the Raspberry Pi
  • HTML5 Canvas
  • Understanding the Persistent Data Structures of Clojure
  • Get low w/HBase
  • Getting started with Phone Gap
  • 20 tools that turbo charge a 1.51 person development team
We will be reviewing the content from these sessions to see if we can share them with you. 

Wednesday, March 13, 2013

Take (and Manipulate!) a Photo with a Web Page

So not that long ago, if you wanted an app to take a photo, it had to be a native app -- such as a Windows/Mac app or a native mobile application.  But HTML5 has brought a number of new APIs that allow not only taking photos, but analyzing and manipulating them all within a browser.

Sadly, there is still inconsistent support for these features across browsers (both desktop and mobile).  So in practice, the best approach may be to target the APIs supported by iOS 6, which is more or less the minimal feature set across browsers that support any of this at all.

The three pieces we'll need are:
  • The Canvas
  • File I/O
  • Changes to the File Upload input and Media Capture
    • Note that Media Capture has been superceded by getUserMedia (more info) but we don't use that here because iOS doesn't support getUserMedia yet

The Canvas is a space on the page to draw into, using either 2-D or 3-D APIs.  Conveniently, it also lets you draw images into it, inspect and alter the pixel data, and export its content as an image. Canvas is supported by IE 9 and modern versions of Firefox, WebKit/Safari/iOS 6, Opera, and Chrome.  However, not all browsers support 3-D (via WebGL), and browsers don't generally support ALL of the Canvas spec (which has continued to evolve even after initial browser support).  Still, the parts we need are supported across browsers.

The additional "accept" and "capture" attributes on the file upload input element let us specify that the user should be able to select an image file, getting it from an attached camera if possible.  Crucially, on iOS you are given the option to select a photo from the photo library or take a photo on the spot (though some desktop browsers only let you browse for an image file, even if a Webcam is attached). Then the "files" property on the input element lets us access the selected files (unfortunately, not supported in IE < 10).

So the formula for taking and manipulating a photo is:
  1. Configure a file input using the new attributes
  2. When an image file is selected (or photo taken), access the image file
  3. Check the image EXIF data for rotation using File I/O
  4. Decide what size to scale the image to (if needed)
  5. Configure a Canvas for the selected image dimensions
  6. Draw the image to the Canvas, rotating and scaling as appropriate
  7. Access and manipulate the pixel data for the Canvas
  8. Write the pixel data back to the Canvas
  9. Export the image on the Canvas as an image file

Taking these one step at a time (and note that I use jQuery for convenience, but it is not needed for this to work):

1. Configure a file input using the new attributes

There are two ways to configure the input (and it makes no difference to desktop browsers). An input configured like this will prompt the user to take a photo or select a saved impage on either iOS or Android:
<input type="file" id="PhotoPicker"
       accept="image/*" />
With the additional capture="camera" attribute, Android goes directly to the camera without giving the option to use a saved photo (though the iOS behavior is the same):
<input type="file" id="PhotoPicker"
       accept="image/*" capture="camera" />
Note that if you don't like the default appearance, you can conceal the input widget and connect a button or link (styled any way you like) to activate it.  The input doesn't work if set to display: 'none', but we can put it inside a div of size 0 to effectively hide it:
<div style="width: 0; height: 0; overflow: hidden;">
    <input type="file" id="PhotoPicker" 
           accept="image/*" capture="camera" />
</div>
<button class="lovely" id="PhotoButton">1. Select Photo</button>
$('#PhotoButton').click(function() {
    $('#PhotoPicker').trigger('click');
    return false;
});

2. When an image file is selected (or photo taken), access the image file

We just use the new files property on the input:
$('#PhotoPicker').on('change', function(e) {
    e.preventDefault();
    if(this.files.length === 0) return;
    var imageFile = this.files[0];
    ...
});

3. Check the image EXIF data for rotation using File I/O:

All images may have a rotation recorded by the camera, such that no matter how the camera was oriented when the photo was taken, the image can be displayed appropriately on screen.  In particular, an iPad considers the landscape orientation to be normal (though it can still be upside-down), and the portrait orientation takes photos with a 90 degree rotation.  The EXIF header in an image records this rotation, so we can read it in order to display the image appropriately.

This part uses two open source (MPL) EXIF-reading scripts:
<script src="http://www.nihilogic.dk/labs/exif/exif.js"
       type="text/javascript"></script>
<script src="http://www.nihilogic.dk/labs/binaryajax/binaryajax.js"
       type="text/javascript"></script>
Then we use the new File API to read the image data (and there's a nice image here describing the EXIF Orientation codes):
var width;
var height;
var binaryReader = new FileReader();
binaryReader.onloadend=function(d) {
    var exif, transform = "none";
    exif=EXIF.readFromBinaryFile(createBinaryFile(d.target.result));

    if(exif.Orientation === 8) {
        width = img.height;
        height = img.width;
        transform = "left";
    } else if(exif.Orientation === 6) {
        width = img.height;
        height = img.width;
        transform = "right";
    }
    ...
};

binaryReader.readAsArrayBuffer(imageFile);

4. Decide what size to scale the image to (if needed)

If you want to limit the size of the image, you can scale the height and width accordingly. With mobile devices with high-resolution cameras, this may be necessary to limit memory usage:
var MAX_WIDTH = 1024;
var MAX_HEIGHT = 768;
if (width/MAX_WIDTH > height/MAX_HEIGHT) {
    if (width > MAX_WIDTH) {
        height *= MAX_WIDTH / width;
        width = MAX_WIDTH;
    }
} else {
    if (height > MAX_HEIGHT) {
        width *= MAX_HEIGHT / height;
        height = MAX_HEIGHT;
    }
}

5. Configure a Canvas for the selected image dimensions

If the canvas is on the page, you can just grab it:
var canvas = $('#PhotoEdit')[0];
Otherwise, you can use an offscreen canvas:
var canvas = document.createElement('canvas');
And then size it accordingly:
canvas.width = width;
canvas.height = height;

6. Draw the image to the Canvas, rotating and scaling as appropriate

In order to draw the image to a Canvas, first we have to load it in an <img />, and a convenient way is to create a URL to assign as the img.src from the selected file (using part of the File API):
var img = new Image();
var url = window.URL ? window.URL : window.webkitURL;
img.src = url.createObjectURL(imageFile);
img.onload = function(e) {
    url.revokeObjectURL(this.src);
    ...
};
Then inside the onload handler, we can draw the image to the canvas. (In practice, I put most of the logic we're discussing inside the onload handler.) A transformation matrix on the context handles rotating the image (if needed) and shifting it back into the viewable area.
var ctx = canvas.getContext("2d");
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, 700, 600);
if(transform === 'left') {
    ctx.setTransform(0, -1, 1, 0, 0, height);
    ctx.drawImage(img, 0, 0, height, width);
} else if(transform === 'right') {
    ctx.setTransform(0, 1, -1, 0, width, 0);
    ctx.drawImage(img, 0, 0, height, width);
} else if(transform === 'flip') {
    ctx.setTransform(1, 0, 0, -1, 0, height);
    ctx.drawImage(img, 0, 0, width, height);
} else {
    ctx.setTransform(1, 0, 0, 1, 0, 0);
    ctx.drawImage(img, 0, 0, width, height);
}
ctx.setTransform(1, 0, 0, 1, 0, 0);

7. Access and manipulate the pixel data for the Canvas

The getImageData method returns an array of pixel data, with one byte each for red, green, blue, and alpha. This example applies a "green screen" effect, setting pixels to transparent (alpha = 0) if they are mainly green.
var pixels = ctx.getImageData(0, 0, canvas.width, canvas.height);
var r, g, b, i;
for (var py = 0; py < pixels.height; py += 1) {
    for (var px = 0; px < pixels.width; px += 1) {
        i = (py*pixels.width + px)*4;
        r = pixels.data[i];
        g = pixels.data[i+1];
        b = pixels.data[i+2];
        if(g > 100 && g > r*1.35 && g > b*1.6) pixels.data[i+3] = 0;
    }
}
There are of course other possibilities for filtering the image.

8. Write the pixel data back to the Canvas

Then we use putImageData to write the array of pixel data back to the canvas.
ctx.putImageData(pixels, 0, 0);

9. Export the image on the Canvas as an image file

Finally, the whole content of the canvas can be exported as an image. There may be a way to do this through the browser (in Firefox, for instance, right-clicking on any Canvas lets you view it as an image), but there is a canvas API call as well. Every browser supports saving the image as a PNG, and some may support other formats:
var data = canvas.toDataURL('image/png');
The resulting data URL looks like this:
data:image/png;base64,...
Where the "..." is the base 64 encoded version of the binary image file. So you can, for instance, upload the data URL to a server as a form field, and the server can strip off the data:image/png;base64, prefix and base 64 decode the rest and save it to a file like mycanvas.png.

Summary

So there you have it -- a Web page that takes a photograph, scales and orients it as appropriate, processes the image as desired, and then displays it to the user and/or uploads it to a server.
Unfortunately, there is not yet a way to present a "Save As" dialog to the user to save the file directly to their local disk -- the FileSystem and FileWriter APIs are not widely supported across browsers. But you can of course upload the image to the server and then redirect the user to a server URL to save it...

Consolidated Sample Code

Here's a single page with a working example using the code we've gone through here.

You can also use this sample image to see the green screen replacement effect.

Platform Support

Bold entries work fully:

Desktop Browsers:
  • Firefox 18
  • Safari 6
  • Chrome 25
  • IE 10
  • IE 9 (does not support getting selected files from file input)

Mobile Browsers:
  • iOS 6
  • iOS 5 (file input doesn't work)
  • BlackBerry 10
  • Android 4.1 (built-in browser)
  • Android 4.1 with Chrome from Play store
  • Android 2 (native browser; does not take photo)
  • Windows Phone 8 (file input doesn't work)
  • Surface RT (doesn't work)

Saturday, March 9, 2013

Configuring the Network used by Mac OS X Internet Connection Sharing

Changing the Subnet

On Mac OS X, Internet Connection Sharing by default hands out IPs on the 192.168.2.x subnet.  Normally this is fine, but sometimes you might want to change it (because you're at a hotel that uses 192.168.2.x or whatever).

The network to use is configured in /etc/bootpd.plist, but that file is overwritten every time you start Internet Connection Sharing (and deleted when you stop it).

The easiest way to change the network is to shut down Internet Connection Sharing, close System Preferences entirely (since it keeps settings in memory and overwrites configuration files), and run the following Terminal command (replacing the last parameter with the network you want it to use):

sudo defaults write \
   /Library/Preferences/SystemConfiguration/com.apple.nat \
   NAT -dict-add SharingNetworkNumberStart 192.168.3.0

Then you can go back into System Preferences and start Internet Connection Sharing again.  If you look at /etc/bootpd.plist you should see the new network listed.


Static IPs for Connected Devices

If you want to assign static IPs to any devices, you can create the file /etc/bootptab like this:

# Bootptab file
# Section 1 -- ignored
%%
# Section 2 -- used
# Hardware types: 1=Ethernet, 6=Wireless
#                 See http://www.ietf.org/rfc/rfc1700.txt
#
# machine entries have the following format:
#
# hostname         hwtype     hwaddr         ipaddr   bootfile
some-ethernet-machine 1 c4:2c:03:3a:7f:65 192.168.3.200 boot
a-wireless-machine    6 60:33:4b:27:6c:62 192.168.3.201 boot
another-ethernet      1 00:0d:93:72:e7:96 192.168.3.202 boot

You can man bootptab, though it isn't very helpful, and man bootpd has only a little more.  Bottom line, there must be a line with %% and the static IP definitions come after that.  The first parameter is the machine name, the second is the hardware type, the third is the Ethernet address of the relevant network interface of the machine, the fourth is the IP to assign, and the last is a boot file (which we aren't using, but it might be necessary to have something there).

Make sure to restart Internet Connection Sharing after editing this file.