>

前端实现,实现数据压缩

- 编辑:至尊游戏网站 -

前端实现,实现数据压缩

动用 canvas 实现数据压缩

2016/03/15 · HTML5 · 1 评论 · Canvas

原稿出处: EtherDream   

前端完成 SVG 转 PNG

2015/11/16 · JavaScript · PNG, SVG

原来的作品出处: 百度FEX - zhangbobell   

前言

HTTP 扶持 GZip 压缩,可节省看不完传输能源。但可惜的是,唯有下载才有,上传并不协助。

要是上传也能减小,那就全盘了。极其符合大批量文件提交的场面,比如今日头条,正是很好的例子。

即使规范不帮忙「上传压缩」,但仍可以够自个儿来促成。

前言

svg 是豆蔻梢头种矢量图形,在 web 上行使很常见,不过过多时候由于采取的风貌,平时供给将 svg 转为 png 格式,下载到本地等。随着浏览器对 HTML 5 的协助度更加高,大家得以把 svg 转为 png 的劳作交给浏览器来成功。

Flash

首选方案当然是 Flash,究竟它提供了压缩 API。除了 zip 格式,还扶持 lzma 这种超级压缩。

因为是原生接口,所以质量异常高。并且对应的 swf 文件,也相当小。

日常方法

  1. 创建 imageimage,src = xxx.svg;
  2. 创办 canvas,dragImage 将图纸贴到 canvas 上;
  3. 采纳 toDataUrl 函数,将 canvas 的意味为 url;
  4. new image, src = url, download = download.png;

但是,在调换的时候一时不经常会碰着如下的如下的七个难点:

JavaScript

Flash 渐渐淘汰,但代替的 HTML5,却绝非提供压缩 API。只可以和谐用 JS 完毕。

那就算实惠,但运转速度就慢多了,并且相应的 JS 也比相当大。

假如代码有 50kb,而数据压缩后只小 10kb,那就不足了。除非量大,才有含义。

难点 1 :浏览器对 canvas 限制

Canvas 的 W3C 的规范上未曾谈起 canvas 的最大高/宽度和面积,不过各样厂家的浏览器出于浏览器质量的思量,在不同的平台上设置了最大的高/宽度或然是渲染面积,当先了那些阈值渲染的结果会是立锥之地。测验了三种浏览器的 canvas 品质如下:

  • chrome (版本 46.0.2490.80 (64-bit))
    • 最大规模:268, 435, 456 px^2 = 16, 384 px * 16, 384 px
    • 最大宽/高:32, 767 px
  • firefox (版本 42.0)
    • 最大范围:32, 767 px * 16, 384 px
    • 最大宽/高:32, 767px
  • safari (版本 9.0.1 (11601.2.7.2))
    • 最大规模: 268, 435, 456 px^2 = 16, 384 px * 16, 384 px
  • ie 10(版本 10.0.9200.17414)
    • 最大宽/高: 8, 192px * 8, 192px

在相似的 web 应用中,恐怕比相当少会超越这个限制。可是,假设赶过了那几个限制,则 会导致导出为空白只怕由于内部存款和储蓄器泄露导致浏览器崩溃。

而且从另如日中天方面来讲, 导出 png 也是风度翩翩项很成本内部存款和储蓄器的操作,粗略估计一下,导出 16, 384 px * 16, 384 px 的 svg 会消耗 16384 * 16384 * 4 / 1024 / 1024 = 1024 M 的内部存款和储蓄器。所以,在近似这个极限值的时候,浏览器也会 反应变慢,能或不能够导出成功也跟系统的可用内部存款和储蓄器大小等等都有关系。

对此这么些难点,有如下两种缓慢解决方法:

  1. 将数据发送给后端,在后端实现 转变;
  2. 后面一个将 svg 切分成多个图片导出;

率先种办法能够应用 PhantomJS、inkscape、ImageMagick 等工具,绝对来讲比较简单,这里大家最首要查究第两种缓和形式。

其他

可不可以不要 JS,而是接纳某个接口,直接实现减弱?

实在,在 HTML5 刚面世时,就注意到了二个效益:canvas 导出图片。可以转移 jpg、png 等格式。

假设在考虑的话,相信你也想到了。没有错,正是 png —— 它是无损压缩的。

大家把平常数据当成像素点,画到 canvas 上,然后导出成 png,就是叁个异样的削减包了~


上边起先商量。。。

svg 切分成八个图片导出

思路:浏览器就算对 canvas 有尺寸和面积的限量,不过对于 image 成分并不曾明显的限定,也正是率先步生成的 image 其实彰显是常规的,大家要做的只是在其次步 dragImage 的时候分多次将 image 成分切分并贴到 canvas 上然后下载下来。 同一时间,应细心到 image 的载入是一个异步的进度。

第一代码

JavaScript

// 构造 svg Url,此处省略将 svg 经字符过滤后转为 url 的进度。 var svgUrl = DomU锐界L.createObjectUENVISIONL(blob); var svgWidth = document.querySelector('#kity_svg').getAttribute('width'); var svgHeight = document.querySelector('#kity_svg').getAttribute('height'); // 分片的拉长率和可观,可依照浏览器做适配 var w0 = 8192; var h0 = 8192; // 每行和每列能宽容的分片数 var M = Math.ceil(svgWidth / w0); var N = Math.ceil(svgHeight / h0); var idx = 0; loadImage(svgUrl).then(function(img) { while(idx < M * N) { // 要分开的面片在 image 上的坐标和尺寸 var targetX = idx % M * w0, targetY = idx / M * h0, targetW = (idx + 1) % M ? w0 : (svgWidth - (M - 1) * w0), targetH = idx >= (N - 1) * M ? (svgHeight - (N - 1) * h0) : h0; var canvas = document.createElement('canvas'), ctx = canvas.getContext('2d'); canvas.width = targetW; canvas.height = targetH; ctx.drawImage(img, targetX, targetY, targetW, targetH, 0, 0, targetW, targetH); console.log('now it is ' + idx); // 计划在前端下载 var a = document.createElement('a'); a.download = 'naotu-' + idx + '.png'; a.href = canvas.toDataU宝马X3L('image/png'); var clickEvent = new Mouse伊夫nt('click', { 'view': window, 'bubbles': true, 'cancelable': false }); a.dispatchEvent(click伊芙nt); idx++; } }, function(err) { console.log(err); }); // 加载 image function loadImage(url) { return new Promise(function(resolve, reject) { var image = new Image(); image.src = url; image.crossOrigin = 'Anonymous'; image.onload = function() { resolve(this); }; image.onerror = function(err) { reject(err); }; }); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// 构造 svg Url,此处省略将 svg 经字符过滤后转为 url 的过程。
var svgUrl = DomURL.createObjectURL(blob);
var svgWidth = document.querySelector('#kity_svg').getAttribute('width');
var svgHeight = document.querySelector('#kity_svg').getAttribute('height');
 
// 分片的宽度和高度,可根据浏览器做适配
var w0 = 8192;
var h0 = 8192;
 
// 每行和每列能容纳的分片数
var M = Math.ceil(svgWidth / w0);
var N = Math.ceil(svgHeight / h0);
 
var idx = 0;
loadImage(svgUrl).then(function(img) {
 
    while(idx < M * N) {
        // 要分割的面片在 image 上的坐标和尺寸
        var targetX = idx % M * w0,
            targetY = idx / M * h0,
            targetW = (idx + 1) % M ? w0 : (svgWidth - (M - 1) * w0),
            targetH = idx >= (N - 1) * M ? (svgHeight - (N - 1) * h0) : h0;
 
        var canvas = document.createElement('canvas'),
            ctx = canvas.getContext('2d');
 
            canvas.width = targetW;
            canvas.height = targetH;
 
            ctx.drawImage(img, targetX, targetY, targetW, targetH, 0, 0, targetW, targetH);
 
            console.log('now it is ' + idx);
 
            // 准备在前端下载
            var a = document.createElement('a');
            a.download = 'naotu-' + idx + '.png';
            a.href = canvas.toDataURL('image/png');
 
            var clickEvent = new MouseEvent('click', {
                'view': window,
                'bubbles': true,
                'cancelable': false
            });
 
            a.dispatchEvent(clickEvent);
 
        idx++;
    }
 
}, function(err) {
    console.log(err);
});
 
// 加载 image
function loadImage(url) {
    return new Promise(function(resolve, reject) {
        var image = new Image();
 
        image.src = url;
        image.crossOrigin = 'Anonymous';
        image.onload = function() {
            resolve(this);
        };
 
        image.onerror = function(err) {
            reject(err);
        };
    });
}

说明:

  1. 是因为在后边二个下载有浏览器宽容性、客户体验等主题素材,在其实中,恐怕须求将扭转后的多少发送到后端,并视作三个减小包下载。
  2. 分片的尺寸这里运用的是 8192 *至尊游戏网站, 9192,在实质上中,为了压实包容性和体验,能够依据浏览器和平台做适配,举例在 iOS 下的 safari 的最大规模是 4096 *4096。

多少转换

数量转像素,并不费劲。1 个像素能够包容 4 个字节:

R = bytes[0] G = bytes[1] B = bytes[2] A = bytes[3]

1
2
3
4
R = bytes[0]
G = bytes[1]
B = bytes[2]
A = bytes[3]

其实有现有的格局,可批量将数据填充成像素:

img = new ImageData(bytes, w, h); context.putImageData(img, w, h)

1
2
img = new ImageData(bytes, w, h);
context.putImageData(img, w, h)

唯独,图片的宽高怎么样设定?

难题 2 :导出饱含图表的 svg

在导出的时候,还恐怕会遇见另四个难题:如果 svg 里面满含图表,你会发觉经过上述措施导出的 png 里面,原本的图片是不显得的。通常感到是 svg 里面包蕴的图纸跨域了,可是若是你把那个图形换花费域的图样,照旧相会世这种意况。至尊游戏网站 1

图表中上局地是导出前的 svg,下图是导出后的 png。svg 中的图片是本域的,在导出后不出示。

尺寸设定

最简易的,就是用 1px 的莫大。举例有 一千 个像素,则填在 1000 x 1 的图片里。

但借使有 一千0 像素,就不可行了。因为 canvas 的尺码,是有限量的。

区别的浏览器,最大尺寸不平等。有 4096 的,也有 32767 的。。。

以最大 4096 为例,要是老是都用那么些幅度,显著不客观。

比方说有 n = 4100 个像素,我们选取 4096 x 2 的尺码:

| 1 | 2 | 3 | 4 | ... | 4095 | 4096 | | 4097 | 4098 | 4099 | 4100 | ...... 未利用 ......

1
2
| 1    | 2    | 3    | 4    | ...  | 4095 | 4096 |
| 4097 | 4098 | 4099 | 4100 | ...... 未利用 ......

第二行只用到 4 个,剩下的 4092 个都空着了。

但 4100 = 41 * 100。假使用那些尺寸,就不会有浪费。

就此,得对 n 分解因数:

n = w * h

1
n = w * h

那般就能够将 n 个像素,正好填满 w x h 的图片。

但 n 是质数的话,就无解了。那时浪费就不可防止了,只是,如何才干浪费最少?

于是乎就形成这样多个标题:

什么用 n + m 个点,拼成七个 w x h 的矩形(0

设想到 MAX 不大,穷举就足以。

笔者们遍历 h,计算相应的 w = ceil(n / h), 然后找寻最相仿 n 的 w * h。

var beg = Math.ceil(n / MAX); var end = Math.ceil(Math.sqrt(n)); var minSize = 9e9; var bestH = 0, // 最后结果 bestW = 0; for (h = beg; h end; h++) { var w = Math.ceil(n / h); var size = w * h; if (size minSize) { minSize = size; bestW = w; bestH = h; } if (size == n) { break; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var beg = Math.ceil(n / MAX);
var end = Math.ceil(Math.sqrt(n));
 
var minSize = 9e9;
 
var bestH = 0,          // 最终结果
    bestW = 0;
 
for (h = beg; h  end; h++) {
    var w = Math.ceil(n / h);
    var size = w * h;
 
    if (size  minSize) {
        minSize = size;
        bestW = w;
        bestH = h;
    }
    if (size == n) {
        break;
    }
}

因为 w * h 和 h * w 是千篇蒸蒸日上律的,所以只需遍历到 sqrt(n) 就可以。

无差异于,也无需从 1 开首,从 n / MAX 就能够。

如此那般,我们就能够找到最符合的图片尺寸。

本来,延续的空白像素,最后减掉后会非常小。这一步其实并不非常首要性。

标题来自

咱俩遵照小说最早叶建议的手续,稳步排查核对,会发掘在率先步的时候,svg 中的图片就不出示了。也便是,当 image 成分的 src 为一个 svg,並且 svg 里面包含图表,那么被含有的图纸是不博览会示的,纵然那几个图形是本域的。

W3C 关于那么些主题素材并未有做表明,最终在  找到了有关这么些题指标表达。 意思是:禁绝这么做是出于安全思量,svg 里面援引的具备 外界能源 包涵image, stylesheet, script 等都会被拦截。

其间还举了叁个例证:若是未有那一个限制,假如三个论坛允许顾客上传那样的 svg 作为头像,就有异常的大可能率出现如此的场景,一个人骇客上传 svg 作为头像,里面包罗代码:<image xlink:href="http://evilhacker.com/myimage.png">(要是那位红客具备对于 evil黑客.com 的调控权),那么那位红客就全盘能做到下边的事体:

  • 设若有人查看他的质地,evil黑客.com 就能摄取到贰次 ping 的央求(进而能够获得查看者的 ip);
  • 能够完毕对于不一致的 ip 地址的人展现不雷同的头像;
  • 能够任何时候改换头像的外观(而不用经过论坛管理员的稽核)。

看样子此间,差不多就通晓了方方面面难题的前因后果了,当然还也许有少数原因大概是幸免图像递归。

渲染难题

定下尺寸,大家就足以「渲染数据」了。

可是现实中,总有个别意外的坑。canvas 也不例外:

<canvas id="canvas" width="100" heigth="100"></canvas> <script> var ctx = canvas.getContext('2d'); // 写入的数额 var bytes = [100, 101, 102, 103]; var buf = new Uint8ClampedArray(bytes); var img = new ImageData(buf, 1, 1); ctx.putImageData(img, 0, 0); // 读取的数码 img = ctx.getImageData(0, 0, 1, 1); console.log(img.data); // chrome [99, 102, 102, 103] // firefox [101, 101, 103, 103] // ... </script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<canvas id="canvas" width="100" heigth="100"></canvas>
<script>
  var ctx = canvas.getContext('2d');
 
  // 写入的数据
  var bytes = [100, 101, 102, 103];
 
  var buf = new Uint8ClampedArray(bytes);
  var img = new ImageData(buf, 1, 1);
  ctx.putImageData(img, 0, 0);
 
  // 读取的数据
  img = ctx.getImageData(0, 0, 1, 1);
  console.log(img.data);
  // chrome  [99,  102, 102, 103]
  // firefox [101, 101, 103, 103]
  // ...
</script>

读取的像素,居然和写入的有过错!何况区别的浏览器,偏差还差别等。

原先,浏览器为了增加渲染品质,有二个 Premultiplied Alpha 的编写制定。可是,那会就义局地精度!

虽说视觉上并不醒目,但用于数据存款和储蓄,就有标题了。

怎么禁止使用它?后生可畏番品尝都没成功。于是,只可以从数据上镌刻了。

要是不利用 Alpha 通道,又会怎样?

// 写入的数量 var bytes = [100, 101, 102, 255]; ... console.log(img.data); // [100, 101, 102, 255]

1
2
3
4
  // 写入的数据
  var bytes = [100, 101, 102, 255];
  ...
  console.log(img.data);  // [100, 101, 102, 255]

这么,倒是避开了难题。

总的来说,只能从数额上出手,跳过 Alpha 通道:

// pixel 1 new_bytes[0] = bytes[0] // R new_bytes[1] = bytes[1] // G new_bytes[2] = bytes[2] // B new_bytes[3] = 255 // A // pixel 2 new_bytes[4] = bytes[3] // R new_bytes[5] = bytes[4] // G new_bytes[6] = bytes[5] // B new_bytes[7] = 255 // A ...

1
2
3
4
5
6
7
8
9
10
11
12
13
// pixel 1
new_bytes[0] = bytes[0]     // R
new_bytes[1] = bytes[1]     // G
new_bytes[2] = bytes[2]     // B
new_bytes[3] = 255          // A
 
// pixel 2
new_bytes[4] = bytes[3]     // R
new_bytes[5] = bytes[4]     // G
new_bytes[6] = bytes[5]     // B
new_bytes[7] = 255          // A
 
...

那时候,就不受 Premultiplied Alpha 的熏陶了。

是因为轻巧,也得以 1 像素存 1 字节:

// pixel 1 new_bytes[0] = bytes[0] new_bytes[1] = 255 new_bytes[2] = 255 new_bytes[3] = 255 // pixel 2 new_bytes[4] = bytes[1] new_bytes[5] = 255 new_bytes[6] = 255 new_bytes[7] = 255 ...

1
2
3
4
5
6
7
8
9
10
11
12
13
// pixel 1
new_bytes[0] = bytes[0]
new_bytes[1] = 255
new_bytes[2] = 255
new_bytes[3] = 255
 
// pixel 2
new_bytes[4] = bytes[1]
new_bytes[5] = 255
new_bytes[6] = 255
new_bytes[7] = 255
 
...

这么,整个图片最七唯有 256 色。假设能导出成「索引型 PNG」的话,也是足以品味的。

化解办法

思路:由于安全因素,其实首先步的时候,图片已经显示不出去了。那么我们以往设想的秘诀是在首先步之后遍历 svg 的布局,将持有的 image 成分的 url、地点和尺寸保存下去。在第三步之后,按梯次贴到 canvas 上。那样,最终导出的 png 图片就能有 svg 里面包车型地铁 image。重视代码

JavaScript

// 此处略去变通 svg url 的经过 var svgUrl = DomU奥迪Q5L.createObjectUCR-VL(blob); var svgWidth = document.querySelector('#kity_svg').getAttribute('width'); var svgHeight = document.querySelector('#kity_svg').getAttribute('height'); var embededImages = document.querySelectorAll('#kity_svg image'); // 由 nodeList 转为 array embededImages = Array.prototype.slice.call(embededImages); // 加载底层的图 loadImage(svgUrl).then(function(img) { var canvas = document.createElement('canvas'), ctx = canvas.getContext("2d"); canvas.width = svgWidth; canvas.height = svgHeight; ctx.drawImage(img, 0, 0); // 遍历 svg 里面装有的 image 元素embededImages.reduce(function(sequence, svgImg){ return sequence.then(function() { var url = svgImg.getAttribute('xlink:href') + 'abc', dX = svgImg.getAttribute('x'), dY = svgImg.getAttribute('y'), dWidth = svgImg.getAttribute('width'), dHeight = svgImg.getAttribute('height'); return loadImage(url).then(function( sImg) { ctx.drawImage(sImg, 0, 0, sImg.width, sImg.height, dX, dY, dWidth, dHeight); }, function(err) { console.log(err); }); }, function(err) { console.log(err); }); }, Promise.resolve()).then(function() { // 计划在前端下载 var a = document.createElement("a"); a.download = 'download.png'; a.href = canvas.toDataUHighlanderL("image/png"); var click伊芙nt = new Mouse伊芙nt("click", { "view": window, "bubbles": true, "cancelable": false }); a.dispatchEvent(click伊芙nt); }); }, function(err) { console.log(err); }) // 省略了 loadImage 函数 // 代码和率先个例子同样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// 此处略去生成 svg url 的过程
var svgUrl = DomURL.createObjectURL(blob);
var svgWidth = document.querySelector('#kity_svg').getAttribute('width');
var svgHeight = document.querySelector('#kity_svg').getAttribute('height');
 
var embededImages = document.querySelectorAll('#kity_svg image');
// 由 nodeList 转为 array
embededImages = Array.prototype.slice.call(embededImages);
// 加载底层的图
loadImage(svgUrl).then(function(img) {
 
var canvas = document.createElement('canvas'),
ctx = canvas.getContext("2d");
 
canvas.width = svgWidth;
canvas.height = svgHeight;
 
ctx.drawImage(img, 0, 0);
    // 遍历 svg 里面所有的 image 元素
    embededImages.reduce(function(sequence, svgImg){
 
        return sequence.then(function() {
            var url = svgImg.getAttribute('xlink:href') + 'abc',
                dX = svgImg.getAttribute('x'),
                dY = svgImg.getAttribute('y'),
                dWidth = svgImg.getAttribute('width'),
                dHeight = svgImg.getAttribute('height');
 
            return loadImage(url).then(function( sImg) {
                ctx.drawImage(sImg, 0, 0, sImg.width, sImg.height, dX, dY, dWidth, dHeight);
            }, function(err) {
                console.log(err);
            });
        }, function(err) {
            console.log(err);
        });
    }, Promise.resolve()).then(function() {
        // 准备在前端下载
        var a = document.createElement("a");
        a.download = 'download.png';
        a.href = canvas.toDataURL("image/png");
 
        var clickEvent = new MouseEvent("click", {
            "view": window,
            "bubbles": true,
            "cancelable": false
        });
 
        a.dispatchEvent(clickEvent);
 
        });
 
      }, function(err) {
        console.log(err);
   })
 
   // 省略了 loadImage 函数
   // 代码和第一个例子相同

说明

  1. 事例中 svg 里面包车型大巴图疑似根节点下边包车型地铁,因而用于表示地方的 x, y 直接取来就可以使用,在实际中,那几个职责可能须要跟别的属性做一些运算之后得出。假诺是依据svg 库营造的,那么能够直接使用Curry面用于固定的函数,比一向从最底层运算尤其惠及和准确。
  2. 作者们那边探讨的是本域的图纸的导出难题,跨域的图形由于「污染了」画布,在进行 toDataUrl 函数的时候会报错。

数据编码

末段,正是将图像进行导出。

万生意盎然 canvas 能直接导出成 blob,那是最棒的。因为 blob 可因此 AJAX 上传。

canvas.toBlob(function(blob) { // ... }, 'image/png')

1
2
3
canvas.toBlob(function(blob) {
    // ...
}, 'image/png')

而是,很多浏览器都不支持。只好导出 data uri 格式:

uri = canvas.toDataURL('image/png') // data:image/png;base64,xxxx

1
uri = canvas.toDataURL('image/png')  // data:image/png;base64,xxxx

但 base64 会增添长度。所以,还得解回二进制:

base64 = uri.substr(uri.indexOf(',') + 1) binary = atob(base64)

1
2
base64 = uri.substr(uri.indexOf(',') + 1)
binary = atob(base64)

此时的 binary,正是终极数额了吗?

若是将 binary 通过 AJAX 提交的话,会意识其实传输字节,比 binary.length 大。

原来 atob 再次回到的数据,仍为字符串型的。传输时,就提到字集编码了。

因而还需再更动一回,产生真的的二进制数据:

var len = binary.length var buf = new Uint8Array(len) for (var i = 0; i len; i++) { buf[i] = binary.charCodeAt(i) }

1
2
3
4
5
6
var len = binary.length
var buf = new Uint8Array(len)
 
for (var i = 0; i  len; i++) {
    buf[i] = binary.charCodeAt(i)
}

此刻的 buf,才干被 AJAX 原封不动的传导。

结语

在那地和豪门大饱眼福了 在前边八个将 svg 转为 png 的法子和进度中恐怕会越过的几个难题,四个是浏览器对 canvas 的尺码限制,另二个是导出图片的主题素材。当然,那五个难点还恐怕有任何的消除方法,同有时间由于文化所限,本文内容难免有尾巴,迎接我们商议指正。最终多谢@techird 和 @Naxior 关于那七个难题的座谈。

1 赞 2 收藏 评论

至尊游戏网站 2

最后效果

总来说之,大家简要演示下:Demo

找一个大块的文件测量试验。例如 qq.com 首页 HTML,有 637,101 字节。

先使用「每像素 1 字节」的编码,各种浏览器生成的 PNG 大小:

Chrome FireFox Safari
体积 289,460 203,276 478,994
比率 45.4% 31.9% 75.2%

中间火狐压缩率最高,收缩了 2/3 的容量。

调换的 PNG 看起来是如此的:

至尊游戏网站 3

可是可惜的是,全部浏览器生成的图片,都不是「256 色索引」的。


再测验「每像素 3 字节」,看看会不会有立异:

Chrome FireFox Safari
体积 297,239 202,785 384,183
比率 46.7% 31.8% 60.3%

Safari 有了相当多的升华,可是 Chrome 却更糟了。

FireFox 有稍许的升迁,压缩率仍然为参天的。

至尊游戏网站 4

黄金时代律缺憾的是,即便全体图片并不曾运用 Alpha 通道,但转换的 PNG 仍然是 叁15个人的。

况兼,也无法设置压缩等第,使得这种压缩方式,效能并不高。

相比较 Flash 压缩,差异就比较多了:

deflate 压缩 lzma 压缩
体积 133,660 108,015
比率 21.0% 17.0%

还要 Flash 生成的是通用格式,后端解码时,使用规范库就能够。

而 PNG 还得位图解码、像素管理等手续,很费劲。

由此,现实中依然优先利用 Flash,本文只是开脑洞而已。

实则用途

而是这种方式,实际依旧平价到过。用在多少个异常的大日志上传的场所(并且无法用 Flash)。

因为后端并不深入分析,仅仅积攒而已。所以,能够将日志对应的 PNG 下回本地,在协会者自个儿计算机上深入分析。

解压更易于,正是将像素还原回数据,这里有个简陋的 Demo。

这样,既降低了宽带,也节省存款和储蓄空间。

3 赞 4 收藏 1 评论

至尊游戏网站 5

本文由门户名站发布,转载请注明来源:前端实现,实现数据压缩