Load an Image from an Arbitrary URL into HTML Canvas

While working on Pixie we wanted to be able to import any image from the web into the editor. Ideally this would all occur in client-side JavaScript, but due to a “security” restriction* I believe that it is not possible without extensive workarounds. Fortunately loading an image on the server is actually much easier than working with the Canvas ImageData API (no joke), so though a loss from an efficiency standpoint, from a simplicity standpoint it may be win.

This particular implementation requires RMagick, though any image library should be about as easy. The first step is to read the image from the user-supplied URL, next gather the width and height meta-data.

  def data_from_url(url)
    image_data = Magick::Image.read(url).first
    width = image_data.columns
    height = image_data.rows
 
    data = image_data.get_pixels(0, 0, width, height).map do |pixel|
      hex_color_to_rgba(pixel.to_color(Magick::AllCompliance, false, 8, true), pixel.opacity)
    end
 
    return {
      :width => width,
      :height => height,
      :data => data,
    }
  end

The only tricky part is converting all the pixel data into a format that can be used by JavaScritpt. I decided on rgba format as that is simple to read, implement, and test. The one downside that I can see is that for large images it will be somewhat inefficient to convert each pixel into a large text string, but since I mostly plan on dealing with images < 100×100 it shouldn’t be a big deal. The hex_color_to_rgba helper method takes care of all the dirty work of converting the moderately unwieldy output from RMagick. It turns "#FAFAFA", 65535 into "rgba(250, 250, 25, 1)" a format that browsers respect.

  def hex_color_to_rgba(color, opacity)
    int_opacity = (Magick::QuantumRange - opacity) / Magick::QuantumRange.to_f
 
    match_data = /^#([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})/.match(color)[1..3].map(&amp;:hex)
 
    "rgba(#{match_data.join(',')},#{int_opacity})"
  end

In the end we return a hash containing the the width, height, and pixel data. This can easily be converted to json via the to_json method, or whatever other format tickles your fancy.

The JavaScript code is pretty dumb, it reads the width and height, then iterates over the data and paints each pixel individually. Not super exciting, but simple and effective. That’s that for loading arbitrary images into HTML Canvas, though I hope one day to develop an entirely JS solution.

* I do not understand the reasoning why you are allowed to load an image from an arbitrary url and display that image, but not have access to the pixel data from it. It sounds pretty silly, especially considering that you can load scripts from an arbitrary URL and run them, or load json from an arbitrary URL. I have no idea what “security” that this restriction provides, other than the “security” of having to load images through your server and hinder the user experience. Here’s a related discussion, but I still don’t get it. This is a hole in my personal understanding, so if anyone knows the reasoning behind the restriction I’d love to hear it.

Random Scope

Here’s a little module that will make adding things like Cards.random(4) a breeze!

# This module takes care of adding a random scope to records
 
module RandomScope
  def self.included(model)
    model.class_eval do
      if connection.adapter_name == "MySQL"
        named_scope :random, lambda { |amount|
          if(amount)
            {:order => "RAND()", :limit => amount}
          else
            {:order => "RAND()"}
          end
        }
      else
        named_scope :random, lambda { |amount|
          if(amount)
            {:order => "RANDOM()", :limit => amount}
          else
            {:order => "RANDOM()"}
          end
        }
      end
    end
  end
end

The Next Big Browser Language

A long time ago in a galaxy far far away… actually a couple years ago, in Japan, a man was toiling away on creating a Ruby VM completely written in JavaScript. The year was 2007, Ruby 1.9.0 was still new and the global economy was in full swing. Everything was looking great for Ruby VM’s, Flash, the browser? It’s all good. Benchmarks proclaimed amazing speed increases and the RSS feeds were abuzz with the news.

But then the months went by and not much happened. Then sometime in June 2008 the source got imported into github. Then another month went by and again, not much happened, although the HotRuby website did get a redesign. Then almost a year went by, nothing much happened. Not much news on any front…

And that about catches us up to last week. I was doing some deep digging into JavaScript. I was thinking about ways to implement more Rubyesque patterns like Modules and the like when I remembered reading about the HotRuby VM a while back. I wanted to know if I could sidestep this whole JavaScript issue by running Ruby as a scripting language in the browser.

JavaScript is the de facto language of the internet. It has a distinct terribleness to it, but also a grotesque beauty. It is a powerful, misunderstood language that grew up to fast, being robbed of it’s childhood during the great browser wars. And now, after a resurgence or two, it is really coming into its own. ECMAScript 5th Edition looks to be a beacon of hope, but will it really be as joyful as being able to program Ruby as a browser scripting language? JavaScript frameworks have shown strong improvement and make working with the DOM nearly pleasant. All this means that we can’t just sit around and wait for JavaScript to die. If we do we’d just get stuck with another compromised language anyway.

But something happened over the past year during which HotRuby was laying fallow. Many things happened. Google released a browser adding another horse to the current browser race. JavaScript implementations are racing to improve performance. In addition, this now makes two major players in the browser market open source browsers: patches can be submitted that provide support for scripting languages beyond JavaScript.

Ruby 1.9.1 was released and is slowly gaining steam. It’s matured significantly and now the opcodes will be less susceptible to change, good news for VM implementers. Ruby has also permeated all the major platforms with JRuby and IronRuby (and even BlueRuby!!). Developers may wish to use Ruby as a clientside scripting language as well, I sure as hell know that I do.

And that’s why I did it. That’s why I did what had to be done. I forked the github repository of HotRuby (github sure makes picking up where others left off easy!), I hammered and hammered until it “worked” with Ruby 1.9.1 (and broke it only a little). And I added jQuery. I thought that in order to get Ruby into the browser that I might have to implement an entire interface to the DOM, but that was misguided. Implementing an entire DOM manipulation package in Ruby would be a waste when jQuery brings an admirable elegance to JavaScript, such that you can almost forget JavaScript’s ugly dark secrets. Now that Ruby can run in the browser and easily access $native objects, jQuery fits in exactly where Ruby needed it.

So check it, the long term vision: JavaScript RubyVM (HotRuby) provides a way to script in Ruby on legacy browsers (IE). Ruby implemented natively as a clientside scripting language in all modern browsers (Chrome, Firefox). jQuery continues to rock the DOM. Everyone wins!

And the good news is that it’s not too far in the future…

Ruby Quiz

So, better late than never I guess… I’ve been Ruby Quizmaster for about two months now.

The Ruby Quiz site is at http://rubyquiz.strd6.com. This is the third incarnation of Ruby Quiz, a weekly quiz that let’s you put your Ruby skills to the test. The first quiz was started by James Edward Grey II, there was also a book Best of Ruby Quiz (Pragmatic Programmers).

Great for keeping your skills of a programmer sharp! Also, there is a submission form for ideas. Please do submit ideas, I’m running out! The more to choose from, the better the quizzes!

Mathematical Image Example for Ruby Quiz #191

This image was generated as an example for Ruby Quiz

This image was generated as an example for Ruby Quiz

This weeks quiz is about generating images from mathematical functions. Here is an example to see what I’m talking about.

depth: 3
red: Math.sin(Math::PI * Math.cos(Math::PI * y * x))
green: Math.sin(Math::PI * (Math.sin(Math::PI * y)) ** 3)
blue: (Math.cos(Math::PI * Math.cos(Math::PI * y))) ** 3

See the full quiz here: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/327126

Hey Raccoon! Stop stealing my fruit!

Dungeon Farmer has been moving along. It now supports two (2!) kinds of plants, so basically any number. That’s the thing about programming, you can either do something once, or any number of times. In addition to the new plant, there have been highlighting improvements, raccoon metabolism balance changes, basically the whole eight yards.

Now comes the time where I contemplate turning Dungeon Farmer into a product. Ugh… Listen to that, product. The only thing that I’m actively turning into product is that burrito I ate for lunch. I guess that’s the dream of the amateur, to create something idealistic, yet appealing; enough so that your user(s) can support you enough to buy a burrito.

So this is a call to action to my reader. Find my user and get his or her input. What can I do to make Dungeon Farmer appealing enough to encourage you to purchase me a burrito? Or a pizza, pizza is good too.

“I take care of the place while The Master is away” said torgo.rb

I just released the pre-alpha version torgo on RubyForge. It currently probably only works on linux, I need to figure out how to create the bin file appropriately. Also it currently only works with wine running uTorrent, or straight uTorrent on Windows.

So what’s it do?

I’m glad I asked… usage:

>torgo Manos the Hands of Fate

This searches a popular torrent indexing site with your query (soon to be many), downloads the first torrent file (soon to be best), and starts the uTorrent application (soon to be your choice).

It generally finds the correct one even though it is so simple. Eventually it will be strong, and it’s real strength will come when combined with other apps for download monitoring and playback. These apps might sit on a media center PC behind your TV and be remote controlled (literally!).

Give it a whirl if you have the patience and send me patches so that I can get it working on other systems.

Git repo here.

Ruby Weekend #2 – Dungeon Farmer

I recently participated in the RubyGame forums Ruby Weekend #2 game programming competition. I feel it turned out pretty well, but judge for yourself. I was pretty rushed during the weekend with other commitments so I didn’t keep a dev blog… next time. Also this blog was fallow until recently. This competition has spurred me to getting my web shizzy together.