You are here

svg_image.module in Svg Image 7

Same filename and directory in other branches
  1. 8 svg_image.module
  2. 2.x svg_image.module
  3. 1.x svg_image.module

File

svg_image.module
View source
<?php

/**
 * Provides SVG support to image fields.
 */
require_once 'includes/svg_image.field.inc';
define('SVG_IMAGE_DEFAULT_WIDTH', 200);
define('SVG_IMAGE_DEFAULT_HEIGHT', 200);

/**
 * Preprocess function for theme_image_style().
 *
 * If theme_image_style() is called without setting explicit height/width for
 * an SVG image, attempt to set those dimensions. This helps in particular when
 * uploading an image for the first time in a content form.
 */
function svg_image_preprocess_image_style(&$variables) {
  $uri = $variables['path'];
  $is_svg = svg_image_is_svg($uri);
  if ($is_svg && empty($variables['width']) && empty($variables['height'])) {
    if ($dimensions = svg_image_get_dimensions($uri)) {
      $variables['width'] = $dimensions['width'];
      $variables['height'] = $dimensions['height'];
    }
    else {
      $variables['width'] = SVG_IMAGE_DEFAULT_WIDTH;
      $variables['height'] = SVG_IMAGE_DEFAULT_HEIGHT;
    }
  }
}

/**
 * Implements hook_file_presave().
 *
 * Set the dimensions in the "metadata" property used by File Entity module.
 */
function svg_image_file_presave($file) {
  if (svg_image_is_svg($file->uri) && isset($file->metadata)) {
    $svg_dimensions = svg_image_get_dimensions($file->uri);
    if ($svg_dimensions) {
      $file->metadata['width'] = $svg_dimensions['width'];
      $file->metadata['height'] = $svg_dimensions['height'];
    }
  }
}

/**
 * Implements hook_field_attach_presave().
 *
 * When saving a entity, this hook is called to make any adjustments to the
 * entire entity's fields before attempting to write to the database. When
 * Image module encounters an SVG image, it sets the height and width values
 * to be empty strings, which would cause a database constraint error when
 * a string is inserted into an integer column.
 *
 * This implementation loops through all fields attached to an entity, finds
 * those that are an image field, then sets the width and height values within
 * that field. These changes are made by reference, so they are in the $entity
 * object when Field module saves to the database.
 */
function svg_image_field_attach_presave($entity_type, $entity) {

  // Get information about which fields are on this type of entity.
  list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
  $bundle_field_info = field_info_instances($entity_type, $bundle);

  // Loop through each of the fields and find those that are image fields.
  foreach ($bundle_field_info as $field_name => $instance_info) {
    $field_info = field_info_field($field_name);
    if ($field_info['type'] === 'image') {

      // Rely on locale API to retrieve the correct langcode
      $langcode = field_is_translatable($entity_type, $field_info) ? field_language($entity_type, $entity, $field_name) : LANGUAGE_NONE;
      if (!isset($entity->{$field_name}[$langcode])) {
        continue;
      }

      // Update the field values (by reference) for SVG images.
      $field_values =& $entity->{$field_name}[$langcode];
      foreach ($field_values as $delta => $field_value) {
        if (!isset($field_value['fid'])) {
          continue;
        }
        $file = file_load($field_value['fid']);
        if ($file && svg_image_is_svg($file->uri)) {

          // Set default 100x100 as a default values.
          $field_values[$delta]['width'] = SVG_IMAGE_DEFAULT_WIDTH;
          $field_values[$delta]['height'] = SVG_IMAGE_DEFAULT_HEIGHT;
          if ($svg_dimensions = svg_image_get_dimensions($file->uri)) {
            $field_values[$delta]['width'] = $svg_dimensions['width'];
            $field_values[$delta]['height'] = $svg_dimensions['height'];
          }
        }
      }
    }
  }
}

/**
 * Implements hook_file_url_alter().
 *
 * Prevent image_style_url() from using a different URL for SVG images. Because
 * image styles cannot operate on SVGs, set the URL back to the original image.
 * This affects theme_image_style(), which normally would point to a new image.
 */
function svg_image_file_url_alter(&$url) {

  // If this is an SVG image in the styles directory...
  if (strpos($url, '/styles/') && strpos($url, '.svg')) {

    // Remove the styles directory portions and use the original image URL.
    $url = preg_replace('!/styles/.*?/.*?/!', '/', $url);
  }
}

/**
 * Get an SVG image's defined dimensions.
 *
 * @param string $uri
 *   The URI or path to an SVG image.
 *
 * @return array|FALSE
 *   An array containing the keys "width" and "height" as integer values. If the
 *   image is an SVG but no set dimensions are available, these keys will have
 *   NULL values. If the image is not an SVG, FALSE will be return.
 */
function svg_image_get_dimensions($uri) {

  // Safety check.
  if (!svg_image_is_svg($uri)) {
    return FALSE;
  }

  // Return cached dimensions if already retrieved once this request.
  $cached_images =& drupal_static(__FUNCTION__, array());
  if (isset($cached_images[$uri])) {
    return $cached_images[$uri];
  }

  // Workaround for a getting a width and height. It cannot be null and need to
  // be defined for the every image. So - if we got SVG file without the
  // dimensions defined in attributes it should be defined from our side to
  // avoid an exception.
  // @todo add a variable which defines this values.
  $svg_dimensions = array(
    'width' => SVG_IMAGE_DEFAULT_WIDTH,
    'height' => SVG_IMAGE_DEFAULT_HEIGHT,
  );
  $file_contents = file_get_contents($uri);
  if ($file_contents) {
    $svg = simplexml_load_string($file_contents);
    foreach ($svg
      ->attributes() as $attribute => $value) {
      if ($attribute === 'width' || $attribute === 'height') {
        $svg_dimensions[$attribute] = (int) $value;
      }
    }
  }

  // Save values to static cache.
  $cached_images[$uri] = $svg_dimensions;
  return $svg_dimensions;
}

/**
 * Determine if a file URI is an SVG image based on its file extension.
 *
 * @param string $uri
 *   A path or URI to an image.
 * @return bool
 *   TRUE if the image is an SVG. FALSE if it is not.
 */
function svg_image_is_svg($uri) {
  $mimetype = file_get_mimetype($uri);
  return $mimetype === 'image/svg+xml';
}

Functions

Namesort descending Description
svg_image_field_attach_presave Implements hook_field_attach_presave().
svg_image_file_presave Implements hook_file_presave().
svg_image_file_url_alter Implements hook_file_url_alter().
svg_image_get_dimensions Get an SVG image's defined dimensions.
svg_image_is_svg Determine if a file URI is an SVG image based on its file extension.
svg_image_preprocess_image_style Preprocess function for theme_image_style().

Constants