嵌入式图像预览加载图像速度更快

本文中介绍的嵌入式图像预览(eip)技术允许我们使用渐进式jpeg,ajax和http范围请求在延迟加载期间加载预览图像,而无需传输其他数据。
低质量图像预览(lqip)和基于svg的变体sqip是延迟图像加载的两种主要技术。两者的共同之处在于您首先生成低质量的预览图像。这将显示模糊,然后由原始图像替换。如果您可以向网站访问者呈现预览图像而无需加载其他数据,该怎么办?
根据规范,主要使用延迟加载的jpeg文件可以以这样的方式存储包含在其中的数据,即首先显示粗略的然后显示详细的图像内容。在加载(基线模式)期间,不是从上到下构建图像,而是可以非常快速地显示模糊图像,其逐渐变得更清晰和更锐利(渐进模式)。
基线模式(大预览)渐进模式(大预览)除了由更快速显示的外观提供的更好的用户体验之外,渐进式jpeg通常也小于其基线编码的对应物。对于大于10 kb的文件,根据雅虎开发团队的stoyan stefanov,使用渐进模式时,图像较小的概率为94%。
如果您的网站包含许多jpeg,您会注意到即使是渐进式jpeg也会依次加载。这是因为现代浏览器只允许六个同时连接到域。因此,单独的渐进式jpeg不是为用户提供最快的页面印象的解决方案。在最坏的情况下,浏览器将在开始加载下一个图像之前完全加载图像。
这里提出的想法现在只是从服务器加载渐进式jpeg的这么多字节,您可以快速获得图像内容的印象。稍后,在我们定义的时间(例如,当加载了当前视口中的所有预览图像时),应该加载图像的其余部分,而不再请求已经为预览请求的部分。
使用两个请求加载渐进式jpeg(大预览)遗憾的是,您无法告诉img属性中的标记应该在什么时间加载多少图像。但是,使用ajax,只要提供映像的服务器支持http范围请求,这是可能的。
使用http范围请求,客户端可以在http请求标头中通知服务器,所请求文件的哪些字节将包含在http响应中。每个较大的服务器(apache,iis,nginx)都支持此功能,主要用于视频播放。如果用户跳到视频的末尾,则在用户最终看到所需部分之前加载完整视频效率不高。因此,服务器仅请求用户请求的时间周围的视频数据,以便用户可以尽可能快地观看视频。
1.创建渐进式jpeg渐进式jpeg由几个所谓的扫描段组成,每个扫描段包含最终图像的一部分。第一次扫描仅非常粗略地显示图像,而文件后面的图像会向已加载的数据添加越来越多的详细信息,最终形成最终外观。
单个扫描的确切外观由生成jpeg的程序决定。在类似的命令行程序cjpeg依据从mozjpeg项目,甚至可以定义哪些数据这些扫描包含。但是,这需要更深入的知识,这超出了本文的范围。为此,我想参考我的文章“?finally understanding jpg?”,它讲授了jpeg压缩的基础知识。在wizard.txt中解释了必须在扫描脚本中传递给程序的确切参数mozjpeg项目。在我看来,默认情况下mozjpeg使用的扫描脚本(七次扫描)的参数是快速渐进结构和文件大小之间的良好折衷,因此可以采用。
要将我们的初始jpeg转换为渐进式jpeg,我们使用jpegtranmozjpeg项目。这是一个对现有jpeg进行无损更改的工具。windows和linux的预编译版本可在此处获得:https://mozjpeg.codelove.de/binaries.html。如果您出于安全考虑而喜欢安全地玩,那么最好自己构建它们。
从命令行我们现在创建渐进式jpeg:
$ jpegtran input.jpg > progressive.jpg复制
我们想要构建渐进式jpeg的事实由jpegtran假定,并且不需要明确指定。图像数据不会以任何方式更改。仅改变文件内的图像数据的排列。
理想情况下,应从jpeg中删除与图像外观无关的元数据(例如exif,iptc或xmp数据),因为如果元数据解码器位于图像内容之前,则相应的段只能被元数据解码器读取。由于这个原因我们无法将它们移动到文件中的图像数据后面,因此它们已经与预览图像一起传送并相应地放大第一个请求。使用命令行程序,exiftool您可以轻松删除这些元数据:
$ exiftool -all= progressive.jpg 复制
如果您不想使用命令行工具,还可以使用在线压缩服务compress-or-die.com生成不带元数据的渐进式jpeg。
2.确定第一个http范围请求必须加载预览图像的字节偏移量jpeg文件被分成不同的段,每个段包含不同的组件(图像数据,诸如iptc,exif和xmp之类的元数据,嵌入的颜色配置文件,量化表等)。这些段中的每一个都以由十六进制ff字节引入的标记开始。接下来是一个表示段类型的字节。例如,d8完成标记到soi标记ff d8(图像开始),每个jpeg文件开始使用。
每次扫描开始都由sos标记(扫描开始,十六进制ff da)标记。由于sos标记后面的数据是熵编码的(jpeg使用霍夫曼编码),因此ff c4在sos段之前还有另一个具有解码所需的霍夫曼表(dht,十六进制)的段。因此,渐进式jpeg文件中的我们感兴趣的区域由交替的霍夫曼表/扫描数据段组成。因此,如果我们想要显示图像的第一次非常粗略的扫描,我们必须ff c4从服务器请求直到第二次出现dht段(十六进制)的所有字节。
jpeg文件的结构(大预览)在php中,我们可以使用以下代码来读取所有扫描到数组所需的字节数:
<?php $img = progressive.jpg; $jpgdata = file_get_contents($img); $positions = []; $offset = 0; while ($pos = strpos($jpgdata, \xff\xc4, $offset)) { $positions[] = $pos+2; $offset = $pos+2; }
我们必须将2的值添加到找到的位置,因为浏览器只在遇到新标记时才会呈现预览图像的最后一行(如前所述,它包含两个字节)。
由于我们对此示例中的第一个预览图像感兴趣,因此我们找到了正确的位置$positions[1],我们必须通过http范围请求来请求该文件。要请求具有更好分辨率的图像,我们可以使用数组中的稍后位置,例如$positions[3]。
3.创建前端javascript代码首先,我们定义一个img标记,我们给出刚刚评估的字节位置:
<img data-src=progressive.jpg data-bytes=<?= $positions[1] ?>>复制
与延迟加载库的情况一样,我们不src直接定义属性,因此浏览器在解析html代码时不会立即开始从服务器请求图像。
使用以下javascript代码,我们现在加载预览图像:
var $img = document.queryselector(img[data-src]); var url = window.url || window.webkiturl; var xhr = new xmlhttprequest(); xhr.onload = function(){ if (this.status === 206){ $img.src_part = this.response; $img.src = url.createobjecturl(this.response); } } xhr.open('get', $img.getattribute('data-src')); xhr.setrequestheader(range, bytes=0- + $img.getattribute('data-bytes')); xhr.responsetype = 'blob'; xhr.send();复制
此代码创建一个ajax请求,该请求告诉http范围标头中的服务器将文件从开头返回到data-bytes…中指定的位置,而不是更多。如果服务器理解http范围请求,它将以blob的形式返回http-206响应(http 206 =部分内容)中的二进制图像数据,我们可以使用它生成浏览器内部url?createobjecturl。我们将此网址用作src我们的img代码。因此我们加载了预览图像。
我们将blob另外存储在属性中的dom对象上src_part,因为我们将立即需要这些数据。
在开发人员控制台的网络选项卡中,您可以检查我们是否未加载完整的图像,但只是一小部分。此外,应显示blob url的加载,大小为0字节。
加载预览图像时的网络控制台(大预览)由于我们已经加载了原始文件的jpeg标题,因此预览图像的大小正确。因此,根据应用,我们可以省略img标签的高度和宽度。
替代方案:内嵌加载预览图像出于性能原因,还可以将预览图像的数据直接作为数据uri传输到html源代码中。这节省了传输http头的开销,但base64编码使图像数据增加了三分之一。如果您使用gzip或brotli等内容编码提供html代码,则会对此进行相对化处理,但您仍应将数据uri用于小型预览图像。
更重要的是,预览图像立即可用,并且在构建页面时用户没有明显的延迟。
首先,我们必须创建数据uri,然后我们在im
上一个:我想做网站之企业建站时犯哪些错误?
下一个:暂无
桦川网站建设,桦川做网站,桦川网站设计