i’m so full of ideas

Archive for the 'bash' category

details

April 9, 2009 8:15 am

As of this writing, a google search for “UIImage rotate” turns up my previous blog article as the third hit. If you ask me, my take on the subject is far more useful than the top two hits. Yes, I am a shameless braggart, thanks for noticing.

The reason I wanted to rotate UIImages is because I’m working on an iPhone card game, soon to be revealed. While casting about the ‘net for playing card images to use, I came across this excellent page at www.jfitz.com. There you will find the original Windows-3-era playing card images, made famous by Windows Solitaire, everyone’s favorite time-waster. I can recall whiling away countless hours with that game myself, back when I was a Windows user. One day in the mid nineties I was poking around in my Windows directory and came across CARDS.DLL, which I opened up with the resource editor that came with Microsoft’s compiler of that era, and discovered the bitmaps for all those playing cards lurking inside. I spent ten minutes contemplating writing a Windows card game, then promptly forgot about it. I didn’t know until recently that those iconic card images were created by the legendary Susan Kare, the woman who earlier made the refreshing, tiny black-and-white icons for the original Macintosh. Check out the one she made depicting Steve Jobs. It captures the essence of him in a mere 32 bytes.

Susan Kare’s Windows playing cards turned out to be perfect for my game. Their dimensions are close to ideal, given the size of the iPhone’s screen. If they were any bigger, you wouldn’t be able to fit enough of them onscreen at once. Any smaller and the player would have trouble selecting individual cards with her fingers.

Ugly green pixel

Ugly green pixel

I used these graphics for a couple of days and then noticed a problem. The card images all have an unnecessary green pixel in each corner. I originally planned to work around it by using that same shade of green for my background, so that the unwanted pixels would be “invisible.” That works okay, sort of, until you draw cards on top of other cards. I refer you now to the picture I’ve included with this post. Look at that! Ugly green pixel in the midst of an otherwise pristine sea of retro Windows-3-era opulence!

The wise move would be to ignore it. I have more work to do than I can finish in this lifetime. It’s a minor detail that can wait until after I find out if anybody will ever play this thing. Sadly, this is me we’re talking about. One thing I don’t like about myself is my inability to ignore minor junk like this and focus on the bigger picture. But there it was in my head as I was working on this, over and over: ugly green pixels, ugly green pixels.

The proper fix is that the pixels that are now green need to be made transparent. I recently bought a license for Acorn, specifically to do programming-related graphics work such as this. Acorn may be capable of making a single pixel transparent, but if so, I can’t figure out how.

I evaluated other options. Make the green pixels transparent at runtime, just before displaying the images? A quick scan of the docs told me that UIImage doesn’t make it very easy. Try a different image editor? I downloaded a couple others, which were downright impenetrable, compared to Acorn. I had a look at the docs for libpng, thinking I might write a one-off utility to transparent-ize the pixels. libpng is a great piece of software, but I quickly determined that it would take me days to figure out the API well enough to do what I want.

You’re bored so let’s cut to the chase: the solution was ImageMagick. I was turned off initially, because it has that faint musty unix smell that makes me fear I’m in for trouble. I wasn’t wrong! I tried to install it via MacPorts, which gave me a fresh new version of the usual rambling useless error messages it always gives me. Maybe it thought my X11 version was too old? As if I really want to spend all day figuring out if that is in fact what it’s upset about, or how I would install a later version of X11 that I’m never going to use. So I downloaded a prebuilt binary distribution from the ImageMagick site, which was, predictably, a pain in the ass to set up. Unix motto: making simple things tedious and unpleasant for four decades!

Have to give them props, though: ImageMagick is a powerful tool. Thirty minutes of poking and prodding later, I devised this bash script to convert my entire folder-full of images at once:

#!/bin/sh for file in $(ls *.png); do     echo "converting $file ..."     convert $file -transparent "rgb(0,128,0)" $file done

Problem solved. Drawing the new-and-improved images in the iPhone simulator does exactly the right thing. The formerly-green pixels are now invisible. I tried drawing a UIImage directly and also putting it inside an UIImageView, both methods work perfectly.

The practical upshot is that my stupid brain can finally stop fixating on this minor detail, and hopefully I can get back to work.

bash: timing long-running processes

February 3, 2009 1:44 pm

The innertubes have spoken. According to the search terms I’m seeing in my access logs, you interwebbernauts want to see more bash articles. Very well, then.

Every now and then I write a bash script that might take an hour or more to run. It’s nice to know exactly how long it took, so you can plan accordingly when you want to run it the next time. So I formalized some bash timing concepts I’ve been using for years and packaged them up into a code library you can use in your own scripts.

If you’re just interested in the code, you can skip to the bottom of this entry and cut-and-paste the parts you want into locations of your choosing. If you’ve got a minute, I’ll explain some of the non-obvious bits.

bash functions can only return small integers, typically not larger than 255 or so. They are intended for use as values you’d return to the shell, when the script is finished running. If you want to write a function that returns a string or a large integer, you’re out of luck. The way I get around that one is to write functions that use echo to print a string to stdout. The output can be captured by a calling function using this rather awkward syntax:

    returnValue=$(functionName)

Unfortunately, variables in bash scripts are by default global, and therefore available to all functions. I don’t like that very much, so my local variable declarations are all prefixed with the keyword local, which is supposed to make them visible only within the current function. I have a sneaking suspicion that supposedly local variables can still “leak” into other functions, however. I suppose I should investigate that situation and use it as the basis for a future blog post.

Finally, you can use the source keyword to pull functions from one script into another, like this:

    source timerlib.sh

Now, on to the code. First up is timerlibtest.sh, a script that demonstrates use of the timerlib functions.

#!/bin/sh # timerlibtest.sh -- test for timerlib.sh # by allen brunson  allen.brunson@gmail.com  february 3 2009 # pull in timerlib functions source timerlib.sh # this function shows how to time a long-running process function main() {     # save current time at the beginning     local time=$(timerStart)         # put whatever you want to time here     echo "starting long-running process ..."     sleep 2         # display how long it took     timerStop $time "elapsed time:" } # execution start main $*

Here is the text for timerlib.sh:

#!/bin/sh # timerlib.sh -- functions for timing long-running operations # by allen brunson  allen.brunson@gmail.com  february 3 2009 # return seconds since 1970 # does not work on some unix variants.  check 'man date' for details function timerCurrent() {     date "+%s" } # inputs a number of seconds, outputs a string like "2 minutes, 1 second" # $1: number of seconds function timerLengthString() {     local days=$((0))     local hour=$((0))     local mins=$((0))     local secs=$1     local text=""         # convert seconds to days, hours, etc     days=$((secs / 86400))     secs=$((secs % 86400))     hour=$((secs / 3600))     secs=$((secs % 3600))     mins=$((secs / 60))     secs=$((secs % 60))         # build full string from unit strings     text="$text$(timerLengthStringPart $days "day")"     text="$text$(timerLengthStringPart $hour "hour")"     text="$text$(timerLengthStringPart $mins "minute")"     text="$text$(timerLengthStringPart $secs "second")"         # trim leading and trailing whitespace     text=${text## }     text=${text%% }         # special case for zero seconds     if [ "$text" == "" ]; then         text="0 seconds"     fi         # echo output for the caller     echo ${text} } # formats a time unit into a string # $1: integer count of units: 0, 6, etc # $2: unit name: "hour", "minute", etc function timerLengthStringPart() {     local unit=$1     local name=$2         if [ $unit -ge 2 ]; then         echo " ${unit} ${name}s"     elif [ $unit -ge 1 ]; then         echo " ${unit} ${name}"     else         echo ""         fi     } # useful for testing timerLengthString function timerLengthStringTest() {     local days=$((86400))     local hour=$((3600))     local mins=$((60))     local secs=$((1))         timerLengthString  0     timerLengthString 20     timerLengthString $(( ($hour * 3) + ($mins * 1) + ($secs * 52) ))     timerLengthString $(( ($days * 1) + ($secs * 14) )) } # synonym for timerCurrent function timerStart() {     timerCurrent $* } # display final elapsed time # $1: value returned from an earlier call to timerStart() # $2: optional descriptive string, such as "total wait time:" function timerStop() {     local desc=$2     local secs=$((0))     local stop=$(timerCurrent)     local text=""     local time=$1         if [ "$desc" != "" ]; then         text="$desc "     fi         secs=$(( $stop - $time ))     text="$text$(timerLengthString $secs)"         echo $text }

bash scripts: glue for unix

January 16, 2009 5:01 pm

At my last full-time job, I wrote some hideously complex bash scripts. They started out small and kind of got away from me. In hindsight, that’s pretty much the way it had to be. I was in charge of dozens of linux computers running hundreds of programs that I wrote, interacting with each other in complex ways. I didn’t fully understand the problem space, and even if I had, I didn’t have time to write all that logic in a more formal language. bash scripts are the perfect medium for spitballing solutions to problems you’re kind of fuzzy about.

This was my first attempt to solve big problems with bash, so I had a lot to learn. For example, I was surprised to discover that this script doesn’t work:

#!/bin/sh function_test function function_test() {     echo "test" }

This is an attempt to call a function before it’s defined. Trivial in C++, my native language, but not allowed in bash.

I’m kind of embarrassed to admit that I struggled with this for a long time. I wrote more and more bash functions, which became increasingly interdependent, so this problem got more troublesome as time went on.

For this reason and many others, I decided to adopt a more C-like structure for my bash scripts. Like this:

#!/bin/sh function main() {     test1     test2 } function test1() {     echo "test1" } function test2() {     echo "test2" } main $*

main() is calling test1() and test2() before they are defined.  But it doesn’t matter anymore, because all functions are defined before the program starts running. The bash interpreter has read the entire script before execution begins at the very last line, when main() is called.

I would have done this right from the beginning, but I didn’t know about the $* trick. That passes all command-line parameters received by the script to the main() function, so it can do whatever it likes with them.