如何从 srcset 中确定最高分辨率图像

how to determine highest resolution image from srcset

假设我有一个图像

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


现在这也可以是

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


此外,(无效 HTML)

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


现在我如何提取具有最高分辨率图像的 URL。
我想拆分 srcset 然后提取大小,但问题是大小可以是 1200w 格式或 2x 格式或两者都可以,我不知道如何区分这是否是 1200w 格式还是 2x 格式,即使我确实知道是什么,我如何比较它们以确定最大尺寸。

我希望我能展示我已经尝试过的东西,但我没有想到如何做到这一点!

嗯,首先你的 HTML 代码是无效的,因为你不能为 srcset 混合 xw 描述符。选择一个,但不能同时选择两个。

1) 除非您全部下载它们,否则您无法知道哪个图像更大,当然您可以 - 当支持服务器端时 - 执行 HEAD 请求对于每个图像并检查 Content-Length header 属性。这并不容易,你得到的只是以字节为单位的图像大小,而不是它的尺寸,但它是一个很好的近似值。大致是这样的:

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"));
        });
    }
});

您可以获得简单地拆分 srcset 属性并忽略大小部分的 URL(我相信对正则表达式有更多了解的人可以做得更好):

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

调用可以并行进行,或者 - 在 IMO 中更容易 - 使用 queues 和 $(document).queue() jQuery 方法顺序调用。

这不能总是完成(可能是因为服务器不接受 HEAD 或由于压缩 and/or 宽高比图像尺寸太相似)那么你必须 解析 srcset 属性。

2) 让我们先看看 概念验证 (读作:它不完整也没有效率)你可以做什么像素密度描述符 x:用白色 space .split(/ /) 分割,然后选择最大的一个。

// 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;
    }
}

宽度描述符 w 的情况有所不同,因为它与 sizes 相关,那么您首先需要确定应用的是哪一个。它有点复杂,但使用 window.matchMedia() 很容易做到(同样,它不是完整的代码,而是概念的说明性证明):

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

for (var descriptor of sizes.split(/,/)) {
    // Love this from https://whosebug.com/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;
}

现在您已经有了所需的尺寸(检查它的单位并适当地转换它,例如 this post)并且您已经完成了将它与从 srcset.[=34= 中提取的宽度描述符一起使用的操作]

请注意,除非下载,否则您不知道哪个图像更大。您可以假设更高的像素密度 x 或更高的宽度描述符 w(但它 必须 是根据 sizes 属性内容计算的,更大的屏幕使用更大的图像)会给你更大的。当然这是一个假设,在某些情况下它可能会失败。要确定必须使用哪一个,只需:

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

只需...将这些示例放在一起,处理遗漏的角落情况、基本错误处理和浏览器特定问题,您就完成了...

我需要对生成的相关 wordpress 图片执行相同的操作 srcset

Wordpress 创建 srcset 的方式是先出现较小的图像,然后不断增加,直到它在 srcset 中获得最大的图像。

wordpress生成的示例图片代码:

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

此外,在某些情况下,当图像太小时,wordpress 根本不会创建 srcset 属性。

所以,这就是我所做的:(将代码中的 my_image_class_to_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);

});

我是Javascript/jQuery的新手,所以如果我走了更长的路,请原谅。 ;)

欢迎对代码进行任何添加/更新。

这是我使用的:

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");
}