Interesting Things

Richard Bradshaw's idea of what is interesting

Speed up writing CSS backgrounds

I often need to write code like:

background: url("/media/img/footer.png") no-repeat;
width: 960px;
height: 147px;

Whenever I do, I have to find the image, then get the dimensions, then copy and paste them in separately. It’s annoying. To help, I put together this small tool, written in Python and using OSX’s pbcopy. You’ll need to tweak it if you are on a different platform.

I put this into a file called css-background in ~/bin, then ran chmod u+x to make it runnable. All the images I ever use are in /media/img, so you may need to change that if you do anything differently. At some point, I may update this to work out the filepath properly, but personally I don’t need it.

Go to the folder with the image in, and run

css-background image_name.png

After running it, the CSS code is in the clipboard ready to paste.

?View Code PYTHON
#!/usr/bin/python
 
import sys, os, argparse, StringIO, struct
 
 
def getImageInfo(data):
 
    # From http://code.google.com/p/bfg-pages/source/browse/trunk/pages/getimageinfo.py
    data = str(data)
    size = len(data)
    height = -1
    width = -1
    content_type = ''
 
    # handle GIFs
    if (size >= 10) and data[:6] in ('GIF87a', 'GIF89a'):
        # Check to see if content_type is correct
        content_type = 'image/gif'
        w, h = struct.unpack("<HH", data[6:10])
        width = int(w)
        height = int(h)
 
    # See PNG 2. Edition spec (http://www.w3.org/TR/PNG/)
    # Bytes 0-7 are below, 4-byte chunk length, then 'IHDR'
    # and finally the 4-byte width, height
    elif ((size >= 24) and data.startswith('\211PNG\r\n\032\n')
          and (data[12:16] == 'IHDR')):
        content_type = 'image/png'
        w, h = struct.unpack(">LL", data[16:24])
        width = int(w)
        height = int(h)
 
    # Maybe this is for an older PNG version.
    elif (size >= 16) and data.startswith('\211PNG\r\n\032\n'):
        # Check to see if we have the right content type
        content_type = 'image/png'
        w, h = struct.unpack(">LL", data[8:16])
        width = int(w)
        height = int(h)
 
    # handle JPEGs
    elif (size >= 2) and data.startswith('\377\330'):
        content_type = 'image/jpeg'
        jpeg = StringIO.StringIO(data)
        jpeg.read(2)
        b = jpeg.read(1)
        try:
            while (b and ord(b) != 0xDA):
                while (ord(b) != 0xFF): b = jpeg.read(1)
                while (ord(b) == 0xFF): b = jpeg.read(1)
                if (ord(b) >= 0xC0 and ord(b) <= 0xC3):
                    jpeg.read(3)
                    h, w = struct.unpack(">HH", jpeg.read(4))
                    break
                else:
                    jpeg.read(int(struct.unpack(">H", jpeg.read(2))[0])-2)
                b = jpeg.read(1)
            width = int(w)
            height = int(h)
        except struct.error:
            pass
        except ValueError:
            pass
 
    return content_type, width, height
 
parser = argparse.ArgumentParser(description='Specify an image')
parser.add_argument('image', action="store", help='image to generate code for')
arguments = parser.parse_args()
 
f = open(arguments.image, 'r')
 
info = getImageInfo(f.read())
 
width = str(info[1])
height = str(info[2])
 
text = 'background: url("/media/img/'+arguments.image+'") no-repeat;\n'
text += 'width: '+width+'px;\n'
text += 'height: '+height+'px;'
 
outf = os.popen("pbcopy", "w")
outf.write(text)
outf.close()

Simple!

Increasing productivity by automating common actions on OSX

Every time I do some web development there are a few things I need to do:

  • Point MAMP to the correct folder and enter password (as I’m serving on port 80)
  • Open the folder in Textmate
  • Open two tabs in iTerm
  • Run livereload in iTerm in that directory
  • Run SASS pointing at CSS in a subdirectory, again in iTerm
  • Open a tab in Chrome pointing at localhost

Each of these takes a few seconds to remember/type the command. Wouldn’t it be nice to speed things up?

First thing I’ve done is to point MAMP at the ~/activeSite, and never change it. To get content there I’m going to symlink the real directory to there, so I don’t have to mess around with MAMP.

Second thing is to declare a couple of bash functions. I’d recommend putting these into your ~/.bashrc file. Remember to run source ~/.bashrc after editing that file to get the new code to work.

I keep all my websites in ~/website, and all have a subdirectory called media, with subdirectory inside that called css. You’ll need to modify this to work for your set up. To run this, type editsite SITE_DIRECTORY_NAME in bash.

editsite() {
 
rm ~/activeSite
ln -s ~/websites/$1 ~/activeSite
 
osascript -e "
tell application \"iTerm\"
	tell the first terminal
		tell the last session
			write text \"cd ~/websites/$1/\"
		end tell
	end tell
 	tell the first terminal
		launch session \"Default Session\"
		tell the last session
			write text \"mate ~/websites/$1\"
			write text \"cd ~/websites/$1\"
			write text \"livereload\"
		end tell
	end tell
	 tell the first terminal
		launch session \"Default Session\"
		tell the last session
			write text \"cd ~/websites/$1/media/\"
			write text \"sass --style compressed --watch css:css\"
		end tell
	 end tell
end tell
tell application \"Google Chrome\"
	set newtab to make new tab at end of tabs of window 1
	set URL of newtab to \"http://localhost/\"
	activate
	tell application \"System Events\" to keystroke "r" using command down # Anyone know how to do command shift down?
end tell"
}

This does pretty much what you’d expect. You could use a docstring instead of this if you wanted, but I’m happy with escaped “s.

This is all well and good, but sometimes I can’t remember what I called the directory, so here’s another function that lets me check, even if I’ve already started typing editsite.

editsites() {
	cd ~/websites
	ls -d */
}

This just lists the directories in my websites directory.

Any improvements, let me know!

A jQuery function to animate using CSS3 transitions if possible, with the built-in animate fallback.

This requires you to use the amazing Modernizr library, or could be modified to use your own check for whether the browser supports CSS transitions. It’s rough and ready, but works fine as far as I know!

For lots more info and demos of transitions, have a look at my CSS3 transitions and transforms tutorial.

All this lot goes before your document ready section.

?View Code JAVASCRIPT
var speed = 500; // Default animation speed in milliseconds (1000 = 1 second)
 
var vP = "";
var transitionEnd = "TransitionEnd";
if ($.browser.webkit) {
	vP = "-webkit-";
	transitionEnd = "webkitTransitionEnd";
} else if ($.browser.msie) {
	vP = "-ms-";
} else if ($.browser.mozilla) {
	vP = "-moz-";
	transitionEnd = "transitionend";
} else if ($.browser.opera) {
	vP = "-o-";
	transitionEnd = "oTransitionEnd";
}
 
function animate2(object, cssProperties, callback, ms) {
	if (!ms) {
		ms = speed;
	}
 
	if (Modernizr.csstransitions) {
		object.css(vP+"transition", "all "+ms+"ms ease-in-out");
 
		object.css(cssProperties);
 
		if ($.isFunction(callback)) {
			object.bind(transitionEnd,function(){
			     object.unbind(transitionEnd);
			     callback();
			});
		}
 
	} else {
		if ($.isFunction(callback)) {		
			object.animate(cssProperties, ms, callback);
		} else {
			object.animate(cssProperties, ms);			
		}
	}
}

Then, the bit that runs once the DOM is built:

?View Code JAVASCRIPT
$(function(){
    // Simplest example. Animate the height of a box to 600px high.
    animate2($("#my_box"), {"height": 600});
 
    // More complex. Animate the height to 600px, and the left-margin to 100px with a callback.
    animate2($("#my_box"), {"height": 600, "margin-left": 10px}, function(){
         console.log("Animation finished");
    }, 1500);
 
});

Rather pleasant I feel. I’d really welcome suggestions for improvement, the idea is to provide a simple way to move things around using the best method possible.

Dynamically drawing gradients with PHP

Just a little script to create a PNG image of a simple linear gradient using PHP. You could adapt this to make it better in many ways! Insipired (by which I mean 99% ripped of!) by http://www.cutcodedown.com/

No demo to avoid load on the server, but it just makes a simple gradient.

I use it as a fallback for CSS3 gradients.

<?php
/* Put on a server, make the gradients folder, then call like so:
 
gradient.php?sc=ff0000&ec=0000ff&h=100&w=200
 
sc = start colour, ec = end colour, h = height, w = width.
 
The file should be cached, though I normally use mod_rewrite to tidy it up a little.
*/
 
/* Change this to suit, you'll need to make the folder first */
$destfolder = $_SERVER[ 'DOCUMENT_ROOT' ]."/gradients/";
 
function caching_headers ($file, $timestamp) {
	$gmt_mtime = gmdate('r', $timestamp);
	header('ETag: "'.md5($timestamp.$file).'"');
 
	if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) || isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
		if ($_SERVER['HTTP_IF_MODIFIED_SINCE'] == $gmt_mtime || str_replace('"', '', stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])) == md5($timestamp.$file)) {
			header('HTTP/1.1 304 Not Modified');
			exit();
		}
	}
 
	header('Last-Modified: '.$gmt_mtime);
	header('Cache-Control: public');
}
 
function gradient($width,$height,$startColor,$endColor) {
	$final=imagecreatetruecolor($width,$height);
 
	$r=($startColor >> 16) & 0xFF;
	$g=($startColor >> 8) & 0xFF;
	$b=($startColor) & 0xFF;
 
	if ($height==0) {
		imagefill($final,0,0,imagecolorallocate($final,$r,$g,$b));
	} else {
 
		$endR=($endColor >> 16) & 0xFF;
		$endG=($endColor >> 8) & 0xFF;
		$endB=($endColor) & 0xFF;
 
		$incR=($endR-$r);
		$incG=($endG-$g);
		$incB=($endB-$b);
 
		$absDisR=abs($incR);
		$absDisG=abs($incG);
		$absDisB=abs($incB);
 
		if ($absDisR>$absDisG) {
			if ($absDisR>$absDisB) {
				$distance=$absDisR;
			} else {
				$distance=$absDisB;
			}
		} else if ($absDisG>$absDisB) {
			$distance=$absDisG;
		} else {
			$distance=$absDisB;
		}
 
		if ($distance==0) {
			imagefill($final,0,0,imagecolorallocate($final,$r,$g,$b));
		} else {
			if ($distance>$height) $distance=$height;
 
			$sliver=imagecreatetruecolor(1,$distance);
			$sliverMax=$distance-1;
 
			$incR/=$sliverMax;
			$incG/=$sliverMax;
			$incB/=$sliverMax;
 
			$style=array();
 
			for ($t=0; $t<$distance; $t++) {
				$style[$t]=imagecolorallocate($sliver,$r,$g,$b);
				$r+=$incR;
				$g+=$incG;
				$b+=$incB;
			}
 
			imagesetstyle($sliver,$style);
			imageline($sliver,0,0,0,$sliverMax,IMG_COLOR_STYLED);
			imagecopyresized(
				$final,$sliver,
				0,0,0,0,
				$width,$height,1,$distance
			);
			imagedestroy($sliver);
		}
	}
	return $final;
}
 
/* This bit isn't really very good, but you get the idea. */
$width=is_numeric(str_replace("px","",$_GET['w'])) ? $_GET['w'] : 96;
$height=is_numeric(str_replace("px","",$_GET['h'])) ? $_GET['h'] : 96;
$startColor=empty($_GET['sc']) ? 0 : hexdec($_GET['sc']);
$endColor=empty($_GET['ec']) ? 0xFFFFFF : hexdec($_GET['ec']);
 
$filename = $width."_".$height."_".$_GET['sc']."_".$_GET['ec'].".png";
 
if (!file_exists($destfolder.$filename)) {
	$image=gradient($width,$height,$startColor,$endColor);
	imagepng($image,$destfolder.$filename);
	imagedestroy($image);
}
 
caching_headers ($filename, filemtime($destfolder.$filename));
 
header('Parameters : '.$_GET['w']."x".$_GET['h']." ".$_GET['sc']." to ".$_GET['ec']);
header('Content-Type: image/png');
 
$image = imagecreatefrompng($destfolder.$filename);	
imagepng($image);
imagedestroy($image);
 
?>

CSS3 Transition, Transform and Animation Tutorial

I’ve just written a tutorial complete with demos showing how to use the CSS3 transition, transform and animation properties – find it here: CSS3 Transition, Transform and Animations Tutorial.

Hopefully it’s useful/interesting – any comments/improvements let me know!

It’s still a work in progress, so I’ll be adding to it over the next few weeks.

Fancy Forms: HTML5 + CSS3 – JS

Forms in HTML have typically been pretty boring – input boxes and buttons with all validation performed by javascript. With the new HTML5 Forms module things have become a little more useful. As of May 2010, only bleeding edge browsers support this, Webkit Nightlies, Chrome Dev Channel builds and Opera.

The HTML5 forms module started out as Web Forms 2.0 before moving into HTML5. The focus has been to increase the number of input types and to allow validation of input to happen in the browser, rather than in javascript.

HTML5 Form Demo

In this demo I’ve set up a simple form with a number of different fields, the code should be pretty self explanatory, but there are a couple of new features of interest.

  • New input types – email, url, number and range
  • New pseudo classes – :valid, :invalid:, :required
  • You can’t submit the form until all fields are counted as valid by the browser

I’ve also added a few CSS3 touches to make things a little nicer to look at:

  • CSS transitions and transformations
  • :not pseudo class

Things to try

  • Submit the form without completing it
  • Notice that the browser checks whether the input is valid
  • The iPhone offers different keyboards depending on the input type
  • Check what it looks like in older browsers (fine, but no validation)

The code is commented where interesting, so take a look at the source.

HTML5 Form Demo

Video of ChromeOS Early Build


Just a quick video made of the ChromeOS build found on the chromium.org server. It’s run on Ubuntu in a virtual machine running on Snow Leopard. Used Quicktime X to record it, which turned out pretty well I think!

Not much in there yet, but good to see that parts of it are on the way!

Interesting links for week ending October 14th

Here are some links that I’ve found interesting:

The State of Solid State Hard Drives

Fugitive gives the game away with Facebook updates

Tesco boss raps school standards

Help us nail spammers

Building a jQuery/PHP Powered Chat Room

Time-travelling Higgs sabotages the LHC. No, really

Tim Berners-Lee’s One Regret Regarding the Web

New in Labs: Got the wrong Bob?

Lightly Edit Images Easily With Acorn [Mac only]

Introducing Google Building Maker

Some interesting links for October 13th

Here are some links that I’ve found interesting:

Interesting Links

Here are some links that I’ve found interesting: