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:

"); break; } } /** * Implementation of hook_menu(). */ function signwriter_menu($may_cache) { $items = array(); if ($may_cache) { $items[] = array( 'path' => 'admin/settings/signwriter', 'title' => t('Signwriter'), 'description' => t('Manage Signwriter profiles, for custom font headings.'), 'callback' => 'signwriter_settings_page', 'access' => user_access('administer signwriter'), 'type' => MENU_NORMAL_ITEM); $items[] = array( 'path' => 'admin/settings/signwriter/profile/add', 'title' => t('Add profile'), 'description' => t('Add a new Signwriter profile.'), 'callback' => 'signwriter_profile_page', 'callback arguments' => null, 'type' => MENU_NORMAL_ITEM, 'weight' => -8); } else { if (arg(2) == 'signwriter') { foreach (signwriter_load_profiles() as $profile) { $items[] = array( 'path' => 'admin/settings/signwriter/profile/' . $profile->id, 'title' => $profile->name, 'description' => t('Manage the ') . $profile->name . t(' Signwriter profile.'), 'callback' => 'signwriter_profile_page', 'callback arguments' => array($profile), 'type' => MENU_NORMAL_ITEM,); $items[] = array( 'path' => 'admin/settings/signwriter/profile/' . $profile->id . '/delete', 'title' => "Delete $profile->name", 'description' => t('Delete the ') . $profile->name . t(' Signwriter profile'), 'callback' => 'signwriter_confirm_delete_profile_page', 'callback arguments' => array($profile), 'type' => MENU_NORMAL_ITEM,); } } } return $items; } /** * Implementation of hook_perm(). */ function signwriter_perm() { return array('administer signwriter'); } function signwriter_filter($op, $delta = 0, $format = -1, $text = '') { switch ($op) { case 'list': $profiles = signwriter_load_profiles(); $filters = array(); foreach ($profiles as $profile) { if (isset($profile->pattern) && !empty($profile->pattern)) { $filters[$profile->id] = $profile->name; } } return $filters; case 'description': $profile = signwriter_load_profile($delta); return t("Replaces anything matching the regular expression: %pattern with the image generated by the '%profilename' signwriter profile.", array('%pattern' => $profile->pattern, '%profilename' => $profile->name)); case "process": // Make the profile global so the preg_replace_callback callback function can access it global $signwriter_filter_profile; $signwriter_filter_profile = signwriter_load_profile($delta); $text = preg_replace_callback($signwriter_filter_profile->pattern, 'signwriter_filter_replace_callback', $text); unset($signwriter_filter_profile); return $text; case 'no cache': return true; default: return $text; } } /** * Callback function for the call to preg_replace_callback() * in the signwriter_filter() function. * This is used to avoid using preg_replace with the e modifier, * which would create a security issue */ function signwriter_filter_replace_callback($matches) { global $signwriter_filter_profile; return signwriter_title_convert($matches[0], $signwriter_filter_profile); } /** * Implementation of hook_filter_tips() */ 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 the signwriter profile %profilename.', 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)); } } 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', 'disable_span'); } 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; } /** * Delete a signwriter profile without asking for confirmation. * 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 */ function signwriter_delete_profile($profile) { if ($where = _signwriter_profile_whereclause($profile)) { db_query("DELETE FROM {signwriter} $where"); drupal_set_message(t("Deleted the '@name' profile.", array('@name' => $profile->name))); } drupal_goto('admin/settings/signwriter'); } /** * 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 */ 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($profile) { $profile = signwriter_load_profile($profile); $form['id'] = array('#type' => 'value', '#value' => $profile->id); $form['#submit'] = array('_signwriter_confirm_delete_profile_submit' => null); return confirm_form($form, t('Are you sure you want to delete the \'%title\' profile?', array('%title' => $profile->name)), 'admin/settings/signwriter', t('Deleting a profile cannot be undone.'), t('Delete'), t('Cancel')); } function _signwriter_confirm_delete_profile_submit($form_id, $form_values) { $profile = signwriter_load_profile($form_values['id']); return signwriter_delete_profile($profile); } /** * Save a profile or update a profile in the database. * * @param $profile * The profile object to save */ function signwriter_save_profile($profile) { $profile->is_new = false; if (empty($profile->id)) { $profile->is_new = true; $profile->id = db_next_id('{signwriter}_id'); } $fields = _signwriter_db_fields(); foreach ($fields as $fieldname) { if (!is_null($profile->$fieldname)) { $keys[] = $fieldname; $value_keywords[] = "'%s'"; $values[] = $profile->$fieldname; } } 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); } else { $where = _signwriter_profile_whereclause($profile); foreach ($keys as $key) { $assignments[] = "$key = '%s'"; } $assignments = implode(', ', $assignments); db_query("UPDATE {signwriter} SET $assignments $where", $values); } } } /** * Load a profile from the database. * * @param $profile * The profile to load. This can be one of: * - a profile id * - a profile name * - a profile object with at least the name or id set * * @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")); } } /** * Load zero or more signwriter profiles. * * @param $profiles * 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)) { $profiles = array(); $results = db_query("SELECT %s FROM {signwriter}", implode(', ', _signwriter_db_fields())); while ($profile = db_fetch_object($results)) { $profiles[] = $profile; } } else { $results = array(); foreach ($profiles as $profile) { $results[] = signwriter_load_profile($profile); } $profiles = $results; } 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($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'); // 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; $form['id'] = array('#type' => 'value', '#value' => $profileid); $form['name'] = array( '#type' => 'textfield', '#title' => t('Profile Name'), '#required' => true, '#default_value' => $p->name, '#size' => 40, ); $form['hidden_span'] = array( '#type' => 'fieldset', '#collapsible' => TRUE, '#collapsed' => FALSE, '#title' => t('Hidden span'), '#description' => t('Signwriter normally prints the signwriter image along with the same text that is in the image in a span with the styling "display: none;". Due to possible issues with search engine rankings some people will want this and some people will not so if you don\'t you can disable it here.'), ); $form['hidden_span']['disable_span'] = array( '#type' => 'checkbox', '#title' => t('Disable hidden span'), '#default_value' => _signwriter_get_val($p->disable_span, FALSE), ); $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; } } $form['font']['fontfile'] = array( '#title' => t('Font'), '#type' => 'select', '#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'))), ); $form['font']["fontsize"] = array( '#type' => 'textfield', '#title' => t("Font Size"), '#default_value' => _signwriter_get_val($p->fontsize, ''), '#description' => t("If you define 'Max Width' below then this size may be overridden in order to fit the text within the given width. Defaults to 20."), '#size' => 4, ); $form['font']["foreground"] = array( '#type' => 'textfield', '#title' => t("Font Colour"), '#default_value' => $p->foreground, '#description' => t("This should be six hexadecimal digits, such as ff0000 for red, 00ff00 for green, or 0000ff for blue."), '#size' => 6, '#maxlength' => 6, ); $form['font']['foreground-farb'] = array('#value' => '
'); $form['font']['multiline'] = array( '#type' => 'checkbox', '#title' => t("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']['drop_shadow'] = array( '#type' => 'checkbox', '#title' => t("Drop Shadow"), '#default_value' => is_null($p->drop_shadow) ? true : $p->drop_shadow, '#description' => t("If enabled, the text will cast a shadow."), ); $form['shadow_settings']["shadow_color"] = array( '#type' => 'textfield', '#title' => t("Shadow Colour"), '#default_value' => $p->shadow_color, '#description' => t("This should be six hexadecimal digits, such as ff0000 for red, 00ff00 for green, or 0000ff for blue."), '#size' => 6, '#maxlength' => 6, ); $form['shadow_settings']['shadow_color-farb'] = array('#value' => '
'); $form['shadow_settings']["shadow_xoffset"] = array( '#type' => 'textfield', '#title' => t("Shadow X Offset"), '#default_value' => _signwriter_get_val($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' => _signwriter_get_val($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']["transparent"] = array( '#type' => 'checkbox', '#title' => t("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( '#type' => 'textfield', '#title' => t("Background Colour"), '#default_value' => $p->background, '#description' => t("This should be six hexadecimal digits, such as ff0000 for red, 00ff00 for green, or 0000ff for blue. To avoid jagged fonts when using transparency, make sure that this colour is the same as the page background colour. If you are using a background image and transparency then this colour will be made transparent in the source background image."), '#size' => 6, '#maxlength' => 6, ); $form['background_settings']['background-farb'] = array('#value' => '
'); $form['background_settings']["bgimage"] = array( '#type' => 'textfield', '#title' => t("Background Image"), '#default_value' => $p->bgimage, '#description' => t("Path to the background image to use, relative to your drupal directory. Leave blank to not use a background image."), '#size' => 40, ); $form['layout'] = array('#type' => 'fieldset', '#collapsible' => true, '#collapsed' => false, '#title' => t('Image Layout')); $form['layout']["width"] = array( '#type' => 'textfield', '#title' => "Width", '#default_value' => _signwriter_get_val($p->width, ''), '#description' => t("Set the width of the image in pixels. Leave blank to have the width automatically assigned, or if you're using a background image."), '#size' => 4, ); $form['layout']["height"] = array( '#type' => 'textfield', '#title' => "Height", '#default_value' => _signwriter_get_val($p->height, ''), '#description' => t("Set the height of the image in pixels. Leave blank to have the height automatically assigned, or if you're using a background image."), '#size' => 4, ); $form['layout']["maxwidth"] = array( '#type' => 'textfield', '#title' => "Max Width", '#default_value' => _signwriter_get_val($p->maxwidth, ''), '#description' => t("This value is in pixels. If it is set then the text size will be decreased so that the text fits within the given width. Leave this blank to have no maximum."), '#size' => 4, ); $form['layout']["textalign"] = array( '#type' => 'select', '#title' => t("Text Align"), '#default_value' => $p->textalign, '#options' => array('left' => 'left', 'center' => 'center', 'right' => 'right'), '#description' => t("Text Align only makes sense if your image is wider than the text. To make this happen either assign a background image, or set the width."), ); $form['layout']["xoffset"] = array( '#type' => 'textfield', '#title' => t("X Offset"), '#default_value' => _signwriter_get_val($p->xoffset, ''), '#description' => t("Adds to the distance from the left of the image to the start of the text (or from the right of the image in the case of right-aligned text)."), '#size' => 4, ); $form['layout']["yoffset"] = array( '#type' => 'textfield', '#title' => t("Y Offset"), '#default_value' => _signwriter_get_val($p->yoffset, ''), '#description' => t("Adds to the distance from the top of the image to the baseline of the text (or something like that)."), '#size' => 4, ); $form["imagetype"] = array( '#type' => 'select', '#title' => t("Image Type"), '#default_value' => $p->imagetype, '#description' => t("For transparency png is best, but it doesn't work in IE without hacks (see http://webfx.eae.net/dhtml/pngbehavior/pngbehavior.html for one such hack), so gif is a good alternative."), '#options' => signwriter_available_image_types(), ); $form["pattern"] = array( '#type' => 'textfield', '#title' => t('Input Filter Pattern'), '#default_value' => $p->pattern, '#description' => t("If this pattern is defined then this profile will be available as an input filter which you can enable on the %inputformats page. When the filter is enabled, anything matching this pattern will be replaced with a signwriter image. The pattern should be a perl regular expression. For example, to replace all headings, use: /<h.*?>.*?<\/h.*?>/is. To replace only h1 headings, use /<h1.*?>.*?<\/h1>/is. 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')); $form['delete'] = array('#type' => 'submit', '#value' => t('Delete')); $form['#submit'] = array('_signwriter_profile_submit' => null); $form['#validate'] = array('_signwriter_profile_validate' => array()); return $form; } function _signwriter_profile_submit($form_id, $form_values) { $profile = (object)$form_values; if ($form_values['op'] == t('Delete')) return 'admin/settings/signwriter/profile/' . $profile->id . '/delete'; signwriter_save_profile($profile); drupal_set_message(t("Fontimage profile '@name' saved.", array('@name' => $profile->name))); if ($form_values['op'] == t('Save and edit')) return; return 'admin/settings/signwriter'; } function _signwriter_profile_validate($form_id, $form_values) { if ($form_values['drop_shadow']) { if (is_null($form_values['shadow_xoffset'])) { form_set_error('shadow_xoffset', t('If using a drop shadow you must have a Shadow X Offset value')); } if (is_null($form_values['shadow_yoffset'])) { form_set_error('shadow_yoffset', t('If using a drop shadow you must have a Shadow Y Offset value')); } if ($form_values['shadow_xoffset'] == 0 && $form_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' => l($profile->name, '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 = 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')); return $form; } function signwriter_settings_form_submit($form_id, $form_values) { variable_set('signwriter_cachedir', $form_values['cachedir']); variable_set('signwriter_fontpath', $form_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 * - $profile->disable_span * * @return * The absolute url to the image. */ function signwriter_url($profile) { $htmltext = _signwriter_get_val($profile->text, ''); $text = html_entity_decode($htmltext, ENT_NOQUOTES, 'UTF-8'); // quotes are significant elements of text $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); $urlfilename = "text:$htmltext-" . $filename; $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. It may be that your font was not found by the freetype library. Do you have GD and Freetype installed? Check the output of phpinfo()."), '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, $line); } } $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) { if (!is_object($signwriter)) { $signwriter = signwriter_load_profile($signwriter); } $text = _signwriter_strip_tags($text); $signwriter->text = $text; $imgsrc = signwriter_url($signwriter); if (isset($signwriter->disable_span) && $signwriter->disable_span) { return '' . htmlspecialchars($text, ENT_QUOTES) . ''; } else { return '' . $text . '' . htmlspecialchars($text, ENT_QUOTES) . ''; } } function _signwriter_strip_tags($text) { $text = preg_replace('/\\\/m','',$text); // $text may contain escaped quotes and the backslash shouldn't show up return preg_replace('/<\/?(i|b|em)>/im', '', $text); // case insensitive and multiple replacements } 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; }