*/ /** * Implements hook_init(). */ function adaptive_image_init() { // According to the documentation of hook_init() it should not be used to // load JS or CSS. The CSS case has been moved to the info file. But the JS is // here by intention, as we want it inline to prevent wait time while loading // the script // No need for drupal behaviours, jquery compatibility wrapper nor ready event $js = "document.cookie = 'adaptive_image=' + Math.max(screen.width, screen.height) + '; path=/';"; drupal_add_js($js, // First-come, first-served array( 'type' => 'inline', 'scope' => 'header', 'group' => JS_LIBRARY, 'every_page' => TRUE, 'weight' => -500, ) ); } /** * Implements hook_menu(). */ function adaptive_image_menu() { $items = array(); // Add image style generation paths adaptive URLs. if (module_exists('image')) { // Generate and deliver image derivatives of public files. $directory_path = file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath(); $items[$directory_path . '/styles/%image_style/adaptive-image'] = array( 'title' => 'Generate image style', 'page callback' => 'adaptive_image_style_deliver', 'page arguments' => array(count(explode('/', $directory_path)) + 1), 'access callback' => TRUE, 'type' => MENU_CALLBACK, 'file' => 'adaptive_image.image.inc', ); // Generate and deliver image derivatives of private files. $items['system/files/styles/%image_style/adaptive-image'] = array( 'title' => 'Generate adaptive image style', 'page callback' => 'adaptive_image_style_deliver', 'page arguments' => array(3), 'access callback' => TRUE, 'type' => MENU_CALLBACK, 'file' => 'adaptive_image.image.inc', ); } return $items; } /** * Implements hook_image_effect_info(). */ function adaptive_image_image_effect_info() { $effects = array(); $effects['adaptive_image'] = array( 'label' => t('Adaptive'), 'help' => t('Adaptive image scale according to client resolution.'), 'effect callback' => 'image_scale_effect', 'dimensions callback' => 'image_scale_dimensions', 'form callback' => 'adaptive_image_scale_form', 'summary theme' => 'adaptive_image_scale_summary', ); return $effects; } /** * Form structure for the image scale form. * * Note that this is not a complete form, it only contains the portion of the * form for configuring the scale options. Therefore it does not not need to * include metadata about the effect, nor a submit button. * * @param $data * The current configuration for this scale effect. */ function adaptive_image_scale_form($data) { $form['resolutions'] = array( '#type' => 'textfield', '#title' => t('Resolutions'), '#default_value' => isset($data['resolutions']) ? $data['resolutions'] : '1382, 992, 768, 480', '#required' => TRUE, '#description' => t('The resolution break-points to use (screen widths, in pixels).'), ); $form['mobile_first'] = array( '#type' => 'checkbox', '#title' => t('Mobile first'), '#default_value' => isset($data['mobile_first']) ? $data['mobile_first'] : TRUE, '#description' => t("Check this to send the smallest version when the resolution can not be determined."), ); $resolutions = explode(',', str_replace(' ', '', $form['resolutions']['#default_value'])); $resolution = adaptive_image_resolution($resolutions); // Provide needed defaults $form['height'] = array('#type' => 'hidden','#default_value' => NULL); $form['width'] = array('#type' => 'hidden','#default_value' => $resolution); $form['upscale'] = array('#type' => 'hidden','#default_value' => NULL); return $form; } /** * Implements hook_theme(). */ function adaptive_image_theme() { return array( 'adaptive_image_scale_summary' => array( 'variables' => array('data' => NULL), ), ); } /** * Returns HTML for a summary of an image scale effect. * * @param $variables * An associative array containing: * - data: The current configuration for this scale effect. * * @ingroup themeable */ function theme_adaptive_image_scale_summary($variables) { $data = $variables['data']; if ($data['resolutions']) { return check_plain($data['resolutions']); } } /** * Implements template_preprocess_image(). * * Adds a class to adaptive images for max-width. */ function adaptive_image_preprocess_image(&$variables) { global $base_url; if (isset($variables['style_name'])) { // Get image style settings $style = image_style_load($variables['style_name']); // Check if style contains the adaptive image effect if ($style && adaptive_image_contains_effect($style)) { $settings = adaptive_image_effect_settings($style); $resolutions = explode(',', $settings['resolutions']); $resolution = adaptive_image_resolution($resolutions); // Only construct direct path if not private if (!strpos($variables['path'], '/system/') && is_numeric($resolution)) { $path_parts = pathinfo($variables['path']); $derivative_uri = $path_parts['dirname'] . '/' . $resolution . '/' . $path_parts['basename']; } if (isset($derivative_uri) && file_exists(str_replace($base_url, '.', $derivative_uri))) { // Deliver existing path to bypass menu callback $variables['path'] = $derivative_uri; } else { // Reconstruct the image path to %/%style_name/adaptive-image/% to // trigger image generation or file access check $variables['path'] = str_replace('styles/' . $variables['style_name'], 'styles/' . $variables['style_name'] . '/adaptive-image', $variables['path']); } // Add class for styling $variables['attributes']['class'] = 'adaptive-image'; // Remove fixed image dimensions unset($variables['height']); unset($variables['width']); } } } /** * Check for adaptive image effect from style */ function adaptive_image_contains_effect($style) { foreach ($style['effects'] as $effect) { if ($effect['name'] == 'adaptive_image') { return TRUE; } } return FALSE; } /** * Get adaptive image effect from style settings */ function adaptive_image_effect_settings($style) { $settings = array(); foreach ($style['effects'] as $effect) { if ($effect['name'] == 'adaptive_image') { $settings = $effect['data']; } } return $settings; } /** * Determine current resolution */ function adaptive_image_resolution($resolutions) { $resolution = ''; /* Check to see if a valid cookie exists */ if (count($resolutions) && isset($_COOKIE['adaptive_image'])) { if (is_numeric($_COOKIE['adaptive_image'])) { $client_width = (int) $_COOKIE['adaptive_image']; // store the cookie value in a variable /* the client width in the cookie is valid, now fit that number into the correct resolution break point */ rsort($resolutions); // make sure the supplied break-points are in reverse size order $resolution = $resolutions[0]; // by default it's the largest supported break-point foreach ($resolutions as $break_point) { // filter down if ($client_width <= $break_point) { $resolution = $break_point; } } } else { setcookie("adaptive_image", "", time() -1); // delete the mangled cookie } } return $resolution; }