thought some of you out there might be interested in generating imagery with
ruby, if so check out

   http://codeforpeople.com/katrina/fast/

the looper is java - but the individual images were generated from binary
grids using this ruby program (the ENVI class is just a thin wrapper on narray
which reads headers to determine types, etc.)

file: katrina.rb

#!/dmsp/reference/bin/ruby

#
# ara's lib
#
   require 'alib'
   require 'mmap'
   require 'narray'
   require 'envi'
#
# main program class
#
   class Main < ALib::SimpleMain
     version '0.0.0'

     author 'ara.t.howard / noaa.gov'

     usage <<-usage
       NAME
         #{ prognam } v#{ version }

       SYNOPSIS
         #{ prognam } [options]+ vis_grid tir_grid rgb_grid
     usage

     arguments 'vis_grid', 'tir_grid', 'rgb_grid'

     def main
       load_grids
       gen_rgb
       write_rgb
       write_rgb_header
     end
     def load_grids
       grid_opts = {
         'cast' => 'int',
         'mmap' => {'mode' => 'r', 'flags' => Mmap::MAP_SHARED}
       }
       @rg = ENVI::Grid::new vis_grid, grid_opts
       @gg = ENVI::Grid::new vis_grid, grid_opts
       @bg = ENVI::Grid::new tir_grid, grid_opts
     end
     def gen_rgb
       r = @rg.narray
       g = @gg.narray
       b = @bg.narray

       r[ (r.eq 255).where ] = 0 # hide missing
       g[ (g.eq 255).where ] = 0 # hide missing

       linear_stretch r, 7 .. 30
       linear_stretch g, 7 .. 30
       linear_stretch b, 175 .. 230

       r[] = r * (1 << 24)
       g[] = g * (1 << 16)
       b[] = (255 - b) * (1 << 8) # invert blue channel

       @rgb = r | g | b
       @rgb = @rgb.hton
       r = g = b = nil
     end
     def linear_stretch na, irange, orange = (0..255)
       fna = NArray::float(*na.shape)
       fna[] = na

       imax, imin = irange.max, irange.min
       isize = imax - imin + 1

       omax, omin = orange.max, orange.min
       osize = omax - omin + 1

     # floor input
       lte_imin, gt_imin = (fna <= imin).where2
       fna[ lte_imin ] = 0
       fna[ gt_imin ] = fna[ gt_imin ] - imin + 1

     # ceil input
       gt_imax = (fna > isize).where
       fna[ gt_imax ] = isize + 1

     # percentage of in range
       fna[] = fna / (isize + 1)

     # scale into out range
       fna[] = fna * (osize - 1)

       na[] = fna
     end
     def write_rgb
       open(rgb_grid, 'w'){|f| f.write @rgb.to_s}
     end
     def write_rgb_header
       h = @rg.header
       open(rgb_grid + ".hdr", 'w') do |f|
         hdr = <<-hdr
           ENVI
           description = { R (#{ vis_grid }), G (#{ vis_grid }), B (#{ tir_grid }), A (alpha) }
           samples = #{ h.samples }
           lines   = #{ h.lines }
           bands   = 4
           header offset = 0
           file type = ENVI Standard
           data type = 1
           interleave = bip
           sensor type = Unknown
           byte order = 1
           map info = #{ h.map_info }
           wavelength units = Unknown
           default stretch = 0.000000 255.000000 linear
           data origin = NGDC
           band names = { R (Band 1:#{ vis_grid }), G (Band 2:#{ vis_grid }), B (Band 3:#{ tir_grid }), A (Band 4:alpha) }
         hdr
         hdr.each do |line|
           f.puts line.strip
         end
       end
     end
   end
#
# run unless included as a lib 
#
   Main::new.run if $0 == __FILE__


only takes about 3 seconds per image for 3001x3001 byte grids too ;-)  the
output images are raw and converted to jpg using something like (i forget
syntax)

   convert -depth 8 -size 3001x3001 rgba:filename.rgba filename.jpg

convert being and image magick utility.  now that tim has made updates to im
though - the narray/mmap could be used directy to set the pixels of an image
from within ruby... i'll figure that out next week. ;-)

-a
-- 
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| Your life dwells amoung the causes of death
| Like a lamp standing in a strong breeze.  --Nagarjuna
===============================================================================