注意:像音频文件这样的压缩最好使用专门针对该类型数据的算法,可能是一些有损压缩的算法。然而,知道在下面提供的合理无损实现的寻找之艰难,我非常担心很难找到一个在特定的数据类型中满足您需求的好的JavaScript实现。
无论如何,我也需要在JavaScript中进行压缩/解压缩,并且需要相同的算法在客户端(浏览器)和服务器端(node.js)上工作,并且需要处理非常大的文件。我曾经尝试过jszip,还尝试过LZW算法以及至少五六个其他算法,但都不能满足要求。我不记得每一个具体的问题是什么,但可以说惊人地难以在JavaScript中找到一个既好又快速的压缩/解压缩器,它可以在服务器和客户端上同时工作并处理大文件!我尝试了至少十几种不同的压缩算法实现,最终选择了这个——它从未让我失望!
更新
这是原始来源:
https://code.google.com/p/jslzjb/source/browse/trunk/Iuppiter.js?r=2
由一个名叫Bear的人编写 - 感谢你,无论你是谁,你是最棒的。
这是LZJB: http://en.wikipedia.org/wiki/LZJB
更新2
- 修正了缺少分号的问题-不再出现对象无法使用函数错误。
- 此实现在数据长度小于约80个字符时停止工作。因此,我更新了示例以反映这一点。
- 意识到此版本传递的对象实际上公开了base64编码/解码方法,因此......
- 目前正在研究我们可以针对特定的Blob类型做些什么 - 例如,图像与音频等最佳方法是什么,这对JS开发者总体有用...将在此处更新所发现的内容。
更新 3
有一个比我下面发布的更好的 Iuppiter 原始源代码包装器。它由 cscott 编写,在这里可以在 github 上找到: https://github.com/cscott/lzjb
我将切换到这个包装器,因为它也支持流。
以下是在 Node.js 中使用 wav 文件的示例。但在复制示例之前,请让我先告诉你一个可怕的消息,至少对于我尝试的这个 wav 文件来说:
63128 Jun 19 14:09 beep-1.wav
63128 Jun 19 17:47 beep-2.wav
89997 Jun 19 17:47 beep-2.wav.compressed
它成功地再生了wav文件(并播放了)。然而,压缩后的文件似乎比原始文件还要大。好吧。无论如何,尝试在您的数据上运行可能是一个不错的选择,您永远不知道,也许会有好运气。以下是我使用的代码:
var fs = require('fs');
var lzjb = require('lzjb');
fs.readFile('beep-1.wav', function(err, wav){
var encoded = wav.toString('base64');
var data = new Buffer(encoded, 'utf8');
var compressed = lzjb.compressFile(data, null, 9);
var compressedBuffer = new Buffer(compressed, 'binary');
fs.writeFile('beep-2.wav.compressed', compressedBuffer, 'binary', function(err) {});
var uncompressed = lzjb.decompressFile(compressed);
var encoded2 = new Buffer(uncompressed).toString('utf8');
var decoded = new Buffer(encoded2, 'base64');
fs.writeFile('beep-2.wav', decoded, function(err) {});
});
在一天结束时,我认为对于大多数未被结果base64编码破坏的二进制数据实现任何压缩级别都将变得太困难。终端控制字符的日子仍然困扰着我们。您可以尝试升级到不同的基础,但这也有其风险和问题。
例如,请参阅:
什么是最有效的二进制到文本编码?
以及这个:
为什么人们不使用base128?
有一件事,就是在接受答案之前,请务必在您的 Blob 上尝试它,我主要用它来压缩 utf-8,并且我希望确保它适用于您特定的数据。
无论如何,这就是它!
var fastcompressor = {};
(function (k) {
k.toByteArray = function (c) {
var h = [],
b, a;
for (b = 0; b < c.length; b++) a = c.charCodeAt(b), 127 >= a ? h.push(a) : (2047 >= a ? h.push(a >> 6 | 192) : (65535 >= a ? h.push(a >> 12 | 224) : (h.push(a >> 18 | 240), h.push(a >> 12 & 63 | 128)), h.push(a >> 6 & 63 | 128)), h.push(a & 63 | 128));
return h
};
k.Base64 = {
CA: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
CAS: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
IA: Array(256),
IAS: Array(256),
init: function () {
var c;
for (c = 0; 256 > c; c++) k.Base64.IA[c] = -1, k.Base64.IAS[c] = -1;
c = 0;
for (iS = k.Base64.CA.length; c < iS; c++) k.Base64.IA[k.Base64.CA.charCodeAt(c)] = c, k.Base64.IAS[k.Base64.CAS.charCodeAt(c)] = c;
k.Base64.IA["="] = k.Base64.IAS["="] = 0
},
encode: function (c, h) {
var b, a, d, e, m, g, f, l, j;
b = h ? k.Base64.CAS : k.Base64.CA;
d = c.constructor == Array ? c : k.toByteArray(c);
e = d.length;
m = 3 * (e / 3);
g = (e - 1) / 3 + 1 << 2;
a = Array(g);
for (l = f = 0; f < m;) j = (d[f++] & 255) << 16 | (d[f++] & 255) << 8 | d[f++] & 255, a[l++] = b.charAt(j >> 18 & 63), a[l++] = b.charAt(j >> 12 & 63), a[l++] = b.charAt(j >> 6 & 63), a[l++] = b.charAt(j & 63);
f = e - m;
0 < f && (j = (d[m] &
255) << 10 | (2 == f ? (d[e - 1] & 255) << 2 : 0), a[g - 4] = b.charAt(j >> 12), a[g - 3] = b.charAt(j >> 6 & 63), a[g - 2] = 2 == f ? b.charAt(j & 63) : "=", a[g - 1] = "=");
return a.join("")
},
decode: function (c, h) {
var b, a, d, e, m, g, f, l, j, p, q, n;
b = h ? k.Base64.IAS : k.Base64.IA;
c.constructor == Array ? (d = c, m = !0) : (d = k.toByteArray(c), m = !1);
e = d.length;
g = 0;
for (f = e - 1; g < f && 0 > b[d[g]];) g++;
for (; 0 < f && 0 > b[d[f]];) f--;
l = "=" == d[f] ? "=" == d[f - 1] ? 2 : 1 : 0;
a = f - g + 1;
j = 76 < e ? ("\r" == d[76] ? a / 78 : 0) << 1 : 0;
e = (6 * (a - j) >> 3) - l;
a = Array(e);
q = p = 0;
for (eLen = 3 * (e / 3); p < eLen;) n = b[d[g++]] << 18 | b[d[g++]] <<
12 | b[d[g++]] << 6 | b[d[g++]], a[p++] = n >> 16 & 255, a[p++] = n >> 8 & 255, a[p++] = n & 255, 0 < j && 19 == ++q && (g += 2, q = 0);
if (p < e) {
for (j = n = 0; g <= f - l; j++) n |= b[d[g++]] << 18 - 6 * j;
for (b = 16; p < e; b -= 8) a[p++] = n >> b & 255
}
if (m) return a;
for (n = 0; n < a.length; n++) a[n] = String.fromCharCode(a[n]);
return a.join("")
}
};
k.Base64.init();
NBBY = 8;
MATCH_BITS = 6;
MATCH_MIN = 3;
MATCH_MAX = (1 << MATCH_BITS) + (MATCH_MIN - 1);
OFFSET_MASK = (1 << 16 - MATCH_BITS) - 1;
LEMPEL_SIZE = 256;
k.compress = function (c) {
var h = [],
b, a = 0,
d = 0,
e, m, g = 1 << NBBY - 1,
f, l, j = Array(LEMPEL_SIZE);
for (b = 0; b < LEMPEL_SIZE; b++) j[b] =
3435973836;
c = c.constructor == Array ? c : k.toByteArray(c);
for (b = c.length; a < b;) {
if ((g <<= 1) == 1 << NBBY) {
if (d >= b - 1 - 2 * NBBY) {
f = b;
for (d = a = 0; f; f--) h[d++] = c[a++];
break
}
g = 1;
m = d;
h[d++] = 0
}
if (a > b - MATCH_MAX) h[d++] = c[a++];
else if (e = (c[a] + 13 ^ c[a + 1] - 13 ^ c[a + 2]) & LEMPEL_SIZE - 1, l = a - j[e] & OFFSET_MASK, j[e] = a, e = a - l, 0 <= e && e != a && c[a] == c[e] && c[a + 1] == c[e + 1] && c[a + 2] == c[e + 2]) {
h[m] |= g;
for (f = MATCH_MIN; f < MATCH_MAX && c[a + f] == c[e + f]; f++);
h[d++] = f - MATCH_MIN << NBBY - MATCH_BITS | l >> NBBY;
h[d++] = l;
a += f
} else h[d++] = c[a++]
}
return h
};
k.decompress = function (c,
h) {
var b, a = [],
d, e = 0,
m = 0,
g, f, l = 1 << NBBY - 1,
j;
b = c.constructor == Array ? c : k.toByteArray(c);
for (d = b.length; e < d;) {
if ((l <<= 1) == 1 << NBBY) l = 1, f = b[e++];
if (f & l)
if (j = (b[e] >> NBBY - MATCH_BITS) + MATCH_MIN, g = (b[e] << NBBY | b[e + 1]) & OFFSET_MASK, e += 2, 0 <= (g = m - g))
for (; 0 <= --j;) a[m++] = a[g++];
else break;
else a[m++] = b[e++]
}
if (!("undefined" == typeof h ? 0 : h)) {
for (b = 0; b < m; b++) a[b] = String.fromCharCode(a[b]);
a = a.join("")
}
return a
}
})(fastcompressor);
如果我的记忆没错... 这是如何使用它的:
var compressed = fastcompressor.compress("0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789")
var decompressed = fastcompressor.decompress(compressed)
Rgds....Hoonto/Matt
此外,我发布的内容是经过压缩但美化过的,并且稍作修改以便使用。请查看上面更新中的链接获取原始内容。
btoa
是你想要使用的,它会产生Base64数据并使事情变得更大。 - mu is too short.wav
文件来确定是否值得花费精力进行压缩?许多文件格式在内部已经被压缩,因此对它们进行压缩是没有用的;这在音频、视频和其他“自然大型”格式中非常普遍。 - mu is too short