View source
<?php
function image_effects_text_help_inc() {
$output = "<p>\n For text rendering to work on a server, we <em>must</em>\n know the system path to the font <em>file</em>, not just the name.\n Font library handling differs too much on different systems and\n the available PHP toolkits are unable to return good diagnostics.\n </p><p>\n On Debian/Ubuntu, you may find your fonts in and under\n <code>/usr/share/fonts/truetype/</code>\n eg <code>'/usr/share/fonts/truetype/ttf-bitstream-vera/VeraMono.ttf'</code>\n </p><p>\n On OSX, they are probably in <code>/Library/Fonts/</code>\n eg <code>'/Library/Fonts/Times New Roman Bold Italic.ttf'</code>\n </p><p>\n On Windows, they are probably in <code>C:\\WINDOWS\\Fonts\\</code>\n eg <code>'C:\\WINDOWS\\Fonts\\comic.ttf'</code>\n </p><p>\n Of course, this will change if you deploy to a different server!\n so the best approach is to place your own TTF font file inside your private\n or public files directory and use that. Just give the filename with the\n 'private://' or 'public://' scheme prefix and it should be found.\n </p>\n ";
$output .= t("<p>Files directory is !files</p>", array(
'!files' => variable_get('file_public_path', conf_path() . '/files'),
));
return $output;
}
function image_effects_text_form_inc(array $data) {
module_load_include('inc', 'imagecache_actions', 'utility');
module_load_include('inc', 'imagecache_actions', 'utility-color');
$allow_php = module_exists('php') && user_access('use PHP for settings');
$defaults = array(
'size' => 50,
'angle' => 0,
'xpos' => '0',
'ypos' => '0',
'halign' => 'left',
'valign' => 'top',
'RGB' => array(
'HEX' => '#000000',
),
'alpha' => 100,
'fontfile' => drupal_get_path('module', 'image_effects_text') . '/Komika_display.ttf',
'text_source' => 'text',
'text' => t('Hello World!'),
'php' => 'if (!$image_context[\'entity\']) {
return \'' . t('No referring entity') . '\';
}
$entity_type = \'node\';
$field_name = \'my_field\';
$entity = $image_context[\'entity\'];
$field = field_get_items($entity_type, $entity, $field_name);
if ($field) {
return isset($field[0][\'value\']) ? $field[0][\'value\'] : \'' . t('No field value') . '\';
}
',
);
$data += $defaults;
$tokens = token_info();
$tokens = array_keys($tokens['types']);
$form = array(
'size' => array(
'#type' => 'textfield',
'#title' => t('Font size'),
'#default_value' => $data['size'],
'#description' => t('The font size in points. Only in GD1 this is in pixels.'),
'#size' => 3,
),
'xpos' => array(
'#type' => 'textfield',
'#title' => t('X offset'),
'#default_value' => $data['xpos'],
'#description' => t('Enter an offset in pixels or use a keyword: <em>left</em>, <em>center</em>, or <em>right</em>. Syntax like <em>right-20</em> is also valid.'),
'#size' => 10,
),
'ypos' => array(
'#type' => 'textfield',
'#title' => t('Y offset'),
'#default_value' => $data['ypos'],
'#description' => t('Enter an offset in pixels or use a keyword: <em>top</em>, <em>center</em>, or <em>bottom</em>. Syntax like <em>bottom-20</em> is also valid.'),
'#size' => 10,
),
'halign' => array(
'#type' => 'select',
'#title' => t('Horizontal alignment'),
'#default_value' => $data['halign'],
'#description' => t('The horizontal alignment of the text around the given %xpos.', array(
'%xpos' => t('X offset'),
)),
'#options' => array(
'left' => t('Left'),
'center' => t('Center'),
'right' => t('Right'),
),
),
'valign' => array(
'#type' => 'select',
'#title' => t('Vertical alignment'),
'#default_value' => $data['valign'],
'#description' => t('The vertical alignment of the text around the given %ypos.', array(
'%ypos' => t('Y offset'),
)),
'#options' => array(
'top' => t('Top'),
'center' => t('Center'),
'bottom' => t('Bottom'),
),
),
'RGB' => imagecache_rgb_form($data['RGB']),
'alpha' => array(
'#type' => 'textfield',
'#title' => t('Opacity'),
'#default_value' => $data['alpha'] ? $data['alpha'] : 100,
'#size' => 3,
'#description' => t('Opacity: 1-100.'),
),
'angle' => array(
'#type' => 'textfield',
'#title' => t('Angle'),
'#default_value' => $data['angle'],
'#description' => t('Angle: The angle in degrees, with 0 degrees being left-to-right reading text. Higher values represent a counter-clockwise rotation. For example, a value of 90 would result in bottom-to-top reading text.'),
'#size' => 3,
),
'fontfile' => array(
'#type' => 'textfield',
'#title' => t('Font file name'),
'#default_value' => $data['fontfile'],
'#description' => imagecache_actions_file_field_description(),
'#element_validate' => array(
'image_effects_text_validate_font',
),
'#size' => 80,
),
'text_help' => array(
'#type' => 'item',
'#title' => t('Text'),
'#description' => t('<p>Select the source of the text:</p>
<ul>
<li><strong>Image alt</strong>: the alt text of an image field referring to this image is taken.</li>
<li><strong>Image title</strong>: the title text of an image field referring to this image is taken.</li>
<li><strong>Text (with token replacement)</strong>: A text with optional token replacement. Line breaks can be inserted with \\n (\\\\n for a literal \\n). You can define the text in the text field below the drop down.</li>
<li><strong>PHP code</strong>: a piece of PHP code that returns the text to display. You can define the PHP code in the text area below the drop down. You will need the \'%use_php\' permission, defined by the \'PHP filter\' module.</li>
</ul>
<p>See the help in README.txt for an extensive explanation of the possibilities.</p>', array(
'%use_php' => t('Use PHP for settings'),
)),
),
'text_source' => array(
'#type' => 'select',
'#title' => t('Text source'),
'#default_value' => $data['text_source'],
'#options' => array(
'alt' => t('Image alt'),
'title' => t('Image title'),
'text' => t('Text (with token replacement)'),
'php' => t('PHP code'),
),
),
'text' => array(
'#type' => 'textfield',
'#title' => t('Text'),
'#default_value' => $data['text'],
'#states' => array(
'visible' => array(
':input[name="data[text_source]"]' => array(
'value' => 'text',
),
),
),
),
'token_help' => array(
'#type' => 'fieldset',
'#title' => t('Token replacement patterns'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'tree' => array(
'#theme' => 'token_tree',
'#token_types' => $tokens,
),
'token_module_notice' => array(
'#markup' => !module_exists('token') ? t('You might want to enable the token module to view token replacement patterns.') : '',
),
'entity_token_module_notice' => array(
'#markup' => !module_exists('entity_token') ? t('You might want to enable the entity_token module to get token options for all entities and field properties.') : '',
),
'#states' => array(
'visible' => array(
':input[name="data[text_source]"]' => array(
'value' => 'text',
),
),
),
),
'php' => array(
'#type' => 'textarea',
'#rows' => 12,
'#title' => t('PHP code'),
'#default_value' => $data['php'],
'#disabled' => !$allow_php,
'#states' => array(
'visible' => array(
':input[name="data[text_source]"]' => array(
'value' => 'php',
),
),
),
'#wysiwyg' => FALSE,
),
);
if (!$allow_php && $data['text_source'] !== 'php') {
unset($form['text_fieldset']['text_source']['#options']['php']);
}
$form['#element_validate'][] = 'image_effects_text_form_validate';
return $form;
}
function image_effects_text_form_validate(array $element) {
if (!is_numeric($element['size']['#value']) || $element['size']['#value'] <= 0) {
form_error($element['size'], t('%field must be a positive number.', array(
'%field' => t('Font size'),
)));
}
if (!is_numeric($element['alpha']['#value']) || $element['alpha']['#value'] < 0 || $element['alpha']['#value'] > 100) {
form_error($element['alpha'], t('%field must be a number between 1 and 100.', array(
'%field' => t('Opacity'),
)));
}
if (!is_numeric($element['angle']['#value'])) {
form_error($element['angle'], t('%field must be a number.', array(
'%field' => t('Angle'),
)));
}
}
function image_effects_text_validate_font(array &$element) {
if (!imagecache_actions_find_file($element['#value'])) {
drupal_set_message(t("Unable to find the font file '%file'. Please check the path. You can ignore this waning, if the font refers to a system or toolkit font, and the text shows correctly.", array(
'%file' => $element['#value'],
)), 'warning');
}
}
function theme_image_effects_text_summary(array $variables) {
$data = $variables['data'];
switch ($data['text_source']) {
case 'alt':
$text = 'image alt';
break;
case 'title':
$text = 'image title';
break;
case 'text':
$text = $data['text'];
break;
case 'php':
$text = 'PHP code';
break;
default:
$text = '';
break;
}
return 'Text: ' . $text . '; Position: ' . $data['xpos'] . ',' . $data['ypos'] . '; Alignment: ' . $data['halign'] . ',' . $data['valign'];
}
function image_effects_text_effect_inc(stdClass $image, array $data) {
module_load_include('inc', 'imagecache_actions', 'utility');
$params = $data;
$params['text'] = image_effects_text_get_text($image, $params);
if (empty($params['text'])) {
return TRUE;
}
$params['fontpath'] = imagecache_actions_find_file($data['fontfile']);
if ($params['fontpath'] === FALSE) {
$params['fontpath'] = $data['fontfile'];
}
$params['xpos'] = image_effects_text_get_offset($data['xpos'], $image->info['width'], $image->info['height'], $image->info['width']);
$params['ypos'] = image_effects_text_get_offset($data['ypos'], $image->info['width'], $image->info['height'], $image->info['height']);
$params['RGB'] = $data['RGB'];
if ($params['RGB']['HEX'] && ($deduced = imagecache_actions_hex2rgba($params['RGB']['HEX']))) {
$params['RGB'] += $deduced;
}
$params['size'] = (int) $params['size'];
$params['xpos'] = (int) $params['xpos'];
$params['ypos'] = (int) $params['ypos'];
return image_toolkit_invoke('image_effects_text', $image, array(
$params,
));
}
function image_gd_image_effects_text(stdClass $image, array $data) {
$data['alpha'] = (int) ((1 - $data['alpha'] / 100) * 127);
$color = imagecolorallocatealpha($image->resource, $data['RGB']['red'], $data['RGB']['green'], $data['RGB']['blue'], $data['alpha']);
if ($color !== FALSE) {
$bounds = NULL;
if ($data['valign'] !== 'bottom') {
$bounds = imagettfbbox($data['size'], 0, $data['fontpath'], $data['text']);
if (!$bounds) {
drupal_set_message(t('Failed to calculate text dimensions using GD toolkit. Ignoring the alignment settings.'), 'warning');
}
else {
$height = $bounds[1] - $bounds[7];
$data['ypos'] += $data['valign'] === 'center' ? (int) ($height / 2) : $height;
}
}
if ($data['halign'] !== 'left') {
if ($bounds === NULL) {
$bounds = imagettfbbox($data['size'], 0, $data['fontpath'], $data['text']);
if (!$bounds) {
drupal_set_message(t('Failed to calculate text dimensions using GD toolkit. Ignoring the alignment.'), 'warning');
}
}
if ($bounds !== FALSE) {
$width = $bounds[2] - $bounds[0];
$data['xpos'] -= $data['halign'] === 'center' ? (int) ($width / 2) : $width;
}
}
$bounds = imagettftext($image->resource, $data['size'], $data['angle'], $data['xpos'], $data['ypos'], $color, $data['fontpath'], $data['text']);
return $bounds !== FALSE;
}
return FALSE;
}
function image_imagemagick_image_effects_text(stdClass $image, array $data) {
static $alignments2gravity = array(
'left' => array(
'top' => array(
'gravity' => 'NorthWest',
'tx' => 0,
'ty' => 0,
),
'center' => array(
'gravity' => 'West',
'tx' => 0,
'ty' => -0.5,
),
'bottom' => array(
'gravity' => 'SouthWest',
'tx' => 0,
'ty' => 1,
),
),
'center' => array(
'top' => array(
'gravity' => 'North',
'tx' => -0.5,
'ty' => 0,
),
'center' => array(
'gravity' => 'Center',
'tx' => -0.5,
'ty' => -0.5,
),
'bottom' => array(
'gravity' => 'South',
'tx' => -0.5,
'ty' => 1,
),
),
'right' => array(
'top' => array(
'gravity' => 'NorthEast',
'tx' => 1,
'ty' => 0,
),
'center' => array(
'gravity' => 'East',
'tx' => 1,
'ty' => -0.5,
),
'bottom' => array(
'gravity' => 'SouthEast',
'tx' => 1,
'ty' => 1,
),
),
);
$alpha = $data['alpha'] / 100;
$color = 'rgba(' . $data['RGB']['red'] . ',' . $data['RGB']['green'] . ',' . $data['RGB']['blue'] . ',' . $alpha . ')';
$alignment_corrections = $alignments2gravity[$data['halign']][$data['valign']];
$gravity = $alignment_corrections['gravity'];
if ($alignment_corrections['tx'] > 0) {
$data['xpos'] = (int) ($alignment_corrections['tx'] * $image->info['width'] - $data['xpos']);
}
else {
$data['xpos'] += (int) ($alignment_corrections['tx'] * $image->info['width']);
}
if ($alignment_corrections['ty'] > 0) {
$data['ypos'] = (int) ($alignment_corrections['ty'] * $image->info['height'] - $data['ypos']);
}
else {
$data['ypos'] += (int) ($alignment_corrections['ty'] * $image->info['height']);
}
if ($data['xpos'] >= 0) {
$data['xpos'] = '+' . $data['xpos'];
}
if ($data['ypos'] >= 0) {
$data['ypos'] = '+' . $data['ypos'];
}
if ($data['angle'] < 0) {
$data['angle'] = $data['angle'] % 360 + 360;
}
$image->ops[] = '-font ' . escapeshellarg($data['fontpath']);
$image->ops[] = "-pointsize {$data['size']}";
$image->ops[] = '-fill ' . escapeshellarg($color);
$tmp_file_name = drupal_tempnam('temporary://', 'image_effects_text');
$tmp_file = fopen($tmp_file_name, 'w');
if ($tmp_file) {
fwrite($tmp_file, $data['text']);
fclose($tmp_file);
image_effects_text_exit($tmp_file_name);
$tmp_file_name = drupal_realpath($tmp_file_name);
$text = "@{$tmp_file_name}";
}
else {
$text = $data['text'];
}
$image->ops[] = "-gravity {$gravity}";
$image->ops[] = "-annotate {$data['angle']}x{$data['angle']}{$data['xpos']}{$data['ypos']} " . escapeshellarg($text);
return TRUE;
}
function image_effects_text_get_offset($position, $width, $height, $length) {
$value = 0;
$tokens = preg_split('/ *(-|\\+) */', $position, 0, PREG_SPLIT_DELIM_CAPTURE);
$sign = 1;
foreach ($tokens as $token) {
switch ($token) {
case '+':
break;
case '-':
$sign = -$sign;
break;
case 'top':
case 'left':
$value += $sign * 0;
$sign = 1;
break;
case 'bottom':
$value += $sign * $height;
$sign = 1;
break;
case 'right':
$value += $sign * $width;
$sign = 1;
break;
case 'center':
$value += $sign * $length / 2;
$sign = 1;
break;
default:
if (substr($token, -strlen('%')) === '%') {
$percentage = (double) substr($token, 0, -strlen('%')) / 100.0;
$value += $sign * ($percentage * $length);
}
else {
$value += $sign * (double) $token;
}
$sign = 1;
break;
}
}
return $value;
}
function image_effects_text_get_text(stdClass $image, array $data) {
$image_context = imagecache_actions_get_image_context($image, $data);
if ($data['text_source'] === 'text') {
$text = preg_replace('/([^\\\\])\\\\n/', "\$1\n", $data['text']);
$text = preg_replace('/\\\\\\\\n/', '\\n', $text);
$token_data = array();
foreach ($image_context['referring_entities'] as $field_referring_entities) {
foreach ($field_referring_entities as $entity_type => $entities) {
$token_data[$entity_type] = reset($entities);
}
}
if ($image_context['managed_file']) {
$token_data['file'] = $image_context['managed_file'];
}
$text = token_replace($text, $token_data, array(
'clear' => TRUE,
'sanitize' => FALSE,
));
}
else {
if ($data['text_source'] === 'alt' || $data['text_source'] === 'title') {
$text = '';
if (!empty($image_context['image_field'][$data['text_source']])) {
$text = $image_context['image_field'][$data['text_source']];
}
else {
if (!empty($image_context['managed_file'])) {
$field = field_get_items('file', $image_context['managed_file'], "field_file_image_{$data['text_source']}_text");
if ($field) {
$text = $field[0]['value'];
}
}
}
}
else {
$GLOBALS['image_context'] = $image_context;
$GLOBALS['image'] = $image;
$text = module_exists('php') ? php_eval('<' . '?php global $image, $image_context; ' . $data['php'] . ' ?' . '>') : '';
unset($GLOBALS['image']);
unset($GLOBALS['image_context']);
}
}
return $text;
}