Imagination Squared (Plus OpenZoom)

There is a community driven art project in Jacksonville Florida, called Imagination Squared. The idea was to have hundreds of members of the local artist community each contribute a small square that they’d decorated. The squares were all a standardized size, and they were all tiled together in an art installation.

Curious as to what people had sent in, I looked through the site. The art page had hundreds of 100×100 pixel thumbnails, and you had to click on individual ones to get to a larger-resolution 300×300 picture. This struck me as an obvious application for the Microsoft Research PhotoSynth/SeaDragon zooming that was infamously demonstrated at the TED conference by Blaise Aguera y Arcas.

I wondered how the Free Software folks had been faring in creating an open-source variant of SeaDragon. Doing some searching I was pleased to find the OpenZoom project. You can see they have a number of cool examples, and I thought the ImaginationSquared project would be an example that would interest a lot of people (the hundreds who contributed squares, at least!)

So here’s the promo video for what I just released the source code to this morning:

Though I’m not going to host the player on hostilefork.com, I pushed the source code out to GitHub today for both the generator (written in Ruby) and the viewer (written in ActionScript 3). I’m also happy to provide built versions of the data and component to individuals who want them:

http://github.com/hostilefork/openzoom-squared

Neither of those two are languages I’ve used before. So I’ll use the rest of this blog entry to talk about my thoughts on that.

Why Use Ruby?

Using ActionScript was pretty much a given, as all the OpenZoom player code that runs in a browser uses it. But why use Ruby?

I’ve been meaning to write some actual code in Ruby. I was casually familiar with the language’s ideas by looking at small tutorials, but I’d never written anything in it that used any libraries. So installing “gems” or use a library like RMagick was beyond my experience level (basically, I’d never looked at any examples that needed a require statement).

The task pulled in a few areas:

  1. Downloading web content - I wanted to get the HTML for the existing grid of images, and use that to get the URLs of the larger images. Then I wanted to get those images via HTTP. This required some basic functionality you can get provided by Ruby’s built-in network functionality (files using this will say require "net/http")
  2. DOM parsing and querying - I could have extracted the information I wanted with string processing of the HTML file, but wanted to see Ruby’s answer to the DOM. There doesn’t seem to be one built-in to the language, but rather (at least) three prominent ones: REXML, Hpricot, libxml-ruby. I chose hpricot because it was jQuery-like and it seemed like it might be more tolerant of HTML that wasn’t XML-compatible.
  3. Large image generation - I didn’t know if the RMagick library would be very happy about the size of the image I was planning on making. But I figured I’d give it a try. As it turned out, I did have to tweak the virtual memory settings on my virtual machine, but I had it working in virtually no time. :)

(Note: You might be wondering why I went through the trouble of web scraping this instead of just asking the Imagination Squared folks for their data. Firstly, because it was an educational exercise in learning Ruby. And secondly, I didn’t know if I was going to get this working, or if it started to get difficult if I’d walk away from the project. I didn’t want to disappoint anyone if that turned out to be the case, so it was better to just keep it a secret until I actually did the work!)

Overall Ruby Impressions

Ruby seems reasonably clean, and appeals to my sensibilities more than Python does. It wasn’t too painful to set up and get work done, though what I was writing wasn’t precisely rocket science, and I paused any further refinement of it once it produced the files I wanted:

http://github.com/hostilefork/openzoom-squared/blob/master/generator/ImaginationGenerator.rb

I liked the lack of need for semicolons—code just looks cleaner. But I’m even more extreme than that because I don’t like commas in lists. You’re always running up against that question in code generation as to whether you’re on the last item or not—especially when you’re generating code. Putting commas at the ends of lists too is not the answer because if, we, had, to, put, commas, between, every, word, in, English, it, would, get, ugly, right,?

The block/yield style of programming is quite nice, though that’s the part I already knew about (and assumed was the main draw over, say, JavaScript). I worked on adding similar features to Rebol and got pretty far with my Rubol project. It would be interesting to check it out now that I’ve written a Ruby program of my own.

My hopes got up for a moment when I found out about “Ruby Symbols”. You can convert from a string to a symbol or a symbol to a string, but you can’t modify a symbol directly using string operations… and symbols may be used as keys in hashes/etc. which are unique from their string equivalents. But they’re an efficiency trick as opposed to any foundation for symbolic programming.

(Note: It seemed that searching Google often found outdated information, or not-very-good advice. What I determined was that the more “noob” your question is, the more likely you are to find documentation from earlier versions or garbage from bloggers who don’t know what they’re talking about. This made me feel that for basics of a language it’s better to start looking on a wiki-like site like StackOverflow.)

Something I liked was that Ruby has borrowed Scheme’s naming convention for ? and !.

Ruby does something that Rebol does, which is to have the return value of a code block come from the last expression that gets evaluated. I find myself with the same wish that I could explicitly call that out with something like a “return” when there’s a case that the evaluated value is important and you expect it to be used. So I put comments on such lines. But perhaps what I should be doing is ending all code blocks that don’t have significant return values with a nil or none?

Overall OpenZoom SDK Impressions

It seemed to be fairly well organized, and I didn’t find it too hard to understand what was going on. More to say on this later.

Overall ActionScript 3 Impressions

As a language, ActionScript just doesn’t seem to have a reason for being. Everything I suspected it wouldn’t do well it didn’t… and those few things I thought it might do well it did not. More to say on this later.

Tags: , ,

4 Responses to “Imagination Squared (Plus OpenZoom)”

  1. Belle Says:

    I love this. Places I want to see it applied:
    Websites for
    –artists (portfolios–this includes visual artists, but also musicians placing album covers, etc.)
    –DVDs/CDs, related media (same with books–can see this on iTunes in their store, or Amazon, etc.)
    –museums (collections)
    –libraries (collections)
    –booksellers (book covers, subdivided by authors/genres/bestsellers, all sorts of queryable categories that will then populate a large visual grid)
    –magazines (every cover of the publication in one grid)
    –School yearbooks online–with ALL of the students from the start of the school till the present in a continual grid, with superimposed and/or mouseover visual breaks for year
    –Personnel photos on company websites
    –Law enforcement lists–missing children/FBI Most Wanted/Watch lists
    –Photo-sharing sites (Flickr, etc. So you can stitch your album together…)
    –Bridal photography
    –Periodic Table educational infographic
    –History timelines for educational sites
    –Blog indices (using a graphic and/or key word for reference)
    –FB Friends grid (where you can see all 5,000 at once rather than scrolling)
    –Online menus for restaurants
    –Even basic search engine results, eventually, when we get better at taxonimizing tags and auto-generating intuitive tag clusters.

    I’ll stop there but I keep thinking of more. The basic thing though, for me, is that it moves large information sets towards a highly navigable infographic model that is visually intuitive. In my mind, this is much more how the internet should be. And will be.
    Bravo!!!

  2. Rory O’Kane Says:

    You may have already learned this since you wrote this post, but there is a solution to your problem with calling out returned values in Ruby. You said you marked values to return with a comment, presumably like ‘sentence_contents + “.” # this is returned’. Ruby actually has a “return” keyword like C and Java, so you could just write that like ‘return sentence_contents + “.”’. You can also use the return keyword to return from a function early, skipping any further code in the function, like in other languages.

    As for whether you should end non-returning functions with nil, I’m not sure of that either. I don’t really like Ruby’s return system; it becomes a problem once your code becomes big enough that you can’t remember in your head whether each function returns a value or not. I solve this by making sure I always put “return” at the last line of functions that return values I will want to use, but that may be hard to get teammates to do, if you’re in a team project. I suppose another possibility would be to write your code such that all functions return useful values – functional rather than imperative style – but I’m not sure if that would end up too complicated or nonperformant in Ruby.

  3. Hostile Fork Says:

    Hi Rory,

    Thanks… I don’t remember if I knew about Ruby’s return keyword or not. But I was certainly under the impression that it was idiomatic to use the last-item-in-the-block format…based on the code I saw in tutorials and that I was cutting-and-pasting from.

    This issue isn’t such a big deal, but I do find myself wishing for language designers to canonize “the answer” instead of finding everyone doing it a different way. In Rebol the source code structure is held in memory (like LISP) and the community which uses it is conscious of every superfluous byte or “word!” instance in the code. So at least they have a uniform opinion to never use return at the end of a block, even if the rationale seems a little weird.

    I actually haven’t done any more Ruby programming since this post. Though I did spend a little time looking into the various hacks people have used to implement code reflection by bundling in a third-party Ruby parser with their projects… :-/ I’m getting into the belief that if I’m going to be using an interpreted language, I should at least be getting a meta-circular evaluator out of the deal!

  4. Karl Says:

    I am loving it. However if someone uses openzoom in a commercial project won’t he be in trouble with microsoft and the patents of Seadragon/deepzoom?

Leave a Reply


Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported
Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported