防止渐进式 jpeg 完全加载
Prevent progressive jpeg from loading completely
所以,假设我有一张大图,只显示为缩略图。是否可以通过使用渐进式 jpeg 来避免缩略图有一个单独的文件,当达到一定数量的扫描时停止加载,并且仅当用户选择完全打开时才继续加载?
如果可以,如何控制图片的加载?
提前致谢。
这是可能的。您只需要修改解码器即可。
只要您有权访问数据流,就可以控制加载。
有两种方法:
1。 Client-side重
先决条件
- 图像服务器必须支持 range HTTP header
- 例如。
Range: bytes=0-1024
表示您只请求前 1024 个字节
- 你必须提前知道你要请求多少字节
- 如果从服务器端推送该值,则可以说是全尺寸的 1/8
- 所以客户端应该知道确切的字节数
- 如果
Range
无效或者不支持,那么服务器会return整张图片,自然好"fallback"
跨域请求:如果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
属性
概览
- 使用
AJAX
请求请求图像
- 将
Range
header of AJAX
请求设置为您想要返回的字节数
- 将
mimeType
设置为明文(以便我们稍后可以对其进行 base64 编码)
- Base64 编码数据并将其设置为图像的 src 属性 (
<img src="data:image/jpeg;base64,...">
)
- 注意较大的图像,这对客户端来说可能会很沉重
- 如果由于某种原因设置 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。 Server-side重
详细说明 ProgressiveMonkey 的评论,您可以使用 php 或任何其他服务器端编程语言轻松 trim 图像数据。
概览
- 服务器端: trim基于url参数的图像数据
- 如果您想知道第一次扫描的确切位置,请阅读这个精彩的答案:How many bytes are needed for a complete thumbnail of a progressive JPEG?
- 客户端:根据需要更改url参数
Server-side代码
<?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 并将其作为整个图像 return 处理:
<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
如果您不能直接访问图像,那么您应该使用代理,这意味着代码本身的结构并没有真正改变,您只是 "fopening" 一个远程文件。
所以,假设我有一张大图,只显示为缩略图。是否可以通过使用渐进式 jpeg 来避免缩略图有一个单独的文件,当达到一定数量的扫描时停止加载,并且仅当用户选择完全打开时才继续加载?
如果可以,如何控制图片的加载?
提前致谢。
这是可能的。您只需要修改解码器即可。
只要您有权访问数据流,就可以控制加载。
有两种方法:
1。 Client-side重
先决条件
- 图像服务器必须支持 range HTTP header
- 例如。
Range: bytes=0-1024
表示您只请求前 1024 个字节
- 例如。
- 你必须提前知道你要请求多少字节
- 如果从服务器端推送该值,则可以说是全尺寸的 1/8
- 所以客户端应该知道确切的字节数
- 如果
Range
无效或者不支持,那么服务器会return整张图片,自然好"fallback"
跨域请求:如果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
属性
概览
- 使用
AJAX
请求请求图像- 将
Range
header ofAJAX
请求设置为您想要返回的字节数 - 将
mimeType
设置为明文(以便我们稍后可以对其进行 base64 编码)
- 将
- Base64 编码数据并将其设置为图像的 src 属性 (
<img src="data:image/jpeg;base64,...">
)- 注意较大的图像,这对客户端来说可能会很沉重
- 如果由于某种原因设置 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。 Server-side重
详细说明 ProgressiveMonkey 的评论,您可以使用 php 或任何其他服务器端编程语言轻松 trim 图像数据。
概览
- 服务器端: trim基于url参数的图像数据
- 如果您想知道第一次扫描的确切位置,请阅读这个精彩的答案:How many bytes are needed for a complete thumbnail of a progressive JPEG?
- 客户端:根据需要更改url参数
Server-side代码
<?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 并将其作为整个图像 return 处理:
<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
如果您不能直接访问图像,那么您应该使用代理,这意味着代码本身的结构并没有真正改变,您只是 "fopening" 一个远程文件。