Serialising A JavaScript Object To JSON

As part of my Draw Something Solver I needed to convert a JavaScript object to a string of JSON data. In the past I’d have resorted to a bit of library code, but as I am coding to a recent version of Safari, I thought I’d try to inbuilt JSON functions available to a modern browser.

The method I needed is JSON.stringify(), and it’s very easy to use.

var text = JSON.stringify(myObject);

The above example serialises myObject into text.

There is an equivilant method, JSON.parse() that can be used to safely take a text JSON string and turn it into an object without relying on JavaScript’s eval() function.

There is a useful chart showing JSON support in modern browsers over at caniuse.com.

Draw Something Solver – First OCR Attempt

As part of my Draw Something Solver, I have worked out how to load and extract images from an HTML 5 canvas, now I need to work out what letters the images represent.

I am hoping that as the images of the letters are all computer generated I can simply compare them and create a lookup table.

I initially tried a basic serialisation by running join() over the ImageData as it was type of array, but this didn’t work as it wasn’t an array as such.

Canvases offer a toDataURL() method, that saves the canvas out as a base64 encoded png or jpeg image. Base64 is a text based encoding, so could be suitable. When I tried this, I found the string to be very long, and not very pratical to use.

So I have a long unique string I need to perform a lookup and match against, this is crying out for a hashing function to turn it into something more manageable.

JavaScript doesn’t have a native hashing function like some languages. I found a good JavaScript SHA1 script so used this to get the encoded images down to a more manageable 40 characters.

Running the resulting code over several images has produced some disappointing results. Not all letters appear to consistantly encode to the same SHA1 hash, which means there is some tiny difference in the images of the letters sometimes, even though visually they look the same to the human eye.

I now need to look at another approach for letter detection. There are two I can think of, the first is to convert the image into one less complex, a simple black and white image that should hopefully be more likely to match. The second is to investigate full OCR technology.

I have looked at Grayscaling Image With Perl in the past, so I hope I can reuse that knowledge again with this project.

Extracting And Drawing Part Of An Image Into An HTML5 Canvas

As part of my Draw Something Solver, I need to be able to extract the letters from the screenshot image.

I’ve already looked at loading an image into a HTML 5 canvas object in an earlier post, so I will assume that code is already in place.

It’s actually very easy to extract part of an image from a canvas, we just need to use the getImageData() method from the canvas context object. This takes 4 parameters, the x and y coordinates for the top left corner of the image, and width and height to extract.

var letterImageData = dsCanvasContext.getImageData(27, 782, 72, 71);

In this case, I’m cutting out a 72×71 block starting from the coordinates 27,782.

If you need to paste this extract into another canvas, or even the same canvas, you can use the putImageData method on the canvas context object. This takes 3 parameters, the ImageData you wish to draw into the canvas, and the top left x and y coordinates to draw it into.

dsCanvasContext.putImageData(letterImageData,0,0);

This will post into the top left hand corner of the original canvas.

Loading An Image Into An HTML5 Canvas

As part of my Draw Something Solver, I need to be able to load an image into an HTML 5 Canvas. I thought I’d share the solution to help others.

Firstly, assume you have an HTML page with an empty canvas element called drawsomething. Secondly, assume the image you want to load is next to the HTML page and is called testimage.png.

I’m not usng a framework like jQuery in this example, so the code may a bit verbose.

Firstly, you want the code to run when the page has finished loading, the easiest way to do this is to tie into the window.onload event. If yoou were using jQuery or similar, ready would be a good point to use.

window.onload = function() {
  // code goes here
}

Now we need to get the canvas element and it’s context. We can do this with the following code.

var dsCanvas = document.getElementById('drawsomething');
var dsCanvasContext = dsCanvas.getContext('2d');

We need an Image object to load the image into…

var screenshotImage = new Image();

When the image has been loaded, we need to draw it into the canvas. Do to this we can hook into the image objects onload event and place our canvas manipulation code into an anonymous function that is called when the event triggers.

Inside the anonymous function, we resize the canvas to the same size as the image and call the canvas context’s drawImage() method, passing in the image, it’s start x and y coordinates, and the width and height of the image.

screenshotImage.onload = function() {
  dsCanvas.width = screenshotImage.width;
  dsCanvas.height = screenshotImage.height;
  dsCanvasContext.drawImage(screenshotImage,0,0,screenshotImage.width, screenshotImage.height);
}

Finally, we assign a filename to the image object’s src attribute. This will cause the image object to load the image, and when loaded it will trigger the onload event we have just written to draw the image into the canvas.

screenshotImage.src = "testimage.png";

The complete example looks like this…

window.onload = function() {
  var dsCanvas = document.getElementById('drawsomething');
  var dsCanvasContext = dsCanvas.getContext('2d');
  var screenshotImage = new Image();
  screenshotImage.onload = function() {
    dsCanvas.width = screenshotImage.width;
    dsCanvas.height = screenshotImage.height;
    dsCanvasContext.drawImage(screenshotImage,0,0,screenshotImage.width, screenshotImage.height);
  }
  screenshotImage.src = "testimage.png";
}

Next time, I will look at how to manipulate the image that has just been loaded into the canvas.

Draw Something Solver – The Platform

I have been putting some more thought into how to build my Draw Something Solver.

I have decided as I use Draw Something on my iPhone 4S, the solver should really run on there. This means coding using Objective C, or using HTML 5 and JavaScript.

As I haven’t written an HTML and JavaScript application for a while, and as it’s more fun, I think this should be the technology to use.

The only difficulty I can see is in getting screenshots from Draw Something into the application. Phonegap looks like it exposes some functionality to achieve this in JavaScript, so it looks like a good idea to use this as well. It also gives me the bonus of being able to create a native iOS application I could choose to upload to the App Store if I wanted, and also look a producing a version for Android in the future.

To give the application a native look and feel, using something like jQTouch or jQuery Mobile would make sense. jQuery Mobile has quite a lot of buzz at the moment and I’ve not had the opportunity to use it before, so I think I’ll try it out in this project.

Handling HTTP And HTTPS Ads With JavaScript

A few days ago I wrote about a problem I had with some javascript ad code defering execution. Well another problem arose today with the code, and I thought I’d share the solution.

Some pages on the site I’m developing on are served over https, others are served over http. They share a common template so the same ad code is served across all pages. At the moment they serve purely over http, and this is great most of the time, however when the page is served over https a security alert is shown asking the user if they want to show unsecure content. Most users would say no in this situation so our ads won’t be shown.

What we need is a way for ads to be shown if a user is on a secure or normal connection.

Thankfully our ad provider allows us to request the same ad in either http or https by just changing the protocol, e.g. http://ad... or https://ad... .

The ad is written out using a document.write statement and is meant to be executed as the page is rendering.

We need to detect how the current page is being served, so we know what protocol to request the ad in.

This is easy in JavaScript, we can just query the value document.location.protocol. This returns either ‘http:’ or ‘https:’. Note the trailing colon…

We can use the value document.location.protocol directly, but just incase another protocol has been used, we can default everything to http if https hasn’t been used. The following code will help here…


var protocol = 'https:' == document.location.protocol ? 'https' : 'http';

Here we are seeing if document.location.protocol is the value ‘https:’, if it is set the value of protocol to ‘https’, else set it to ‘http’.

Let’s look at the original ad code…


<script type="text/javascript">
<!--
if (window.adgroupid == undefined) {
window.adgroupid = Math.round(Math.random() * 1000);
}
document.write('>scr'+'ipt language="javascript1.1" src="http://adserver.adtech.de/addyn|3.0|311.0|3328078|0|225|ADTECH;cookie=info;alias=FindClassicCars+Maserati+7+leaderboard;loc=100;target=_blank;key=key1+key2+key3+key4;grp='+window.adgroupid+';misc='+new Date().getTime()+'"></scri'+'pt>');
//-->
</script>

We can take our earlier ternary expression to embed the protocol directly into the ad code like this.


<script type="text/javascript">
<!--
if (window.adgroupid == undefined) {
window.adgroupid = Math.round(Math.random() * 1000);
}
document.write('>scr'+'ipt language="javascript1.1" src="'+( 'https:'==document.location.protocol?'https':'http') +'://adserver.adtech.de/addyn|3.0|311.0|3328078|0|225|ADTECH;cookie=info;alias=FindClassicCars+Maserati+7+leaderboard;loc=100;target=_blank;key=key1+key2+key3+key4;grp='+window.adgroupid+';misc='+new Date().getTime()+'"></scri'+'pt>');
//-->
</script>

The ad code will now serve ads to our customers if they are on either a normal or secure page, and our ad team is happy again.

Defering Inline JavaScript Problems

I came across an interesting problem trying to debug a website that had issues with some ad code earlier. The site was working fine until ad code had been added, then in Internet Explorer it was only showing the ad instead of the page. Firefox, Safari and Chrome were fine, so it suggested a problem with the ad code.

The ad code in question was pretty common, the sort that inserts a script tag via a document.write.

<script language="javascript" defer="defer" async >
<!--
if (window.adgroupid == undefined) {
window.adgroupid = Math.round(Math.random() * 1000);
}
document.write('>scr'+'ipt language="javascript1.1" src="http://adserver.adtech.de/addyn|3.0|311.0|3328078|0|225|ADTECH;cookie=info;alias=FindClassicCars+Maserati+7+leaderboard;loc=100;target=_blank;key=key1+key2+key3+key4;grp='+window.adgroupid+';misc='+new Date().getTime()+'"></scri'+'pt>');
//-->
</script>

The problem turned out to be with the attribute defer in the script tag.

Defer gives the browser a clue that a piece of JavaScript can be run later, rather than as soon as the browser sees it. This can be used to speed up the rendering of a site. However, Internet Explorer runs differently to other browsers. As the script in question was inline, all the other browsers ran it immediately, whereas Internet Explorer didn’t. On Internet Explorer the code was run once the page DOM had been created, so writing out the fresh tags after the document was closed. This caused the ads to show on what looked like a new page on IE’s below version 9, and on IE 9 the ads appeared at the bottom of the page.

The fix is to simply remove the defer attribute and change the the opening script tag to the following, leaving the rest of the ad tag in place.

<script type="text/javascript">

You may have noticed I’ve ignored the async attribute that was in the original script tag. That’s an interesting new attribute in HTML5, but alas a topic for another time.

JavaScript Date, Time And Node.js

JavaScript Dates and times seem to pose a bit of problem to JavaScript developers. Looking at the access logs to my website, one of the most popular popular pages is about Writing a Daytime Server In Node.js. However, most people are actually searching for how to use a JavaScript Date in Node.js.

I thought I’d put together a few notes for those developers struggling use dates and times in node.js.

The good news is that as node.js is just a server side version of Google’s V8 JavaScript engine, node.js developers have full access to the JavaScript Date object.

A date in JavaScript is represented behind the scenes as the number of milliseconds since midnight on January 1st, 1970 (01-01-1970 00:00:00).

Initializing A JavaScript Date

To create a new Date object in node.js, or JavaScript in general, just call it’s initializer.

var now = new Date();
var now = new Date(milliseconds);
var now = new Date(dateString);
var now = new Date(jsonDate);
var now = new Date(year, month, day);
var now = new Date(year, month, day, hour, minute, second, millisecond);

dateString must be an RFC1123 compliant timestamp, I’ll come to jsonDate in just a minute.

Remember that Date objects can only be instantiated by calling Date or using it as a constructor; unlike other JavaScript object types, Date objects have no literal syntax.

Dates In JSON

Node.js offers great native JSON support, and that extends to encoding and decoding dates. Dates were not part of the original JSON specification, so it’s always been down to developers to decide on the best approach in the past. Things have changes, and now the standard is to use an ISO 8601 formatted date string.

To convert a date to JSON format, we can use the toJSON method of the Date object. This is a fairy new addition to the JavaScript language and is only supported in version 1.8.5 and above. Thankfully node.js supports this out of the box.

var now = new Date();
var jsonDate = now.toJSON();

To convert back, we just pass an ISO 8601 date string back into the JavaScript Date constructor.

var jsonDate = "2011-05-26T07:56:00.123Z";
var then = new Date(jsonDate);

Getting Specific Date Details

The JavaScript object provides various getters to extract information from the Date object. These include getDate to get the day of the month, getMonth to get the month (more on that in a minute), getFullYear to get the year (more on that in a minute as well), getHours, getMinutes, getSeconds, getMillisconds, as well several more.

There are a few gotcha’s here. The one that gets most people firt time, is that getMonth returns the current month, but months according to the Date object run between 0 and 11 instead of 1 to 12 as you are probably used to. The second is that the getYear method only returns a two digit date, you really want to use getFullYear as that returns a four digit date.

Setting Specific Date Details

To compliment the getters, there are mirror setter functions. These include setDate, setMonth, setFullYear, setHours. setMinutes, setSeconds, setMilliseconds as well as several more.

Manipulating Dates

You will probably want to manipulate the Date objects you have.

Let’s see what the time is in 6 hours time.

var myDate = new Date();
myDate.setHours(myDate.getHours() + 6);

But what about the time in 100 hours time? No problem…

var myDate = new Date();
myDate.setHours(myDate.getHours() + 100);

The JavaScript Date object is clever enough to change the date correctly.

I hope this has given you a few pointers on how to use dates and times in node.js.

Detecting Retina Displays From JavaScript And CSS

I was looking at how to target Apple’s retina display for high resolution web pages earlier.

My first attempt was to look at the user agent string, but an up to date iPhone 4 sends the same string as an up to date iPhone 3GS.

A quick look around the internet reveals the solution for JavaScript is to actually use the window.devicePixelRatio property.

For a standard browser, this will be 1. However, on a retina display it will 2 – meaning twice the pixels.

For example…

if (window.devicePixelRatio >= 2) {
// retina display
} else {
// standard display
}

You can check your current devicePixelRatio using the following…

<script type="text/javascript">
document.write("Your browser has a devicePixelRatio of " + window.devicePixelRatio + "");
</script>

Apple aren’t the only ones using this in their webkit based browsers, you can read how to target device pixel density on Android. Android defines a density of 1 to be medium density, anything 1.5 or above as high density and anything under 0.75 to be low density.

On the client side we can use this to decide if we want to bring in retina quality imags, or standard ones. There is a jQuery plugin called Retina that does this.

If want to to pass display information back to the server to decide what images to render, this is a bit more complicated.

The best way to approach this would be to have a JavaScript set a cookie containing the devicePixelRadio and have the server read this back. A quick Google reveals that Ben Doran is doing just this, Detecting the iPhone4 and Resolution with Javascript or PHP.

Here’s Ben’s example code (slightly tweaked)…

<?php
if( isset($_COOKIE["pixel_ratio"]) ){
$pixel_ratio = $_COOKIE["pixel_ratio"];
if( $pixel_ratio >= 2 ){
echo "Is HiRes Device";
}else{
echo "Is NormalRes Device";
}
}else{
?>
<script type="text/javascript">
writeCookie();
function writeCookie()
{
the_cookie = document.cookie;
if( the_cookie ){
if( window.devicePixelRatio >= 2 ){
the_cookie = "pixel_ratio="+window.devicePixelRatio+";"+the_cookie;
document.cookie = the_cookie;
location = '<?=$_SERVER['PHP_SELF']?>';
}
}
}
</script>
<?php

A different approach could be to use CSS and media types. Webkit browsers like Safari on an iPhone have -webkit-min-device-pixel-ratio, Gecko browsers like Firefox have -moz-device-pixel-ratio.

An example using this approach on webkit could be

<link
rel="stylesheet"
type="text/css"
href="/css/retina.css"
media="only screen and (-webkit-min-device-pixel-ratio: 2)"
/>

Writing A Daytime Server In Node.js

I’ve previously written about using node.js as a simple UDP listener, now I thought I’d expand on this and give an example of a node.js application that works as both a UDP and TCP server.

A simple service that offers both UDP and TCP connections would be the Daytime Protocol, as defined in RFC 867. It listens to port 13 for both TCP and UDP connections, and returns the current date and time. Your local computer may well have this function enabled, to test the TCP version, you can simply telnet to port 13 and see what is returned.

telnet localhost 13

If you find you don’t have a local Daytime service running, try calling the one at time.ien.it, you should see something like this…

$ telnet time.ien.it 13
Trying 193.204.114.105...
Connected to ntp.ien.it.
Escape character is '^]'.
12 APR 2011 18:51:11 CEST
Connection closed by foreign host.

As you can see it simply returns the date and time before closing the connection.

We could write something like this very easily in node.js. In this case we’ll return the date in JavaScript’s UTC string format instead to keep it simple.

var net = require('net');
var port = 1300;
var now = function() {
  var date = new Date();
  return new Buffer(date.toUTCString() + "rn");
};
var tcpserver = net.createServer(function(c) {
  c.write(now());
  c.end();
});
tcpserver.listen(port);

We can test this by telneting to localhost on port 13

$ telnet localhost 1300
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Tue, 12 Apr 2011 17:17:55 GMT
Connection closed by foreign host.

Let’s take a quick detour into what the code is doing if you’ve not used node.js for any network programming before.

We require('net') so we can use node.js’s network socket support.

The now() function simply returns a Buffer with the current UTC date and time string in. A Buffer in node.js refers to the raw memory used behind the data, in this case our string with the date and time in.

Finally, we create the server, and add a callback function that is called when something connects to the socket. In this case we’re just writing out the contents of the now() function and ending the connection. Last but not least, we tell the socket which port to listen on.

We can see that this code works, but the Daytime protocol also offers a UDP service on the same port that can return the date and time string to a client.

Let’s add in some code to support this. We’ll assume our now() function and port variable are available already.

var dgram = require('dgram');
var udpserver = dgram.createSocket("udp4", function(msg, rinfo) {
  var daytime = now();
  udpserver.send(daytime, 0, daytime.length, rinfo.port, rinfo.address);
});
udpserver.bind(port);

So what is going on here? Well like the TCP code, we have to require('dgram'); to have access to node.js’s UDP support.

Next we create the socket and create a callback function that returns the date and time string back to the IP address and port of the calling computer. Finally we bind this to the port so we start listening for messages.

It’s harder to test a UDP server as we can’t telnet in, we will have to write a simple UDP client to send a blank message to the server and print out any replies to the console.

var dgram = require('dgram');
var message = new Buffer(" ");
var server_ip = '127.0.0.1';
var server_port = 43278;
var client = dgram.createSocket("udp4");
client.on('message', function (msg) {
  console.log(msg.toString());
  client.close();
});
client.send(message, 0, message.length, server_port, server_ip);

When you run this client on the same machine as your server you should get back the current date and time.

Here’s the final code for our Daytime server.

var net = require('net');
var dgram = require('dgram');
var port = 1300;
var now = function() {
  var date = new Date();
  return new Buffer(date.toUTCString() + "rn");
}
var tcpserver = net.createServer(function(c) {
  c.write(now());
  c.end();
});
tcpserver.listen(port);
var udpserver = dgram.createSocket("udp4", function(msg, rinfo) {
  var daytime = now();
  udpserver.send(daytime, 0, daytime.length, rinfo.port, rinfo.address);
});
udpserver.bind(port);