2024-11-18

Web 图像:完美(自动)调整大小和转换

web 图像:完美(自动)调整大小和转换

几乎每个前端开发人员都知道,我们需要在不影响质量的情况下向用户提供尽可能小的图像。我们都知道如何实现这一目标。但这是一件没人喜欢做的苦差事。同样从商业角度来看,这需要时间,而时间就是金钱。所以,“足够好”就够了。

让我分享一下我们如何改进和自动化完美图像交付,而不会给开发人员带来更多工作。

通常是如何完成的

也许不是你,但有很多人——可能是我们大多数人。

您以 2 倍预期尺寸导出 png 图片,以满足高密度屏幕的需求,并将其用于 Web 图像:完美(自动)调整大小和转换 标签。如果您愿意多花 30 秒(或更长时间),您可以做得更好:将其转换为 webp 并将两个版本放入 元素中,让浏览器选择最好的一个(好吧,不是最好的,只是最新支持且浏览器最喜欢的格式)。

这就是“足够好”,而且通常确实如此。

但这并不完美。新的 ipad 很大,可以使用 2.5 倍甚至 3 倍的图像。另一方面,标准的企业 lenovo thinkpad 不需要额外的细节,1× 图像就完美了。

老实说,这一切对于手工工作来说都很好。没有人可以在一张照片上花费 15 分钟。

自动化至完美

对于我的完美主义大脑来说,“足够好”并不是这句话所说的那样。此外,我们的一些客户处于竞争激烈的领域,因此我们开始研究选择。没过多久。我们已经知道浏览器会发送 http 标头来指示它们支持的图像格式。

我们需要的是找出 元素可以加载图像基于给定屏幕的像素密度。这是服务器端渲染很难做到的事情,并且由于多种原因,通过 javascript 调整 src 是不可能的。

有了这个,我们就拥有了所需的一切:

  • 服务器可以提供的格式
  • 前端开发者请求的图片尺寸
  • 显示屏的像素密度

过程

以下是我们如何自动化图像优化过程:

  1. 接受任何图片上传

    我们让开发者和管理员上传并保存他们想要的任何图片(当然开发者需要更加小心)。我们的系统可以处理任何事情 – 甚至是直接来自 dslr 相机的 250 mb jpeg,我们成功地对其进行了转换和调整大小,然后当我们看到日志时放声大笑。

  2. 自动转换和压缩

上传图片后,我们的系统会自动:

  • 将其转换为多种格式:pngwebpavif
  • 使用 90% 质量 设置压缩每个版本。

为什么是90%?因为最后 10% 的质量往往会导致收益大幅递减。您可以节省大量存储空间和带宽,而且视觉质量没有任何明显差异。

  1. 生成多个分辨率

    对于每个图像,我们根据像素密度乘数生成多个尺寸:

  • 1.5×
  • 这可确保具有高分辨率屏幕的设备获得清晰的图像,而其他设备则接收适当大小的图像。

    为了面向未来,我们只需添加或更改数字,一切都会自动处理(我们还没有制作 vr / ar 内容,但我怀疑这就是它会派上用场的技术)。

  1. 动态图像服务

    在我们的 html 模板中,我们指定所需的图像尺寸(宽度或高度)。然后我们的服务器端代码:

  • 检查优化图像是否存在。
  • 如果没有,请将它们排队等待处理。
  • 使用像素密度的 srcset 生成适当的 元素。

    浏览器会根据设备的功能自动选择最佳图像。

结果如下所示:

<picture>
  <source srcset="/upload/2024/03/11/tn-w200-frantisek.webp 1x,
                   /upload/2024/03/11/tn-w300-frantisek.webp 1.5x,
                   /upload/2024/03/11/tn-w400-frantisek.webp 2x,
                   /upload/2024/03/11/tn-w600-frantisek.webp 3x">
  @@##@@
</picture>
登录后复制

处理大图像

如果我们作为开发人员避免完美地调整图片大小和转换图片,我们就不能指望普通管理员或客户能够做到这一点。因此,我们让人们上传他们想要的内容,然后我们对其进行处理(良好的用户体验和客户关系)。

最初,我们没想到调整大小会如此频繁,因此我们几次完全终止了演示服务器。所以我们开发了这种方法:

  • 我们在专用于图像处理的独立低端 vps 上构建了一个简单的 api 服务。
  • 我们的制作服务器将图像和所需的格式/尺寸发送到此服务。
  • 处理后的图像被返回并存储以供服务。

结果

  • 用户很高兴:图像加载速度快,并且在任何设备上看起来都很棒。
  • 管理员很高兴:他们不必担心在上传之前调整图像大小或优化图像。
  • 开发人员很高兴:该过程是自动化的,不需要额外的工作。
  • 服务器很高兴:减少了服务图片的带宽消耗和 cpu 负载。

我知道我们可以使用任何公共商业服务来调整图片大小,但说实话,这是一个下午的工作(意思 – 更便宜),我们已经控制了所有方面。

我们是否将其商业化发布?

我们对此解决方案非常满意,因此我们正在考虑完善此调整大小和转换服务并使其可供您使用。这样的服务有兴趣吗?让我知道。也许我们可以削减很多。

对于开发者,由开发者 – 在这一点上可能是一个模因,但在这种情况下是残酷的事实。

代码(简化)

我无法分享调整大小的方面,但我可以向您展示选择和 创建。我们使用 php 工作,这就是我们的工作方式。

生成 元素

function generatepictureelement($imagepath, $width = null, $height = null, $alt = '') {
    $multipliers = [1, 1.5, 2, 2.5, 3];
    $srcset = [];
    foreach ($multipliers as $multiplier) {
        $resizedwidth = $width ? intval($width * $multiplier) : null;
        $resizedheight = $height ? intval($height * $multiplier) : null;
        $resizedimagepath = getresizedimagepath($imagepath, $resizedwidth, $resizedheight);
        if ($resizedimagepath) {
            $srcset[] = $resizedimagepath . ' ' . $multiplier . 'x';
        }
    }

    $srcsetattribute = implode(', ', $srcset);
    $originalimagepath = getoriginalimagepath($imagepath);

    return "
    <picture>
        <source srcset="$srcsetattribute">
        @@##@@
    </picture>
    ";
}
function getresizedimagepath($imagepath, $width = null, $height = null) {
    $formats = ['avif', 'webp', 'jpg', 'png', 'gif'];

    // determine the directory and filename
    $pathinfo = pathinfo($imagepath);
    $dir = $pathinfo['dirname'];
    $filename = $pathinfo['filename'];
    $ext = $pathinfo['extension'];

    // decide which formats to check based on browser support
    if (supportsavif()) {
        $preferredformats = ['avif', 'webp', 'jpg', 'png', 'gif'];
    } elseif (supportswebp()) {
        $preferredformats = ['webp', 'jpg', 'png', 'gif'];
    } else {
        $preferredformats = ['jpg', 'png', 'gif'];
    }

    // loop through preferred formats to find the smallest suitable image
    foreach ($preferredformats as $format) {
        $resizedimagename = "{$filename}-w{$width}-h{$height}.{$format}";
        $resizedimagepath = "{$dir}/{$resizedimagename}";

        if (file_exists($resizedimagepath)) {
            // resized image exists, return its path
            return $resizedimagepath;
        }
    }

    // resized image doesn't exist, queue it for processing
    queueimageforprocessing($imagepath, $width, $height, $preferredformats);

    // return original image path as a fallback
    return $imagepath;
}
function supportswebp() {
    return isset($_server['http_accept']) && strpos($_server['http_accept'], 'image/webp') !== false;
}

function supportsavif() {
    return isset($_server['http_accept']) && strpos($_server['http_accept'], 'image/avif') !== false;
}
登录后复制

我们使用自定义模板系统,其中 html 与 php 混合(我知道这并不常见,但它最适合我们的需求)。

<div class="Image">
    <?php echo generatePictureElement('/path/to/image.png', 500, alt: 'Image alt description'); ?>
</div>
登录后复制

这段代码展示了一个逻辑。我们实际上做的是我们有一个文件及其变体的数据库,因此我们使用数组和对象而不是路径。但是,正如我所说,这完美地展示了我们所做工作的逻辑。

正如你所看到的,如果前端开发人员编写了这段代码或 video poster 标签,谁会关心花费的时间。

让我们指出问题

此方法的构建不会在现实世界中引起任何问题。但它有两个需要改进的地方,我迫不及待地想确定(再次,只是出于完美主义者的角度)。

  1. 双重排队

    在前端首次加载该图像后,它会排队等待调整大小。如果网站流量大的话,其实可以排队两次。在现实世界中使用 – 没问题;所以它处理两次。这种情况在高流量网站上一年只发生两次。

  2. 大图初始显示

    如果管理员上传大图片,则需要 5-10 分钟来调整大小和转换,因为这是在计划任务中进行的。同时,大图片也显示在他们的网页上。在实际使用中 – 通常只有管理员才能看到它,因为新内容在用户访问之前通常需要一些时间。在高流量网站上,我们将此计时器缩短至 1 分钟,因此这不是问题。

存储注意事项

您可能会指出,现在我们有各种尺寸和格式的多个图像,这可能会占用大量存储空间。如果您的网站充满了图片和画廊,并且您需要每个图片和画廊的缩略图和详细图像,是的,它将使用大量存储空间。

但磁盘空间是当今最便宜的组件。性能和用户体验方面的好处通常远远超过成本。这样,您就降低了 cpu 和整个基础设施的负载。

旁注 – 为什么关心基础设施?其他人正在处理这个问题,对吗?这是我经常听到的。简单的事实是,这不是真的。如果托管公司由于负载增加而没有更多客户而必须添加硬件以获得更高的带宽,他们将无法维持下去,并会很乐意将这些成本转嫁给服务器租用者。

我们的实际结果和经验

在 google search console 中,core web vitals 比以往任何时候都更加环保,加载时间通常要短得多,并且访问者会话时间更长(几个百分点,但我会接受!)。开发人员或管理员不需要额外的工作 – 一切都很顺利。

我强烈建议每个开发者都使用这样的东西。它为我们做了很多事情,而我们实际上可能会忘记这个东西在后台存在并完成它的工作。事实上,我写这篇文章的时间比设置和完善所有系统的时间还要长。

结论

通过自动化图像优化,我们实现了:

  • 针对每个设备量身定制的完美图像交付。
  • 改进了页面加载时间和用户体验。
  • 减少开发人员的手动工作。

如果您厌倦了图像优化的繁琐工作,请考虑自动化该过程。这对所有参与者来说都是双赢的。

你的图像是否使用了一些系统性的解决方案?

还是手动转换它们?

您尝试过 avif 吗?它们对较大图像有惊人的好处。

"$alt"Web 图像:完美(自动)调整大小和转换

以上就是Web 图像:完美(自动)调整大小和转换的详细内容,更多请关注php中文网其它相关文章!

https://www.php.cn/faq/1101837.html

发表回复

Your email address will not be published. Required fields are marked *