Scaling An Image In An HTML5 Canvas

As part of my Draw Something Solver, I’ve been working with HTML 5 Canvas objects quite a bit. As I want my application to work on all iPhones, I need to support both regular and retina displays. As I need to detect the letters on the image, I really need the images to be of the same size, however a regular image is 320×480, whereas a retina image is 640×960.

The eagle eyed amongst you will see that this is a factor of 2 difference between the two.

The Canvas Context object provides a scale() method, that you pass in x and y scaling factors into.

So if I have a Canvas object called screenshotCanvas, and an Image object called screenshotImage I want to scale down by half, I can use the following JavaScript code.

screenshotCanvasContext = screenshotCanvas.getContext('2d');
screenshotCanvasContext.scale(0.5, 0.5);
screenshotCanvasContext.drawImage(screenshotImage,
                                  0,
                                  0,
                                  screenshotImage.width,
                                  screenshotImage.height);

If I want to double the image in size, I just change the scale factor to 2.

screenshotCanvasContext = screenshotCanvas.getContext('2d');
screenshotCanvasContext.scale(2, 2);
screenshotCanvasContext.drawImage(screenshotImage,
                                  0,
                                  0,
                                  screenshotImage.width,
                                  screenshotImage.height);

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)"
/>