最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - how to determine highest resolution image from srcset - Stack Overflow

programmeradmin1浏览0评论

Say i have an image as

<img srcset="large.jpg 1400w, medium.jpg 700w, small.jpg 400w"
     sizes="(min-width: 700px) 700px, 100vw"
     alt="A woman reading">


Now this can also be in a format like

<img srcset="large.jpg 2x, medium.jpg 1.3x, small.jpg 0.8x"
     sizes="(min-width: 700px) 700px, 100vw"
     alt="A woman reading">


Also, (Not a valid HTML)

<img srcset="large.jpg 1400w, medium.jpg 1.3x, small.jpg 0.8x"
     sizes="(min-width: 700px) 700px, 100vw"
     alt="A woman reading">


Now how do i extract URL that has the highest resolution image.
I thought of splitting the srcset and then extracting the size but the problem is that sizes can be in 1200w format or in 2x format or in both of them and i don't know how to distinguish whether this is the 1200w format or 2x format and even if i do find out what's what, how do i pare them for determining the biggest size.

I wish i could show what i've tried but there is nothing ing to my head about how to do this!

Say i have an image as

<img srcset="large.jpg 1400w, medium.jpg 700w, small.jpg 400w"
     sizes="(min-width: 700px) 700px, 100vw"
     alt="A woman reading">


Now this can also be in a format like

<img srcset="large.jpg 2x, medium.jpg 1.3x, small.jpg 0.8x"
     sizes="(min-width: 700px) 700px, 100vw"
     alt="A woman reading">


Also, (Not a valid HTML)

<img srcset="large.jpg 1400w, medium.jpg 1.3x, small.jpg 0.8x"
     sizes="(min-width: 700px) 700px, 100vw"
     alt="A woman reading">


Now how do i extract URL that has the highest resolution image.
I thought of splitting the srcset and then extracting the size but the problem is that sizes can be in 1200w format or in 2x format or in both of them and i don't know how to distinguish whether this is the 1200w format or 2x format and even if i do find out what's what, how do i pare them for determining the biggest size.

I wish i could show what i've tried but there is nothing ing to my head about how to do this!

Share edited Apr 11, 2016 at 12:21 Tushar Shukla asked Apr 11, 2016 at 7:01 Tushar ShuklaTushar Shukla 6,6352 gold badges32 silver badges46 bronze badges 5
  • This seems like an XY problem. Why do you need this? – John Dvorak Commented Apr 11, 2016 at 7:08
  • Also, why can't you assume it's the first item in the list? – John Dvorak Commented Apr 11, 2016 at 7:08
  • @JanDvorak XY problem?? I've to inject a script on user's page and then show him images available on the page separately in a popup. Now i can use SRC simply but it would give me the default image however i want to get the best picture available. – Tushar Shukla Commented Apr 11, 2016 at 7:10
  • @JanDvorak Is it necessary that the first one would be the biggest one? – Tushar Shukla Commented Apr 11, 2016 at 7:11
  • 3 @JanDvorak whether it's an XY problem isn't relevant, as long as the question is clear. – MaxArt Commented Apr 11, 2016 at 7:47
Add a ment  | 

3 Answers 3

Reset to default 5

Here is what I use :

static getHighestResImg(element) {
  if (element.getAttribute("srcset")) {
    return element
      .getAttribute("srcset")
      .split(",")
      .reduce(
        (acc, item) => {
          let [url, width] = item.trim().split(" ");
          width = parseInt(width);
          if (width > acc.width) return { width, url };
          return acc;
        },
        { width: 0, url: "" }
      ).url;
  }

  return element.getAttribute("src");
}

Well, first of all your HTML code is invalid because you can not mix x and w descriptors for srcset. Pick one but not both.

1) You can't know which image is bigger unless you download them all, of course you may - when supported server side - perform an HEAD request for each image and check Content-Length header property. It's not easy and what you get is just image size in bytes, not its dimensions but it's a good approximation. Roughly something like this:

var sizes = [];

// Peform this for each UR...
$.ajax({
    type: "HEAD",
    url: imageUrl,
    success: function(data, textStatus, request) {
        sizes.push({
            url: imageUrl,
            size: parseInt(request.getResponseHeader("Content-Length"));
        });
    }
});

You can obtain URLs simply splitting srcset attribute and ignoring size part (I'm sure someone with better knowledge about regex can do something better):

var urls = srcset.replace(/\s+[0-9]+(\.[0-9]+)?[wx]/g, "").split(/,/); 

Calls may be done in parallel or - more easily IMO - sequentially using queues and $(document).queue() jQuery method.

This can't be always done (maybe because server doesn't accept HEAD or image sizes are too similar because of pression and/or aspect ratios) then you have to parse srcset attribute.

2) Let's first see a proof of concept (read as: it's not plete nor efficient) of what you may do for pixel density descriptor x: split with over white space .split(/ /) and then pick biggest one.

// Read value from tag...this is just for testing
var srcset = "small.jpg 0.8x, large.jpg 1.5x, medium.jpg 1.3x";

var biggestImage = "";
var highestPixelDensity = 1;

for (var descriptor of srcset.split(/,/)) {
    var parts = descriptor.trim().split(/ /);

    // Here we check only for pixel density, see later for
    // width descriptor but code is straightforward
    var pixelDensity = parseFloat(parts[1].substring(-1));
    if (pixelDensity > highestPixelDensity) {
        biggestImage = parts[0];
        highestPixelDensity = pixelDensity;
    }
}

Things are different for width descriptor w because it relates to sizes then you first need to determine which one is applied. It's little bit more convoluted but it's easy to do with window.matchMedia() (again it's not plete code but an illustrative proof of concept):

// Read this from tag...
var sizes = "(min-width: 800px) 700px, (min-width: 700px) 300px";

for (var descriptor of sizes.split(/,/)) {
    // Love this from https://stackoverflow./a/651646/1207195
    var imageSize = descriptor.split(/[, ]+/).pop();

    // You still need to handle last item special case (where there is not media query).
    var mediaQuery = descriptor.substring(-imageSize.length);

    // You can stop with first matched media query, you have your required imageSize
    var isMatch = window.matchMedia(mediaQuery).matches;
}

Now you have required size (check its unit and convert it appropriately, for example this post) and you're done to use it with width descriptor extracted from srcset.

Note that you don't know which image is bigger unless you download it. What you can assume is that higher pixel density x or higher width descriptor w (but it must be calculated in relation to sizes attribute content, bigger screen uses bigger image) will give you the bigger one. Of course it's an assumption then it may fail in some cases. To determine which one must be used is simply:

var isPixelDensity = srcset.trim().substr(-1) === "x";

Just...put those samples together, handle missing corners cases, basic error handling and browser specific issues and you're done...

I needed to do the same for wordpress images generated and relevant srcset

Wordpress creates the srcset in a way that the smaller image es first and then it keeps on increasing until it gets the biggest image in srcset.

Sample image code generated by wordpress:

<img width="300" height="221" src="http://www.example./wp-content/uploads/2017/01/Sharon-Ron-Chip-300x221.jpg" class="vc_single_image-img attachment-medium" alt="" srcset="http://www.example./wp-content/uploads/2017/01/Sharon-Ron-Chip-300x221.jpg 300w, http://www.example./wp-content/uploads/2017/01/Sharon-Ron-Chip-768x566.jpg 768w, http://www.example./wp-content/uploads/2017/01/Sharon-Ron-Chip-1024x755.jpg 1024w" sizes="(max-width: 300px) 100vw, 300px">

also, in some cases when the image is too small, then wordpress does not create srcset attribute at all.

So, this is what i did: (CHANGE my_image_class_to_target in the code to your required target class)

jQuery('img.my_image_class_to_target').each(function () {
    var mysrcset = jQuery(this).attr('srcset');
    if (typeof mysrcset !== 'undefined'){ //checking if the srcset attribute is defined
        lastsrcset = mysrcset.split(',');
        lastsrc = lastsrcset[(lastsrcset.length - 1)];
        lastpuresrc = lastsrc.split(' ');
        mysrc = lastpuresrc[1];

    } else { //when srcset is not defined in case of small images
    var mysrcset = jQuery(this).attr('src');
        mysrc = mysrcset;
    }

    // display or use src of biggest image src
    console.log(mysrc);

});

I am new to Javascript/jQuery, so please forgive if i have taken a longer route. ;)

Any additions/ updates to code are wele.

发布评论

评论列表(0)

  1. 暂无评论