Just checking in…

Wow, so my last post was September? That’s just not good blogging, and for that I apologise… There’s been a lot going on, but this is no time for excuses – I’m just posting this to let you all know that I’m still here, still writing code (lately, not as much as I’d like, but there you go) and I’m soon going to be making a start on the huge list of Open Source stuff that’s been building up over the past few months. Here are a few highlights of what’s in store:

  • Some awesome new stuff will be going into ORMDroid very soon, with some great contributions from Jacob Ferrero including one-to-many support. I can only apologise to Jacob for the time it’s taking to get these reviewed and merged!
  • Speaking or ORMDroid, it must be about time for that 1.0 release…
  • I’m planning to finally finish up Deelang. It still needs the new parser architecture sorting out, and some bug-fixes, plus some decent documentation. It’s been sitting there for too long, it needs to be pushed out the door!
  • I have some new code to put into Mink, including some rudimentary user-mode bootstrap code, along with a basic round-robin scheduler and other basic bits that will allow development to continue. A lot of this code is written, but still shockingly untested and even-more-shockingly out of version control!

Outside of Open Source, I still have to do something with retroify.me, a fact I was reminded of the other day when the domain name came up for renewal. The annoying thing there is that it’s done – I just need a reasonably-priced swag supplier who can print up cool T-shirts and the like for people to buy (any suggestions much appreciated!). We’ve also got an exciting new venture on the verge of private beta, which we hope to be launching as a commercial product later in the year.

So, all in all, exciting times. Now I just have to actually get on and do all this stuff.

Watch this space.

 

Advertisements

ORMDroid 0.40 released

ORMDroid 0.40 is now available from the releases area on Github. This is the first packaged release since 0.20 almost eleven months ago, and incorporates new features, reworked old features, and bugfixes. There’s a full announcement at the link above.

As well as packaging this release, we’ve now also closed the (legacy) Google Code site for ORMDroid – we’re now 100% Github!

This release marks the last call for major new features for the 1.0 series. If you’ve got any burning issues you’d like us to look at, discuss in the comments or post an issue on Github and we’ll take a look.

Enjoy!

Android and the Form Post Download problem…

Only 338 points *and* no POST download???
Only 338 points *and* no POST download???

Another day, another workaround… This time, it was for this rather annoying issue that’s been open for over four years (maybe because it’s in as an RFE and not an actual bug, who knows?). It basically describes an unexpected behaviour in the stock Android browser, whereby it cannot handle form POST requests that result in a file download.

This was picked up by one of the testers on Retroify.me (thanks Natalie!) where we’re using form post to facilitate saving image data from an HTML 5 canvas to the user’s computer. This is something that some browsers can handle without server involvement, but support varies and the various browsers implement filename selection in different ways, so we went with the solution of posting the Base64-encoded image data back to the server, which then initiates a download with disposition: attachment, allowing us to give the file whatever name we like.

This works fine on every browser we’re targeting, except the stock Android browser in everything from Gingerbread to Jelly Bean. Clicking the “Download” button on that browser resulted in “Download unsuccessful” 100% of the time.

This took some tracking down, and after sanity checking the appropriate code to make sure we were returning the right content-type and so forth, I turned to the logs to see if I could see anything out of the ordinary. Sure enough, enlightenment ensued:

Started POST "/download" for 192.168.0.4 at 2013-04-28 20:17:28 +0100
<<Base64 parameters elided>>
Processing by AppController#download as HTML
Rendered text template (0.0ms)
Sent data retroified.me.png (1.5ms)
Completed 200 OK in 3ms (Views: 1.3ms | ActiveRecord: 0.0ms) 

Started GET "/download" for 192.168.0.4 at 2013-04-28 20:17:29 +0100
Processing by AppController#download as HTML
Completed 500 Internal Server Error in 2ms (Views: 1.1ms | ActiveRecord: 0.0ms)

Immediately after sending the POST, Android follows up with a GET to the same endpoint. After some thinking (read: Googling) I decided that this must be the download manager trying to grab the file – the browser simply ignores the first (successful) response, and instead launches the download manager to grab the file via a GET. The problem is, somewhere along the way, the form post data is discarded.

In our particular case even if the post data wasn’t discarded, GET would never work because the Base64-encoded image data is simply too big for a GET request – Our Heroku dyno would simply refuse to touch it. Even if the browser insists on using a download manager in this way, my expected behaviour would be for it to pass along the entire request to it. However, on Android that might mean stuffing a large amount of Base64 into an intent, which could cause other problems.

It’s at this point that I found the aforementioned “RFE” 1780 and realised that this is what I was up against. Given the previous paragraph I can allow that this isn’t as simple a fix as it might first appear, but still – four years and no love?

In the end, I decided the only way forward was simply to work-around the problem by doing the image download a different way on the stock Android browser. Fortunately, I had already implemented server-side image generation for use with the Facebook integration, so all I needed to do was make the download button behave differently in Android stock. Here’s the Javascript that does that:

/* Download image from canvas */
function downloadImage(canvas) {
  var data = canvas.toDataURL("image/png");

  // Stock android browser can't download from post.
  // See: https://code.google.com/p/android/issues/detail?id=1780
  var ua = navigator.userAgent.toLowerCase();
  var isStockAndroid = ua.indexOf("android") > -1 && ua.indexOf("chrome") == -1 && ua.indexOf("dolphin") == -1;

  if(isStockAndroid || data.substr(0,6) == "data:,") {
    // redirect to server-side download
    window.location = getGeneratedPictureURL() + "?d=1&f=retroified.me.png";
  } else {
    post_to_url("/download", { data: data });
  }
}

(Note: This also works around an issue with pre-Gingerbread, where canvas.toDataURL is not actually implemented).

What this actually does is check if the user-agent reports Android, but also that it doesn’t specify any of the browsers that are known to work. I had to go this way since the stock browser’s user agent doesn’t easily allow us to do single-step sniffing. If the stock browser is detected, the form post is skipped, and server-side generation is used instead (getGeneratedPictureURL() returns the server-side URL for the currently-displayed image, and we just add some parameters to force disposition: attachment and set the filename).

This works, but in my opinion it’s not ideal. The user’s browser has already done the work of generating this image, but that load is then pushed back onto the server when the Download button is clicked. This is not a trivial thing – the image generation (using ImageMagick behind the scenes) is a relatively slow operation. Of course we cache the generated images, but with 20M+ possible combinations we don’t keep them cached forever.

All we can hope at this point is that 1780 gets some attention at some point soon. If you’re so inclined, you might even want to head over there and star it to let the AOSP guys know it’s still alive…

Biting the bullet – time for a rewrite

In response to a feature request from some of the guys here, my current work on Deelang focusses on implementing proper equality and comparison operators as part of the language. The current release has no support for operators beyond basic arithmetic – equality and comparison have traditionally been implemented as methods hacked on top of the standard library. This results in code such as:

1.eql(2)  => true
5.lt(10)  => true
10.gt(20) => false

Leaving aside for a moment that the above isn’t actually that bad (in my opinion at least), implementing this as operators is actually quite simple for both the dex and deevm compilers. However, while putting it together I ran up against an old elephant that’s been sitting quietly in the corner for some time now – the current parser is a mess, and it might just be time to rewrite the grammar.

The problem is not new, but I’ve ignored it for a while. Basically, it boils down to the fact that the current parser cannot handle code such as:

(1+2).foo()

Not only does this not work, but it fails miserably with nothing more specific than a MismatchedSetException at the terminator, after a lot of backtracking and ultimately ignoring the method call completely. The above code parses to the following tree:

Parse Tree Notice all the abandoned trees (in red), before the (erroneous) final parse, and the MismatchSetException up there on the right. The method call gets parsed at one point, but that tree was then abandoned in favour of a tree in which the call is quietly ignored. This is clearly one confused parser, and all over something as simple as (1+2).foo()! Clearly, this needs fixing.

As I say, I’ve ignored this for a while. It should be relatively simple to fix (and indeed it is) with a bit of rejigging in the grammar. However, this problem is actually symptomatic of something deeper – namely, that the Deelang grammar is a mess. In the past, as problems such as this have cropped up, they’ve been fixed by adding to the grammar. New productions, imaginary tokens, and syntactic predicates have all been added to cope with a specific case, with no real wider plan.As long as the tests still passed at the end, the additions stayed.

The result of all this is that things that should be handled in a unified way are actually handled in a variety of ways. My personal favourite example of this is the way chained method calls are handled – I won’t illustrate it here, but if you’re interested just debug something like “foo().bar().baz().quux()” in ANTLRWorks. Trust me, it’s not pretty. It’s inefficient, it’s inconsistent with other parts of the grammar, and it requires the compiler to jump through some pretty awkward hoops to keep track of who is using what target register. It worked well when the only target was the (stack-based) Dee vm, but as requirements have grown it’s become cumbersome – the only reason it still works this way is inertia.

With all this in mind, I’ve decided that now is the ideal time to rewrite the grammar to get rid of these issues. I’ve never been a big believer in planning to throw one away, but in this case it looks like I will, anyhow. To be fair, I’m not planning a complete rewrite – large parts of the grammar are fine as they are (literals, for example). But the meat of it – from atoms through function calls to method calls – will be rewritten in a way that’s more consistent, cleaner, and hopefully requires a lot less backtracking. I’m also aiming to reduce the lookahead where I can, although some of the actual language design makes this quite difficult.

Unfortunately this grand plan must remain just that for now – I’m very short on time to actually work on this at the moment. Since it’s not an actual key requirement I can’t allocate any actual work time to it (even though it will make things easier and save time down the line). So provisionally, I’ve set aside Sunday for the rewrite.

Now I just need to hope nothing more pressing crops up between now and then. Wish me luck!

Deelang 0.20 released!

After about a month of coding (on and off), The Deelang DEX compiler is now feature complete, and what better way to celebrate than by releasing the code? It’s always been available in Subversion of course, but now you can download all the new stuff from the downloads page as either a source package or ready-made Jar, without all that messing around with Subversion, finding the right branch, or any of that. It’s right there, on the downloads page, just waiting for you to grab and go!

I’ve blogged a bit about the new features in this version (for example, here, here and here), and if you missed all that and are now wondering what on Earth I’m on about, I’ve also blogged generally about Deelang (e.g. here). The short version is that Deelang is a compiled script language designed for embedded devices (especially Android) that allows developers to give their users a simple way to extend their apps by writing small scripts.

Now that there’s a file release available, we’re hoping to get some bug reports and open a discussion about where Deelang could/should go. Other than the DEX compiler (which has been about a month of solid effort in OSS terms) development is a bit haphazard – it works for us, so we leave it. If we need something new, we implement it, then we leave it at that. I really want to get a community going around this thing, to make it more generally useful for everyone…

So why not grab the code, play around with it, file issues if you find any bugs, and come over and join the mailing list?

Dex vs Dee VM – A microbenchmark

During a recent discussion, I had the need to show some numbers demonstrating why Deelang needs the new DEX compiler. As I said in that thread, it’s all about removing reflection from the compiled classes.

We all know that “reflection is slow” (for some value of slow) and especially on Android, that it isn’t generally a good solution for general use in method invocation. Looking up methods by reflection is slow, as is performing the actual invoke. But how slow? Could I quantify the difference?

Since the Deelang DEX compiler is still being actively developed, I’ve never paid much attention to performance before, and have certainly never benchmarked it. We knew that the Dee VM wasn’t fast enough for some of the things we were using it for, and I knew from experience that it would be faster without reflection, and we left it at that. This discussion got me thinking though, and I decided it would be nice to have some idea of the actual difference between the Dee VM and scripts compiled to DEX.

Despite the fact that microbenchmarks are often a bad idea, and are a bit of a minefield at the best of times, I wrote one in this instance. After all, I only want some idea of the comparative performance for the sake of discussion – I won’t actually be basing any design or implementation decisions on these results.

I expected a decent performance boost in the DEX compiled scripts, but I honestly wasn’t quite prepared for how much of a boost:

09-27 10:45:27.525: I/BENCHMARK(15853): Rehearsal
09-27 10:45:37.665: I/BENCHMARK(15853): DeeVM completed : 10000 runs : 10107ms (10.107 seconds)
09-27 10:45:37.725: I/BENCHMARK(15853): Dex completed   : 10000 runs : 31ms (0.031 seconds)
09-27 10:45:37.725: I/BENCHMARK(15853): Real
09-27 10:45:46.695: I/BENCHMARK(15853): DeeVM completed : 10000 runs : 8938ms (8.938 seconds)
09-27 10:45:46.745: I/BENCHMARK(15853): Dex completed   : 10000 runs : 25ms (0.025 seconds)

(This is logcat from the benchmark running on-device on a HTC One X)

That’s right – almost 9 seconds for the reflection-based Dee VM, compared to 0.025 seconds for the DEX compiled version. The difference is so marked that I at first didn’t believe the results. I changed the script to actually produce some output to logcat, to make sure that it was actually running each implementation properly, and it was. It turns out that, in this case, reflection has a much bigger impact that I expected.

In case you’re interested, you can see the benchmark code at the this page on the project wiki on Google Code.

ORMDroid 0.20 now available

ORMDroid 0.20, the first packaged release of the ORM framework for android, is now available from the project downloads page on Google Code. This first release packages up the Android library ADT project, adds some documentation (which you can view online here), and makes it easy to grab and go if you don’t like to/want to work with the Subversion repository.

In case you missed it, you can read more about ORMDroid here, here and here.

DEXing Deelang – On a real device!

Further to my previous post, I’ve been working this week on the new native compiler for Deelang on Android. This is a drop-in replacement for the standard custom bytecode compiler and VM that compiles Deelang scripts directly to Dalvik Executable  (DEX) bytecode for use on the Dalvik VM used in Android.

Development has moved fairly quickly, and there is now support for some of the basic features of the language. Not everything is supported at present (there’s no field access, no method blocks, and no arithmetic support) but the basics of function/method calls are implemented, along with local variable assignment and access, and a lot of behind the scenes support that make implementing the missing features a lot easier.

The compiler is being written largely test-first, so there’s good test coverage of new features as they go in (using Dex2Jar to generate readable dumps of the generated code, which is then compared against the expected code), but this doesn’t prove a crucial fact – that we can load the code into a running device, and execute it. To this end, there’s a small sample app that lets us write code on a device, compile it and run it against a simple binding we provide.

The screenshot shows this simple (and, if I’m honest, ugly) app running on an HTC One X. Compiling the code is quick enough given the early stage of development, but it’s actually running it where the native compiler shines – because the code is a standard Java class (it’s implemented as a subclass of the com.roscopeco.deelang.runtime.CompiledScript class, which is also a java.lang.Runnable) there’s no discernible difference between running a script and calling any other Java method.

We’re not benchmarking this in any serious way at this early stage in the project, but it’s nice to get a feel for how things are going from a performance perspective.

If you’re interested in taking a look at the work so far, you can get the sample app from SVN at the following repository URL:

http://deelang.googlecode.com/svn/branches/DEXCOMPILER/DeeSample/

The sample includes a snapshot Deelang jar, so you don’t need the actual project to try it out. Of course, if you want to play around with the code you can grab it from:

http://deelang.googlecode.com/svn/branches/DEXCOMPILER/deelang/

Updating the snapshot is as simple as running ‘ant jar‘ in the deelang directory, and then copying out the new snapshot over to the DeeSample libs/ directory.

DEXing Deelang – First steps in SVN

If you’re one of the few who’ve already taken a look at Deelang, you’ll know that it’s a simple scripting language that compiles to a custom bytecode format, which then runs in a simple virtual machine. It can run anywhere, but is targeted mostly for embedded devices, and especially for Android.

All this is fine, and for the most part it doesn’t perform too badly. Unfortunately though it does mean that it’s most common operation (calling out to Java methods) is relatively slow, because under the hood reflection is used everywhere. This has the potential to be a problem since in Dee, everything is a method – you can’t define your own classes, methods or functions in scripts, but instead rely on a (Java-side) API provided by whoever embedded the language in their application. Even arithmetic and conditionals are done with methods. Reflection (especially on Android) is just too slow for this kind of usage.

To address this, I’ve been thinking for some time about a implementing a native (i.e. Dex) compiler for Deelang on Android, and over the past few days I’ve finally made a start. The architecture is pretty well mapped out in a first-cut kind of way (well, in my mind at least) but the implementation is only just taking it’s first baby steps. Hardly anything is supported right now – in fact, the only thing it’s possible to actually compile is literals and simple, direct function calls (what the Dee VM calls SELFCALLs). But it’s a start, and it’s in Subversion on Googlecode now if you feel like taking a look. All the work is being done in a branch, which you can browse or check-out at:

http://deelang.googlecode.com/svn/branches/DEXCOMPILER/deelang

What can it do?

As mentioned above, it’s very limited at the moment. In fact, about the most exciting thing it can do is take code such as:

foo(1,2)

and compile it to native Dex bytecode like:

//class:0000  access:0x0001
public class DexCompiledScript531a8036-8e20-4965-8148-e87dfb51283f extends com.roscopeco.deelang.runtime.CompiledScript

//method:0000  access:0x0001
//LDexCompiledScript531a8036-8e20-4965-8148-e87dfb51283f;.run(Ldee/lang/DeelangObject;Lcom/roscopeco/deelang/runtime/Binding;)V
public V run(dee.lang.DeelangObject,com.roscopeco.deelang.runtime.Binding)
                this:v3   //DexCompiledScript531a8036-8e20-4965-8148-e87dfb51283f
                    :v4   //dee.lang.DeelangObject
                    :v5   //com.roscopeco.deelang.runtime.Binding
CONST               |     |v1=0x00000001  // int:1   float:0.000000
NEW_INSTANCE        |     |v0=NEW Ldee/lang/DeelangInteger;
INVOKE_DIRECT       |     |v0.(v5,v1)  //Ldee/lang/DeelangInteger;.(Lcom/roscopeco/deelang/runtime/Binding;I)V
CONST               |     |v1=0x00000002  // int:2   float:0.000000
NEW_INSTANCE        |     |v2=NEW Ldee/lang/DeelangInteger;
INVOKE_DIRECT       |     |v2.(v5,v1)  //Ldee/lang/DeelangInteger;.(Lcom/roscopeco/deelang/runtime/Binding;I)V
INVOKE_VIRTUAL      |     |v4.foo(v0,v2)  //Lcom/roscopeco/deelang/compiler/dex/CompilerFuncTestBase$Foo;.foo(Ldee/lang/DeelangInteger;Ldee/lang/DeelangInteger;)V
RETURN_VOID         |     |return

Development is moving quite quickly though, so over the next few days expect some support for most of the current (VM-based) capabilities.

Why go native?

As mentioned, the current VM architecture makes heavy use of reflection, which in some cases just doesn’t have the performance we need. Compiling ‘natively’ to Dex bytecode will eliminate all reflection in the generated code and core runtime, and will make compiled scripts fully-fledged members of your application. There won’t be any need to carry around the VM and it’s runtime, and instead you’ll only need a lightweight core runtime package that provides the standard implementations of the arithmetic operators, the if and or operators, and so on.

The trade off is flexibility. In the VM, all binding is done at runtime, with the ability to swap out any bound object (including the self reference) at any time. In the compiler, binding has to be static, so some of that flexibility is lost. But in 90% of cases (at least in our code) this doesn’t matter, as scripts are run against a fixed binding anyway (that’s what provides the ‘API’ for users to script against).

In any event, this isn’t about replacing the current VM setup – the new compiler is actually just a new back-end for the existing com.roscopeco.deelang.compiler.Compiler class. To compile the script above, you use the standard compiler with the new backend, like so:

Compiler c = new Compiler();
byte[] dex = c.compile(new DexCompilationUnit(c, "<no file>", Foo.class),
                 Parser.staticParse("foo(1,2)")).getCode();

You can still use the old (now called DVM) compiler and VM runtime as before (although there have been some slightly incompatible API changes during implementation of the new architecture, notably the moving of the deelang.* namespace to dee.vm.lang.*, so you’ll need to tweak your code a bit) if you feel it fits your needs better. There are currently no plans to drop the VM (although it may stop being the default at some point).

Spritesheets with Gimp – An adventure in Scheme

One of the coolest Android projects I’m involved with at the moment is a new strategy game, and one of the coolest things about it is it’s retro-look 8-bit style graphics. Growing up in the 80’s I obviously got a lot of exposure to the unique look of games in the 8-bit era, and I have fond memories of hacking away on the C64 and Spectrum, trying to represent real objects in a tiny number of pixels. So I’m really loving the resurgence of these techniques on current mobile devices.

Although there are a few “pixel art” graphics tools out there, we’re actually using the gimp to create our art (it’s what we know and love) and the game itself is using a layered sprite system to allow us to keep raw data to a minimum and also to make it easy for us to use different permutations of layers to create different sprites. For example, all the characters in the game are built from a small set of sprite layers which we just overlay in different combinations.

Perhaps an example is in order. Consider the rather snazzy (and somewhat surprised) looking individual on the left. He’s actually composed of a number of different layers in gimp, which are grouped and arranged in such an order that when one layer from each group is visible, they combine to create a character (in this case a mildly-shocked purple-haired gentleman in a blue sweater).

There are a number of these files, some covering people (as in this example), some with vehicles, some with background objects, and so on. And in each one, there are many layers each with a different sprite image. Not all are overlaid in this way, but they all use gimp’s layer features. Continuing the example, the image on the right shows you the gimp layers palette with the various layers that comprise the purple-haired dude.

If you look carefully you’ll see that our chap comprises a number of layers, with helpful names such as “skin_med” and “hair_02_purple”. All this works great while we’re actually drawing stuff, but once we come to actually put it into the game, we’re obviously not importing layered XCF  files – instead we break up the layers into a sprite sheet which flattens all the layers out and arranges them side-by-side in a single image (traditional sprite-sheets actually use multiple rows and columns, usually to give a fixed width and height as required by the hardware – we’re not doing this at the moment, although we do support it in the graphics engine). Turns out that this is not especially well supported in gimp.

Originally, we were using the built-in filmstrip plugin to accomplish this, but this was always a stop-gap solution – filmstrip is designed for use with photos, as a visual effect. As such, it actually adds virtual sprocket holes, frame numbers, and other assorted things. All nice if you’re making a montage of your week in Barbados, but no so great if you’re trying to get an exact-sized image you can then index into by pixel from your code. It is possible to stop these effects by tweaking the settings, but they don’t get saved across sessions, and in any event it doesn’t support transparent backgrounds so there’s always an extra select by colour/delete step once the sheet is made.

Luckily, Gimp supports scripting (via it’s Script-Fu interface to the Scheme language), so it was a fairly simple matter to knock up a script to take care of the conversion from layered image to flattened spritesheet. Gimp also supports Python scripts, but given the choice between a whitespace-sensitive language and a Lisp-like dialect, I’ll take the latter every time. It’s been a while since I last wrote Scheme, making it an ideal time to brush up some skills. A definite win-win situation!

After a little hacking around the API (Script-Fu has changed a bit since I last used it, but not so much that it’s unrecognisable) I had a basic working script, which I could call at any time through a menu item (on a new ‘Sprite’ menu I added, in anticipation of further scripts and plug-ins the guys have already asked me for). Going back to our example, the script creates a spritesheet in a new image, which for the guy above looks like:

Obviously, this example is so contrived as to be pointless. The real files have many more sprite tiles than this – I don’t think I’d be too popular if I started dumping all our graphic artifacts on here – but you get the idea.

And just in case you’re doing something similar and might find this useful, here’s the code. Call it a Saturday present from me, to you.

; Script to convert image layers to a sprite sheet.
; Copyright (c) 2012 Ross Bamford.
; http://www.apache.org/licenses/LICENSE-2.0.html
(define (script-fu-spritesheet img)
  (let* (
      (layer-count (car  (gimp-image-get-layers img)))
      (layer-ids   (cadr (gimp-image-get-layers img)))
      (sprite-width(car  (gimp-image-width img)))
      (spritesheet-width (* sprite-width layer-count))

      ; Create new image with appropriate size
      (spritesheet-image (car (gimp-image-new 
                                      spritesheet-width
                                      (car (gimp-image-height img)) 
                                      RGB)
                          )
      )
    )

    ; Copy and move each source layer appropriately
    (let (
        (i (- layer-count 1))
      )

      (while (> i -1)
        (let (
            (new-layer (car(gimp-layer-new-from-drawable 
                                      (aref layer-ids i) 
                                      spritesheet-image)
                        )
            )                     
          )

          (gimp-image-insert-layer spritesheet-image new-layer 0 -1)        
          (gimp-layer-translate new-layer (- spritesheet-width (* sprite-width (+ i 1))) 0)
          (gimp-item-set-visible new-layer TRUE)
        )

        (set! i (- i 1))
      )
    )

    ; Merge layers and rename
    (gimp-image-merge-visible-layers spritesheet-image CLIP-TO-IMAGE)
    (gimp-item-set-name (aref (cadr (gimp-image-get-layers spritesheet-image)) 0) "spritesheet")

    ; Create view for new image
    (gimp-display-new spritesheet-image)
  )
)

(script-fu-register "script-fu-spritesheet"
                    "Create spritesheet"
                    "Create a spritesheet from current image layers"
                    "Ross Bamford"
                    "Copyright (c)2012 Ross Bamford"
                    "2012"
                    "*"
                    SF-IMAGE    "Image"         0)
(script-fu-menu-register "script-fu-spritesheet"
                         "<Image>/Sprites")

(Caveat: I’m not primarily a scheme programmer. If you are, and you find my style abhorrent, well, tough :D)

(Postscript: Turns out that WordPress.com doesn’t support Scheme in it’s sourcecode tags! Thanks to the guys over at tohtml.com for their highlighter, even though I had to pretend this was lisp to get it highlighted anything like properly.)