« November 2005 | Main | January 2006 »

Main > Software

December 31, 2005

Progress Bars with GD2 and Ruby

Just in time for the new year...

I went milling about for source for progress bars that would be suitably embedded within a Ruby on Rails application I'm working on and came up with nada. Sure, sure there are lots of bars that have to do with live uploading and whatnot (see: here); but nothing that grabbed me with the interface I was looking for (call function, return data).

Like cheating on a lover, I went looking into PHP territory and found a really quite wonderful and straightforward example here by Bård (Bob) Johannessen.

It only took about 20 minutes to adapt to a halfway decent ruby class and now I'm rollin'. Here are some output examples:



Generic LED-ish:


You can download a tarball of my musings: ruby_progressbar.tar.gz.

Here's the source:

#!/bin/env ruby18
# copyright 2005, Jordan Husney <jordan@husney.com>
# (http://jordan.husney.com/main.html)
# derived directly from the following source and protected under
# the GNU GENERAL PUBLIC LICENSE, Version 2, June 1991
# http://db.org/demo/2003/02/17/progress-bar/?view=source
# php+gd dynamic progress bar image script.
# copyright 2003, B. Johannessen <bob@db.org>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version, and provided that the above
# copyright and permission notice is included with all distributed
# copies of this or derived software.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# GNU General Public License for more details.
# A copy of the GNU General Public License is available from the GNU
# website at the following URL: http://www.gnu.org/licenses/gpl.txt

require 'rubygems'
require 'gd2'

class RubyProgressbar
  include GD2

  IMAGE_DIR = "./images/"
  IMAGE_STYLES = [ 'winxp', 'osx', 'led', 'solaris' ]


  def initialize
    @image = nil

  def create(style, width, completed, total)
    # Check arugments:
    raise ArgumentError, "style '#{style}' unknown" if
      not IMAGE_STYLES.include?(style)
    raise ArgumentError, "width must be between 64 and 1280 pixels" if
      width < 64 || width > 1280
    raise ArgumentError,
      "completed must be greater than 0 and less than total" if
        completed < 0 || completed > total
    raise ArgumentError, "total must be greater than 0" if
      total < 1

    # Open images according to defined style:
      bg        = Image.import(IMAGE_DIR + style + '-bg.png')
      fill      = Image.import(IMAGE_DIR + style + '-fill.png')
      bg_cap    = Image.import(IMAGE_DIR + style + '-bg-cap.png')
      fill_cap  = Image.import(IMAGE_DIR + style + '-fill-cap.png')
    rescue Exception => e
      raise "Unable to load required images for style #{style}!"

    # calculate the fill width:
    fill_width = (((width - bg_cap.width) * completed) / total).round -

    # create the new image, and copy the fragments into it:
    image = Image::TrueColor.new(width, bg.height)
    image.copy_from(bg, 0, 0, 0, 0, bg.w, (width - bg_cap.w))
    image.copy_from(bg_cap, (width - bg_cap.w), 0, 0, 0, bg_cap.w, bg_cap.h)
    image.copy_from(fill, 0, 0, 0, 0, fill_width, fill.h)
    image.copy_from(fill_cap, fill_width, 0, 0, 0, fill_cap.w, fill_cap.h)

    @image = image

    # return success
    return true

  def destroy
    @image = nil

  def gif()
    raise Exception, "image not created" if @image.nil?
    return @image.gif()

  def jpeg(compression = nil)
    raise Exception, "image not created" if @image.nil?
    return @image.jpeg(compression)

  def png(compression = nil)
    raise Exception, "image not created" if @image.nil?
    return @image.png(compression)


It can be used thusly:

require 'ruby_progressbar'

bar = RubyProgressbar.new
# OSX style, 320px wide, 3 of 10 units completed on the bar:
bar.create("osx", 320, 3, 10)
f = File.new("output.png", "w")

Please let me know if you've got any feedback or make any extensions!

Update, 2006-Jun-28: fixed recollation typographic error and added syntax highlighting.

Posted by jordanh at 5:43 PM | Comments (9) | TrackBack |

Main > Diary > Politics

December 19, 2005

Analog Hole to be Sewn Shut?

We got computers, we're tapping phone lines
I know that ain't allowed

(Life during wartime, Talking Heads)

It's life during wartime alright and it looks as though the erosion of civil liberties continues and we're being told it's fully legal as the president has a "duty to uphold the laws of the United States" [1] and therefore somehow while holding up the law he must be acting under it as well. The logic confounds.

If that weren't enough, I was made aware of legislation introduced into congress and lobbied for by the RIAA and MPAA which limits the rights of fair use of analog content in an attempt to "close the analog hole" [2] whereby requiring analog devices to honor the "rights signaling system" imposed within the digital domain, including the ability to flag certain content as Copy Prohibited Content thus denying the viewer the ability to produce even an analog copy of the content for personal use. The notion that this legislation was even introduced further convinces me of how far out of whack the business model of media distribution really is.

Imagine that a disruptive technology comes along that changes the way you must do business. Instead of adapting your business to work with the new technology, you try and get the new technology to be crippled by legislation so your old business model is still profitable. The RIAA and MPAA in concert with the large, slow moving media distribution organizations seem to be doing exactly this.

To my mind, legislating against analog fair use is exactly as ridiculous as if Kodak lobbied for the introduction of legislation that would ban anybody from printing photos taken via a digital process without paying Kodak a small fee for the privilege; or if book publishers required photocopiers to recongnize watermarks in text and thereby not makng a copy. I had better not give anybody any fancy ideas or soon I'll find myself trying to sketch my photos and hand copy my paper citations.

Will the law win and hackers loose? Will all this digital convenience yield to the legal impediments introduced by special intrest? Absolutely not. The old way of content distribution is dying a slow, painful death. But it isn't going to stop them from trying to take a few of them with us by using legal wrangling on their way down into the ground.

Posted by jordanh at 11:34 PM | Comments (2) | TrackBack |

Main > Photoblog

Man Kills Fish

View in Photoblog
CameraKonica Minolta 7d
LensTamron 28-200mm f/2.8 @ 28mm
Shutter / Aperture1/30s / f/4

This week's entries are all going to be a little graphic. My apologies for anybody that has found this out too late.

What surprised me was the contrast between the relatively clean work of finishing processing tuna as compared to preparing the smaller items of seafood for market. Whereas I understand that most of the dirty, messy work relating to tuna (gutting, beheading, what have you) is done out at sea, the smaller creatures have to be done the old fashioned way.

Everywhere you would walk in Tsukiji you couldn't help but notice the final moments of something. Knives and needles everywhere. The end of the line.


Posted by jordanh at 8:20 AM | Comments (1) | TrackBack |

Main > Photoblog

December 14, 2005

Finished Product

View in Photoblog
CameraKonica Minolta 7d
LensTamron 28-200mm f/2.8 @ 28mm
Shutter / Aperture1/40s / f/6.3

This is the last shot in the series on Tuna; we will continue here with a few final shots from Tsukiji before I move on to some general shots from this and my more recent trip to Japan.

I find the fishermen of Tsukiji remarkable for being able to take so many fish and reduce them into such clean, coherient forms. Look at how beautiful that case is! A far cry from the corpse I showed you just a couple of weeks ago...

On a sushi related tangent, have you seen this video on Japanese sushi eating tradition? It's hysterical if you haven't seen it yet! I mean for outsiders Japanese culture can seem complex, daunting, and at times non-sensical but this is ridiculous!


Posted by jordanh at 8:12 AM | Comments (1) | TrackBack |

Main > Photoblog

December 11, 2005

Wiping the Tuna

View in Photoblog
CameraKonica Minolta 7d
LensTamron 28-200mm f/2.8 @ 42mm
Shutter / Aperture1/125s / f/3.5
ISO (Adj.)800

"Wiping the Tuna," sounds a bit Euphemistic doesn't it? By almost any "blanking the blank" phrases do: cleaning the attic, dressing the salad, teasing the turtle, &c. Maybe its just me...but I doubt it.

My sincerely apologies for my lack of updates around here recently. It's exam time around the university and I've been putting off just about everything. I know you're out there to!

Site traffic has been increasing rather steadily with time. We are up to 2,100 page views per week! Wow!

In other news, I'm looking for an entry-level 4x5 field camera or highly portable monorail system, cheap. If anything has something collecting dust, drop me a line. I'd rather buy from somebody who would like to see me produce photography with it!


Posted by jordanh at 8:34 PM | Comments (1) | TrackBack |

Main > Photoblog

December 9, 2005

Super Maguro-O-Matic '05

View in Photoblog
CameraKonica Minolta 7d
LensTamron 28-200mm f/2.8 @ 42mm
Shutter / Aperture1/25s / f/4

Here is another man demonstrating the Super Maguro-O-Matic '05: the safe and convienent way to clean a huge pile of tuna. I suppose as long as I am making '70s vintage SNL references I might as well try: Samurai Fisherman.

If you want to see inventive ways of cleaning a fish, and most of them involving a blade longer than 48 inches: get down to Tsukiji.


Posted by jordanh at 8:59 AM | Comments (0) | TrackBack |

Main > Photoblog

December 6, 2005

Through the Bandsaw

View in Photoblog
CameraKonica Minolta 7d
LensTamron 28-200mm f/2.8 @ 42mm
Shutter / Aperture1/30s / f/4
ISO (Adj.)400 (+0.30 EV)

I love how the man off at the left looks rather terrified of something. Perhaps its just the hour. His expression embodies how I feel when I wake up before the sun rises.

Although not the finest shot technically, I do like the action presented in this shot. It provides just another small sampling of the chaos at Tsukiji. Try and imagine the sounds of hundreds of fish being hacked and run through saws. It was chilling.


Posted by jordanh at 7:42 AM | Comments (0) | TrackBack |

Main > Photoblog

December 5, 2005

Pick a Fish

View in Photoblog
CameraKonica Minolta 7d
LensTamron 28-200mm f/2.8 @ 50mm
Shutter / Aperture1/25s / f/3.5

Much of the tuna that enters Tsukiji fish market is partially processed and flash frozen on the huge fishing vessles. At Tsukiji it is sorted and processed further into sizes consumed by industry and consumer alike.


Posted by jordanh at 7:37 AM | Comments (0) | TrackBack |