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!
- 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
3 Answers
Reset to default 5Here 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.