Javascript GIF(重新)压缩的概念验证
Javascript proof-of-concept of GIF (re)compression
我的维基百科程序 Precomp can be used to further compress already compressed file formats like GIF, PNG, PDF, ZIP and more. Roughly summarized, it does this by decompressing the compressed streams, recompressing them and storing the differences between the expected compressed stream and the actual compressed stream. As an example, this rotating earth picture 从 1429 KB 压缩到 755 KB。过程是无损的,所以可以恢复原GIF文件。
GIF 文件格式的算法可以相对容易地分离和实现,所以我在考虑 JavaScript 中的概念验证实现。这将导致网络服务器发送一个压缩版本的 GIF 文件(.pcf 结尾,本质上是一个 bzip2 压缩文件
GIF 图像内容)和客户端解压缩数据,重新压缩为 GIF 并显示它。需要完成以下事情:
- 网站作者必须使用标准版本的 Precomp 压缩他的 GIF 文件,并将这些文件而不是 GIF 文件与客户端重新压缩的 JavaScript 一起提供。
- 客户端会解压 bzip2 压缩文件,这可以使用 one of the existing bzip2 Javascript implementations.
来完成
- 客户端会将图片内容重新压缩成原始GIF文件。
该过程是带宽与客户端 CPU 使用率的交易。
现在我的问题如下:
- 加载不同文件并将其 "converting" 为 GIF 的过程是否存在任何一般性问题?
- 您建议在客户端完成之前显示什么(图像占位符)?
- 我必须做什么才能确保缓存 .pcf 文件?如果不缓存,带宽节省就没有用了。
- 有没有办法在 JavaScript 停用时显示原始 GIF,但在 JavaScript 激活时避免加载 GIF?
- 我可以为用户提供一种配置行为的方法吗?例如。在移动设备上,有些人可能会避开带宽,但其他人可能希望减少 CPU 使用率。
- 是否可以按预期显示隔行扫描的 GIF(从粗略版本到最终图像)?这将需要在重新压缩的不同阶段多次更新图像内容。
让我们首先回答您的具体问题。下面的代码示例。
问答
- Are there any general problems with the process of loading a different file and "converting" it to GIF?
主要问题是复杂化。您正在有效地编写一个浏览器插件,例如 JPEG2000 的插件。
如果您正在编写真正的浏览器插件,每个主要浏览器的做法都不同,并且偶尔会更改插件格式,因此您必须积极维护它们。
如果你写的是JS库,那么编写和维护起来会更容易,但是会没有特权,会受到cross original restriction.
等限制
- What would you recommend to display before the client side finishes (image placeholder)?
取决于您的格式可以提供什么。
如果您及早对图像尺寸和小缩略图进行编码,则可以很早地显示准确的占位符。
毕竟这是你的格式。
- What do I have to do to make sure the .pcf file is cached? Bandwidth savings were useless if doesn't get cached.
与其他文件没有什么不同。
在服务器端配置Expires
and Cache-Control
header,它们将被缓存。
Manifest
and prefetch
也可以用
- Is there a way to display the original GIF if JavaScript is deactivated, but avoid loading the GIF if JavaScript is activated?
这很棘手。当 JavaScript 被禁用时,您只能 replace elements,而不是属性。
这意味着您无法在指向 .pcf 文件的某处创建图像,并在 JS 不可用时要求浏览器重写 src 属性。
我认为不支持 JS 的最佳解决方案是使用 document.write
输出图像,使用 noscript
作为后备:
<noscript>
<img src=demo.gif width=90>
</noscript><script>
loadPcf("demo.pcf","width=90")
</script>
(某些库或框架可能会让您考虑 <img src=demo.gif data-pcf=demo.pcf>
。
这对你不起作用,因为浏览器 will preload 'demo.gif' 在你的脚本启动之前,会导致额外的数据传输。)
另外,浏览器插件不受 "disable JS" 设置的影响,因此如果您制作插件,则无需担心。
- Can I give the users a way to configure the behaviour? E.g. on mobile devices, some might avoid bandwidth, but others might want less CPU usage.
也许吧。您可以编写用户界面并将首选项存储在 cookie 或 localStorage 中。
然后您可以检测偏好并在服务器代码(如果是 cookie)或客户端代码中切换逻辑。
如果你在做插件,所有的浏览器都提供可靠的偏好机制。
问题是,每个浏览器的处理方式都不一样。
- Would it be possible to display interlaced GIFs as supposed (going from a rough version to the final image)? This would require updating the image content multiple times at different stages of recompression.
如果您向浏览器提供部分图像,他们可能认为图像已损坏并拒绝显示。
在这种情况下,为了安全起见,您必须实现自己的 GIF 解码器和编码器,以便您可以向浏览器提供 完整 占位符图像。
- (new) Can I decode image loaded from another site?
我还必须重复警告,非插件 JS 图像解码不适用于 cross origin images。
这意味着,所有 .pcf 文件必须与使用它的站点位于同一服务器、同一端口和同一协议上。
例如,您不能为多个站点共享图像或进行 domain sharding 等优化。
代码示例
这是一个最小的例子,它创建一个 <img>
,加载一个 gif,宽度的一半,然后放回 <img>
。
要支持占位符或渐进式加载,请听取 onprogress 而不是 of/in 添加到 onload。
<!DOCTYPE html><html><head><meta charset="UTF-8"><script>
function loadPcf( file, attr ) {
var atr = attr || '', id = loadPcf.autoid = 1 + ~~loadPcf.autoid;
document.write( '<img id=pcf'+id+' ' + atr + ' />' );
var xhr = new XMLHttpRequest();
xhr.responseType = 'arraybuffer'; // IE 10+ only, sorry.
xhr.onload = function() { // I am loading gif for demo, you can load anything.
var data = xhr.response, img = document.querySelector( '#pcf' + id );
if ( ! img || ! data instanceof ArrayBuffer ) return;
var buf = new DataView( data ), head = buf.getUint32(0), width = buf.getUint16(6,1);
if ( head !== 1195984440 ) return console.log( 'Not a GIF: ' + file ); // 'GIF8' = 1195984440
// Modify data, image width in this case, and push it to the <img> as gif.
buf.setInt16( 6, ~~(width/2), 1 );
img.src = URL.createObjectURL( new Blob( [ buf.buffer ], { type: "image/gif" } ) );
};
xhr.open( 'GET', file );
xhr.send();
}
</script>
<h1>Foo<noscript><img src=a.gif width=90></noscript><script>loadPcf("a.gif","width=90")</script>Bar</h1>
如果你不需要 <noscript>
兼容性(从而防止 facebook/google+ 在页面共享时看到图像),你可以将 pcf 文件放在 <img>
src 并使用 JS 来处理它们,这样你就不需要为每个图像调用 loadPcf 并且会使 html much 更简单。
<video>
怎么样?
理论上,您设想的大部分是可行的,但也许您应该重新考虑。
从你问的问题来看,你很难顺利地定义和实现你的愿景。
最好在 WebM 和 use <video>
instead.
中编码您的动画
- 更好的浏览器支持 回到 IE 9 - 只需添加 H.264 使其成为 dual format video. You need IE 10+ 修改二进制数据。
- 大小:电影有很多很多选项和技巧来最小化大小,你学到的东西可以在未来重复使用。
- 进步:
<video>
有had some techs for adaptive video,希望能尽快稳定
- JavaScript:
<video>
不依赖于JavaScript.
- 面向未来:许多程序都支持 WebM 和 H.264,即使在您停止使用特殊格式很久之后。
- 成本效益: 使用更小或质量更低的媒体创建低带宽选项比自定义格式更容易、更可靠。这就是维基百科和 youtube 提供不同分辨率的媒体的原因。
对于非动画,PNG 也可以进行颜色索引和 7z optimised(保持 PNG 格式)。
图标大小索引 PNG 通常小于相同的 GIF。
或者您的愿景(如 pcf 网站所述)是能够对许多不同的文件进行编码,而不仅仅是 GIF。
这将更像是支持一种新的网络协议,并且可能超出了谦虚的范围JavaScript。 (例如,您将如何处理 pdf 下载或流式传输?)
我的维基百科程序 Precomp can be used to further compress already compressed file formats like GIF, PNG, PDF, ZIP and more. Roughly summarized, it does this by decompressing the compressed streams, recompressing them and storing the differences between the expected compressed stream and the actual compressed stream. As an example, this rotating earth picture 从 1429 KB 压缩到 755 KB。过程是无损的,所以可以恢复原GIF文件。
GIF 文件格式的算法可以相对容易地分离和实现,所以我在考虑 JavaScript 中的概念验证实现。这将导致网络服务器发送一个压缩版本的 GIF 文件(.pcf 结尾,本质上是一个 bzip2 压缩文件 GIF 图像内容)和客户端解压缩数据,重新压缩为 GIF 并显示它。需要完成以下事情:
- 网站作者必须使用标准版本的 Precomp 压缩他的 GIF 文件,并将这些文件而不是 GIF 文件与客户端重新压缩的 JavaScript 一起提供。
- 客户端会解压 bzip2 压缩文件,这可以使用 one of the existing bzip2 Javascript implementations. 来完成
- 客户端会将图片内容重新压缩成原始GIF文件。
该过程是带宽与客户端 CPU 使用率的交易。
现在我的问题如下:
- 加载不同文件并将其 "converting" 为 GIF 的过程是否存在任何一般性问题?
- 您建议在客户端完成之前显示什么(图像占位符)?
- 我必须做什么才能确保缓存 .pcf 文件?如果不缓存,带宽节省就没有用了。
- 有没有办法在 JavaScript 停用时显示原始 GIF,但在 JavaScript 激活时避免加载 GIF?
- 我可以为用户提供一种配置行为的方法吗?例如。在移动设备上,有些人可能会避开带宽,但其他人可能希望减少 CPU 使用率。
- 是否可以按预期显示隔行扫描的 GIF(从粗略版本到最终图像)?这将需要在重新压缩的不同阶段多次更新图像内容。
让我们首先回答您的具体问题。下面的代码示例。
问答
- Are there any general problems with the process of loading a different file and "converting" it to GIF?
主要问题是复杂化。您正在有效地编写一个浏览器插件,例如 JPEG2000 的插件。
如果您正在编写真正的浏览器插件,每个主要浏览器的做法都不同,并且偶尔会更改插件格式,因此您必须积极维护它们。
如果你写的是JS库,那么编写和维护起来会更容易,但是会没有特权,会受到cross original restriction.
等限制
- What would you recommend to display before the client side finishes (image placeholder)?
取决于您的格式可以提供什么。 如果您及早对图像尺寸和小缩略图进行编码,则可以很早地显示准确的占位符。
毕竟这是你的格式。
- What do I have to do to make sure the .pcf file is cached? Bandwidth savings were useless if doesn't get cached.
与其他文件没有什么不同。
在服务器端配置Expires
and Cache-Control
header,它们将被缓存。
Manifest
and prefetch
也可以用
- Is there a way to display the original GIF if JavaScript is deactivated, but avoid loading the GIF if JavaScript is activated?
这很棘手。当 JavaScript 被禁用时,您只能 replace elements,而不是属性。
这意味着您无法在指向 .pcf 文件的某处创建图像,并在 JS 不可用时要求浏览器重写 src 属性。
我认为不支持 JS 的最佳解决方案是使用 document.write
输出图像,使用 noscript
作为后备:
<noscript>
<img src=demo.gif width=90>
</noscript><script>
loadPcf("demo.pcf","width=90")
</script>
(某些库或框架可能会让您考虑 <img src=demo.gif data-pcf=demo.pcf>
。
这对你不起作用,因为浏览器 will preload 'demo.gif' 在你的脚本启动之前,会导致额外的数据传输。)
另外,浏览器插件不受 "disable JS" 设置的影响,因此如果您制作插件,则无需担心。
- Can I give the users a way to configure the behaviour? E.g. on mobile devices, some might avoid bandwidth, but others might want less CPU usage.
也许吧。您可以编写用户界面并将首选项存储在 cookie 或 localStorage 中。 然后您可以检测偏好并在服务器代码(如果是 cookie)或客户端代码中切换逻辑。
如果你在做插件,所有的浏览器都提供可靠的偏好机制。 问题是,每个浏览器的处理方式都不一样。
- Would it be possible to display interlaced GIFs as supposed (going from a rough version to the final image)? This would require updating the image content multiple times at different stages of recompression.
如果您向浏览器提供部分图像,他们可能认为图像已损坏并拒绝显示。 在这种情况下,为了安全起见,您必须实现自己的 GIF 解码器和编码器,以便您可以向浏览器提供 完整 占位符图像。
- (new) Can I decode image loaded from another site?
我还必须重复警告,非插件 JS 图像解码不适用于 cross origin images。 这意味着,所有 .pcf 文件必须与使用它的站点位于同一服务器、同一端口和同一协议上。
例如,您不能为多个站点共享图像或进行 domain sharding 等优化。
代码示例
这是一个最小的例子,它创建一个 <img>
,加载一个 gif,宽度的一半,然后放回 <img>
。
要支持占位符或渐进式加载,请听取 onprogress 而不是 of/in 添加到 onload。
<!DOCTYPE html><html><head><meta charset="UTF-8"><script>
function loadPcf( file, attr ) {
var atr = attr || '', id = loadPcf.autoid = 1 + ~~loadPcf.autoid;
document.write( '<img id=pcf'+id+' ' + atr + ' />' );
var xhr = new XMLHttpRequest();
xhr.responseType = 'arraybuffer'; // IE 10+ only, sorry.
xhr.onload = function() { // I am loading gif for demo, you can load anything.
var data = xhr.response, img = document.querySelector( '#pcf' + id );
if ( ! img || ! data instanceof ArrayBuffer ) return;
var buf = new DataView( data ), head = buf.getUint32(0), width = buf.getUint16(6,1);
if ( head !== 1195984440 ) return console.log( 'Not a GIF: ' + file ); // 'GIF8' = 1195984440
// Modify data, image width in this case, and push it to the <img> as gif.
buf.setInt16( 6, ~~(width/2), 1 );
img.src = URL.createObjectURL( new Blob( [ buf.buffer ], { type: "image/gif" } ) );
};
xhr.open( 'GET', file );
xhr.send();
}
</script>
<h1>Foo<noscript><img src=a.gif width=90></noscript><script>loadPcf("a.gif","width=90")</script>Bar</h1>
如果你不需要 <noscript>
兼容性(从而防止 facebook/google+ 在页面共享时看到图像),你可以将 pcf 文件放在 <img>
src 并使用 JS 来处理它们,这样你就不需要为每个图像调用 loadPcf 并且会使 html much 更简单。
<video>
怎么样?
理论上,您设想的大部分是可行的,但也许您应该重新考虑。
从你问的问题来看,你很难顺利地定义和实现你的愿景。
最好在 WebM 和 use <video>
instead.
- 更好的浏览器支持 回到 IE 9 - 只需添加 H.264 使其成为 dual format video. You need IE 10+ 修改二进制数据。
- 大小:电影有很多很多选项和技巧来最小化大小,你学到的东西可以在未来重复使用。
- 进步:
<video>
有had some techs for adaptive video,希望能尽快稳定 - JavaScript:
<video>
不依赖于JavaScript. - 面向未来:许多程序都支持 WebM 和 H.264,即使在您停止使用特殊格式很久之后。
- 成本效益: 使用更小或质量更低的媒体创建低带宽选项比自定义格式更容易、更可靠。这就是维基百科和 youtube 提供不同分辨率的媒体的原因。
对于非动画,PNG 也可以进行颜色索引和 7z optimised(保持 PNG 格式)。 图标大小索引 PNG 通常小于相同的 GIF。
或者您的愿景(如 pcf 网站所述)是能够对许多不同的文件进行编码,而不仅仅是 GIF。 这将更像是支持一种新的网络协议,并且可能超出了谦虚的范围JavaScript。 (例如,您将如何处理 pdf 下载或流式传输?)