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 original headings.
There are several ways in which you can use signwriter:
'.print_r($s, TRUE).''); // drupal_set_message('signwriter_save_profile::$profile =
'.print_r($profile, TRUE).''); // return $profile->id; $int_fields = _signwriter_db_fields('integer'); $string_fields = _signwriter_db_fields('string'); $values = $value_keywords = $assignments = array(); foreach ($int_fields as $field) { if ($profile->$field !== '') { $values[] = (int) $profile->$field; $value_keywords[] = '%d'; $assignments[] = "$field = %d"; } else { $value_keywords[] = 'NULL'; $assignments[] = "$field = NULL"; } } foreach ($string_fields as $field) { $values[] = $profile->$field; $value_keywords[] = "'%s'"; $assignments[] = "$field = '%s'"; } if (empty($profile->id)) { db_query('INSERT INTO {signwriter} ('. implode(', ', array_merge($int_fields, $string_fields)) .') VALUES ('. implode(', ', $value_keywords) .')', $values); return db_result(db_query('SELECT LAST_INSERT_ID()')); } else { db_query('UPDATE {signwriter} SET '. implode(', ', $assignments) .' WHERE id = '. $profile->id, $values); return $profile->id; } } /** * Deletes a signwriter profile. * * @param $profile * The profile object to delete. */ function _signwriter_delete_profile($profile) { if (db_query('DELETE FROM {signwriter} WHERE id = %d', $profile->id)) { drupal_set_message(t("Deleted the '@name' profile.", array('@name' => $profile->name))); } 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 object to delete. */ function signwriter_confirm_delete_profile_form(&$form_state, $profile) { $form = array(); $form['id'] = array('#type' => 'value', '#value' => $profile->id); 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')); } /** * Form_submit function for profile deletion. * Executes deletion and returns the user to the main signwriter settings page. */ function signwriter_confirm_delete_profile_form_submit($form, &$form_state) { $profile = signwriter_load_profile($form_state['values']['id']); _signwriter_delete_profile($profile); $form_state['redirect'] = 'admin/settings/signwriter'; } 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'); // TODO: add a preview, $profileid = _signwriter_get_val($p, 'id'); $profilename = _signwriter_get_val($p, 'name'); drupal_set_title(t('Editing signwriter profile @profilename', array('@profilename' => $profilename))); $form = array(); $form['id'] = array( '#type' => 'value', '#value' => $profileid ); $form['name'] = array( '#type' => 'textfield', '#title' => t('Profile Name'), '#required' => TRUE, '#default_value' => $profilename, '#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 $active_font = _signwriter_get_val($p, 'fontfile'); // Clone the current profile so some values can be changed for better display without affecting the form fields. if (is_object($p)) { $preview_profile = drupal_clone($p); } else { $preview_profile = new stdClass(); } foreach ($all_fonts as $fontfile => $fontname) { $preview_profile->fontfile = $fontfile; // $preview_profile->fontsize = 12; // $preview_profile->maxwidth = 400; $all_fonts[$fontfile] = theme_signwriter_text("$fontname - Sample text (0123456789)", $preview_profile, array('style' => 'vertical-align:middle')); if (strpos($active_font, '/') === FALSE && strpos($active_font, '\\') === FALSE && preg_match('/'. $active_font .'.ttf/i', $fontname)) { $active_font = $fontfile; } } $profiles = signwriter_load_profiles(); $all_profiles = array(0 => 'None'); foreach ($profiles as $profile) { if ($profile->id != $p->id) { $all_profiles[$profile->id] = theme_signwriter_text($profile->name, $profile, array('style' => 'vertical-align:middle')); } } $form['font']['fontfile'] = array( '#type' => 'radios', '#title' => t('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_fontpaths()), '!signwriter_admin' => l('the signwriter settings page', 'admin/settings/signwriter'))), '#options' => $all_fonts, '#default_value' => $active_font, ); $form['font']['hover_profile'] = array( '#type' => 'radios', '#title' => t('Hover profile'), '#description' => t('If a profile is selected, the selected profile will be used to create images to be used in menus when the mouse hovers over a signwriter image. Note: When using this hover profile you should also select a profile for the active class or you will experience issues with the active state.'), '#options' => $all_profiles, '#default_value' => _signwriter_get_val($p, 'hover_profile', 0), ); $form['font']['active_profile'] = array( '#type' => 'radios', '#title' => t('Active profile'), '#description' => t('If a profile is selected, the selected profile will be used to create images to be used in menus if the menu item is active. Note: When using this active profile you should also select a profile for the hover class or you will experience issues.'), '#options' => $all_profiles, '#default_value' => _signwriter_get_val($p, 'active_profile', 0), ); $form['font']['allowed_nonasciichars'] = array( '#type' => 'textfield', '#title' => t('Allowed non-ASCII characters'), '#description' => t('Most fonts support only the ASCII character set so by default so strings containing unicode characters will not be replaced by default. Paste here all unicode characters your font does include so strings which only contain characters from this list and the default ASCII charset will be converted as requested. Put \'all\' in this field to allow all unicode characters.'), '#default_value' => _signwriter_get_val($p, 'allowed_nonasciichars'), ); $form['font']['fontsize'] = array( '#type' => 'textfield', '#title' => t('Font Size'), '#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."), '#default_value' => _signwriter_get_val($p, 'fontsize'), '#size' => 4, ); $form['font']['foreground'] = array( '#type' => 'textfield', '#title' => t('Font Colour'), '#description' => t('This should be six hexadecimal digits, such as ff0000 for red, 00ff00 for green, or 0000ff for blue.'), '#default_value' => _signwriter_get_val($p, 'foreground'), '#size' => 6, '#maxlength' => 6, ); $form['font']['foreground-farb'] = array('#value' => ''); $form['font']['multiline'] = array( '#type' => 'checkbox', '#title' => t('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.'), '#default_value' => _signwriter_get_val($p, 'multiline', TRUE), ); $form['border_settings'] = array( '#type' => 'fieldset', '#collapsible' => TRUE, '#collapsed' => FALSE, '#title' => t('Border'), ); $form['border_settings']['border'] = array( '#type' => 'checkbox', '#title' => t('Border'), '#description' => t('If enabled, the text will be surrounded by a border.'), '#default_value' => _signwriter_get_val($p, 'border', FALSE), ); $form['border_settings']['border_color'] = array( '#type' => 'textfield', '#title' => t('Border Colour'), '#description' => t('This should be six hexadecimal digits, such as ff0000 for red, 00ff00 for green, or 0000ff for blue.'), '#default_value' => _signwriter_get_val($p, 'border_color'), '#size' => 6, '#maxlength' => 6, ); $form['border_settings']['border_color-farb'] = array('#value' => ''); $form['border_settings']['border_radius'] = array( '#type' => 'textfield', '#title' => t('Border Radius'), '#description' => t('The radius of the border. Use only small values.'), '#default_value' => _signwriter_get_val($p, 'border_radius', 1), '#size' => 4, ); $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'), '#description' => t('If enabled, the text will cast a shadow.'), '#default_value' => _signwriter_get_val($p, 'drop_shadow', FALSE), ); $form['shadow_settings']['shadow_color'] = array( '#type' => 'textfield', '#title' => t('Shadow Colour'), '#description' => t('This should be six hexadecimal digits, such as ff0000 for red, 00ff00 for green, or 0000ff for blue.'), '#default_value' => _signwriter_get_val($p, 'shadow_color'), '#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'), '#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.'), '#default_value' => _signwriter_get_val($p, 'shadow_xoffset', 5), '#size' => 4, ); $form['shadow_settings']['shadow_yoffset'] = array( '#type' => 'textfield', '#title' => t('Shadow Y Offset'), '#description' => t('The vertical distance of the shadow from the actual text. A negative value will put the shadow above the text.'), '#default_value' => _signwriter_get_val($p, 'shadow_yoffset', 5), '#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'), '#description' => t('If enabled, then the background colour selected below will be made transparent in the generated image.'), '#default_value' => _signwriter_get_val($p, 'transparent', TRUE), ); $form['background_settings']['background'] = array( '#type' => 'textfield', '#title' => t('Background Colour'), '#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.'), '#default_value' => _signwriter_get_val($p, 'background'), '#size' => 6, '#maxlength' => 6, ); $form['background_settings']['background-farb'] = array('#value' => ''); $form['background_settings']['bgimage'] = array( '#type' => 'textfield', '#title' => t('Background Image'), '#description' => t('Path to the background image to use, relative to your drupal directory. Leave blank to not use a background image.'), '#default_value' => _signwriter_get_val($p, 'bgimage'), '#size' => 40, ); $form['layout'] = array( '#type' => 'fieldset', '#collapsible' => TRUE, '#collapsed' => FALSE, '#title' => t('Image Layout') ); $form['layout']['width'] = array( '#type' => 'textfield', '#title' => t('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."), '#default_value' => _signwriter_get_val($p, 'width'), '#size' => 4, ); $form['layout']['height'] = array( '#type' => 'textfield', '#title' => t('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."), '#default_value' => _signwriter_get_val($p, 'height'), '#size' => 4, ); $form['layout']['maxwidth'] = array( '#type' => 'textfield', '#title' => t('Max Width'), '#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.'), '#default_value' => _signwriter_get_val($p, 'maxwidth'), '#size' => 4, ); $form['layout']['textalign'] = array( '#type' => 'select', '#title' => t('Text Align'), '#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.'), '#default_value' => _signwriter_get_val($p, 'textalign'), '#options' => array('left' => 'left', 'center' => 'center', 'right' => 'right'), ); $form['layout']['xoffset'] = array( '#type' => 'textfield', '#title' => t('X Offset'), '#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).'), '#default_value' => _signwriter_get_val($p, 'xoffset'), '#size' => 4, ); $form['layout']['yoffset'] = array( '#type' => 'textfield', '#title' => t('Y Offset'), '#description' => t('Adds to the distance from the top of the image to the baseline of the text (or something like that).'), '#default_value' => _signwriter_get_val($p, 'yoffset'), '#size' => 4, ); $form['imagetype'] = array( '#type' => 'select', '#title' => t('Image Type'), '#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."), '#default_value' => _signwriter_get_val($p, 'imagetype'), '#options' => _signwriter_available_image_types(), ); $form['pattern'] = array( '#type' => 'textfield', '#title' => t('Input Filter Pattern'), '#default_value' => _signwriter_get_val($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.*?>/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 ($p) {
$form['delete'] = array('#type' => 'submit', '#value' => t('Delete'));
}
return $form;
}
function signwriter_profile_form_validate($form, $form_state) {
$shadow_error = t('If using a drop shadow, the Shadow X Offset and Shadow Y Offset values must not both be zero.');
if ($form_state['values']['drop_shadow']) {
if ($form_state['values']['shadow_xoffset'] == 0 && $form_state['values']['shadow_yoffset'] == 0) {
form_set_error('shadow_xoffset', $shadow_error);
form_set_error('shadow_yoffset', $shadow_error);
}
}
if ($form_state['values']['border_radius'] < 0) {
form_set_error('border_radius', 'The border radius must not be negative.');
}
if ($form_state['values']['active_profile'] != '0' && $form_state['values']['hover_profile'] == '0') {
form_set_error('hover_profile', 'If you have selected an active profile you must select a hover profile');
}
else if ($form_state['values']['active_profile'] == '0' && $form_state['values']['hover_profile'] != '0') {
form_set_error('hover_profile', 'If you have selected a hover profile you must select an active profile');
}
if (!is_numeric($form_state['values']['fontsize']) && $form_state['values']['fontsize']) {
form_set_error('fontsize', 'Font size must be numeric.');
}
}
function signwriter_profile_form_submit($form, &$form_state) {
$profile = (object)$form_state['values'];
// To allow for font size default of 20.
if (!$profile->fontsize) {
$profile->fontsize = 20;
}
$clicked_button = $form_state['clicked_button']['#value'];
if ($clicked_button == 'Delete') {
$form_state['redirect'] = 'admin/settings/signwriter/profile/'. $profile->id .'/delete';
}
else {
$id = signwriter_save_profile($profile, $form_state['values']['id']);
$message = t("Profile '@name' saved.", array('@name' => $profile->name));
drupal_set_message(theme('signwriter_text', $message, $profile));
$form_state['redirect'] = ($clicked_button == 'Save and edit') ? 'admin/settings/signwriter/profile/'. $id : 'admin/settings/signwriter';
}
}
/**
* The main admin>>settings>>signwriter page
*/
function signwriter_settings_page() {
if (!function_exists('imagetypes')) {
print theme('page', t('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 the !phpimagedoc', array('!phpimagedoc' => l('PHP Image library documentation.', 'http://php.net/image'))));
}
else {
$profiles = signwriter_load_profiles();
$rows = array();
foreach ($profiles as $profile) {
$links[] = l($profile->name, '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)) {
$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');
return $output;
}
}
function signwriter_settings_form($form_state) {
$form = 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 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'),
);
$form['paths']['signwriter_cachecleanperiod'] = array(
'#type' => 'radios',
'#title' => t('Cache cleanup period'),
'#description' => t('Choose how often the images in the signwriter cache directory should be purged.'),
'#default_value' => variable_get('signwriter_cachecleanperiod', '100 years'),
'#options' => array('1 day' => t('Daily'), '1 week' => t('Weekly'), '100 years' => t('Never')),
);
$form['paths']['signwriter_cachecleannow'] = array(
'#type' => 'submit',
'#value' => t('Clean signwriter cache now'),
);
$form['paths']['signwriter_fontpath'] = array(
'#type' => 'textfield',
'#title' => t('Font Search Path'),
'#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.'),
'#default_value' => variable_get('signwriter_fontpath', ''),
);
$form['signwriter_specialcharnotice'] = array(
'#type' => 'checkbox',
'#title' => t('Special character notice'),
'#description' => t('Each time time a string is to be rendered it is checked for special characters outside the ASCII character set. If any are found and the current user has the permission to configure signwriter, output a notice how to allow these characters.'),
'#default_value' => variable_get('signwriter_specialcharnotice', TRUE),
);
$titleoptions = array('disabled' => t('Disabled (headers unchanged)'));
$profiles = signwriter_load_profiles();
foreach ($profiles as $profile) {
$titleoptions[$profile->id] = 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' => $titleoptions,
);
$form['hooks']['signwriter_blockhookprofile'] = array(
'#type' => 'radios',
'#title' => t('Block titles'),
'#default_value' => variable_get('signwriter_blockhookprofile', 'disabled'),
'#options' => $titleoptions,
);
if (module_exists('panels')) {
$form['hooks']['signwriter_panelshooktitleprofile'] = array(
'#type' => 'radios',
'#title' => t('Panels titles'),
'#default_value' => variable_get('signwriter_panelshooktitleprofile', 'disabled'),
'#options' => $titleoptions,
);
}
return system_settings_form($form);
}
function signwriter_settings_form_validate($form, &$form_state) {
if ($form_state['clicked_button']['#value'] == t('Clean signwriter cache now')) {
signwriter_cron(TRUE);
$form_state['rebuild'] = TRUE;
}
}
/**
* Generate a signwriter image using the given profile.
*
* @param $profile
* 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
* 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->drop_shadow
* - $profile->shadow_xoffset
* - $profile->shadow_yoffset
* - $profile->shadow_color
* - $profile->hover_profile
* - $profile->active_profile
* - $profile->disable_span
* @param $text
* The text to display. Can contain html entities. For example, &
* will be displayed as &
*
* @return
* The absolute url to the image.
*/
function signwriter_image($text, $profile) {
$text = html_entity_decode($text, ENT_QUOTES);
$fontfile = $profile->fontfile;
$fontsize = (float) _signwriter_get_val($profile, 'fontsize', 20);
$hover_profile = _signwriter_get_val($profile, 'hover_profile', 0);
$active_profile = _signwriter_get_val($profile, 'active_profile', 0);
# image dimensions, type
$width = _signwriter_get_val($profile, 'width');
$height = _signwriter_get_val($profile, 'height');
$maxwidth = _signwriter_get_val($profile, 'maxwidth');
$align = _signwriter_get_val($profile, 'textalign', 'left');
$imagetype = _signwriter_get_val($profile, 'imagetype', 'gif');
$xoffset = _signwriter_get_val($profile, 'xoffset', 0);
$yoffset = _signwriter_get_val($profile, 'yoffset', 0);
# shadow, colors, background
$drop_shadow = _signwriter_get_val($profile, 'drop_shadow', 0);
$shadow_rgb = _signwriter_parse_colour(_signwriter_get_val($profile, 'shadow_color', 'd2d2d2'));
$shadow_xoffset = _signwriter_get_val($profile, 'shadow_xoffset', 0);
$shadow_yoffset = _signwriter_get_val($profile, 'shadow_yoffset', 0);
$border = _signwriter_get_val($profile, 'border', 0);
$border_rgb = _signwriter_parse_colour(_signwriter_get_val($profile, 'border_color', 'd2d2d2'));
$border_radius = _signwriter_get_val($profile, 'border_radius', 0);
$fg = _signwriter_parse_colour(_signwriter_get_val($profile, 'foreground', '000000'));
$transparent = _signwriter_get_val($profile, 'transparent', TRUE);
$bg = _signwriter_parse_colour(_signwriter_get_val($profile, 'background', 'ffffff'));
$bgimage = _signwriter_get_val($profile, 'bgimage');
$bgimagetype = _signwriter_get_image_type($bgimage);
if ($bgimage && !$bgimagetype) {
drupal_set_message("Signwriter: unsupported image type: $bgimage", 'error');
return '';
}
$cachedir = variable_get('signwriter_cachedir', file_directory_path() .'/signwriter');
file_check_directory($cachedir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
$imagefileid = "text:$text-". serialize($profile);
// for shorter filenames that are still unique and repeatable (for caching)
$imagefilename = preg_replace('/[^\w\d]/', '', $text) .'-'. md5($imagefileid) .'-signwriter.'. $imagetype;
$imagefile = "$cachedir/$imagefilename";
$hover = NULL;
if ($hover_profile) {
$hover = signwriter_load_profile($hover_profile);
}
$active = NULL;
if ($active_profile) {
$active = signwriter_load_profile($active_profile);
}
if (!is_readable($imagefile)) {
$angle = 0;
// calculate the size of the text
$box = imagettfbbox($fontsize, $angle, $fontfile, $text);
if (!$box) {
drupal_set_message(t('Unable to generate a signwriter image with font !font at size !size.', array('!font' => $fontfile, '!size' => $fontsize)), 'error');
return '';
}
// calculate the maximum possible hight of the text to properly vertically align multiple images
$biggest_box = imagettfbbox($fontsize, $angle, $fontfile, "ÅßåŮůÃÕÑÁÉÍÓÚÄËÏÖÜÀÈÌÒÙÂÊÎÔÛÇçabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
if ($hover) {
$hover_box = imagettfbbox($hover->fontsize, $hover->angle, $hover->fontfile, "ÅßåŮůÃÕÑÁÉÍÓÚÄËÏÖÜÀÈÌÒÙÂÊÎÔÛÇçabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
if (($hover_box[1] - $hover_box[7]) >= ($biggest_box[1] - $biggest_box[7])) {
$biggest_box = $hover_box;
}
unset($hover_box);
}
if ($active) {
$active_box = imagettfbbox($active->fontsize, $active->angle, $active->fontfile, "ÅßåŮůÃÕÑÁÉÍÓÚÄËÏÖÜÀÈÌÒÙÂÊÎÔÛÇçabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
if (($active_box[1] - $active_box[7]) >= ($biggest_box[1] - $biggest_box[7])) {
$biggest_box = $active_box;
}
unset($active_box);
}
foreach (array(1, 3, 5, 7) as $i) {
$box[$i] = $biggest_box[$i];
}
unset($biggest_box);
// If there is a shadow add the offset to the size of the box.
// Do the same for borders (*2 because the border is on the top, bottom, left and right).
$max_shadow_xoffset = max($shadow_xoffset, $hover->shadow_xoffset, $active->shadow_yoffset);
$max_shadow_yoffset = max($shadow_yoffset, $hover->shadow_yoffset, $active->shadow_yoffset);
$max_border_radius = max($border_radius, $hover->border_radius, $active->border_radius) * 2;
if ($drop_shadow || $hover->drop_shadow || $active->drop_shadow) {
$textwidth = abs($box[2]) + abs($box[0]) + abs($max_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($max_shadow_yoffset);
}
else {
$textwidth = abs($box[2]) + abs($box[0]) + 5;
$textheight = abs($box[1]) + abs($box[7]);
}
if ($border_radius || $hover->border_radius || $active->border_radius) {
$textwidth += $max_border_radius;
$textheight += $max_border_radius;
}
// 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 > 0 && $textwidth > $maxwidth) {
if ($profile->multiline) {
$words = split(' ', $text);
$line = '';
foreach ($words as $word) {
$wordbox = imagettfbbox($fontsize, 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($fontsize, 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($fontsize, 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 {
// We do not want to tamper with the original profile object.
$profile_clone = drupal_clone($profile);
$profile_clone->fontsize = ($fontsize * ($maxwidth / $textwidth)) - 0.5; // we take an extra 0.5 to avoid endless recursing due to actual font size not decreasing
return signwriter_image($text, $profile_clone);
}
}
else{
$lines[] = $text;
}
if ($maxlinewidth) {
$width = $width ? $width : $maxlinewidth;
}
else {
$width = $width ? $width : $textwidth + $xoffset;
}
$height = $height ? $height : $textheight * count($lines) + $yoffset;
$hover_offset = $hover ? $height : 0;
$active_offset = $active ? $height + $hover_offset : 0;
// create the image
if (!empty($bgimage)) {
$imagefunction = 'imagecreatefrom'. $bgimagetype;
$im = $imagefunction($bgimage);
$width = imagesx($im);
$height = imagesy($im);
}
else {
$image_height = $hover ? $height + $height : $height;
$image_height = $active ? $image_height + $height : $image_height;
$im = imagecreate($width, $image_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]);
$border_color = imagecolorallocate($im, $border_rgb[0], $border_rgb[1], $border_rgb[2]);
if ($hover) {
$fg = _signwriter_parse_colour(_signwriter_get_val($hover, 'foreground', '000000'));
$shadow_rgb = _signwriter_parse_colour(_signwriter_get_val($hover, 'shadow_color', 'd2d2d2'));
$border_rgb = _signwriter_parse_colour(_signwriter_get_val($hover, 'border_color', 'd2d2d2'));
$hover_foreground = imagecolorallocate($im, $fg[0], $fg[1], $fg[2]);
$hover_shadow_color = imagecolorallocate($im, $shadow_rgb[0], $shadow_rgb[1], $shadow_rgb[2]);
$hover_border_color = imagecolorallocate($im, $border_rgb[0], $border_rgb[1], $border_rgb[2]);
}
if ($active) {
$fg = _signwriter_parse_colour(_signwriter_get_val($active, 'foreground', '000000'));
$shadow_rgb = _signwriter_parse_colour(_signwriter_get_val($active, 'shadow_color', 'd2d2d2'));
$border_rgb = _signwriter_parse_colour(_signwriter_get_val($active, 'border_color', 'd2d2d2'));
$active_foreground = imagecolorallocate($im, $fg[0], $fg[1], $fg[2]);
$active_shadow_color = imagecolorallocate($im, $shadow_rgb[0], $shadow_rgb[1], $shadow_rgb[2]);
$active_border_color = imagecolorallocate($im, $border_rgb[0], $border_rgb[1], $border_rgb[2]);
}
unset($bg);
unset($fg);
unset($shadow_rgb);
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($fontsize, 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;
if (!$border) {
$border_radius = 0;
}
if ($hover && !$hover->border) {
$hover->border_radius = 0;
}
if ($active && !$active->border) {
$active->border_radius = 0;
}
// This is so that the shadow doesn't go outside of the box.
if ($drop_shadow || $hover->drop_shadow || $hover->drop_shadow) {
if ($shadow_xoffset < 0 && $shadow_yoffset < 0) {
// Main
if ($drop_shadow) {
imagettftext($im, $fontsize, $angle, $x + abs($box[0]), $y + abs($box[5]), $shadow_color, $fontfile, $line); // Shadow
}
signwriter_bordered_text($im, $fontsize, $angle, $x + abs($box[0]) - $shadow_xoffset, $y + abs($box[5]) - $shadow_yoffset, $foreground, $fontfile, $line, $border_radius, $border_color); // Text
// Hover
if ($hover_profile) {
if ($hover->drop_shadow) {
imagettftext($im, $hover->fontsize, $hover->angle, $x + abs($box[0]), $y + abs($box[5]) + $hover_offset, $hover_shadow_color, $hover->fontfile, $line); // Shadow
}
signwriter_bordered_text($im, $hover->fontsize, $hover->angle, $x + abs($box[0]) - $hover->shadow_xoffset, $y + abs($box[5]) - $hover->shadow_yoffset + $hover_offset, $hover_foreground, $hover->fontfile, $line, $hover->border_radius, $hover_border_color); // Text
}
// Active
if ($active_profile) {
if ($active->drop_shadow) {
imagettftext($im, $active->fontsize, $active->angle, $x + abs($box[0]), $y + abs($box[5]) + $active_offset, $active_shadow_color, $active->fontfile, $line); // Shadow
}
signwriter_bordered_text($im, $active->fontsize, $active->angle, $x + abs($box[0]) - $active->shadow_xoffset, $y + abs($box[5]) - $active->shadow_yoffset + $active_offset, $active_foreground, $active->fontfile, $line, $active->border_radius, $active_border_color); // Text
}
}
else if ($shadow_xoffset > 0 && $shadow_yoffset > 0) {
if ($drop_shadow) {
imagettftext($im, $fontsize, $angle, $x + abs($box[0]) + $shadow_xoffset, $y + abs($box[5]) + $shadow_yoffset, $shadow_color, $fontfile, $line); // Shadow
}
signwriter_bordered_text($im, $fontsize, $angle, $x + abs($box[0]), $y + abs($box[5]), $foreground, $fontfile, $line, $border_radius, $border_color); // Text
// Hover
if ($hover_profile) {
if ($hover->drop_shadow) {
imagettftext($im, $hover->fontsize, $hover->angle, $x + abs($box[0]) + $hover->shadow_xoffset, $y + abs($box[5]) + $hover->shadow_yoffset + $hover_offset, $hover_shadow_color, $hover->fontfile, $line); // Shadow
}
signwriter_bordered_text($im, $hover->fontsize, $hover->angle, $x + abs($box[0]), $y + abs($box[5]) + $hover_offset, $hover_foreground, $hover->fontfile, $line, $hover->border_radius, $hover_border_color); // Text
}
// Active
if ($active_profile) {
if ($active->drop_shadow) {
imagettftext($im, $active->fontsize, $active->angle, $x + abs($box[0]) + $active->shadow_xoffset, $y + abs($box[5]) + $active->shadow_yoffset + $active_offset, $active_shadow_color, $active->fontfile, $line); // Shadow
}
signwriter_bordered_text($im, $active->fontsize, $active->angle, $x + abs($box[0]), $y + abs($box[5]) + $active_offset, $active_foreground, $active->fontfile, $line, $active->border_radius, $active_border_color); // Text
}
}
else if ($shadow_xoffset < 0 && $shadow_yoffset > 0) {
if ($drop_shadow) {
imagettftext($im, $fontsize, $angle, $x + abs($box[0]), $y + abs($box[5]) + $shadow_yoffset, $shadow_color, $fontfile, $line); // Shadow
}
signwriter_bordered_text($im, $fontsize, $angle, $x + abs($box[0]) - $shadow_xoffset, $y + abs($box[5]), $foreground, $fontfile, $line, $border_radius, $border_color); // Text
// Hover
if ($hover_profile) {
if ($hover->drop_shadow) {
imagettftext($im, $hover->fontsize, $hover->angle, $x + abs($box[0]), $y + abs($box[5]) + $hover->shadow_yoffset + $hover_offset, $hover_shadow_color, $hover->fontfile, $line); // Shadow
}
signwriter_bordered_text($im, $hover->fontsize, $hover->angle, $x + abs($box[0]) - $hover->shadow_xoffset, $y + abs($box[5]) + $hover_offset, $hover_foreground, $hover->fontfile, $line, $hover->border_radius, $hover_border_color); // Text
}
// Active
if ($active_profile) {
if ($active->drop_shadow) {
imagettftext($im, $active->fontsize, $active->angle, $x + abs($box[0]), $y + abs($box[5]) + $active->shadow_yoffset + $active_offset, $active_shadow_color, $active->fontfile, $line); // Shadow
}
signwriter_bordered_text($im, $active->fontsize, $active->angle, $x + abs($box[0]) - $active->shadow_xoffset, $y + abs($box[5]) + $active_offset, $active_foreground, $active->fontfile, $line, $active->border_radius, $active_border_color); // Text
}
}
else if ($shadow_xoffset > 0 && $shadow_yoffset < 0) {
if ($drop_shadow) {
imagettftext($im, $fontsize, $angle, $x + abs($box[0]) + $shadow_xoffset, $y + abs($box[5]), $shadow_color, $fontfile, $line); // Shadow
}
signwriter_bordered_text($im, $fontsize, $angle, $x + abs($box[0]), $y + abs($box[5]) - $shadow_yoffset, $foreground, $fontfile, $line, $border_radius, $border_color); // Text
// Hover
if ($hover_profile) {
if ($hover->drop_shadow) {
imagettftext($im, $hover->fontsize, $hover->angle, $x + abs($box[0]) + $hover->shadow_xoffset, $y + abs($box[5]) + $hover_offset, $hover_shadow_color, $hover->fontfile, $line); // Shadow
}
signwriter_bordered_text($im, $hover->fontsize, $hover->angle, $x + abs($box[0]), $y + abs($box[5]) - $hover->shadow_yoffset + $hover_offset, $hover_foreground, $hover->fontfile, $line, $hover->border_radius, $hover_border_color); // Text
}
// Active
if ($active_profile) {
if ($active->drop_shadow) {
imagettftext($im, $active->fontsize, $active->angle, $x + abs($box[0]) + $active->shadow_xoffset, $y + abs($box[5]) + $active_offset, $active_shadow_color, $active->fontfile, $line); // Shadow
}
signwriter_bordered_text($im, $active->fontsize, $active->angle, $x + abs($box[0]), $y + abs($box[5]) - $active->shadow_yoffset + $active_offset, $active_foreground, $active->fontfile, $line, $active->border_radius, $active_border_color); // Text
}
}
}
else {
imagettftext($im, $fontsize, $angle, $x + abs($box[0]), $y + abs($box[5]), $foreground, $fontfile, $line);
signwriter_bordered_text($im, $fontsize, $angle, $x + abs($box[0]), $y + abs($box[5]), $foreground, $fontfile, $line, $border_radius, $border_color);
if ($hover) {
signwriter_bordered_text($im, $hover->fontsize, $hover->angle, $x + abs($box[0]), $y + abs($box[5]) + $hover_offset, $hover_foreground, $hover->fontfile, $line, $hover->border_radius, $hover_border_color);
}
if ($active) {
signwriter_bordered_text($im, $active->fontsize, $active->angle, $x + abs($box[0]), $y + abs($box[5]) + $active_offset, $active_foreground, $active->fontfile, $line, $active->border_radius, $active_border_color);
}
}
}
$imagefunction = "image$imagetype";
$imagefunction($im, $imagefile);
imagedestroy($im);
}
return $imagefile;
}
/**
* Slightly crude way of getting a bordered effect
*/
function signwriter_bordered_text(&$im, $fontsize, $angle, $x, $y, $text_color, $fontfile, $line, $border_radius = 0, $border_color = 0) {
if ($border_radius) {
imagettftext($im, $fontsize, $angle, $x - $border_radius, $y, $border_color, $fontfile, $line); // Text
imagettftext($im, $fontsize, $angle, $x + $border_radius, $y, $border_color, $fontfile, $line); // Text
imagettftext($im, $fontsize, $angle, $x, $y - $border_radius, $border_color, $fontfile, $line); // Text
imagettftext($im, $fontsize, $angle, $x, $y + $border_radius, $border_color, $fontfile, $line); // Text
}
// Actual Text
imagettftext($im, $fontsize, $angle, $x, $y, $text_color, $fontfile, $line); // Text
}
function _signwriter_strip_tags($text) {
return preg_replace('/<\/?(i|b|em|strong)>/', '', $text);
}
/**
* 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
* @param $attributes
* An associative array of attributes to be placed in the img tag.
* @param $hover
* Boolean value that specifies whether or not the hover feature will be used.
* If true, the class signwriter-hover will be added to the image and will
* be used by jQuery to determine which images need hover functionality.
*
* @return
* HTML text to replace the title.
*/
function signwriter_title_convert($title, $signwriter, $attributes = NULL, $hover = FALSE) {
$title = _signwriter_strip_tags($title);
preg_match('/^(<.*?>)*([^<]*)(<.*?>)*($)/s', $title, $matches);
$openingtags = $matches[1];
$titletext = $matches[2];
$closingtags = $matches[3];
return $openingtags . theme('signwriter_text', $titletext, $signwriter, $attributes, $hover) . $closingtags;
}
/**
* Turn text into a signwriter image.
*
* @param $text
* The text to display
* @param $profile
* 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
* @param $attributes
* An associative array of attributes to be placed in the img tag.
* @param $hover
* Boolean value that specifies whether or not the hover feature will be used.
* If true, the class signwriter-hover will be added to the image and will
* be used by jQuery to determine which images need hover functionality.
*
* @return
* HTML text to replace the input text.
*/
function theme_signwriter_text($text, $profile, $attributes = NULL, $hover = FALSE) {
drupal_add_css(drupal_get_path('module', 'signwriter') .'/signwriter.css');
if (empty($profile->fontfile)) {
$profile = signwriter_load_profile($profile);
}
$unicode_rest = array();
$alttext = '"'. decode_entities($text);
preg_match_all('/[^[:print:]'. $profile->allowed_nonasciichars .']/u', $alttext, $unicode_rest);
if (mb_detect_encoding($alttext) === 'UTF-8' && $profile->allowed_nonasciichars !== 'all' && !empty($unicode_rest[0])) {
if (variable_get('signwriter_specialcharnotice', TRUE) && user_access('administer signwriter')) {
unset($profile->width);
unset($profile->maxwidth);
foreach ($unicode_rest[0] as $num => $character) {
$alttext = t($character .'rendered with profile '. $profile->name);
$unicode_rest[0][$num] = $character .' ('. theme( 'image', signwriter_image($character, $profile), $alttext, $alttext, array('style' => 'vertical-align:middle')) .')';
}
drupal_set_message(t("Signwriter notice: The unicode string '$text' will not be replaced by an
image because it contains following special characters = ". implode(',', $unicode_rest[0])
.'. If your font indeed does include these glyphs, paste them into the allowed charactersfield on the
!profilesettings.', array('!profilesettings' => l("profile's setting page", 'admin/settings/signwriter/profile/'. $profile->id))));
}
return $text;
}
if ($hover && $profile->hover_profile) {
$attributes['class'] = $attributes['class'] ? $attributes['class'] . ' signwriter signwriter-hover' : 'signwriter signwriter-hover';
}
else {
$attributes['class'] = $attributes['class'] ? $attributes['class'] . ' signwriter' : 'signwriter';
}
$text = _signwriter_strip_tags($text);
$alttext = htmlspecialchars($text, ENT_QUOTES);
$imgsrc = signwriter_image($text, $profile);
$output = $text;
if (!empty($imgsrc)) {
if ($profile->disable_span) {
$output = theme('image', $imgsrc, $alttext, $alttext, $attributes);
}
else {
$output = '' . $text . '' . theme('image', $imgsrc, $alttext, $alttext, $attributes);
}
}
return $output;
}
/**
* 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);
}
}
/**
* Implementation of hook_panels_pre_render() from panels module.
*//*
function signwriter_panels_pre_render (&$display) {
$panelstitlehookprofile = variable_get('signwriter_panelshooktitleprofile', 'disabled');
foreach ($display->content as $pid => &$panel) {
if ($panelstitlehookprofile !== 'disabled' && !empty($panel->configuration['title'])) {
$panel->configuration['title'] = signwriter_title_convert($panel->configuration['title'], $panelstitlehookprofile);
}
}
}*/
function signwriter_panels_pane_content_alter (&$content, $pane, $args, $context) {
$panelstitlehookprofile = variable_get('signwriter_panelshooktitleprofile', 'disabled');
if ($panelstitlehookprofile !== 'disabled' && !empty($content->subject)) {
$content->title = signwriter_title_convert($content->title, $panelstitlehookprofile);
}
}