You are here

picture.module in Picture 7

Same filename and directory in other branches
  1. 8 picture.module
  2. 7.2 picture.module

Picture formatter.

File

picture.module
View source
<?php

/**
 * @file
 * Picture formatter.
 */
define('PICTURE_CLASS', 'picture');
define('PICTURE_SEPARATOR', '__');
define('PICTURE_EMPTY_IMAGE', '_empty image_');
define('PICTURE_ORIGINAL_IMAGE', '_original image_');
define('PICTURE_IMPLEMENTATION_PICTUREFILL2', 'picturefill2');
define('PICTURE_IMPLEMENTATION_PICTUREFILL', 'picturefill');
define('PICTURE_IMPLEMENTATION_WEBLINC', 'weblinc');
define('PICTURE_IMPLEMENTATION_DEFAULT', 'picturefill');
if (!variable_get('picture_updated_to_file_entity_2', FALSE)) {
  module_load_include('file_entity_1.inc', 'picture');
}

/**
 * Implements hook_permission().
 */
function picture_permission() {
  return array(
    'administer pictures' => array(
      'title' => t('Administer Pictures'),
      'description' => t('Administer Pictures'),
    ),
  );
}

/**
 * Implements hook_menu().
 */
function picture_menu() {
  $items = array();
  $items['admin/config/media/picture'] = array(
    'title' => 'Picture',
    'description' => 'Manage Pictures',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'picture_admin_breakpoints',
    ),
    'access arguments' => array(
      'administer pictures',
    ),
    'file' => 'picture.admin.inc',
  );
  $items['admin/config/media/picture/groups'] = array(
    'title' => 'Groups',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => 10,
  );
  $items['admin/config/media/picture/settings'] = array(
    'title' => 'Settings',
    'type' => MENU_LOCAL_TASK,
    'weight' => 20,
    'description' => 'Pictures settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'picture_admin_settings',
    ),
    'access arguments' => array(
      'administer pictures',
    ),
    'file' => 'picture.admin.inc',
  );
  $items['admin/config/media/picture/groups/global'] = array(
    'title' => 'Map breakpoints and image styles',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -1,
  );
  $items['admin/config/media/picture/groups/import'] = array(
    'title' => 'Import mappings',
    'page arguments' => array(
      'picture_admin_import_form',
    ),
    'type' => MENU_LOCAL_TASK,
    'access arguments' => array(
      'administer pictures',
    ),
    'file' => 'picture.admin.inc',
    'weight' => 999,
  );
  $breakpoint_groups = breakpoints_breakpoint_group_load_all();
  foreach ($breakpoint_groups as $breakpoint_group_name => $breakpoint_group) {
    if (!empty($breakpoint_group->machine_name)) {
      $items['admin/config/media/picture/groups/' . $breakpoint_group->machine_name] = array(
        'title' => $breakpoint_group->name,
        'page arguments' => array(
          'picture_admin_breakpoints',
          $breakpoint_group->machine_name,
        ),
        'type' => MENU_LOCAL_TASK,
        'access arguments' => array(
          'administer pictures',
        ),
        'file' => 'picture.admin.inc',
        'weight' => 15,
      );
      $items['admin/config/media/picture/groups/' . $breakpoint_group->machine_name . '/export'] = array(
        'title' => 'Export ' . check_plain($breakpoint_group->name) . ' mappings',
        'page callback' => 'drupal_get_form',
        'page arguments' => array(
          'picture_admin_export_form',
          $breakpoint_group->machine_name,
        ),
        'type' => MENU_LOCAL_ACTION,
        'access arguments' => array(
          'administer pictures',
          $breakpoint_group->machine_name,
        ),
        'access callback' => 'picture_mappings_export_access',
        'file' => 'picture.admin.inc',
        'weight' => 15,
      );
    }
  }
  $items['admin/config/media/picture/ckeditor'] = array(
    'title' => 'CKEditor',
    'type' => MENU_LOCAL_TASK,
    'description' => 'Choose picture groups to present in the CKEditor image dialog',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'picture_ckeditor_settings',
    ),
    'access arguments' => array(
      'administer pictures',
    ),
    'file' => 'picture.admin.inc',
    'weight' => 0,
  );
  return $items;
}

/**
 * Access callback.
 */
function picture_mappings_export_access($perm, $mapping_name) {
  return picture_mapping_load($mapping_name) && user_access($perm);
}

/**
 * Load mappings.
 */
function picture_mapping_load($name = NULL) {
  ctools_include('export');
  if ($name) {
    $mappings = ctools_export_load_object('picture_mapping', 'names', array(
      $name,
    ));
    $mapping = isset($mappings[$name]) ? $mappings[$name] : FALSE;
    return $mapping;
  }
  return ctools_export_load_object('picture_mapping');
}

/**
 * Load all mappings.
 */
function picture_mapping_load_all() {
  ctools_include('export');
  return ctools_export_load_object('picture_mapping');
}

/**
 * Save mappings.
 */
function picture_mapping_save(&$mapping) {
  ctools_include('export');
  $update = isset($mapping->id) ? array(
    'id',
  ) : array();
  return drupal_write_record('picture_mapping', $mapping, $update);
}

/**
 * Implements hook_library().
 */
function picture_library() {
  $libraries = array();
  switch (variable_get('picture_implementation', PICTURE_IMPLEMENTATION_DEFAULT)) {
    case PICTURE_IMPLEMENTATION_PICTUREFILL2:
      $libraries['picturefill'] = array(
        'title' => t('Picturefill'),
        'website' => 'https://github.com/scottjehl/picturefill',
        'version' => '2.0',
        'js' => array(
          drupal_get_path('module', 'picture') . '/picturefill2/picturefill.js' => array(
            'type' => 'file',
            'weight' => -10,
            'group' => JS_DEFAULT,
            'scope' => 'footer',
            'need_jquery' => FALSE,
          ),
        ),
      );
      break;
    case PICTURE_IMPLEMENTATION_PICTUREFILL:
      $libraries['matchmedia'] = array(
        'title' => t('Matchmedia'),
        'website' => 'https://github.com/attiks/picturefill-proposal',
        'version' => '0.1',
        'js' => array(
          drupal_get_path('module', 'picture') . '/picturefill/matchmedia.js' => array(
            'type' => 'file',
            'weight' => -10,
            'group' => JS_DEFAULT,
            'scope' => 'footer',
            'need_jquery' => FALSE,
          ),
        ),
      );
      $libraries['picturefill'] = array(
        'title' => t('Picturefill'),
        'website' => 'https://github.com/attiks/picturefill-proposal',
        'version' => '0.1',
        'js' => array(
          drupal_get_path('module', 'picture') . '/picturefill/picturefill.js' => array(
            'type' => 'file',
            'weight' => -10,
            'group' => JS_DEFAULT,
            'scope' => 'footer',
            'need_jquery' => FALSE,
          ),
        ),
      );
      $libraries['picture.ajax'] = array(
        'title' => t('Ajax support for picture'),
        'version' => VERSION,
        'js' => array(
          drupal_get_path('module', 'picture') . '/picture.js' => array(
            'type' => 'file',
            'weight' => -10,
            'group' => JS_DEFAULT,
            'scope' => 'footer',
            'need_jquery' => FALSE,
          ),
        ),
      );
      break;
    case PICTURE_IMPLEMENTATION_WEBLINC:
      $libraries['matchmedia'] = array(
        'title' => t('Matchmedia'),
        'website' => 'https://github.com/weblinc/media-match',
        'version' => '0.1',
        'js' => array(
          drupal_get_path('module', 'picture') . '/weblinc/media.js' => array(
            'type' => 'file',
            'weight' => -10,
            'group' => JS_DEFAULT,
            'scope' => 'footer',
            'need_jquery' => FALSE,
          ),
          drupal_get_path('module', 'picture') . '/weblinc/media.extension.js' => array(
            'type' => 'file',
            'weight' => -10,
            'group' => JS_DEFAULT,
            'scope' => 'footer',
            'need_jquery' => FALSE,
          ),
        ),
        'css' => array(
          drupal_get_path('module', 'picture') . '/weblinc/media.css' => array(
            'type' => 'file',
          ),
        ),
      );
      $libraries['picturefill'] = array(
        'title' => t('Picturefill'),
        'website' => 'https://github.com/weblinc/picture',
        'version' => '0.1',
        'js' => array(
          drupal_get_path('module', 'picture') . '/weblinc/picture.js' => array(
            'type' => 'file',
            'weight' => -10,
            'group' => JS_DEFAULT,
            'scope' => 'footer',
            'need_jquery' => FALSE,
          ),
        ),
      );
      $libraries['picture.ajax'] = array(
        'title' => t('Ajax support for picture'),
        'version' => VERSION,
        'js' => array(
          drupal_get_path('module', 'picture') . '/picture.weblinc.js' => array(
            'type' => 'file',
            'weight' => -10,
            'group' => JS_DEFAULT,
            'scope' => 'footer',
            'need_jquery' => FALSE,
          ),
        ),
        'css' => array(
          drupal_get_path('module', 'picture') . '/picture.weblinc.css' => array(
            'type' => 'file',
          ),
        ),
      );
      break;
  }
  return $libraries;
}

/**
 * Empty picture object.
 */
function picture_empty_object() {
  return (object) picture_empty_array();
}

/**
 * Empty picture array.
 */
function picture_empty_array() {
  return array(
    'machine_name' => '',
    'breakpoint_group' => '',
    'mapping' => array(),
  );
}

/**
 * Validate mappings.
 */
function picture_mapping_validate($mapping) {
  if (!is_object($mapping)) {
    return FALSE;
  }
  foreach (array(
    'machine_name',
    'breakpoint_group',
    'mapping',
  ) as $property) {
    if (!property_exists($mapping, $property)) {
      return FALSE;
    }
  }
  return TRUE;
}

/**
 * Implements hook_theme().
 */
function picture_theme() {
  return array(
    'picture' => array(
      'variables' => array(
        'style_name' => NULL,
        'path' => NULL,
        'uri' => NULL,
        'width' => NULL,
        'height' => NULL,
        'alt' => '',
        'title' => NULL,
        'attributes' => array(),
        'breakpoints' => array(),
      ),
    ),
    'picture_formatter' => array(
      'variables' => array(
        'item' => NULL,
        'path' => NULL,
        'image_style' => NULL,
        'attributes' => array(),
        'breakpoints' => array(),
      ),
    ),
    'picture_formatter_colorbox' => array(
      'variables' => array(
        'item' => NULL,
        'path' => NULL,
        'image_style' => NULL,
        'breakpoints' => array(),
        'colorbox_group' => array(),
        'colorbox_image_style' => NULL,
        'colorbox_group_id' => NULL,
        'colorbox_caption' => NULL,
      ),
    ),
    'picture_source' => array(
      'variables' => array(
        'src' => NULL,
        'dimension' => NULL,
        'media' => NULL,
      ),
    ),
  );
}

/**
 * Implements hook_field_formatter_info().
 */
function picture_field_formatter_info() {
  $formatters = array(
    'picture' => array(
      'label' => t('Picture'),
      'field types' => array(
        'image',
      ),
      'settings' => array(
        'picture_group' => '',
        'fallback_image_style' => '',
        'image_link' => '',
        'colorbox_settings' => array(
          'colorbox_group' => '',
          'colorbox_gallery' => 'post',
          'colorbox_gallery_custom' => '',
          'colorbox_caption' => 'auto',
          'colorbox_caption_custom' => '',
          'colorbox_multivalue_index' => NULL,
        ),
      ),
    ),
  );
  return $formatters;
}

/**
 * Implements hook_field_formatter_settings_form().
 */
function picture_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
  $display = $instance['display'][$view_mode];
  $settings = $display['settings'];
  $options = picture_get_mapping_options();
  if ($options) {
    $element['picture_group'] = array(
      '#title' => t('Picture group'),
      '#type' => 'select',
      '#default_value' => $settings['picture_group'],
      '#required' => TRUE,
      '#options' => $options,
    );
  }
  else {
    $element['picture_group'] = array(
      '#title' => t('Picture group'),
      '#type' => 'item',
      '#markup' => t('There are no picture groups defined. !create_link.', array(
        '!create_link' => l(t('Create a picture group'), 'admin/config/media/picture'),
      )),
    );
  }
  $image_styles = image_style_options(FALSE);
  $element['fallback_image_style'] = array(
    '#title' => t('Fallback image style'),
    '#type' => 'select',
    '#default_value' => $settings['fallback_image_style'],
    '#empty_option' => t('Automatic'),
    '#options' => $image_styles,
  );
  $link_types = picture_link_types($instance);
  $element['image_link'] = array(
    '#title' => t('Link image to'),
    '#type' => 'select',
    '#default_value' => $settings['image_link'],
    '#empty_option' => t('Nothing'),
    '#options' => $link_types,
    '#attributes' => array(
      'class' => array(
        'picture-image-link',
      ),
    ),
  );

  // Settings for the colorbox option.
  $element['colorbox_settings'] = array(
    '#type' => 'fieldset',
    '#tree' => TRUE,
    '#title' => t('Colorbox settings'),
    '#collapsed' => FALSE,
    '#collapsible' => TRUE,
    '#states' => array(
      'visible' => array(
        ':input[name$="[settings][image_link]"].picture-image-link' => array(
          'value' => 'colorbox',
        ),
      ),
    ),
  );
  $element['colorbox_settings']['colorbox_group'] = array(
    '#title' => t('Colorbox group'),
    '#type' => 'select',
    '#default_value' => $settings['colorbox_settings']['colorbox_group'],
    '#required' => FALSE,
    '#options' => picture_get_mapping_options(),
  );
  $gallery = array(
    'post' => t('Per post gallery'),
    'page' => t('Per page gallery'),
    'field_post' => t('Per field in post gallery'),
    'field_page' => t('Per field in page gallery'),
    'custom' => t('Custom'),
    'none' => t('No gallery'),
  );
  $element['colorbox_settings']['colorbox_gallery'] = array(
    '#title' => t('Gallery (image grouping)'),
    '#type' => 'select',
    '#default_value' => $settings['colorbox_settings']['colorbox_gallery'],
    '#options' => $gallery,
    '#description' => t('How Colorbox should group the image galleries.'),
    '#attributes' => array(
      'class' => array(
        'picture-colorbox-gallery',
      ),
    ),
  );
  $element['colorbox_settings']['colorbox_gallery_custom'] = array(
    '#title' => t('Custom gallery'),
    '#type' => 'textfield',
    '#maxlength' => 32,
    '#default_value' => $settings['colorbox_settings']['colorbox_gallery_custom'],
    '#description' => t('All images on a page with the same gallery value (rel attribute) will be grouped together. It must only contain lowercase letters, numbers, hyphen and underscores.'),
    '#element_validate' => array(
      'colorbox_gallery_custom_validate',
    ),
    '#required' => FALSE,
    '#states' => array(
      'visible' => array(
        ':input[name$="[settings][colorbox_settings][colorbox_gallery]"].picture-colorbox-gallery' => array(
          'value' => 'custom',
        ),
      ),
    ),
  );
  $caption = array(
    'auto' => t('Automatic'),
    'title' => t('Title text'),
    'alt' => t('Alt text'),
    'node_title' => t('Content title'),
    'custom' => t('Custom (with tokens)'),
    'none' => t('None'),
  );
  $element['colorbox_settings']['colorbox_caption'] = array(
    '#title' => t('Caption'),
    '#type' => 'select',
    '#default_value' => $settings['colorbox_settings']['colorbox_caption'],
    '#options' => $caption,
    '#description' => t('Automatic will use the first none empty value of the title, the alt text and the content title.'),
    '#attributes' => array(
      'class' => array(
        'picture-colorbox-caption',
      ),
    ),
  );
  $element['colorbox_settings']['colorbox_caption_custom'] = array(
    '#title' => t('Custom caption'),
    '#type' => 'textfield',
    '#default_value' => $settings['colorbox_settings']['colorbox_caption_custom'],
    '#states' => array(
      'visible' => array(
        ':input[name$="[settings][colorbox_settings][colorbox_caption]"].picture-colorbox-caption' => array(
          'value' => 'custom',
        ),
      ),
    ),
  );

  // Allow users to hide or set a custom recursion limit.
  // The module token_tweaks sets a global recursion limit that can not be bypassed.
  if (module_exists('token') && ($recursion_limit = min(variable_get('token_tree_recursion_limit', 3), variable_get('colorbox_token_recursion_limit', 3)))) {
    $element['colorbox_settings']['colorbox_token'] = array(
      '#type' => 'fieldset',
      '#title' => t('Replacement patterns'),
      '#theme' => 'token_tree',
      '#token_types' => array(
        $instance['entity_type'],
        'file',
      ),
      '#recursion_limit' => $recursion_limit,
      '#dialog' => TRUE,
      '#states' => array(
        'visible' => array(
          ':input[name$="[settings][colorbox_settings][colorbox_caption]"].picture-colorbox-caption' => array(
            'value' => 'custom',
          ),
        ),
      ),
    );
  }
  else {
    $element['colorbox_settings']['colorbox_token'] = array(
      '#type' => 'fieldset',
      '#title' => t('Replacement patterns'),
      '#description' => '<strong class="error">' . t('For token support the <a href="@token_url">token module</a> must be installed.', array(
        '@token_url' => 'http://drupal.org/project/token',
      )) . '</strong>',
      '#states' => array(
        'visible' => array(
          ':input[name$="[settings][colorbox_settings][colorbox_caption]"].picture-colorbox-caption' => array(
            'value' => 'custom',
          ),
        ),
      ),
    );
  }
  return $element;
}

/**
 * Returns a list of picture mappings for use in a select list.
 */
function picture_get_mapping_options() {
  $picture_mapping_options = array();
  $picture_mappings = picture_mapping_load_all();
  if ($picture_mappings && !empty($picture_mappings)) {
    foreach ($picture_mappings as $machine_name => $picture_mapping) {
      $breakpoint_group = breakpoints_breakpoint_group_load($picture_mapping->breakpoint_group);
      if ($breakpoint_group) {
        $picture_mapping_options[$machine_name] = $breakpoint_group->name;
      }
    }
  }
  return $picture_mapping_options;
}

/**
 * Implements hook_field_formatter_settings_summary().
 */
function picture_field_formatter_settings_summary($field, $instance, $view_mode) {
  $display = $instance['display'][$view_mode];
  $settings = $display['settings'];
  $summary = array();
  if (isset($settings['picture_group']) && !empty($settings['picture_group'])) {
    $picture_mapping = picture_mapping_load($settings['picture_group']);
    $breakpoint_group = breakpoints_breakpoint_group_load($picture_mapping->breakpoint_group);
    if ($breakpoint_group) {
      $summary[] = t('Picture group: @picture_group', array(
        '@picture_group' => $breakpoint_group->name,
      ));
    }
    else {
      $summary[] = t("Picture group doesn't exists");
    }
  }
  else {
    $summary[] = t("You have to select a mapping first.");
  }
  $image_styles = image_style_options(FALSE);
  unset($image_styles['']);
  if (isset($image_styles[$settings['fallback_image_style']])) {
    $summary[] = t('Fallback Image style: @style', array(
      '@style' => $image_styles[$settings['fallback_image_style']],
    ));
  }
  else {
    $summary[] = t('Automatic fallback');
  }
  $link_types = picture_link_types($instance);

  // Display this setting only if image is linked.
  if (isset($link_types[$settings['image_link']])) {
    $summary[] = filter_xss_admin($link_types[$settings['image_link']]);
  }

  // Display the settings for the colorbox if chosen.
  if ($settings['image_link'] == 'colorbox') {
    $summary[] = t('Colorbox Group: @setting', array(
      '@setting' => $settings['colorbox_settings']['colorbox_group'],
    ));
    $gallery = array(
      'post' => t('Per post gallery'),
      'page' => t('Per page gallery'),
      'field_post' => t('Per field in post gallery'),
      'field_page' => t('Per field in page gallery'),
      'custom' => t('Custom'),
      'none' => t('No gallery'),
    );
    $summary[] = t('Colorbox Gallery: @setting', array(
      '@setting' => $gallery[$settings['colorbox_settings']['colorbox_gallery']],
    ));
    if ($settings['colorbox_settings']['colorbox_gallery'] == 'custom') {
      $summary[] = '&#8594; ' . t('Colorbox Gallery Custom: @setting', array(
        '@setting' => $settings['colorbox_settings']['colorbox_gallery_custom'],
      ));
    }
    $caption = array(
      'auto' => t('Automatic'),
      'title' => t('Title text'),
      'alt' => t('Alt text'),
      'node_title' => t('Content title'),
      'custom' => t('Custom (with tokens)'),
      'none' => t('None'),
    );
    $summary[] = t('Colorbox Caption: @setting', array(
      '@setting' => $caption[$settings['colorbox_settings']['colorbox_caption']],
    ));
    if ($settings['colorbox_settings']['colorbox_caption'] == 'custom') {
      $summary[] = '&#8594; ' . t('Colorbox Caption Custom: @setting', array(
        '@setting' => $settings['colorbox_settings']['colorbox_caption_custom'],
      ));
    }
  }
  return implode('<br />', $summary);
}

/**
 * Implements hook_field_formatter_view().
 */
function picture_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $element = array();

  // Check if the formatter involves a link.
  $image_link = $display['settings']['image_link'];
  if ($image_link == 'content') {
    $uri = entity_uri($entity_type, $entity);
  }
  elseif ($image_link == 'file') {
    $link_file = TRUE;
  }
  elseif ($image_link) {
    if (isset($entity->{$image_link})) {

      // Support for field translations.
      $language = field_language($entity_type, $entity, $field['field_name']);
      $link_field = $entity->{$image_link};
      if (isset($link_field[$language])) {
        $link_values = $link_field[$language];
      }
    }
  }
  $fallback_image_style = '';
  $mappings = picture_mapping_load($display['settings']['picture_group']);
  $breakpoint_styles = picture_get_mapping_breakpoints($mappings, $fallback_image_style);
  if (isset($display['settings']['fallback_image_style']) && !empty($display['settings']['fallback_image_style'])) {
    $fallback_image_style = $display['settings']['fallback_image_style'];
  }

  // Assume regular display.
  $formatter = 'picture_formatter';
  $colorbox_breakpoints = array();
  $colorbox_fallback_image_style = '';

  // Check for colorbox link.
  if (module_exists('colorbox') && $display['settings']['image_link'] == 'colorbox') {
    $formatter = 'picture_formatter_colorbox';
    $mappings = picture_mapping_load($display['settings']['colorbox_settings']['colorbox_group']);
    $colorbox_breakpoints = picture_get_mapping_breakpoints($mappings, $colorbox_fallback_image_style);
  }
  foreach ($items as $delta => $item) {
    if (isset($link_file)) {
      $uri = array(
        'path' => file_create_url($item['uri']),
        'options' => array(),
      );
    }

    // Handle multiple link with image values.
    if (isset($link_values)) {
      if (isset($link_values[$delta]['url'])) {
        $uri = array(
          'path' => $link_values[$delta]['url'],
          'options' => array(
            'attributes' => $link_values[$delta]['attributes'],
          ),
        );

        // Handle query fragment if there is any.
        if (!empty($link_values[$delta]['query'])) {
          $uri['options']['query'] = $link_values[$delta]['query'];
        }
      }
      else {
        unset($uri);
      }
    }
    $element[$delta] = array(
      '#theme' => $formatter,
      '#attached' => array(
        'library' => array(
          array(
            'picture',
            'matchmedia',
          ),
          array(
            'picture',
            'picturefill',
          ),
          array(
            'picture',
            'picture.ajax',
          ),
        ),
      ),
      '#item' => $item,
      '#image_style' => $fallback_image_style,
      '#breakpoints' => $breakpoint_styles,
      '#path' => isset($uri) ? $uri : '',
      '#colorbox_group' => $colorbox_breakpoints,
      '#colorbox_image_style' => $colorbox_fallback_image_style,
    );

    // Add css and js for colorbox.
    if ($formatter == 'picture_formatter_colorbox') {
      $element[$delta]['#attached']['css'][drupal_get_path('module', 'picture') . '/picture_colorbox.css'] = array(
        'type' => 'file',
      );
      $element[$delta]['#attached']['js'][drupal_get_path('module', 'picture') . '/picture_colorbox.js'] = array(
        'type' => 'file',
      );
      if (!variable_get('colorbox_inline', 0)) {
        $element[$delta]['#attached']['js'][drupal_get_path('module', 'colorbox') . '/js/colorbox_inline.js'] = array(
          'type' => 'file',
        );
      }
      $colorbox_settings = $display['settings']['colorbox_settings'];

      // Add the group ID.
      list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
      $entity_id = !empty($id) ? $entity_type . '-' . $id : 'entity-id';

      // If this is a file entity field check for the referencing entity to do
      // the proper grouping.
      if (isset($entity->referencing_entity) && isset($entity->referencing_field)) {

        // Because we don't have the entity type we use some "magic" to get a
        // unique entity identifier.
        $entity_id = spl_object_hash($entity->referencing_entity);
        $colorbox_group_field = $entity->referencing_field;
      }
      else {
        $colorbox_group_field = $field['field_name'];
      }
      switch ($colorbox_settings['colorbox_gallery']) {
        case 'post':
          $gallery_id = 'gallery-' . $entity_id;
          break;
        case 'page':
          $gallery_id = 'gallery-all';
          break;
        case 'field_post':
          $gallery_id = 'gallery-' . $entity_id . '-' . $colorbox_group_field;
          break;
        case 'field_page':
          $gallery_id = 'gallery-' . $colorbox_group_field;
          break;
        case 'custom':
          $gallery_id = $colorbox_settings['colorbox_gallery_custom'];
          break;
        default:
          $gallery_id = '';
      }
      $element[$delta]['#colorbox_group_id'] = $gallery_id;

      // Add the caption.
      $entity_title = entity_label($entity_type, $entity);
      switch ($colorbox_settings['colorbox_caption']) {
        case 'auto':

          // If the title is empty use alt or the entity title in that order.
          if (!empty($item['title'])) {
            $caption = $item['title'];
          }
          elseif (!empty($item['alt'])) {
            $caption = $item['alt'];
          }
          elseif (!empty($entity_title)) {
            $caption = $entity_title;
          }
          else {
            $caption = '';
          }
          break;
        case 'title':
          $caption = $item['title'];
          break;
        case 'alt':
          $caption = $item['alt'];
          break;
        case 'node_title':
          $caption = $entity_title;
          break;
        case 'custom':
          $caption = token_replace($colorbox_settings['colorbox_caption_custom'], array(
            $entity_type => $entity,
            'file' => (object) $item,
          ), array(
            'clear' => TRUE,
          ));
          break;
        default:
          $caption = '';
      }

      // Shorten the caption for the example styles or when caption shortening
      // is active.
      $colorbox_style = variable_get('colorbox_style', 'default');
      $trim_length = variable_get('colorbox_caption_trim_length', 75);
      if ((strpos($colorbox_style, 'colorbox/example') !== FALSE || variable_get('colorbox_caption_trim', 0)) && drupal_strlen($caption) > $trim_length) {
        $caption = drupal_substr($caption, 0, $trim_length - 5) . '...';
      }
      $element[$delta]['#colorbox_caption'] = $caption;
    }
  }
  return $element;
}

/**
 * Theme picture.
 */
function theme_picture_formatter($variables) {
  if (!isset($variables['breakpoints']) || empty($variables['breakpoints'])) {
    return theme('image_formatter', $variables);
  }
  $item = $variables['item'];

  // Do not output an empty 'title' attribute.
  if (isset($item['title']) && drupal_strlen($item['title']) == 0) {
    unset($item['title']);
  }
  $item['style_name'] = $variables['image_style'];
  $item['breakpoints'] = $variables['breakpoints'];
  $item['attributes'] = $variables['attributes'];
  if (!isset($item['path']) && isset($variables['uri'])) {
    $item['path'] = $variables['uri'];
  }
  $output = theme('picture', $item);
  if (is_array($variables['path']) && isset($variables['path']['path'])) {
    $path = $variables['path']['path'];
    $options = isset($variables['path']['options']) ? $variables['path']['options'] : array();
    $options['html'] = TRUE;
    $output = l($output, $path, $options);
  }
  return $output;
}

/**
 * Theme function to add support for colorbox.
 */
function theme_picture_formatter_colorbox($variables) {
  if (!isset($variables['breakpoints']) || empty($variables['breakpoints'])) {
    return theme('image_formatter', $variables);
  }
  $item = $variables['item'];

  // Do not output an empty 'title' attribute.
  if (isset($item['title']) && drupal_strlen($item['title']) == 0) {
    unset($item['title']);
  }
  $item['style_name'] = $variables['image_style'];
  $item['breakpoints'] = $variables['breakpoints'];
  if (!isset($item['path']) && isset($variables['uri'])) {
    $item['path'] = $variables['uri'];
  }
  $output = theme('picture', $item);
  if (isset($variables['colorbox_group'])) {
    $item['breakpoints'] = $variables['colorbox_group'];
    $item['style_name'] = $variables['colorbox_image_style'];
    $id = 'picture-colorbox-' . user_password();
    $colorbox = '<div style="display: none;"><div id="' . $id . '" class="picture-colorbox-container">' . theme('picture', $item) . '</div></div>';
    $options = array(
      'attributes' => array(
        'class' => array(
          'colorbox-inline',
        ),
      ),
      'query' => array(
        'maxWidth' => '80%',
        'maxHeight' => '80%',
        'inline' => 'true',
      ),
      'fragment' => $id,
      'html' => TRUE,
    );
    if (!empty($variables['colorbox_group_id'])) {
      $options['attributes']['rel'] = $variables['colorbox_group_id'];
    }
    if (!empty($variables['colorbox_caption'])) {
      $options['query']['title'] = $variables['colorbox_caption'];
    }

    // Do not load picture automatically.
    $colorbox = str_replace('span data-picture=""', 'span data-picture-lazy="lazy"', $colorbox);
    $output = l($output, current_path(), $options) . $colorbox;
  }
  return $output;
}

/**
 * Returns HTML for a picture.
 *
 * @param $variables
 *   An associative array containing:
 *   - uri: Either the path of the image file (relative to base_path()) or a
 *     full URL.
 *   - width: The width of the image (if known).
 *   - height: The height of the image (if known).
 *   - alt: The alternative text for text-based browsers.
 *   - breakpoints: An array containing breakpoints.
 *   - attributes: An array containing attributes.
 *
 * @ingroup themeable
 */
function theme_picture($variables) {

  // Make sure that width and height are proper values
  // If they exists we'll output them
  // @see http://www.w3.org/community/respimg/2012/06/18/florians-compromise/
  if (variable_get('picture_implementation', PICTURE_IMPLEMENTATION_DEFAULT) !== PICTURE_IMPLEMENTATION_PICTUREFILL2) {
    if (isset($variables['width']) && empty($variables['width'])) {
      unset($variables['width']);
      unset($variables['height']);
    }
    elseif (isset($variables['height']) && empty($variables['height'])) {
      unset($variables['width']);
      unset($variables['height']);
    }
    if (isset($variables['metadata']['width']) && isset($variables['metadata']['height'])) {
      $variables['width'] = $variables['metadata']['width'];
      $variables['height'] = $variables['metadata']['height'];
    }
  }
  else {
    unset($variables['width']);
    unset($variables['height']);
  }
  $sources = array();
  $output = array();

  // Fallback image, output as source with media query.
  $sources[] = array(
    'src' => _picture_image_style_url($variables['style_name'], $variables['uri']),
    'dimensions' => picture_get_image_dimensions($variables, 1),
  );

  // All breakpoints and multipliers.
  foreach ($variables['breakpoints'] as $breakpoint_name => $multipliers) {
    $breakpoint = breakpoints_breakpoint_load_by_fullkey($breakpoint_name);
    if ($breakpoint) {
      $new_sources = array();
      switch (variable_get('picture_implementation', PICTURE_IMPLEMENTATION_DEFAULT)) {
        case PICTURE_IMPLEMENTATION_PICTUREFILL:
        case PICTURE_IMPLEMENTATION_PICTUREFILL2:
        case PICTURE_IMPLEMENTATION_WEBLINC:
          foreach ($multipliers as $multiplier => $image_style) {
            $new_source = $variables;
            $new_source['style_name'] = $image_style;
            $new_source['#media_query'] = $breakpoint->breakpoint;
            $new_source['#multiplier'] = $multiplier;
            $new_sources[] = $new_source;
          }

          // Only one image, use src.
          if (count($new_sources) == 1) {
            foreach ($new_sources as $new_source) {
              $sources[] = array(
                'src' => _picture_image_style_url($new_source['style_name'], $new_source['uri']),
                'dimensions' => picture_get_image_dimensions($new_source, $new_source['#multiplier']),
                'media' => $new_source['#media_query'],
              );
            }
          }
          else {

            // Mutliple images, use srcset.
            $srcset = array();
            foreach ($new_sources as $new_source) {
              $srcset[] = _picture_image_style_url($new_source['style_name'], $new_source['uri']) . ' ' . $new_source['#multiplier'];
            }
            $sources[] = array(
              'srcset' => implode(', ', $srcset),
              'dimensions' => picture_get_image_dimensions($new_sources[0], $new_sources[0]['#multiplier']),
              'media' => $new_source['#media_query'],
            );
          }
          break;
      }
    }
  }
  if (!empty($sources)) {
    $attributes = array();
    foreach (array(
      'alt',
      'title',
    ) as $key) {
      $field = sprintf('field_file_image_%s_text', $key);
      if (isset($variables[$key]) && !empty($variables[$key])) {
        $attributes['data-' . $key] = decode_entities($variables[$key]);
      }
      elseif (isset($variables[$field]) && is_array($variables[$field]) && isset($variables[$field]['und'][0]['safe_value'])) {
        $attributes['data-' . $key] = decode_entities($variables[$field]['und'][0]['safe_value']);
      }
    }

    // Add attributes that are already prefixed by 'data-'
    foreach (array(
      'data-picture-group',
      'data-picture-align',
    ) as $key) {
      if (isset($variables[$key]) && !empty($variables[$key])) {
        $attributes[$key] = $variables[$key];
      }
    }

    // Add additional attributes passed in through the render array.
    if (isset($variables['attributes']) && !empty($variables['attributes'])) {
      $attributes = array_merge($attributes, $variables['attributes']);
    }
    if (variable_get('picture_implementation', PICTURE_IMPLEMENTATION_DEFAULT) === PICTURE_IMPLEMENTATION_PICTUREFILL2) {
      $output[] = '<picture' . drupal_attributes($attributes) . '>';
    }
    else {
      $output[] = '<span data-picture=""' . drupal_attributes($attributes) . '>';
    }

    // Add source tags to the output.
    foreach ($sources as $source) {
      $output[] = theme('picture_source', $source);
    }

    // Output the fallback image.
    if (!empty($variables['uri'])) {
      $variables['path'] = $variables['uri'];
    }
    if (variable_get('picture_implementation', PICTURE_IMPLEMENTATION_DEFAULT) === PICTURE_IMPLEMENTATION_PICTUREFILL2) {
      $output[] = theme('image_style', $variables);
      $output[] = '</picture>';
    }
    else {
      $output[] = '<noscript>' . theme('image_style', $variables) . '</noscript>';
      $output[] = '</span>';
    }
    return implode("\n", $output);
  }
}

/**
 * Generates the media query for multipliers of an image
 *
 * @param $multiplier
 *   A string containing the multiplier for which the media query is for.
 *
 * @param $breakpoint
 *   A string containing the breakpoint media query.
 *
 * @return sting
 *   The sting containing the media query for the multiplier.
 */
function picture_get_multiplier_media_query($multiplier, $breakpoint) {
  $media_query = $breakpoint;
  if ($multiplier != '1x') {
    $multiplier_formatted = str_replace('x', '', $multiplier);
    if (variable_get('picture_implementation', PICTURE_IMPLEMENTATION_DEFAULT) === PICTURE_IMPLEMENTATION_PICTUREFILL2) {
    }
    else {
      $media_query = $breakpoint . ' and (min-device-pixel-ratio: ' . $multiplier_formatted . '), ';
      $media_query .= $breakpoint . ' and (-o-min-device-pixel-ratio: ' . $multiplier_formatted . '), ';
      $media_query .= $breakpoint . ' and (-webkit-min-device-pixel-ratio: ' . $multiplier_formatted . '), ';
      $media_query .= $breakpoint . ' and (min-resolution: ' . $multiplier_formatted . 'dppx)';
    }
  }
  return $media_query;
}

/**
 * Returns HTML for a source tag.
 *
 * @param type $variables
 *   An associative array containing:
 *   - media: The media query to use.
 *   - src: Either the path of the image file (relative to base_path()) or a
 *     full URL.
 *   - dimensions: The width and height of the image (if known).
 *
 * @ingroup themeable
 */
function theme_picture_source($variables) {
  $output = array();

  // Convert width, height to data-width, data-height.
  foreach (array(
    'width',
    'height',
  ) as $key) {
    if (isset($variables['dimensions'][$key])) {
      $variables['dimensions']['data-' . $key] = $variables['dimensions'][$key];
    }
    unset($variables['dimensions'][$key]);
  }
  if (isset($variables['media']) && !empty($variables['media'])) {
    if (isset($variables['srcset']) && !empty($variables['srcset'])) {
      if (variable_get('picture_implementation', PICTURE_IMPLEMENTATION_DEFAULT) === PICTURE_IMPLEMENTATION_PICTUREFILL2) {
        $output[] = '<source media="' . $variables['media'] . '" srcset="' . $variables['srcset'] . '">';
      }
      else {
        $output[] = '<span data-media="' . $variables['media'] . '" data-srcset="' . $variables['srcset'] . '" ' . drupal_attributes($variables['dimensions']) . '></span>';
      }
    }
    else {
      if (variable_get('picture_implementation', PICTURE_IMPLEMENTATION_DEFAULT) === PICTURE_IMPLEMENTATION_PICTUREFILL2) {
        $output[] = '<source media="' . $variables['media'] . '" srcset="' . $variables['src'] . '">';
      }
      else {
        $output[] = '<span data-media="' . $variables['media'] . '" data-src="' . $variables['src'] . '" ' . drupal_attributes($variables['dimensions']) . '></span>';
      }
    }
  }
  else {
    if (variable_get('picture_implementation', PICTURE_IMPLEMENTATION_DEFAULT) === PICTURE_IMPLEMENTATION_PICTUREFILL2) {

      //$output[] = '<source src="' . $variables['src'] . '"></source>';
    }
    else {
      $output[] = '<span data-src="' . $variables['src'] . '" ' . drupal_attributes($variables['dimensions']) . '></span>';
    }
  }
  return implode("\n", $output);
}

/**
 * Determines the dimensions of an image.
 *
 * @param $variables
 *   An associative array containing:
 *   - style_name: The name of the style to be used to alter the original image.
 *   - width: The width of the source image (if known).
 *   - height: The height of the source image (if known).
 * @param $multiplier
 *   Multiplier from the source
 *
 * @return array
 *   Dimensions to be modified - an array with components width and height, in
 *   pixels.
 */
function picture_get_image_dimensions($variables, $multiplier = 1) {

  // Determine the dimensions of the styled image.
  $dimensions = array();
  if (isset($variables['width'])) {
    $dimensions['width'] = $variables['width'];
  }
  if (isset($variables['height'])) {
    $dimensions['height'] = $variables['height'];
  }
  if ($variables['style_name'] == PICTURE_EMPTY_IMAGE) {
    $dimensions = array(
      'width' => 1,
      'height' => 1,
    );
  }
  elseif ($variables['style_name'] == PICTURE_ORIGINAL_IMAGE) {

    // NOOP.
  }
  else {
    image_style_transform_dimensions($variables['style_name'], $dimensions);
    if ($multiplier != 0 && $multiplier != 1) {
      $dimensions['width'] = ceil($dimensions['width'] / $multiplier);
      $dimensions['height'] = ceil($dimensions['height'] / $multiplier);
    }
  }
  return $dimensions;
}

/**
 * Implements hook_filter_info().
 */
function picture_filter_info() {
  $filters = array();
  $filters['picture'] = array(
    'title' => t('Make images responsive with the picture module'),
    'description' => t('Replace img tags with markup that contains media width breakpoints. The appropriate image file size will be chosen.'),
    'process callback' => '_picture_filter_process',
    'tips callback' => '_picture_filter_tips',
    'type' => 'FILTER_TYPE_TRANSFORM_REVERSIBLE',
  );
  return $filters;
}

/**
 * Process callback for inline image filter.
 */
function _picture_filter_process($text, $filter) {

  // Find all img tags with a data-picture-group attribute.
  preg_match_all('/<img.*?data-picture-group=".*?>/i', $text, $images);
  if (!empty($images[0])) {
    foreach ($images[0] as $image) {

      // Create the render array expected by theme_picture_formatter.
      $image_render_array = _picture_filter_prepare_image($image);
      if (!$image_render_array) {
        continue;
      }

      // Get the responsive markup for this image.
      $new_markup = theme('picture_formatter', $image_render_array);

      // Replace the original img tag with the responsive markup.
      $text = str_replace($image, $new_markup, $text);
    }
  }
  return $text;
}

/**
 * Prepares a Render Array for theme_picture_formatter().
 * It is similar to picture_field_formatter_view()
 * with modifications for inline images.
 *
 * @param $image
 *   An img tag
 * @see picture_field_formatter_view()
 */
function _picture_filter_prepare_image($image) {

  // Make sure the closing tag is right.
  $image = str_replace('/>', '>', $image);
  $image = str_replace('>', ' />', $image);
  $image = htmlspecialchars($image);

  // Parse the tag as xml.
  $xml = simplexml_load_string('<image>' . html_entity_decode($image, ENT_QUOTES, "utf-8") . '</image>');
  if (isset($xml->img[0]) && is_object($xml->img[0])) {
    $attributes = array();
    foreach ($xml->img[0]
      ->attributes() as $a => $b) {
      $attributes[$a] = (string) $b;
    }
  }
  $fallback_image_style = '';
  $mappings = picture_mapping_load($attributes['data-picture-group']);
  $breakpoint_styles = picture_get_mapping_breakpoints($mappings, $fallback_image_style);

  // Make sure we have a src attribute.
  if (!isset($attributes['src'])) {
    return FALSE;
  }
  $src = $attributes['src'];

  // Make sure we have map src to uri.
  $uri = picture_image_uri($src);
  if (!$uri) {
    return FALSE;
  }
  $image_info = image_get_info($uri);
  if (!$image_info) {

    // It's not an image.
    return FALSE;
  }
  $picture_groups = variable_get('picture_ckeditor_groups', array());
  $image_render_array = array(
    '#theme' => 'picture_formatter',
    '#item' => array(
      'style_name' => $picture_groups[$attributes['data-picture-group']]['fallback'],
      'uri' => $uri,
      'width' => $image_info['width'],
      'height' => $image_info['height'],
      'data-picture-group' => $attributes['data-picture-group'],
      'data-picture-align' => isset($attributes['data-picture-align']) ? $attributes['data-picture-align'] : '',
      'alt' => isset($attributes['alt']) ? $attributes['alt'] : '',
      'title' => isset($attributes['title']) ? $attributes['title'] : '',
      'filemime' => $image_info['mime_type'],
    ),
    '#image_style' => $picture_groups[$attributes['data-picture-group']]['fallback'],
    '#breakpoints' => $breakpoint_styles,
    '#path' => '',
  );
  return $image_render_array;
}

/**
 * Implements callback_filter_tips().
 */
function _picture_filter_tips($filter, $format, $long = FALSE) {
  return t('Images with a data-picture-group attribute will be responsive, with a file size appropriate for the browser width.');
}

/**
 * Implements hook_page_build().
 *
 * Add the image processing javascript to every page. This allows these scripts
 * to get included in aggregation, which is probably good since there will be
 * pictures needing this javascript on most pages. The library does not get
 * added twice, even if it's attached to multiple fields that are also being
 * displayed with responsive images. Maybe this should check that the
 * page is not an admin theme page?
 */
function picture_page_build(&$page) {
  drupal_add_library('picture', 'matchmedia', TRUE);
  drupal_add_library('picture', 'picturefill', TRUE);
  drupal_add_library('picture', 'picture.ajax', TRUE);

  // Integrate with the WYSIWYG module, and the CKEditor module.
  $picture_groups = picture_get_mapping_options();
  $ckeditor_groups = variable_get('picture_ckeditor_groups', array());
  $groups = array();

  // CKEditor library expects an array of options formatted as
  // ['Display name', 'machine_name'].
  foreach ($ckeditor_groups as $machine_name => $parameters) {
    if (array_key_exists($machine_name, $picture_groups)) {
      if ($parameters['enabled'] == 1) {
        $groups[] = array(
          $picture_groups[$machine_name],
          $machine_name,
        );
      }
    }
  }
  if (!empty($groups)) {
    $groups[] = array(
      'Not Set',
      'not_set',
    );
    drupal_add_js(array(
      'picture' => array(
        'groups' => $groups,
        'label' => variable_get('picture_ckeditor_label', 'Image size (required)'),
      ),
    ), 'setting');
  }
}

/**
 * Helper function to figure out the uri of an image given the
 * image src.
 *
 * @param
 *   Image src starting with http://, https://, or root relative /.
 */
function picture_image_uri($src) {
  foreach (module_implements('picture_image_uri') as $module) {
    $function = $module . '_picture_image_uri';
    if ($uri = $function($src)) {
      $uri = file_stream_wrapper_uri_normalize($uri);
      return urldecode($uri);
    }
  }
  return FALSE;
}

/**
 * Implements hook_picture_image_uri().
 */
function picture_picture_image_uri($src) {
  global $base_path;
  $uri = '';

  // Prepare the src by removing http:// or https://.
  $src = parse_url($src, PHP_URL_PATH);

  // Remove leading or trailing slashes.
  $src = trim($src, '/');

  // List all visible stream wrappers. Make sure they're also local since the
  // getDirectoryPath method exists only for classes that extend
  // DrupalLocalStreamWrapper.
  $local_visible_stream_wrappers = array_intersect_key(file_get_stream_wrappers(STREAM_WRAPPERS_LOCAL), file_get_stream_wrappers(STREAM_WRAPPERS_VISIBLE));
  $needles = array();
  $matches = array();
  foreach ($local_visible_stream_wrappers as $scheme => $data) {
    $class = file_stream_wrapper_get_class($scheme);
    $stream_wrapper = new $class();

    // Trim leading or trailing slashes since the Directory could be root
    // relative.
    $needles[$scheme] = trim($base_path . $stream_wrapper
      ->getDirectoryPath(), '/');

    // Check whether the file stream directory is at the beginning of
    // the image src. Use === since strpos could return false.
    if (!empty($needles[$scheme]) && strpos($src, $needles[$scheme]) === 0) {
      $matches[$scheme] = $needles[$scheme];
    }
  }

  // No file stream wrapper is starting with the image src.
  // So it's not a public file.
  if (empty($matches)) {

    // Check for managed/private file with relative path like 'system/files/...'.
    $src_exploded = explode('/', $src);
    if ($src_exploded[0] == 'system' && $src_exploded[1] == 'files') {

      // Managed/private file recognized.
      // Check for image style derivatives.
      if ($src_exploded[2] == 'styles') {

        // Image style recognized.
        $unwanted_part = 'system/files/styles/' . $src_exploded[3] . '/private/';
        $uri = str_replace($unwanted_part, 'private://', $src);
        $uri = file_stream_wrapper_uri_normalize($uri);
        return urldecode($uri);
      }
      else {

        // No image style recognized; must be an original.
        $unwanted_part = 'system/files/';
        $uri = str_replace($unwanted_part, 'private://', $src);
        $uri = file_stream_wrapper_uri_normalize($uri);
        return urldecode($uri);
      }

      // It's not a managed/private file.
    }
    else {

      // Can't figure out the Drupal uri.
      return FALSE;
    }
  }

  // If one file scheme directory is a subdirectory of another file
  // scheme directory, choose the longer one. This issue is possible with
  // the following scenario:
  // public file dir: /sites/default/files/
  // private file dir: /sites/default/files/private/
  // image src: /sites/default/files/private/the-image.jpg
  // In this example, the intended scheme would be 'private'.
  // Find the length of each matching directory path.
  $lengths = array_map('strlen', $matches);

  // Determine the key of the longest one.
  $the_scheme = array_search(max($lengths), $lengths);

  // Construct the Drupal uri.
  $uri = $the_scheme . '://' . str_replace($matches[$the_scheme], '', $src);
  return $uri;
}

/**
 * Implements hook_wysiwyg_plugin() to modify the CKEditor image dialog for use
 * with the picture module.
 */
function picture_wysiwyg_plugin($editor, $version) {
  if ($editor == 'ckeditor') {
    return array(
      'picture_ckeditor' => array(
        'path' => drupal_get_path('module', 'picture') . '/plugins/',
        'load' => TRUE,
        'extensions' => array(
          'picture_ckeditor' => t('Responsive images with the Picture Module'),
        ),
        'url' => 'http://drupal.org/projects/picture',
      ),
    );
  }
}

/**
 * Implements hook_ckeditor_plugin() to modify the CKEditor image dialog for use
 * with the picture module.
 */
function picture_ckeditor_plugin() {
  return array(
    'picture_ckeditor' => array(
      // Name of the plugin used to write it.
      'name' => 'picture_ckeditor',
      // Description of the plugin - it would be displayed in the plugins management section of profile settings.
      'desc' => t('Support responsive images with the Picture module.'),
      // The full path to the CKEditor plugins directory, with the trailing slash.
      'buttons' => FALSE,
      'path' => drupal_get_path('module', 'picture') . '/plugins/',
      'default' => 't',
    ),
  );
}

/**
 * Wrapper around image_style_url() so we can return an empty image.
 */
function _picture_image_style_url($style_name, $path) {
  if ($style_name == PICTURE_EMPTY_IMAGE) {
    return 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
  }
  if ($style_name == PICTURE_ORIGINAL_IMAGE) {
    return file_create_url($path);
  }
  return image_style_url($style_name, $path);
}

/**
 * Implements hook_wysiwyg_editor_settings_alter().
 */
function picture_wysiwyg_editor_settings_alter(&$settings, $context) {
  if ($context['profile']->editor == 'ckeditor') {
    if (!isset($settings['extraAllowedContent'])) {
      $settings['extraAllowedContent'] = array(
        'img[src,title,alt,style,width,height,class,hspace,vspace,view_mode,format,fid,data-picture-group,data-picture-align]',
      );
    }
    else {

      // @todo: try finding the img entry and add data- attributes if needed.
    }
  }
}

/**
 * Returns a list with the image styles of a mapping configuration.
 *
 * @param object $mappings
 *   The mapping configuration.
 * @param string $fallback_image_style
 *   Reference to access the evaluated fallback image style.
 *
 * @return array
 *   List with the image styles of a mapping configuration.
 *   The array has following structure:
 *   array(
 *     breakpoint_name => array(
 *       multiplier => image_style
 *     )
 *   )
 */
function picture_get_mapping_breakpoints($mappings, &$fallback_image_style = NULL) {
  $breakpoint_styles = array();
  if (is_object($mappings)) {
    foreach ($mappings->mapping as $breakpoint_name => $multipliers) {
      if (!empty($multipliers)) {
        foreach ($multipliers as $multiplier => $image_style) {
          if (!empty($image_style)) {
            if (empty($fallback_image_style)) {
              $fallback_image_style = $image_style;
            }
            if (!isset($breakpoint_styles[$breakpoint_name])) {
              $breakpoint_styles[$breakpoint_name] = array();
            }
            $breakpoint_styles[$breakpoint_name][$multiplier] = $image_style;
          }
        }
      }
    }
  }
  return $breakpoint_styles;
}

/**
 * Helper function to compute the list of possible link types.
 */
function picture_link_types($instance) {
  $link_types = array(
    'content' => t('Content'),
    'file' => t('File'),
  );
  if (module_exists('colorbox')) {
    $link_types['colorbox'] = t('Colorbox');
  }

  // If the link module is installed, also allow any link fields to be used.
  foreach (field_info_fields() as $field_key => $field_info) {
    if ($field_info['type'] == 'link_field') {
      $field_instance = field_info_instance($instance['entity_type'], $field_info['field_name'], $instance['bundle']);
      if ($field_instance) {
        $link_types[$field_key] = "{$field_instance['label']} ({$field_info['field_name']})";
      }
    }
  }
  return $link_types;
}

Functions

Namesort descending Description
picture_ckeditor_plugin Implements hook_ckeditor_plugin() to modify the CKEditor image dialog for use with the picture module.
picture_empty_array Empty picture array.
picture_empty_object Empty picture object.
picture_field_formatter_info Implements hook_field_formatter_info().
picture_field_formatter_settings_form Implements hook_field_formatter_settings_form().
picture_field_formatter_settings_summary Implements hook_field_formatter_settings_summary().
picture_field_formatter_view Implements hook_field_formatter_view().
picture_filter_info Implements hook_filter_info().
picture_get_image_dimensions Determines the dimensions of an image.
picture_get_mapping_breakpoints Returns a list with the image styles of a mapping configuration.
picture_get_mapping_options Returns a list of picture mappings for use in a select list.
picture_get_multiplier_media_query Generates the media query for multipliers of an image
picture_image_uri Helper function to figure out the uri of an image given the image src.
picture_library Implements hook_library().
picture_link_types Helper function to compute the list of possible link types.
picture_mappings_export_access Access callback.
picture_mapping_load Load mappings.
picture_mapping_load_all Load all mappings.
picture_mapping_save Save mappings.
picture_mapping_validate Validate mappings.
picture_menu Implements hook_menu().
picture_page_build Implements hook_page_build().
picture_permission Implements hook_permission().
picture_picture_image_uri Implements hook_picture_image_uri().
picture_theme Implements hook_theme().
picture_wysiwyg_editor_settings_alter Implements hook_wysiwyg_editor_settings_alter().
picture_wysiwyg_plugin Implements hook_wysiwyg_plugin() to modify the CKEditor image dialog for use with the picture module.
theme_picture Returns HTML for a picture.
theme_picture_formatter Theme picture.
theme_picture_formatter_colorbox Theme function to add support for colorbox.
theme_picture_source Returns HTML for a source tag.
_picture_filter_prepare_image Prepares a Render Array for theme_picture_formatter(). It is similar to picture_field_formatter_view() with modifications for inline images.
_picture_filter_process Process callback for inline image filter.
_picture_filter_tips Implements callback_filter_tips().
_picture_image_style_url Wrapper around image_style_url() so we can return an empty image.

Constants