The Problem with Code Samples

Up until about thirty seconds before I hit publish on this post, there was a section on this site called “Code Samples.”  I removed it (after pulling one piece of code over to this blog) because I realized it wasn’t providing what it should.

Said section was made up of four links to zip files, each containing the code for a different project.  Aside from a text description of the project, there was no breakdown of why the code was written a certain way or what was learned from writing it.

Since I started this blog, I realized that what I’d hoped to accomplish with the “Code Samples” section was being achieved with posts on things like my work with the Twitter and Trello APIs.  These posts explained not just the how of what I did but the why.

I’m going to keep posting new stuff under the “Code Sample” category in the blog. Hopefully that way I can make my samples less a display of specific code and more a discussion of how I code.

Retro Code Sample: Opening Night Countdown Image

Sometime soon I’ll write a bit on my new-ish philosophy about code samples.  For now it’s enough to say that I’m cleaning out that section of my site but there’s one project I wanted to keep documented, so I’m writing it up here and now even though the code is from 2005.

The “Opening Night Countdown Image” was my first foray into using the PHP image functions and the GD2 library.  Based heavily on the code from the Church Sign Generator, it took the hard-coded date of the Detroit Red Wings’ first game back after the 2004-05 NHL lockout and generated an image displaying the number of days remaining until that date.

There were four parts to the project: Two resource image files in .gif format, the actual PHP that mashed those together properly, and a .htaccess file that allowed for a pretty URL for the image.

The .htaccess file was simple enough.  Inside a folder called /nhl_countdown/ it looked as follows:

# General rewrites
RewriteEngine on
Options +FollowSymlinks
RewriteBase /
RewriteRule ^.htaccess$ - [F]

# image rewrite
RewriteRule countdown.gif /nhl_countdown/image.php

Turn rewrites on, allow Symlinks (completely unnecessary), set the rewrite base, block the .htaccess file, and actually rewrite requests for countdown.gif (the pretty filename) to the actual PHP script that generated the image.

The resource images were also pretty simple.

background

numbers

The first was just a static background featuring the team logos and an empty space where the countdown numbers should be. The second was the set of numbers to use in the countdown itself.  Both were .gif for some reason, probably because of the lack of support for .png in 2005.

The code is where it gets fun so let’s get into that.

// FIND OUT THE TIME REMAINING
$date = '2005-10-05';  // SET THE DATE

$parts = explode('-', $date);

$zero_hour = mktime (0, 0, 0, $parts['1'], $parts['2'], $parts['0']);
$today = mktime (date('H'), date('i'), date('s'), date('m'), date('d'), date('Y'));

$difference = $zero_hour - $today;

$s = $difference;
$d = intval($s / 86400);
$s -= $d * 86400;
$h = intval($s / 3600);
$s -= $h * 3600;
$m = intval($s / 60);
$s -= $m * 60;

if ($d <= '0') {
	$days = '0';
} else {
	$days = $d + 1;
}

We first determine the number of days remaining until gameday. This is horribly inefficient but it’s easy to say that with eight more years of development experience. This isn’t a code review, it’s a sample, so I’m not going to correct myself.

/* This is the list of allowed characters. The reason more characters aren't allowed is because I didn't put more characters in the characters image. More characters means more figuring out coordinates, ie. more work. Each character array comprises the character itself, its X coordinate (the Y coordinate is always 0), and its width (the height is always 12, the height of the image). */

$allowed_chars = array(
	array('1', 0, 33),
	array('2', 33, 35),
	array('3', 68, 32),
	array('4', 100, 35),
	array('5', 135, 32),
	array('6', 167, 33),
	array('7', 200, 31),
	array('8', 231, 34),
	array('9', 265, 32),
	array('0', 297, 33),
);

Next we map out what parts of the number resource file relate to each actual number. This is another thing I’d probably do differently now.

/* load the characters image and the background image into memory */
$chars_img = imagecreatefromgif('numbers.gif');
$background_img = imagecreatefromgif('background.gif');

/* get the width and height of the background image */
$src_w = imagesx($background_img);
$src_h = imagesy($background_img);

/* create a new image, that will be output to the browser */
$output_img = imagecreatetruecolor($src_w, $src_h);

/* copy the background image onto the output image */
imagecopy($output_img, $background_img, 0, 0, 0, 0, $src_w, $src_h);

/* Since the letters are centered on the background, the x centerpoint gives a starting point from which the x offset for each letter can be calculated. The y offset is simply the distance from the top of the image to the top of the first row of letters. */
$x_center = 300;
$y_offset = 27;

Then we do a little setup, getting the image resources loaded in and getting ready to do our typesetting.

/* This calculates the x offset for the text. It loops through the letters of the text and adds the width of each letter to the x centerpoint to get the beginning point. */

$x_offset = 0;

// calculate offset
for ($i = 0; $i < strlen($days); $i++) {
	/* Get the current character */
	$curchar = substr($days, $i, 1);

	/* loop through the characters array until we reach the one matching the current character, and add half its width to the x offset. */
	foreach($allowed_chars as $char) {
		if ($curchar == $char[0]) {
			$x_offset += ceil($char[2] / 2);
		}
	}
}

for ($i = 0; $i < strlen($days); $i++) {
	/* The second pass actually copies each letter from the characters image onto the output image. */
	$curchar = substr($days, $i, 1);

	foreach($allowed_chars as $char) {
		if ($curchar == $char[0]) {
			/* The imagecopymerge() function copies a rectangular area from one image onto another image. This is documented more than adequately on php.net. */
			imagecopymerge($output_img, $chars_img, ($x_center - $x_offset), $y_offset, $char[1], 0, $char[2], 45, 100);
			$x_offset -= $char[2];
		}
	}
}

We loop through each digit in the number of days remaining twice. First to find the size of the image representing the character so we can properly center the completed text, then to actually add said text to the new image.

/* Now that the image is built, it gets sent to the browser. First, send out HTTP headers to tell the browser a GIF image is coming. */
header("Content-Type: image/gif");
header("Content-Disposition: inline; filename=countdown.gif");

/* The imagegif() function sends the output img to the browser. */
imagegif($output_img);

/* Housekeeping functions - destroy the scratch images to free up the memory they take up. */
imagedestroy($background_img);
imagedestroy($chars_img);
imagedestroy($output_img);

Then we actually output the new image and do some cleanup.

As I said, it’s old, horribly inefficient code. As I’m cleaning up my code samples, though, this is something I didn’t want to lose (perhaps as a reminder of how far I’ve come) so I thought it made sense to write up a post on it.