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.
There are several ways in which you can use signwriter:
/<h.*?>.*?<\/h.*?>/s
. To replace only h1 headings, use /<h1.*>.*?<\/h1>/s
. To define a custom pseudo-html tag (such as <signwriter>), use: /<signwriter>.*?<\/signwriter>/
", array('@input-formats-url' => url('admin/settings/filters'), '%inputformats' => 'Administer >> Site configuration >> Input formats')),
'#size' => 20,
);
$form['save'] = array('#type' => 'submit', '#value' => t('Save'));
$form['submit'] = array('#type' => 'submit', '#value' => t('Save and edit'));
// Don't add the delete button if they are on the add new profile page
// Otherwise clicking the button will return page not found due to there not being a profile to delete.
if (request_uri() != '/admin/settings/signwriter/profile/add') {
$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) {
$profile = (object)$form_state['values'];
if ($form_state['clicked_button']['#value'] == '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)));
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;
}
}
else {
$form_state['redirect'] = 'admin/settings/signwriter';
}
}
}
function _signwriter_profile_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.'));
form_set_error('shadow_yoffset', t('If using a drop shadow, the Shadow X Offset and Shadow Y Offset values must not both be zero.'));
}
}
}
/**
* The main admin>>settings>>signwriter page
*/
function signwriter_settings_page() {
if (!function_exists('imagetypes')) {
print theme('page', "It appears that you do not have the GD image library installed. GD is enabled by default in PHP >= 4.3, but can be enabled at compile time in earlier versions. If your php installation is on windows, try uncommenting the line which reads 'extension=php_gd2.dll' in your php.ini. For more information see php's Image library.");
}
else {
$profiles = signwriter_load_profiles();
$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),
'delete' => l(t('delete'), "admin/settings/signwriter/profile/$profile->id/delete"));
}
if (empty($rows)) {
$rows[] = array(array('data' => t('No profiles'), 'colspan' => '3', 'class' => 'message'));
}
$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 = '' . theme('table', $header, $rows) . '
'; $output .= '' . drupal_get_form('signwriter_settings_form') . '
'; 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( '#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('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.'); if (ini_get('safe_mode')) { // 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( '#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; } 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.')); } function _signwriter_get_val($var, $default = null) { return empty($var) ? $default : $var; } /** * 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, & * will be displayed as & * - $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 * path or your drupal files directory. * These fields are optional: * - $profile->fontsize * - $profile->foreground * - $profile->background * - $profile->width * - $profile->height * - $profile->maxwidth * - $profile->imagetype * - $profile->textalign * - $profile->transparent * - $profile->bgimage * - $profile->xoffset * - $profile->yoffset * * @return * The absolute url to the image. */ function signwriter_url($profile) { $htmltext = _signwriter_get_val($profile->text, ''); $text = html_entity_decode($htmltext, 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); $bg = (is_string($profile->background)) ? _signwriter_parse_colour($profile->background) : array(255, 255, 255); $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; $imagetype = _signwriter_get_val($profile->imagetype, 'gif'); $cachedir = variable_get('signwriter_cachedir', 'signwriter-cache'); $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'); return ''; } } $xoffset = _signwriter_get_val($profile->xoffset, 0); $yoffset = _signwriter_get_val($profile->yoffset, 0); $shadow_xoffset = _signwriter_get_val($profile->shadow_xoffset, 0); $shadow_yoffset = _signwriter_get_val($profile->shadow_yoffset, 0); file_check_directory($cachedir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); // 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)); } $fontname = basename($fontfile); $filename = serialize($profile); $filename = "text:$text-" . $filename; //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; $file = "$cachedir/$filename"; if (!is_readable($file)) { $angle = 0; // 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'); 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) { $box[$i] = $biggest_box[$i]; } // If there is a shadow add the offset to the size of the box. if ($profile->drop_shadow) { $textwidth = abs($box[2]) + abs($box[0]) + abs($shadow_xoffset) + 5; // sometimes text is clipped. I don't know why, so I add 5px here... $textheight = abs($box[1]) + abs($box[7]) + abs($shadow_yoffset); } else { $textwidth = abs($box[2]) + abs($box[0]) + 5; $textheight = abs($box[1]) + abs($box[7]); } // if we exceed maxwidth, then use a smaller font size unless multiline is selected // LS:. Start of the multiline magic $lines = array(); $maxlinewidth = 0; if ($maxwidth && ($textwidth > $maxwidth)) { if ($profile->multiline) { $words = split(' ', $text); $line = ''; 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 ); $linewidth = $tempbox[4] - $tempbox[0] + abs($shadow_xoffset) + 5; if ($maxlinewidth < $linewidth) { $maxlinewidth = $linewidth; } $line = ''; } $line .= $word . ' '; } $lines[] = trim($line); $tempbox = imagettfbbox ( $size, 0, $fontfile, $line ); $linewidth = $tempbox[4] - $tempbox[0] + abs($shadow_xoffset) + 5; if ($maxlinewidth < $linewidth) { $maxlinewidth = $linewidth; } // Check for and remove any empty lines. $lines = array_values(array_filter($lines)); } 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); } } else{ $lines[] = $text; } if ($maxlinewidth) { $width = $width ? $width : $maxlinewidth; } else { $width = $width ? $width : ($maxwidth ? $maxwidth : $textwidth + $xoffset); } $height = $height ? $height : $textheight * count($lines) + $yoffset; // create the image if ($backgroundimage) { $imagefunction = 'imagecreatefrom' . $bgimagetype; $im = $imagefunction($backgroundimage); $width = imagesx($im); $height = imagesy($im); } else { $im = imagecreate($width, $height); } $background = imagecolorallocate($im, $bg[0], $bg[1], $bg[2]); $foreground = imagecolorallocate($im, $fg[0], $fg[1], $fg[2]); $shadow_color = imagecolorallocate($im, $shadow_rgb[0], $shadow_rgb[1], $shadow_rgb[2]); if ($transparent) { // the background is transparent, but it should be the same colour as // whatever the image is over, otherwise you will get jagged edges // (unless you're using png). imagecolortransparent($im, $background); } foreach($lines as $n => $line){ // align the text $linebox = imagettfbbox($size, 0, $fontfile, $line); $linewidth = $linebox[4] - $linebox[0]; switch ($align) { case 'center': case 'centre': $x = $xoffset + ($width - $linewidth) / 2; break; case 'right': $x = $width - $linewidth - $xoffset; break; default: $x = $xoffset; } $y = $yoffset + $n * $textheight; // This is so that the shadow doesn't go outside of the box. if ($profile->drop_shadow) { if ($shadow_xoffset < 0 && $shadow_yoffset < 0) { 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) { 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); } else if ($shadow_xoffset < 0 && $shadow_yoffset > 0) { imagettftext($im, $size, $angle, $x + abs($box[0]), $y + abs($box[5]) + $shadow_yoffset, $shadow_color, $fontfile, $line); imagettftext($im, $size, $angle, $x + abs($box[0]) - $shadow_xoffset, $y + abs($box[5]), $foreground, $fontfile, $line); } else if ($shadow_xoffset > 0 && $shadow_yoffset < 0) { imagettftext($im, $size, $angle, $x + abs($box[0]) + $shadow_xoffset, $y + abs($box[5]), $shadow_color, $fontfile, $line); imagettftext($im, $size, $angle, $x + abs($box[0]), $y + abs($box[5]) - $shadow_yoffset, $foreground, $fontfile, $line); } } else { imagettftext($im, $size, $angle, $x + abs($box[0]), $y + abs($box[5]), $foreground, $fontfile, $text); } } $imagefunction = "image$imagetype"; $imagefunction($im, $file); imagedestroy($im); } return base_path() . $cachedir . '/' . $urlfilename; } /** * Turn a title into a signwriter image. * * @param $title * The title text. Can be wrapped in html tags. * @param $signwriter * The signwriter profile to use. Can be one of: * - a profile id * - a profile name * - a profile object with at least the name or id set * * @return * HTML text to replace the title. */ function signwriter_title_convert($title, $signwriter) { $title = _signwriter_strip_tags($title); preg_match('/(<.*?>)*([^<]*)(<.*?>)*/s', $title, $matches); $titletext = $matches[2]; $openingtags = $matches[1]; $closingtags = $matches[3]; return $openingtags . theme('signwriter_text_convert', $titletext, $signwriter) . $closingtags; } /** * Turn text into a signwriter image. * * @param $text * The text to display * @param $signwriter * The signwriter profile to use. Can be one of: * - a profile id * - a profile name * - a profile object with at least the name or id set * * @return * HTML text to replace the input text. */ function theme_signwriter_text_convert($text, $signwriter) { $text = _signwriter_strip_tags($text); $signwriter->text = $text; $imgsrc = signwriter_url($signwriter); return " "; } function _signwriter_strip_tags($text) { return preg_replace('/<\/?(i|b|em)>/i', '', $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()); $userfontpath = variable_get('signwriter_fontpath', ''); if ($userfontpath != '') { array_push($fontpath, $userfontpath); } return $fontpath; } /** * Return a list of all available fonts in the system, searching the font path and other likely spots */ function signwriter_available_fonts() { $fontpath = signwriter_get_fontpath(); $fonts = array(); foreach ($fontpath as $dir) { $ttfs = glob($dir . '/*.ttf'); if (!empty($ttfs)) { foreach ($ttfs as $font) { $fonts[$font] = $font; } } } return $fonts; } /** * Return a list of the image types available in this php install * * @return * An array in the form 'type' => 'type' (for convenient use in form select) */ function signwriter_available_image_types() { $types = imagetypes(); $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_WBMP) $return['bmp'] = 'bmp'; if ($types & IMG_XPM) $return['xpm'] = 'xpm'; return $return; } /** * Determine the type of image from a filename extension. * * @param $imagename * The image filename. * * @return * A string representing the image type (gif, png, jpeg, bmp, or xpm), or * 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; } /** * Parse a six letter colour code into a colour array. * * @param $str * A string of six hexadecimal digits. * * @return * 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); return array($red, $green, $blue); } return false; } function signwriter_profile_load($pid) { if (!is_numeric($pid)) { return FALSE; } $profile = signwriter_load_profile($pid); if (!isset($profile->id)) { return FALSE; } return $profile; } function signwriter_theme() { return array( 'signwriter_text_convert' => array( 'arguments' => array('text','signwriter'), ), ); }