Will this module always output a picture tag? Reading about the responsive images implementation (like http://www.smashingmagazine.com/2014/05/14/responsive-images-done-right-...) often a picture tag with sources is not necessary, even considered harmful. I just cannot find how to do that with this module. It appeared to me that the “images with sizes” could be the way to do this, but than I get a picture-tag too.

So is it possible to get only this:

<img sizes="(min-width: 36em) 33.3vw, 100vw" srcset="large.jpg  1024w, medium.jpg 640w, small.jpg  320w" />
CommentFileSizeAuthor
#11 2450863-11-img-srcset.patch3.95 KBjnettik
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Honza Pobořil’s picture

Title: Is it possible to only use img with srcset? » Option to only use img with srcset
Version: 7.x-2.9 » 7.x-2.x-dev
Component: Documentation » Code
Category: Support request » Feature request

This module currently support only
tag, so this is feature request.

Honza Pobořil’s picture

More motivation:

  1. Syntax like <img src="biggest picture for old browsers" srcset="responzive pictures" sizes=""> don't need any JS polyfill necessary, it just download the biggest picture specified in src, so it shows "some" picture with JS disabled or broken.
  2. It is shorter, so less bandwidth consuming
  3. ... (some idea?)
giupenni’s picture

Priority: Normal » Major

I agree with rolfmeijer, the module is bad. For the majority of the images on the web,
is the wrong solution.

http://blog.cloudfour.com/dont-use-picture-most-of-the-time/

To summarize:

  • The picture specification contains more than just the
    element. Think of it as the responsive images specification.
  • For most responsive images, you shouldn’t use the
    element. You should use srcset and/or sizes.
  • The way to know when to use the
    element is based on the use case you’re trying to solve.
  • If you’re solving for the art direction use case, use the
    element. Anything else, you should stick to srcset and sizes.
  • Getting this right early—before we have thousands of pages using
    incorrectly—is critical for the future of the web.
giupenni’s picture

attiks’s picture

#2 it depends if you mind double downloads or not
#3 i think "bad" is a bit exaggerated, when we first build this module, sizes was not even available

The way forward similar to D8:

- output img whenever possible
- polyfill can already be disabled

Patches are welcomed

rolfmeijer’s picture

attiks, if I understand the D8-issue correctly the preferred way is to make this an option, not something that is done automatically, based on some conditions.

Can you please explain what the “Image with sizes” options does? Why is this an option besides the picture mappings. Because to me that sounds like a proper solution to use for the img-only option. Does that make sense or do I misunderstand the functionality of “Image with sizes”?

attiks’s picture

#6 There's no consensus for D8 yet, I think it should be automatic, otherwise site builders have to decide what to use, which will make their job harder.

I added "image with sizes" to the D7 version because we needed it, but the output is still using a picture tag to avoid double downloads.

I think it is doable to output just an img tag when we can, it will probably be a config option to not break older sites, I know some people add css on the picture tag. Initially the option will be disabled by default, but eventually it will be enabled by default.

attiks’s picture

Status: Active » Needs work

Since a lot of people are involved, can somebody write a patch. I added an option to use src as fallback, so this sounds like a next logical step.

The current output has to remain unchanged, but feel free to add an option to the admin settings to output only an image tag.

supermoos’s picture

This isn't a patch, but put it in your theme's template.php file, and it will output the correct modern markup (https://html.spec.whatwg.org/multipage/embedded-content.html#viewport-ba...), just choose the formatter "Image with sizes", input your sizes string like: "(max-width: 767px) 50vw, 19vw" and check the image styles you want to be outputted in the srcset.

If you use manualcrop you will need this patch: https://www.drupal.org/node/1556244#comment-9244007
This is because the image style needs to define a 'dimensions callback' in order for this function to work properly.

This is a first attempt, so improvements can probably made, and just as note; I removed the width, height from the outputted <img />-tag markup.


/**
 * Theme pictue sizes formatter.
 */
function YOURTHEME_picture_sizes_formatter($variables)
{
    $variables['image_style'] = $variables['fallback_image_style'];
    $variables['breakpoints'][BREAKPOINTS_SOURCE_TYPE_MODULE . '.picture.empty_srcset']['1x'] = array(
        'mapping_type' => 'sizes',
        'sizes' => $variables['sizes'],
        'sizes_image_styles' => $variables['image_styles'],
    );
    return spec_image_srcset($variables);
}


function spec_image_srcset(array $variables)
{
    // Make sure we have an array.
    $attributes = isset($variables['attributes']) ? $variables['attributes'] : array();

    // Sizes is mandatory, so make sure the key is set, default is 100vw.
    if (!isset($variables['sizes']) || empty($variables['sizes'])) {
        $attributes['sizes'] = '100vw';
    } else {
        $attributes['sizes'] = $variables["sizes"];
    }


    if (isset($variables["item"]) && !empty($variables["item"])) {
        $image_info = $variables["item"];
        if (isset($image_info['uri']) && !empty($image_info['uri'])) {
            // TODO: remove when https://www.drupal.org/node/1342504 is fixed.
            if (strpos($image_info['uri'], 'data:') === 0) {
                $attributes['src'] = $image_info['uri'];
            } else {
                $attributes['src'] = file_create_url($image_info['uri']);
            }
        }
        if (isset($variables["image_styles"]) && !empty($variables["image_styles"])) {
            $srcset = array();
            foreach ($variables["image_styles"] as $image_style_name) {
                $dimensions = array(
                    'width' => $image_info['width'],
                    'height' => $image_info['height'],
                );

                $dimensions_clone = $dimensions;
                picture_get_image_dimensions($image_style_name, $dimensions_clone);
                $srcset[$dimensions_clone['width']] = _picture_image_style_url($image_style_name, $image_info['uri'], $image_info['timestamp']) . ' ' . $dimensions_clone['width'] . 'w';
            }
            $attributes['srcset'] = implode(', ', $srcset);
        }

        foreach (array('alt', 'title', 'sizes') as $key) {
            if (isset($image_info[$key])) {
                $attributes[$key] = $image_info[$key];
            }
        }
        if (isset($variables['path']) && !empty($variables['path'])) {
            return l('<img ' . drupal_attributes($attributes) . ' />', $variables['path']['path'], array('html' => TRUE) + $variables['path']['options']);
        }
        return '<img ' . drupal_attributes($attributes) . ' />';
    }
}
attiks’s picture

#9 Nice work, it would be great if you can roll a patch that:

- adds a new option to the settings screen, picture_admin_settings
- changes the output if the option is enabled to output only an image tag when using 'image with sizes'

jnettik’s picture

Status: Needs work » Needs review
FileSize
3.95 KB

Here's a patch that adds a new global setting, and provides logic in theme_picture_sizes_formatter() to use either theme_picture_formatter() which is how it currently works or theme_image_srcset() depending on that new setting.

I did have a question about the duplicate download issue. I'm mostly seeing posts that are a couple years old already. Is there a description of the issue that's current to what browsers currently have implemented? I appreciate any background on this you can provide.

jnettik’s picture

Never mind about the duplicate download resources. I just found some and understand the issue better now.

attiks’s picture

Status: Needs review » Fixed

Thanks all, committed

  • attiks committed a89e397 on 7.x-2.x authored by jnettik
    Issue #2450863 by jnettik, Bobík, giupenni, rolfmeijer, supermoos:...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

phm’s picture

Status: Closed (fixed) » Fixed

I'm using the "image with sizes" formatter.

When I tick the setting to only use img elements, I get an empty 'w' descriptor for one of the image styles ("w" and "600w"):

<img src="http://path/to/files/styles/work_thumbnail/public/Image_recto.jpg" srcset="http://path/to/files/styles/work_thumbnail__2x/public/Image.jpg 600w, http://path/to/files/styles/work_thumbnail/public/Image.jpg w" alt="" title="" sizes="(max-device-pixel-ratio: 1) 300px, (max-resolution: 96dpi) 300px, (min-device-pixel-ratio: 1.5) 600px, (min-resolution: 192dpi) 600px">

Whereas with picture, I get the correct w descriptors ("300w" and "600w"):

<source srcset="http://path/to/files/styles/work_thumbnail/public/Image.jpg?itok=8B02-ATC&amp;timestamp=1442695856 300w, http://path/to/files/styles/work_thumbnail__2x/public/Image.jpg?itok=4FkQJwAW&amp;timestamp=1442695856 600w" sizes="(max-device-pixel-ratio: 1) 300px, (max-resolution: 96dpi) 300px, (min-device-pixel-ratio: 1.5) 600px, (min-resolution: 192dpi) 600px">

phm’s picture

Status: Fixed » Needs work
Wongjn’s picture

I have encountered another problem with the img with srcset output option. When selecting more than two image styles, the output srcset attribute will output only the last two styles selected in the list and with the incorrect w descriptor as comment #17.

Edit: It seems this is because all but one of the image styles have not been generated, and thus have no image information attached to them. These non-existed images all have the same empty w key so they override each other which is why there is only one srcset image with an empty w.

Edit 2: I've managed to fix this by adapting some code from a comment on this page. I don't know how to post patches so here is a diff instead:

---
 sites/all/modules/picture/picture.module | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/sites/all/modules/picture/picture.module b/sites/all/modules/picture/picture.module
index 5ae419a..2139941 100644
--- a/sites/all/modules/picture/picture.module
+++ b/sites/all/modules/picture/picture.module
@@ -1229,6 +1229,21 @@ function theme_picture_sizes_formatter($variables) {
       $image_style_uri = image_style_path($image_style, $image['uri']);
       $image_style_info = image_get_info($image_style_uri);
 
+      // If empty image info, assume the file does not exist, so we shall go
+      // through the steps to create it.
+      if (!$image_style_info) {
+        // load the style definition - empty array returned if image_style_load
+        // fails
+        $image_style_definition = image_style_load($image_style);
+
+        if ($image_style_definition) {
+          // finally, we can create the styled derivative file
+          image_style_create_derivative($image_style_definition, $image['uri'], image_style_path($image_style, $image['uri']));
+        }
+
+        $image_style_info = image_get_info($image_style_uri);
+      }
+
       $variables['srcset'][] = array(
         'uri' => $image_style_uri,
         'width' => $image_style_info['width'] . 'w',
-- 
1.9.5.msysgit.0
Wongjn’s picture

I'm not sure how to post a patch so here's an updated theme function instead that fixes some issues with image srcsetoutput.

/**
 * Theme pictue sizes formatter.
 */
function theme_picture_sizes_formatter($variables) {
  $output_method = variable_get('picture_img_sizes_output_method', 'picture_element');
  $variables['image_style'] = $variables['fallback_image_style'];

  if ($output_method == 'picture_element') {
    $variables['breakpoints'][BREAKPOINTS_SOURCE_TYPE_MODULE . '.picture.empty_srcset']['1x'] = array(
      'mapping_type' => 'sizes',
      'sizes' => $variables['sizes'],
      'sizes_image_styles' => $variables['image_styles'],
      'lazyload' => !empty($variables['lazyload']),
      'lazyload_aspect_ratio' => !empty($variables['lazyload_aspect_ratio']),
    );
    return theme('picture_formatter', $variables);
  }

  if ($output_method == 'img_srcset') {
    $image = $variables['item'];

    // Map image attributes
    $variables['uri'] = image_style_path($variables['fallback_image_style'], $image['uri']);

    if (!empty($image['alt'])) {
      $variables['alt'] = $image['alt'];
    }
    if (!empty($image['title'])) {
      $variables['title'] = $image['title'];
    }

    // Set up image source options
    $variables['srcset'] = array();
    foreach($variables['image_styles'] as $image_style) {
      $image_style_uri = image_style_path($image_style, $image['uri']);
      $image_style_info = image_get_info($image_style_uri);

      // If empty image info, assume the file does not exist, so we shall go
      // through the steps to create it.
      if (!$image_style_info) {
        if ($image_style != PICTURE_EMPTY_IMAGE) {
          // load the style definition
          $image_style_definition = image_style_load($image_style);

          if ($image_style_definition) {
            // finally, we can create the styled derivative file
            image_style_create_derivative($image_style_definition, $image['uri'], image_style_path($image_style, $image['uri']));

            $image_style_info = image_get_info($image_style_uri);
          }
        } else {
          $image_style_uri = _picture_image_style_url($image_style, $image['uri']);
          // Cannot have 0w descriptor as invalid
          $image_style_info['width'] = 1; 
        }
      }

      if ($image_style_info) {
        $variables['srcset'][] = array(
          'uri' => $image_style_uri,
          'width' => $image_style_info['width'] . 'w',
        );
      }
    }
    return theme('image_srcset', $variables);
  }
}
attiks’s picture

Assigned: Unassigned » Jelle_S
jnettik’s picture

Is the code in #20 aimed to fix the issues in #17? If not can you elaborate on what issues you saw the code fixes?

For the issue in #17, it would be helpful to know what effects are in the image styles you're using. I'm not sure how to create that issue locally.

attiks’s picture

Keep in mind that inDrupal 7 there are image effects not returning width/height of image, so that might be the reason

jnettik’s picture

@attiks I tested this with various combinations of image styles in D7 core. Desaturate doesn't have any dimensions defined, but I'm still getting a value for the w selector. It's falling back to the size of the original image. image_get_info($image_style_uri) shouldn't be trying to pull dimensions from the image style, but from the image itself.

attiks’s picture

#24 All effects should implement dimensions passthrough or dimensions callback see https://api.drupal.org/api/drupal/modules!image!image.api.php/function/h...

Getting dimensions from images means the image has to exists and getting the info out of the image is sloooow. Best to test with a simple resize or crop

phm’s picture

In my image styles I used only the "scale" effect, set to 300px width and 600px width. So I would assume that should return an image width.

Wongjn’s picture

Wongjn’s picture

I was in a bit of a rush when I commented before (#20) so here's an explanation on what my modifications do.

I added in this bit of code:

      // If empty image info, assume the file does not exist, so we shall go
      // through the steps to create it.
      if (!$image_style_info) {
        if ($image_style != PICTURE_EMPTY_IMAGE) {
          // load the style definition
          $image_style_definition = image_style_load($image_style);


          if ($image_style_definition) {
            // finally, we can create the styled derivative file
            image_style_create_derivative($image_style_definition, $image['uri'], image_style_path($image_style, $image['uri']));


            $image_style_info = image_get_info($image_style_uri);
          }
        } else {
          $image_style_uri = _picture_image_style_url($image_style, $image['uri']);
          // Cannot have 0w descriptor as invalid
          $image_style_info['width'] = 1; 
        }
      }

This bit of code tries to ensure that an image derivative is generated, because during the code run of the img with srcset option, the images are not requested and their derivatives are not generated. This then causes all the derivatives (apart from one for some reason) to have an empty width.

In theme_img_srcset, it uses the widths as the key to array, so all other image derivatives override each other into one w descriptor, meaning only two image URLs get output by that function – one with a valid w descriptor and one with just the w letter and nothing else. This solves #17.

I also programed in the instance where the Empty Image option is used, and since it's width can't be 0 (for a true empty image), I manually set its width as 1px.

Jelle_S’s picture

I just noticed. Apparently we committed a patch without fully checking it. The fault is at http://cgit.drupalcode.org/picture/tree/picture.module#n1229

Following lines:

$image_style_uri = image_style_path($image_style, $image['uri']);
$image_style_info = image_get_info($image_style_uri);

$variables['srcset'][] = array(
  'uri' => $image_style_uri,
  'width' => $image_style_info['width'] . 'w',
);

should be changed to something like:

$image_style_uri = image_style_path($image_style, $image['uri']);
// Get the dimensions of the original image.
$image_info = image_get_info($image['uri']);
// Let the the image style transform the dimensions. This way we avoid the performance cost of actually having to generate the derivative.
// The image style can transform the dimensions without the derivative having to exist.
$dimensions = picture_get_image_dimensions($image_style, $image_info);

$variables['srcset'][] = array(
  'uri' => $image_style_uri,
  'width' => $dimensions['width'] . 'w',
);

I'll fix it asap.

Jelle_S’s picture

Status: Needs work » Fixed

Fixed in latest dev.

  • Jelle_S committed 3862ee3 on 7.x-2.x
    Issue #2450863 by jnettik, Bobík, rolfmeijer, giupenni, supermoos:...
rolfmeijer’s picture

Wow, this is really brilliant. I just implemented the last commited dev version and it works great.

Just one tiny remark, on the page the help-text for the "Image with sizes" output method says you get double downloads. As far as I know, this is only true if you use Picturefill. (See f.i. https://css-tricks.com/responsive-images-youre-just-changing-resolutions...).

Suggestion for the text:
"srcset on Image tag" creates the correct markup, however in combination with Polyfill you get double downloads.

Thank you all very much anyway!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.