Stack-Based Processing, Part 2

In Part 1 I discussed stack-based representations of functions in very general terms. Now I’m going to present a real-world example.

I’ve been working on a new feature for EasyAs123Web.com recently – image cropping. When building your web-pages, we allow you to upload images, and then use them in the web-page, either as simple images in the normal flow of things, or merged into the website theme itself. Since many themes need odd-shaped images (e.g. letterbox formats in the header), we desperately needed a way for the user to control which bits of the image would be displayed.

(I’m using this jQuery plug-in to handle the client-side stuff).

Now to merge these images into the website theme, I’ve been writing handlers that spit out an image, based on certain parameters. For example, I had one that resized an image from the database; another that combined two images (one from the database, one from the theme); one that cross-faded two images; and so forth.

The problem is that these handlers all start resembling each other. They all need to do a bit of resizing, a bit of aspect ratio calculating, and with the new cropping feature, they’d all have to support cropping, and so the code was getting messy and repeated.

So I needed a new approach. I needed something that was easy to encode and decode in a URI; something that could be modified (for example to insert a crop operation); and something that would keep my code tidy.

Stacks!

I based my approach around a Stack<Bitmap>. My handler parses its query string into a sequence of operations. Each operation is then applied in turn, with the stack as the only parameter. At the end, I expect the stack to contain exactly one image, which is returned by the handler.

My operations now become really really simple. For example, I have simple load operations:

  • Load an image from database, push it onto the stack.
  • Load a static image, push it onto the stack.
  • Load a field of solid colour at a particular size, and push it onto the stack.

I have simple combining operations:

  • Pop two images; draw one on top of the other; push the resulting single image back onto the stack.
  • Pop two images; tile one as background; draw the other as foreground; push the resulting single image back onto the stack.

I have manipulation operations:

  • Pop an image; resize it; push it back onto the stack.
  • Pop an image; crop it; push it back onto the stack.

And finally, I have a handy “swap” operation [POP A; POP B; PUSH A; PUSH B].

Examples

Let’s suppose I have two images, A and B:

A – a picture of a tree, with a transparent background.

B – a picture of some sort of sky-like background.

I can combine them as follows:

PUSH COLOR – #F00 ; PUSH A ; COMBINE

PUSH B ; PUSH A ; COMBINE

PUSH B ; PUSH A ; CROP – 0.0, 0.4, 1.0, 0.7 ; COMBINE

Hopefully you can see that I can get a variety of effects simply by combining a variety of simply stack operations. I can very easily represent a sequence of operations in a URI too, since they’re sequential.

One Response to “Stack-Based Processing, Part 2”

  1. The granddaddy of stack operations is the Forth language [see http://en.wikipedia.org/wiki/Forth_(programming_language) . Makes for very simple operations.

    The function Square would replace the top value on the stack by its square.

    : SQUARE ( n — n*n ) DUP * ;

    Nice to see good ideas being re-used.

    Chris

Leave a Reply