Favicon to PNG

Ever want to add a link to a site with the favourites icon in the page along with the link? I did, so I made this cool little toy:

http://favicon.bitplane.net/

The site looks like nothing more than a directory filled with icons in PNG format, but it actually uses an Apache directive to make sure that every file served is sent back with the image/png mimetype, and the HTTP 404 error page points to a script:

ErrorDocument 404 /.downloader/404.php
ForceType image/png

404.php page actually downloads the favicon from a remote site and converts it to PNG format:

error_reporting(E_ERROR);
 
$fullstring = explode('/', $_SERVER['REQUEST_URI']);
$server = addslashes($fullstring[1]);
 
// load the icon into $in_file_name
if ($fin = fopen("http://$server/favicon.ico", "r"))
{
  $in_file_name = tempnam(".", "ico_");
 
  $fout = fopen($in_file_name, "wb");
 
  while(!feof($fin)) {
    $buffer = fread($fin, 2048);
    fwrite($fout, $buffer);
  }
 
  fclose($fin);
  fclose($fout);
 
  // convert the file
 
  $file_name = "../$server";
 
  if (`python ConvertIcon.py '$in_file_name' '$file_name'` != 0)
    $file_name = "../default.png";
}
else
  $file_name = "../default.png";
 
// serve up the output file
 
header("Content-type: image/png");
 
$fin = fopen($file_name, "r");
while(!feof($fin)) {
  $buffer = fread($fin, 2048);
  echo $buffer;
}

The conversion is done by a simple script which uses Python Imaging Library to convert the icon file to a PNG file. I would have done this in PHP but ImageMagick didn’t like transparency, and I prefer Python.

from sys import argv
import PIL
 
from LoadIcon import load_icon
 
# load the icon from first argument
try:
  image = load_icon(argv[1], 0)
except IOError: # sometimes people use other file types, ie bitmaps
  image = PIL.Image.open(argv[1])
 
# save it to file in second argument
f = file(argv[2], "w")
 
image.thumbnail( (16, 16), PIL.Image.ANTIALIAS)
image.save(f, "PNG", quality=95)
 
f.close()

LoadIcon just contains a function I stole from StackOverflow, which works round the transparency bug in PIL.

The solution isn’t quite perfect, it doesn’t choose the best quality icons and there could be gaping security vulnerabilities all over it… I’ve taken the precaution of running it under a locked down user, if you use it then you should do the same. It also doesn’t have much in the way of caching, nor does it deal with case sensitivity or honour caching policies.

Finally, it was of course inspired by Google’s undocumented ico to png converter.