php sprite script


So js1k got slashdotted a few days after the contest closed. On the one hand that's a shame. May have had a lot more entries if it would have happened before. On the other hand, I would have had to move the whole thing around because the slashdot effect hit hard. And the sudden increase in popularity would have given me much more work as well more potential abusive submissions.

Anyways, it was after so the discussion is moot. However, getting my ass on slashdot did put a big knife into my server. Up to the point where I got a dreamhost message. "We are contacting you to inform you that we have had to throttle the connections to your site ( as it was causing the apache server you are on to run out of available connection slots.". Later I heard that "Currently, the throttle is set at 50Mbps with 100 connections per second."

Well wow, even ajaxian and smashing magazine didn't manage to do that. Nor did reddit, which (probably) caused a spike of 56k uniques on one day. Still, the contest is over, it was late so I left it at that. The flood will go away soon enough, why bother.

Well it doesn't seem to go away. One day later and the domain is still very unresponsive. Even though the visitor count is at about 35k uniques (469737 page views). Hm. So might there be an easy fix? I'm caching most query heavy pages. But the demo page does have a few thumbnails.

Turns out the demo page has about 350 thumbnails. For each request to the demos page. At 35k visitors, of which many are likely to visit that page... oops. So I built a small sprite building script now. Nothing fancy, but I wanted to share it anyways.

It reduced the weight of that page from about 350 images at 800k to 1 image at 350k. The image is actually a little bloated at that, but I don't really have the time to filter used thumb images. I'm actually a little surprised at how fast PHP manages to do this.

Code: (PHP)
$thumbWidth = 50;
$thumbHeight = 50;
$images = 800;
$imagesX = 25;
$imagesY = ceil($images / $imagesX);
$img = imagecreatetruecolor($imagesX*$thumbWidth, $imagesY*$thumbHeight);
$white = imagecolorallocate($img, 255,255,255);
imagefilledrectangle($img, 0, 0, $imagesX*$thumbWidth, $imagesY*$thumbHeight, $white);
$i = 0;
// build the sprite map
for ($i=0; $i<$images; ++$i) {
// get the source file name
$file = 'img/'.$i.'.png';
// make sure it exists (in my case, not all files needed to exist)
if (file_exists($file)) {
$img2 = imagecreatefrompng($file);
// add to sprite
imagecopyresampled($img, $img2, ($i%$imagesX)*$thumbWidth, floor($i/$imagesX)*$thumbHeight, 0, 0, $thumbWidth, $thumbHeight, imagesx($img2), imagesy($img2));
// write image to disk
imagepng($img, 'sprite.png');

And now you have an image map, you can easily refer to the sprites. The css looks like this:

Code: (css)
.sprite {
display: inline-block;
background-image: url(sprite.png);
background-repeat: no-repeat;
width: 50px;
height: 50px;
overflow: hidden;

And the "dynamic" html like this:

Code: (html)
<div class="sprite" style="background-position: -<?=(($id%$imagesX)*50)?>px -<?=(($id/$imagesX)*50)?>px;"></div>

It's pretty basic spriting stuff, but maybe it helps you. I hope it does :)