--- signwriter.install.orig	2008-10-07 17:47:46.000000000 +0200
+++ signwriter.install	2008-10-07 17:43:15.000000000 +0200
@@ -2,6 +2,11 @@
 // $Id: signwriter.install,v 1.8 2008/09/08 02:07:34 agileware Exp $
 
 /**
+ * @file
+ * (Un)Install/Update hooks for Signwriter.
+ */
+
+/**
  * Implementation of hook_install().
  */
 function signwriter_install() {
@@ -143,3 +148,13 @@ function signwriter_schema() {
 
   return $schema;
 }
+
+function signwriter_update_6000() {
+  $ret = array();
+  variable_del('cachedir');
+  variable_del('fontpath');
+  cache_clear_all();
+  menu_rebuild();
+  drupal_set_message(t('The signwriter module now cleans up the generated image files once a week. Files generated by previous versions have to be removed manually from the old signwriter cache directory. The new one is located within the files directory.'));
+  return $ret;
+}
--- signwriter.module.orig	2008-10-07 17:44:09.000000000 +0200
+++ signwriter.module	2008-10-07 17:43:15.000000000 +0200
@@ -2,12 +2,12 @@
 // $Id: signwriter.module,v 1.17 2008/09/08 02:07:34 agileware Exp $
 
 /**
- * Implementation of hook_help()
+ * Implementation of hook_help().
  */
 function signwriter_help($path, $arg) {
   switch ($path) {
     case 'admin/help#signwriter':
-      return t("<p>The signwriter module allows you to use custom truetype fonts for headings. It does this by creating images with the headings' text, and replacing the headings with the images.</p><p>There are several ways in which you can use signwriter: <ul><li>It can be used as an input filter to replace headers in content,</li><li>it can be used and configured by a theme, or</li><li>it can be used by a theme and configured in drupal.</li></ul></p>");
+      return t("<p>The signwriter module allows you to use custom TRUEtype fonts for headings. It does this by creating images with the headings' text, and replacing the headings with the images.</p><p>There are several ways in which you can use signwriter: <ul><li>It can be used as an input filter to replace headers in content,</li><li>it can be used and configured by a theme, or</li><li>it can be used by a theme and configured in drupal.</li></ul></p>");
       break;
   }
 }
@@ -24,32 +24,35 @@ function signwriter_menu() {
     'page callback' => 'signwriter_settings_page',
     'access arguments' => array('administer signwriter'),
     'type' => MENU_NORMAL_ITEM,
-    );
+  );
 
   $items['admin/settings/signwriter/profile/add'] = array(
     'title' => 'Add profile',
     'description' => 'Add a new Signwriter profile.',
-    'page callback' => 'signwriter_profile_page',
+    'page callback' => 'drupal_get_form',
     'access arguments' => array('administer signwriter'),
-    'page arguments' => null,
+    'page arguments' => array('signwriter_profile_form'),
     'type' => MENU_NORMAL_ITEM,
-    'weight' => -8);
+    'weight' => -8,
+  );
 
   $items['admin/settings/signwriter/profile/%signwriter_profile'] = array(
     'title' => 'signwriter profile',
     'description' => t('Manage the  Signwriter profile.'),
-    'page callback' => 'signwriter_profile_page',
+    'page callback' => 'drupal_get_form',
     'access arguments' => array('administer signwriter'),
-    'page arguments' => array(4),
-    'type' => MENU_NORMAL_ITEM,);
+    'page arguments' => array('signwriter_profile_form', 4),
+    'type' => MENU_NORMAL_ITEM,
+  );
 
   $items['admin/settings/signwriter/profile/%signwriter_profile/delete'] = array(
     'title' => "Delete signwriter profile",
     'description' => t('Delete the Signwriter profile'),
-    'page callback' => 'signwriter_confirm_delete_profile_page',
+    'page callback' => 'drupal_get_form',
     'access arguments' => array('administer signwriter'),
-    'page arguments' => array(4),
-    'type' => MENU_NORMAL_ITEM,);
+    'page arguments' => array('signwriter_confirm_delete_profile_form', 4),
+    'type' => MENU_NORMAL_ITEM,
+  );
 
   return $items;
 }
@@ -79,10 +82,10 @@ function signwriter_filter($op, $delta =
 
       case "process":
         $profile = signwriter_load_profile($delta);
-      return preg_replace($profile->pattern . 'e', 'signwriter_title_convert("$0", $profile)', $text);
+      return preg_replace($profile->pattern .'e', 'signwriter_title_convert("$0", $profile)', $text);
 
     case 'no cache':
-      return true;
+      return TRUE;
 
     default:
       return $text;
@@ -90,12 +93,12 @@ function signwriter_filter($op, $delta =
 }
 
 /**
- * Implementation of hook_filter_tips()
+ * Implementation of hook_filter_tips().
  */
-function signwriter_filter_tips($delta, $format, $long = false) {
+function signwriter_filter_tips($delta, $format, $long = FALSE) {
   $profile = signwriter_load_profile($delta);
   if ($long) {
-    return t('The signwriter filter will replace headings matching the regular expression %pattern with images according to the settings of <a href="@profile-admin-url">the signwriter profile %profilename</a>.', array('%pattern' => $profile->pattern, '@profile-admin-url' => url('admin/settings/signwriter/profile/' . $profile->id), '%profilename' => $profile->name));
+    return t('The signwriter filter will replace headings matching the regular expression %pattern with images according to the settings of <a href="@profile-admin-url">the signwriter profile %profilename</a>.', array('%pattern' => $profile->pattern, '@profile-admin-url' => url('admin/settings/signwriter/profile/'. $profile->id), '%profilename' => $profile->name));
   }
   else {
     return t("The signwriter filter '%profilename' is enabled.", array('%profilename' => $profile->name));
@@ -103,19 +106,7 @@ function signwriter_filter_tips($delta, 
 }
 
 function _signwriter_db_fields() {
-  return array('id', 'name', 'pattern', 'fontfile', 'fontsize', 'imagetype', 'background', 'foreground','multiline', 'drop_shadow', 'shadow_color', 'shadow_xoffset', 'shadow_yoffset', 'transparent', 'bgimage', 'width', 'height', 'maxwidth', 'textalign', 'xoffset', 'yoffset');
-}
-
-function _signwriter_profile_whereclause($profile) {
-  if ($profile->id)
-    return "WHERE id = '{$profile->id}'";
-  if ($profile->name)
-    return "WHERE name = '{$profile->name}'";
-  if (is_numeric($profile))
-    return "WHERE id = '$profile'";
-  if (is_string($profile))
-    return "WHERE name = '$profile'";
-  return false;
+  return array('id', 'name', 'pattern', 'fontfile', 'fontsize', 'imagetype', 'background', 'foreground', 'multiline', 'drop_shadow', 'shadow_color', 'shadow_xoffset', 'shadow_yoffset', 'transparent', 'bgimage', 'width', 'height', 'maxwidth', 'textalign', 'xoffset', 'yoffset');
 }
 
 /**
@@ -123,36 +114,26 @@ function _signwriter_profile_whereclause
  * Returns the user to the main signwriter settings page.
  *
  * @param $profile
- *   The profile to delete. This can be one of:
- *     - a profile id
- *     - a profile name
- *     - a profile object with at least the name or id set
+ *   The profile object to delete.
  */
 function signwriter_delete_profile($profile) {
-  if ($where = _signwriter_profile_whereclause($profile)) {
-    db_query("DELETE FROM {signwriter} $where");
+  if (db_query('DELETE FROM {signwriter} WHERE id = %d', $profile->id)) {
     drupal_set_message(t("Deleted the '@name' profile.", array('@name' => $profile->name)));
   }
-  drupal_goto('admin/settings/signwriter');
+  else {
+    drupal_set_message(t("Deleting the '@name' profile failed!", array('@name' => $profile->name)), 'warning');
+  }
 }
 
 /**
  * Ask for user confirmation before deleting a profile.
  *
  * @param $profile
- *   The profile to delete. This can be one of:
- *     - a profile id
- *     - a profile name
- *     - a profile object with at least the name or id set
+ *   The profile object to delete.
  */
-function signwriter_confirm_delete_profile_page($profile) {
-  print theme('page', drupal_get_form('signwriter_confirm_delete_profile_form', $profile));
-}
-
-function signwriter_confirm_delete_profile_form($form_state, $profile) {
-//  $profile = signwriter_load_profile($profile);
+function signwriter_confirm_delete_profile_form($profile) {
+  $form = array();
   $form['id'] = array('#type' => 'value', '#value' => $profile->id);
-  $form['#submit'] = array('_signwriter_confirm_delete_profile_submit');
   return confirm_form($form,
       t('Are you sure you want to delete the \'%title\' profile?', array('%title' => $profile->name)),
       'admin/settings/signwriter',
@@ -161,9 +142,10 @@ function signwriter_confirm_delete_profi
       t('Cancel'));
 }
 
-function _signwriter_confirm_delete_profile_submit($form, $form_state) {
+function signwriter_confirm_delete_profile_form_submit($form, $form_state) {
   $profile = signwriter_load_profile($form_state['values']['id']);
-  return signwriter_delete_profile($profile);
+  signwriter_delete_profile($profile);
+  $form_state['redirect'] = 'admin/settings/signwriter';
 }
 
 /**
@@ -173,36 +155,30 @@ function _signwriter_confirm_delete_prof
  *   The profile object to save
  */
 function signwriter_save_profile($profile) {
-  $profile->is_new = false;
-  if (empty($profile->id)) {
-    $profile->is_new = true;
-  }
-
   $fields = _signwriter_db_fields();
-  foreach ($fields as $fieldname) {
-    if (!is_null($profile->$fieldname)) {
-      $keys[] = $fieldname;
-      $value_keywords[] = "'%s'";
-      $values[] = $profile->$fieldname;
+  $values = array();
+  foreach ($fields as $field) {
+    if (!empty($profile->$field)) {
+      $values[$field] = $profile->$field;
+    }
+    else {
+      unset($fields[$field]);
     }
   }
 
-  if (count($keys)) {
-    if ($profile->is_new) {
-      $keys = implode(', ', $keys);
-      $value_keywords = implode(', ', $value_keywords);
-      db_query("INSERT INTO {signwriter} ($keys) VALUES ($value_keywords)", $values);
-      $result = db_result(db_query("SELECT LAST_INSERT_ID()"));
-      return $result;
+  if (count($values)) {
+    if (empty($profile->id)) {
+      db_query("INSERT INTO {signwriter} ('%s') VALUES ('%s')", implode(', ', $fields), implode(', ', $values));
+      $newid = db_result(db_query("SELECT LAST_INSERT_ID()"));
+      return $newid;
     }
     else {
-      $where = _signwriter_profile_whereclause($profile);
-      foreach ($keys as $key) {
-        $assignments[] = "$key = '%s'";
+      $assignments = array();
+      foreach ($fields as $field) {
+        $assignments[] = "$field = '%s'";
       }
-      $assignments = implode(', ', $assignments);
-      db_query("UPDATE {signwriter} SET $assignments $where", $values);
-      return FALSE;
+      db_query("UPDATE {signwriter} SET ". implode(', ', $assignments) ." WHERE id = ", $values, $profile->id);
+      return 0;
     }
   }
 }
@@ -210,7 +186,7 @@ function signwriter_save_profile($profil
 /**
  * Load a profile from the database.
  *
- * @param $profile
+ * @param $p
  *   The profile to load. This can be one of:
  *     - a profile id
  *     - a profile name
@@ -219,10 +195,15 @@ function signwriter_save_profile($profil
  * @return
  *   A signwriter profile object.
  */
-function signwriter_load_profile($profile) {
-  if ($where = _signwriter_profile_whereclause($profile)) {
-    $fields = implode(', ', _signwriter_db_fields());
-    return db_fetch_object(db_query("SELECT $fields FROM {signwriter} $where"));
+function signwriter_load_profile($p) {
+  $id = is_numeric($p) ? $p : (!empty($p->id) ? $p->id : 0);
+  $name = is_string($p) ? $p : (!empty($p->name) ? $p->name : '');
+  $fields = implode(', ', _signwriter_db_fields());
+  if ($id) {
+    return db_fetch_object(db_query("SELECT %s FROM {signwriter} WHERE id = %d", $fields, $id));
+  }
+  else {
+    return db_fetch_object(db_query("SELECT %s FROM {signwriter} WHERE name = '%s'", $fields, $name));
   }
 }
 
@@ -230,15 +211,15 @@ function signwriter_load_profile($profil
  * Load zero or more signwriter profiles.
  *
  * @param $profiles
- *   Describes which profile(s) to load. If absent or null then load all
+ *   Describes which profile(s) to load. If absent or NULL then load all
  *   profiles. Otherwise this should be an array, each element of which should
  *   be one of:
  *     - a profile id
  *     - a profile name
  *     - a profile object with at least the name or id set
  */
-function signwriter_load_profiles($profiles = null) {
-  if (is_null($profiles)) {
+function signwriter_load_profiles($profiles = NULL) {
+  if (is_NULL($profiles)) {
     $profiles = array();
     $results = db_query("SELECT %s FROM {signwriter}", implode(', ', _signwriter_db_fields()));
     while ($profile = db_fetch_object($results)) {
@@ -255,50 +236,41 @@ function signwriter_load_profiles($profi
   return $profiles;
 }
 
-/**
- * The signwriter profile settings form page.
- *
- * @param $p
- *    The profile object to edit (optional).
- */
-function signwriter_profile_page($p = null) {
-  $output = drupal_get_form('_signwriter_profile_form', $p);
-  print theme('page', $output);
-}
-
-function _signwriter_profile_form(&$form_state, $p = null) {
+function signwriter_profile_form(&$form_state, $p = NULL) {
   drupal_add_css('misc/farbtastic/farbtastic.css', 'module', 'all', FALSE);
   drupal_add_js('misc/farbtastic/farbtastic.js');
-  drupal_add_js(drupal_get_path('module', 'signwriter') . '/color.js');
+  drupal_add_js(drupal_get_path('module', 'signwriter') .'/color.js');
 
   // TODO: add a preview, and maybe an 'Apply' button which submits the page
   // then returns to it, rather than back to the main signwriter settings page.
-  $profileid = empty($p->id) ? null : $p->id;
+  $profileid = empty($p->id) ? NULL : $p->id;
   $form = array();
   $form['id'] = array('#type' => 'value', '#value' => $profileid);
   $form['name'] = array(
       '#type' => 'textfield',
       '#title' => t('Profile Name'),
-      '#required' => true,
+      '#required' => TRUE,
       '#default_value' => $p->name,
       '#size' => 40,
       );
 
-  $form['font'] = array('#type' => 'fieldset', '#collapsible' => true, '#collapsed' => false, '#title' => t('Text'));
+  $form['font'] = array('#type' => 'fieldset', '#collapsible' => TRUE, '#collapsed' => FALSE, '#title' => t('Text'));
   $all_fonts = signwriter_available_fonts();
-
   // Match font names selected in an older version of signwriter
   $default_font = $p->fontfile;
-  foreach ($all_fonts as $font) {
-    if (strpos($default_font, '/') === false && strpos($default_font, '\\') === false && preg_match('/' . $default_font . '.ttf/', $font)) {
-      $default_font = $font;
-      break;
+  $preview_profile = $p;
+  unset($preview_profile->maxwidth);
+  foreach ($all_fonts as $fontfile => $fontname) {
+    $preview_profile->fontfile = $fontfile;
+    $all_fonts[$fontfile] = theme_signwriter_text("$fontname Sample text (0123456789)", $preview_profile, array('style' => 'vertical-align:middle'));
+    if (strpos($default_font, '/') === FALSE && strpos($default_font, '\\') === FALSE && preg_match('/'. $default_font .'.ttf/', $fontname)) {
+      $default_font = $fontfile;
     }
   }
 
   $form['font']['fontfile'] = array(
       '#title' => t('Font'),
-      '#type' => 'select',
+      '#type' => 'radios',
       '#options' => $all_fonts,
       '#default_value' => $default_font,
       '#description' => t('These fonts have been found on the host system. The directories searched for fonts were @fontsearch. To change the font search path, go to !signwriter_admin.', array('@fontsearch' => implode(', ', signwriter_get_fontpath()), '!signwriter_admin' => l('the signwriter settings page', 'admin/settings/signwriter'))),
@@ -322,15 +294,15 @@ function _signwriter_profile_form(&$form
   $form['font']['multiline'] = array(
     '#type' => 'checkbox',
     '#title' => t("Multiline"),
-    '#default_value' => is_null($p->multiline) ? true : $p->multiline,
+    '#default_value' => is_NULL($p->multiline) ? TRUE : $p->multiline,
     '#description' => t("If enabled and the max width is set, the text will roll over to a new line when max width is reached, otherwise the font size will be decreased to fit the text in one line."),
   );
 
-  $form['shadow_settings'] = array('#type' => 'fieldset', '#collapsible' => true, '#collapsed' => false, '#title' => t('Drop Shadow'));
+  $form['shadow_settings'] = array('#type' => 'fieldset', '#collapsible' => TRUE, '#collapsed' => FALSE, '#title' => t('Drop Shadow'));
   $form['shadow_settings']['drop_shadow'] = array(
     '#type' => 'checkbox',
     '#title' => t("Drop Shadow"),
-    '#default_value' => is_null($p->drop_shadow) ? false : $p->drop_shadow,
+    '#default_value' => is_NULL($p->drop_shadow) ? FALSE : $p->drop_shadow,
     '#description' => t("If enabled, the text will cast a shadow."),
   );
   $form['shadow_settings']["shadow_color"] = array(
@@ -345,23 +317,23 @@ function _signwriter_profile_form(&$form
   $form['shadow_settings']["shadow_xoffset"] = array(
       '#type' => 'textfield',
       '#title' => t("Shadow X Offset"),
-      '#default_value' => is_null($p->shadow_xoffset) ? 5 : $p->shadow_xoffset,
+      '#default_value' => is_NULL($p->shadow_xoffset) ? 5 : $p->shadow_xoffset,
       '#description' => t("The horizontal distance of the shadow from the actual text.  A negative value will put the shadow to the left of the text."),
       '#size' => 4,
       );
   $form['shadow_settings']["shadow_yoffset"] = array(
       '#type' => 'textfield',
       '#title' => t("Shadow Y Offset"),
-      '#default_value' => is_null($p->shadow_yoffset) ? 5 : $p->shadow_yoffset,
+      '#default_value' => is_NULL($p->shadow_yoffset) ? 5 : $p->shadow_yoffset,
       '#description' => t("The vertical distance of the shadow from the actual text.  A negative value will put the shadow above the text."),
       '#size' => 4,
       );
 
-  $form['background_settings'] = array('#type' => 'fieldset', '#collapsible' => true, '#collapsed' => false, '#title' => t('Background'));
+  $form['background_settings'] = array('#type' => 'fieldset', '#collapsible' => TRUE, '#collapsed' => FALSE, '#title' => t('Background'));
   $form['background_settings']["transparent"] = array(
       '#type' => 'checkbox',
       '#title' => t("Transparent"),
-      '#default_value' => is_null($p->transparent) ? true : $p->transparent,
+      '#default_value' => is_NULL($p->transparent) ? TRUE : $p->transparent,
       '#description' => t("If enabled, then the background colour selected below will be made transparent in the generated image."),
       );
   $form['background_settings']["background"] = array(
@@ -381,7 +353,7 @@ function _signwriter_profile_form(&$form
       '#size' => 40,
       );
 
-  $form['layout'] = array('#type' => 'fieldset', '#collapsible' => true, '#collapsed' => false, '#title' => t('Image Layout'));
+  $form['layout'] = array('#type' => 'fieldset', '#collapsible' => TRUE, '#collapsed' => FALSE, '#title' => t('Image Layout'));
   $form['layout']["width"] = array(
       '#type' => 'textfield',
       '#title' => "Width",
@@ -449,23 +421,22 @@ function _signwriter_profile_form(&$form
     $form['delete'] = array('#type' => 'submit', '#value' => t('Delete'));
   }
 
-  $form['#submit'] = array('_signwriter_profile_submit');
-  $form['#validate'] = array('_signwriter_profile_validate');
   return $form;
 }
 
-function _signwriter_profile_submit($form, &$form_state) {
+function signwriter_profile_form_submit($form, &$form_state) {
   $profile = (object)$form_state['values'];
   if ($form_state['clicked_button']['#value'] == 'Delete') {
-    $form_state['redirect'] = 'admin/settings/signwriter/profile/' . $profile->id . '/delete';
+    $form_state['redirect'] = 'admin/settings/signwriter/profile/'. $profile->id .'/delete';
   }
   else {
     $newid = signwriter_save_profile($profile);
-    drupal_set_message(t("Fontimage profile '@name' saved.", array('@name' => $profile->name)));
+    $message = t("Fontimage profile '@name' saved.", array('@name' => $profile->name));
+    drupal_set_message(signwriter_title_convert($message, $profile));
     if ($form_state['clicked_button']['#value'] == 'Save and edit') {
       // If a new profile has been created redirect from the add page to the new profile's page, otherwise just reload.
-      if ($newid !== FALSE) {
-        $form_state['redirect'] = 'admin/settings/signwriter/profile/' . $newid;
+      if ($newid !== 0) {
+        $form_state['redirect'] = 'admin/settings/signwriter/profile/'. $newid;
       }
     }
     else {
@@ -475,7 +446,7 @@ function _signwriter_profile_submit($for
   }
 }
 
-function _signwriter_profile_validate($form, $form_state) {
+function signwriter_profile_form_validate($form, $form_state) {
   if ($form_state['values']['drop_shadow']) {
     if ($form_state['values']['shadow_xoffset'] == 0 && $form_state['values']['shadow_yoffset'] == 0) {
       form_set_error('shadow_xoffset', t('If using a drop shadow, the Shadow X Offset and Shadow Y Offset values must not both be zero.'));
@@ -496,8 +467,8 @@ function signwriter_settings_page() {
     $rows = array();
     foreach ($profiles as $profile) {
       $links[] = l($profile->name, 'admin/settings/signwriter/profile/'. $profile->id);
-      $rows[] = array('name' => check_plain($profile->name),
-          'edit' => l(t('edit'), 'admin/settings/signwriter/profile/' . $profile->id),
+      $rows[] = array('name' => theme_signwriter_text($profile->name, $profile, array('style' => 'vertical-align:middle')),
+          'edit' => l(t('edit'), 'admin/settings/signwriter/profile/'. $profile->id),
           'delete' => l(t('delete'), "admin/settings/signwriter/profile/$profile->id/delete"));
     }
     if (empty($rows)) {
@@ -506,20 +477,20 @@ function signwriter_settings_page() {
 
     $rows[] = array(array('data' => l(t('Add a profile'), 'admin/settings/signwriter/profile/add'), 'colspan' => '3'));
     $header = array(array('data' => t('Profiles'), 'colspan' => '3'));
-    $output = '<p>' . theme('table', $header, $rows) . '</p>';
-    $output .= '<p>' . drupal_get_form('signwriter_settings_form') . '</p>';
+    $output = '<p>'. theme('table', $header, $rows) .'</p>';
+    $output .= '<p>'. drupal_get_form('signwriter_settings_form') .'</p>';
     print theme('page', $output);
   }
 }
 
 function signwriter_settings_form($form_state) {
   $form = array();
-  $form['settings'] = array('#type' => 'fieldset', '#title' => t('Settings'), '#collapsible' => true, '#collapsed' => false);
-  $form['settings']['cachedir'] = array(
+  $form['paths'] = array('#type' => 'fieldset', '#title' => t('Paths'), '#collapsible' => TRUE, '#collapsed' => FALSE);
+  $form['paths']['signwriter_cachedir'] = array(
     '#type' => 'textfield',
     '#title' => t('Cache Directory'),
-    '#description' => t('This is the directory that signwriter will store its generated images in. It should be a path relative to the drupal base directory. The default is \'signwriter-cache\'. If your files directory is publicly accessible, then another good option would be \'files/signwriter-cache\'. Make sure that your webserver process is able to create and write to this directory. Files can be deleted from this directory at any time.'),
-    '#default_value' => variable_get('signwriter_cachedir', 'signwriter-cache'),
+    '#description' => t('This is the directory that signwriter will store its generated images in. It must be publicly accessible; the default is \'files/signwriter-cache\'. Make sure that your webserver process is able to create and write to this directory. Files can be deleted from this directory at any time.'),
+    '#default_value' => variable_get('signwriter_cachedir', file_directory_path() .'/signwriter'),
   );
 
   $description = t('Add a : separated list of directories to search for your font files. Signwriter will automatically search the drupal directory, your files directory, and your current theme\'s directory.');
@@ -527,26 +498,41 @@ function signwriter_settings_form($form_
     // full path must be specified in safe mode since we can't putenv
     $description .= t(' WARNING: this will be ignored because your PHP installation is in safe mode. You will need to use the full path to your fonts in any Signwriter profiles.');
   }
-  $form['settings']['fontpath'] = array(
+  $form['paths']['signwriter_fontpath'] = array(
     '#type' => 'textfield',
     '#title' => t('Font Search Path'),
     '#default_value' => variable_get('signwriter_fontpath', ''),
     '#description' => $description,
   );
-  $form['submit'] = array('#type' => 'submit', '#value' => t('Save Settings'));
-
-  $form['#submit'] = array('signwriter_settings_form_submit');
-
-  return $form;
-}
+  $profileoptions = array('disabled' => t('Disabled (headers unchanged)'));
+  $profiles = signwriter_load_profiles();
+  foreach ($profiles as $profile) {
+    $profileoptions[$profile->name] = theme_signwriter_text($profile->name, $profile, array('style' => 'vertical-align:middle'));
+  }
+  $form['hooks'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Template Hooks'),
+    '#description' => t('Choose a profile for each specific signwriter_preprocess hook to replace normal /text) headers with signwritten versions.'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE
+  );
+  $form['hooks']['signwriter_pagehookprofile'] = array(
+    '#type' => 'radios',
+    '#title' => t('Page titles'),
+    '#default_value' => variable_get('signwriter_pagehookprofile', 'disabled'),
+    '#options' => $profileoptions,
+  );
+  $form['hooks']['signwriter_blockhookprofile'] = array(
+    '#type' => 'radios',
+    '#title' => t('Block titles'),
+    '#default_value' => variable_get('signwriter_blockhookprofile', 'disabled'),
+    '#options' => $profileoptions,
+  );
 
-function signwriter_settings_form_submit($form, &$form_state) {
-  variable_set('signwriter_cachedir',  $form_state['values']['cachedir']);
-  variable_set('signwriter_fontpath',  $form_state['values']['fontpath']);
-  drupal_set_message(t('Signwriter settings updated.'));
+  return system_settings_form($form);
 }
 
-function _signwriter_get_val($var, $default = null) {
+function _signwriter_get_val($var, $default = NULL) {
   return empty($var) ? $default : $var;
 }
 
@@ -554,11 +540,8 @@ function _signwriter_get_val($var, $defa
  * Generate a signwriter image using the given profile.
  *
  * @param $profile
- *   The signwriter profile to use to render the image. The following fields
- *   are required:
- *     - $profile->text
- *         The text to display. Can contain html entities. For example, &amp;
- *         will be displayed as &
+ *   The signwriter profile to render the image with.
+ *   The following field is required:
  *     - $profile->fontfile
  *         Which font to use. This can be a system path to a .ttf file, or the
  *         basename minus the .ttf extension of a .ttf font file in your font
@@ -576,13 +559,15 @@ function _signwriter_get_val($var, $defa
  *     - $profile->bgimage
  *     - $profile->xoffset
  *     - $profile->yoffset
+ * @param $text
+ *   The text to display. Can contain html entities. For example, &amp;
+ *   will be displayed as &
  *
  * @return
  *   The absolute url to the image.
  */
-function signwriter_url($profile) {
-  $htmltext = _signwriter_get_val($profile->text, '');
-  $text = html_entity_decode($htmltext, ENT_QUOTES);
+function signwriter_image($text, $profile) {
+  $text = html_entity_decode($text, ENT_QUOTES);
   $fontfile = $profile->fontfile;
   $size = _signwriter_get_val($profile->fontsize, 20);
   $fg = (is_string($profile->foreground)) ? _signwriter_parse_colour($profile->foreground) : array(0, 0, 0);
@@ -590,16 +575,15 @@ function signwriter_url($profile) {
   $shadow_rgb = (is_string($profile->shadow_color)) ? _signwriter_parse_colour($profile->shadow_color) : array(210, 210, 210);
   $width = _signwriter_get_val($profile->width);
   $height = _signwriter_get_val($profile->height);
-  $maxwidth = ($profile->maxwidth > 0) ? $profile->maxwidth : null;
+  $maxwidth = (!empty($profile->maxwidth)) ? $profile->maxwidth : NULL;
   $imagetype = _signwriter_get_val($profile->imagetype, 'gif');
-  $cachedir = variable_get('signwriter_cachedir', 'signwriter-cache');
+  $cachedir = variable_get('signwriter_cachedir', file_directory_path() .'/signwriter');
   $align = _signwriter_get_val($profile->textalign, 'left');
-  $transparent = (isset($profile->transparent)) ? $profile->transparent : true;
-  if ($profile->bgimage) {
-    $backgroundimage = $profile->bgimage;
-    $backgroundimagename = basename($backgroundimage);
-    if (!($bgimagetype = signwriter_get_image_type($backgroundimagename))) {
-      drupal_set_message("Signwriter: unsupported image type: $backgroundimage", 'error');
+  $transparent = (isset($profile->transparent)) ? $profile->transparent : TRUE;
+  if (!empty($profile->bgimage)) {
+    $bgimage = $profile->bgimage;
+    if (!($bgimagetype = signwriter_get_image_type(basename($bgimage)))) {
+      drupal_set_message("Signwriter: unsupported image type: $bgimage", 'error');
       return '';
     }
   }
@@ -614,17 +598,12 @@ function signwriter_url($profile) {
   // can't putenv in safe mode
   if (!ini_get('safe_mode')) {
     $fontpath = signwriter_get_fontpath();
-    $path_delimiter = (substr(PHP_OS, 0, 3) == 'WIN') ? ';' : ':';
-    putenv('GDFONTPATH=' . implode($path_delimiter, $fontpath));
+    $path_delimiter = (drupal_substr(PHP_OS, 0, 3) == 'WIN') ? ';' : ':';
+    putenv('GDFONTPATH='. implode($path_delimiter, $fontpath));
   }
-  $fontname = basename($fontfile);
-
-  $filename = serialize($profile);
-  $filename = "text:$text-" . $filename;
-
+  $fileid = "text:$text-". serialize($profile);
   //for shorter filenames that are still unique and repeatable (for caching)
-  //TODO: fix question marks in text when md5 filenames aren't used
-  $filename = $urlfilename = md5($filename) . '.' . $imagetype;
+  $filename = preg_replace('/[^\w\d]/', '', $text) .'-'. md5($fileid) .'-signwriter.'. $imagetype;
 
   $file = "$cachedir/$filename";
 
@@ -634,13 +613,13 @@ function signwriter_url($profile) {
     // calculate the size of the text
     $box = imagettfbbox($size, $angle, $fontfile, $text);
     if (!$box) {
-      drupal_set_message(t("Unable to generate a signwriter image. Is your font set correctly in the %profilename signwriter profile?", array('%profilename' => $profile->name)), 'error');
+      drupal_set_message(t('Unable to generate a signwriter image with font !font at size !size. Is your font set correctly in the %profilename signwriter profile?', array('%profilename' => $profile->name, '!size' => $size, '!font' => $fontfile)), 'error');
       return '';
     }
 
     // calculate the maximum possible hight of the text to properly vertically align multiple images
     $biggest_box = imagettfbbox($size, $angle, $fontfile, "HÅßåŮůÃÕÑÁÉÍÓÚÄËÏÖÜÀÈÌÒÙÂÊÎÔÛÇçjgpq");
-    foreach (array(1,3,5,7) as $i) {
+    foreach (array(1, 3, 5, 7) as $i) {
       $box[$i] = $biggest_box[$i];
     }
 
@@ -663,22 +642,22 @@ function signwriter_url($profile) {
       if ($profile->multiline) {
         $words = split(' ', $text);
         $line = '';
-        foreach ( $words as $word ) {
-          $wordbox  = imagettfbbox ( $size, 0, $fontfile, $line . $word );
+        foreach ($words as $word) {
+          $wordbox  = imagettfbbox($size, 0, $fontfile, $line . $word);
           $newwidth = $wordbox[4] - $wordbox[0] + abs($shadow_xoffset) + 5; // +5: dirty hack to avoid clipping on some lines
-          if ($newwidth > $maxwidth){
-            $lines[] = trim ($line);
-            $tempbox   = imagettfbbox ( $size, 0, $fontfile, $line );
+          if ($newwidth > $maxwidth) {
+            $lines[] = trim($line);
+            $tempbox   = imagettfbbox($size, 0, $fontfile, $line);
             $linewidth = $tempbox[4] - $tempbox[0] + abs($shadow_xoffset) + 5;
             if ($maxlinewidth < $linewidth) {
               $maxlinewidth = $linewidth;
             }
             $line = '';
           }
-          $line .= $word . ' ';
+          $line .= $word .' ';
         }
         $lines[] = trim($line);
-        $tempbox   = imagettfbbox ( $size, 0, $fontfile, $line );
+        $tempbox   = imagettfbbox($size, 0, $fontfile, $line);
         $linewidth = $tempbox[4] - $tempbox[0] + abs($shadow_xoffset) + 5;
         if ($maxlinewidth < $linewidth) {
           $maxlinewidth = $linewidth;
@@ -688,13 +667,13 @@ function signwriter_url($profile) {
       }
       else {
         $profile->fontsize = ($size * ($maxwidth / $textwidth)) - 0.5; // we take an extra 0.5 to avoid endless recursing due to actual font size not decreasing
-        return signwriter_url($profile);
+        return signwriter_image($text, $profile);
       }
     }
     else{
       $lines[] = $text;
     }
-    
+
     if ($maxlinewidth) {
       $width = $width ? $width : $maxlinewidth;
     }
@@ -704,9 +683,9 @@ function signwriter_url($profile) {
     $height = $height ? $height : $textheight * count($lines) + $yoffset;
 
     // create the image
-    if ($backgroundimage) {
-      $imagefunction = 'imagecreatefrom' . $bgimagetype;
-      $im = $imagefunction($backgroundimage);
+    if (!empty($bgimage)) {
+      $imagefunction = 'imagecreatefrom'. $bgimagetype;
+      $im = $imagefunction($bgimage);
       $width = imagesx($im);
       $height = imagesy($im);
     }
@@ -725,7 +704,7 @@ function signwriter_url($profile) {
       imagecolortransparent($im, $background);
     }
 
-    foreach($lines as $n => $line){
+    foreach ($lines as $n => $line) {
       // align the text
       $linebox = imagettfbbox($size, 0, $fontfile, $line);
       $linewidth = $linebox[4] - $linebox[0];
@@ -748,7 +727,7 @@ function signwriter_url($profile) {
           imagettftext($im, $size, $angle, $x + abs($box[0]), $y + abs($box[5]), $shadow_color, $fontfile, $line);
           imagettftext($im, $size, $angle, $x + abs($box[0]) - $shadow_xoffset, $y + abs($box[5]) - $shadow_yoffset, $foreground, $fontfile, $line);
         }
-        else if($shadow_xoffset > 0 && $shadow_yoffset > 0) {
+        else if ($shadow_xoffset > 0 && $shadow_yoffset > 0) {
           imagettftext($im, $size, $angle, $x + abs($box[0]) + $shadow_xoffset, $y + abs($box[5]) + $shadow_yoffset, $shadow_color, $fontfile, $line);
           imagettftext($im, $size, $angle, $x + abs($box[0]), $y + abs($box[5]), $foreground, $fontfile, $line);
         }
@@ -770,7 +749,7 @@ function signwriter_url($profile) {
     $imagefunction($im, $file);
     imagedestroy($im);
   }
-  return base_path() . $cachedir . '/' . $urlfilename;
+  return $file;
 }
 
 /**
@@ -789,11 +768,11 @@ function signwriter_url($profile) {
  */
 function signwriter_title_convert($title, $signwriter) {
   $title = _signwriter_strip_tags($title);
-  preg_match('/(<.*?>)*([^<]*)(<.*?>)*/s', $title, $matches);
+  preg_match('/(<.*?>)*([^<]*)(<.*?>)*($)/s', $title, $matches);
   $titletext = $matches[2];
   $openingtags = $matches[1];
   $closingtags = $matches[3];
-  return $openingtags . theme('signwriter_text_convert', $titletext, $signwriter) . $closingtags;
+  return $openingtags . theme('signwriter_text', $titletext, $signwriter) . $closingtags;
 }
 
 /**
@@ -801,7 +780,7 @@ function signwriter_title_convert($title
  *
  * @param $text
  *   The text to display
- * @param $signwriter
+ * @param $profile
  *   The signwriter profile to use. Can be one of:
  *     - a profile id
  *     - a profile name
@@ -810,11 +789,14 @@ function signwriter_title_convert($title
  * @return
  *   HTML text to replace the input text.
  */
-function theme_signwriter_text_convert($text, $signwriter) {
+function theme_signwriter_text($text, $profile, $attributes = NULL) {
+  if (empty($profile->fontfile)) {
+    $profile = signwriter_load_profile($profile);
+  }
   $text = _signwriter_strip_tags($text);
-  $signwriter->text = $text;
-  $imgsrc = signwriter_url($signwriter);
-  return "<span style='display: none'>$text</span><img src='$imgsrc' alt='" . htmlspecialchars($text, ENT_QUOTES) . "' />";
+  $alttext = htmlspecialchars($text, ENT_QUOTES);
+  $imgsrc = signwriter_image($text, $profile);
+  return (!empty($imgsrc)) ? "<span style='display: none'>$text</span>". theme('image', $imgsrc, $alttext, $alttext, $attributes) : $text;
 }
 
 function _signwriter_strip_tags($text) {
@@ -823,7 +805,7 @@ function _signwriter_strip_tags($text) {
 
 function signwriter_get_fontpath() {
   // search drupal's base dir, files dir, and current theme dir, as well as user-supplied dirs for a font
-  $fontpath = array('.', file_directory_path(), path_to_theme());
+  $fontpath = array('.', file_directory_path(), file_directory_path() .'/fonts', path_to_theme(), path_to_theme() .'/fonts');
   $userfontpath = variable_get('signwriter_fontpath', '');
   if ($userfontpath != '') {
     array_push($fontpath, $userfontpath);
@@ -838,10 +820,10 @@ function signwriter_available_fonts() {
   $fontpath = signwriter_get_fontpath();
   $fonts = array();
   foreach ($fontpath as $dir) {
-    $ttfs = glob($dir . '/*.ttf');
+    $ttfs = glob($dir .'/*.ttf');
     if (!empty($ttfs)) {
       foreach ($ttfs as $font) {
-        $fonts[$font] = $font;
+        $fonts[$font] = basename($font);
       }
     }
   }
@@ -859,7 +841,10 @@ function signwriter_available_image_type
   $return = array();
   if ($types & IMG_GIF) $return['gif'] = 'gif';
   if ($types & IMG_PNG) $return['png'] = 'png';
-  if ($types & IMG_JPG) $return['jpeg'] = 'jpeg';
+  if ($types & IMG_JPG) {
+    $return['jpeg'] = 'jpeg';
+    $return['jpg'] = 'jpeg'; // synonym for jpeg
+  }
   if ($types & IMG_WBMP) $return['bmp'] = 'bmp';
   if ($types & IMG_XPM) $return['xpm'] = 'xpm';
   return $return;
@@ -873,15 +858,14 @@ function signwriter_available_image_type
  *
  * @return
  *   A string representing the image type (gif, png, jpeg, bmp, or xpm), or
- *   false if the image type is not recognised.
+ *   FALSE if the image type is not recognised.
  */
 function signwriter_get_image_type($imagename) {
   $types = signwriter_available_image_types();
-  $types['jpg'] = 'jpeg'; // synonym for jpeg
   foreach ($types as $extension => $imagetype) {
     if (preg_match("/.*$extension$/", $imagename)) return $imagetype;
   }
-  return false;
+  return FALSE;
 }
 
 /**
@@ -891,20 +875,19 @@ function signwriter_get_image_type($imag
  *   A string of six hexadecimal digits.
  *
  * @return
- *   An array in the form (red, green, blue), or false.
+ *   An array in the form (red, green, blue), or FALSE.
  */
 function _signwriter_parse_colour($str) {
-  if (strlen($str) == 6) {
-    $red = intval(substr($str, 0, 2), 16);
-    $green = intval(substr($str, 2, 2), 16);
-    $blue = intval(substr($str, 4, 2), 16);
+  if (drupal_strlen($str) == 6) {
+    $red = intval(drupal_substr($str, 0, 2), 16);
+    $green = intval(drupal_substr($str, 2, 2), 16);
+    $blue = intval(drupal_substr($str, 4, 2), 16);
     return array($red, $green, $blue);
   }
-  return false;
+  return FALSE;
 }
 
-function signwriter_profile_load($pid)
-{
+function signwriter_profile_load($pid) {
   if (!is_numeric($pid)) {
     return FALSE;
   }
@@ -915,10 +898,48 @@ function signwriter_profile_load($pid)
   return $profile;
 }
 
+function signwriter_cron($now = FALSE) {
+  $cachedir = variable_get('signwriter_cachedir', file_directory_path() .'/signwriter');
+  // Prevent removal of files not created by this module.
+  $cached_images = glob($cachedir .'/*-signwriter.*');
+  $last_cleanup = variable_get('signwriter_last_cleanup', 0);
+  if ($last_cleanup < strtotime('-1 week') || $now) {
+    array_walk($cached_images, 'unlink');
+  }
+  variable_set('signwriter_last_cleanup', time());
+}
+
 function signwriter_theme() {
   return array(
-    'signwriter_text_convert' => array(
-      'arguments' => array('text','signwriter'),
+    'signwriter_text' => array(
+      'arguments' => array('text', 'signwriter'),
     ),
   );
 }
+
+/**
+ * Implementation of hook_preprocess_page().
+ */
+function signwriter_preprocess_page(&$variables) {
+  $pagehookprofile = variable_get('signwriter_pagehookprofile', 'disabled');
+  $title = &$variables['title'];
+  if ($pagehookprofile !== 'disabled' && !empty($title)) {
+    $title = signwriter_title_convert($title, $pagehookprofile);
+  }
+}
+
+/**
+ * Implementation of hook_preprocess_block().
+ */
+function signwriter_preprocess_block(&$variables) {
+  static $blockhookprofile = NULL;
+
+  if (!$blockhookprofile) {
+    $blockhookprofile = variable_get('signwriter_blockhookprofile', 'disabled');
+  }
+
+  $subject = &$variables['block']->subject;
+  if ($blockhookprofile !== 'disabled' && !empty($subject)) {
+    $subject = signwriter_title_convert($subject, $blockhookprofile);
+  }
+}
