6

So, let's say I have a large version of an image that gets displayed only as a thumbnail. Would it be possible to avoid having a separate file for the thumbnail by using a progressive jpeg, stopping its loading when a certain number of scans have been reached, and continue loading only when the user chooses to open it in full?

If so, how can the loading of the image be controlled?

Thanks in advance.

4

2 回答 2

7

有2种方法:

1.客户端重

先决条件

  • 图像服务器必须支持范围 HTTP 标头
    • 例如。Range: bytes=0-1024表示您只请求前 1024 个字节
  • 必须提前知道要请求多少字节
    • 如果您从服务器端推送该值,您可以说是全尺寸的 1/8
    • 所以客户端应该知道确切的字节数
  • 如果Range无效或不支持,则服务器将返回整个图像,这是一个很好的自然“后备”

跨域请求:如果 html 和图像在不同的域中

  • Access-Control-Allow-Headers: "range"必须设置

图像服务器上的Apache.htaccess示例:

<IfModule mod_headers.c>
    Header set Access-Control-Allow-Origin "*"
    Header set Access-Control-Allow-Headers: "range"
</IfModule>
  • 如果浏览器由于CROS设置不当导致请求失败,代码回退设置data-src属性到src属性

概述

  1. AJAX请求 图像
    • 将请求的Range标头设置为AJAX您想要返回的字节数
    • 将其设置mimeType为纯文本(以便我们以后可以对其进行 base64 编码)
  2. Base64 编码数据并将其设置为图像的 src 属性 ( <img src="data:image/jpeg;base64,...">)
    • 当心较大的图像,这对客户端来说可能很重
  3. 如果设置 src 属性由于任何原因(例如不正确的CROS设置)失败,则回退到将data-src属性设置为src属性

编码

这是建立在 gaetanoM 的精彩回答的基础上的:Get Image using jQuery.ajax() and decode it to base64

// for each img, which has data-src and data-bytes attributes
$('img[data-src][data-bytes]').each(function(i,e){
	$.ajax({
	    url: $(e).data('src'), // url of image
	    type: 'GET',
	    headers: {
	    	'Range':'bytes=0-'+$(e).data('bytes') // Range header, eg. Range: bytes=0-1024
	    },
	    mimeType: "text/plain; charset=x-user-defined"
	}).done(function( data, textStatus, jqXHR ) {
	    $(e).attr('src', 'data:image/jpeg;base64,' + base64encode(data)); // on success we set the base64 encoded data to the image's src attribute
	}).always(function(){
	    // if setting the src failed for whatever reason, we fall back to set the data-src attribute to src attribute
	    if(!$(e).attr('src'))
	        $(e).attr('src', $(e).data('src'));
	});
});

function base64encode(str) {
    var CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    var out = "", i = 0, len = str.length, c1, c2, c3;
    while (i < len) {
        c1 = str.charCodeAt(i++) & 0xff;
        if (i == len) {
            out += CHARS.charAt(c1 >> 2);
            out += CHARS.charAt((c1 & 0x3) << 4);
            out += "==";
            break;
        }
        c2 = str.charCodeAt(i++);
        if (i == len) {
            out += CHARS.charAt(c1 >> 2);
            out += CHARS.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
            out += CHARS.charAt((c2 & 0xF) << 2);
            out += "=";
            break;
        }
        c3 = str.charCodeAt(i++);
        out += CHARS.charAt(c1 >> 2);
        out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
        out += CHARS.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
        out += CHARS.charAt(c3 & 0x3F);
    }
    return out;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- total filesize is 35 933 bytes -->
<img data-src="http://shoepimper.com/doklist.com-logo.jpg" data-bytes="1900">
<img data-src="http://shoepimper.com/doklist.com-logo.jpg" data-bytes="2500">
<img data-src="http://shoepimper.com/doklist.com-logo.jpg" data-bytes="5600">

<!-- if data-bytes are erroneous the server will return the whole image -->
<img data-src="http://shoepimper.com/doklist.com-logo.jpg" data-bytes="error">
<!-- if CROS fails, then it falls back to set the data-src attribute to the src attribute -->
<img data-src="https://i.stack.imgur.com/QOPRf.jpg" data-bytes="error">

2.服务器端重

详细说明 ProgressiveMonkey 的评论,您可以使用 php 或任何其他服务器端编程语言轻松修剪图像数据。

概述

服务器端代码

<?php
    $div = isset($_GET['div']) && intval($_GET['div'])>1 ? intval($_GET['div']) : 1; // what fraction of the image shall we return
    $img = 'doklist.com-logo.jpg';
    $size = round(filesize($img) / $div); // calculating the size in bytes what we return

    // setting the headers
    header("Content-Type: image/jpeg");
    header("Content-Length: $size");

    $fp = fopen($img, 'r');
        echo fread($fp, $size); // returning the necessary amount of bytes
    fclose($fp);
?>

例子

请在此处查看我们网站徽标之一的示例 ( Doklist.com )

请随意使用此 url 的div参数(另请注意,我的测试服务器可能无法很好地处理增加的流量): http ://shoepimper.com/progressive-thumb.php?div=14

仅读取文件大小的1/24并将其作为整个图像返回: <img src="http://shoepimper.com/progressive-thumb.php?div=24"> 在此处输入图像描述

读取图像的1/14<img src="http://shoepimper.com/progressive-thumb.php?div=14"> 在此处输入图像描述

读取图像的1/6<img src="http://shoepimper.com/progressive-thumb.php?div=6"> 在此处输入图像描述

读取整个图像(1/1) <img src="http://shoepimper.com/progressive-thumb.php?div=1"> 在此处输入图像描述

如果您需要帮助来确定图像是否是渐进式编码的,请使用:http ://codepen.io/sergejmueller/full/GJKwv

如果您无法直接访问图像,那么您应该使用代理,这意味着代码本身的结构并没有真正改变,您只是“打开”一个远程文件。

于 2017-05-04T22:34:35.807 回答
1

这是可能的。您只需要修改解码器即可。

只要您有权访问数据流,您就可以控制加载。

于 2015-11-06T00:50:28.043 回答