您的位置:澳门新葡8455最新网站 > Web前端 > 实现数据压缩,前端实现

实现数据压缩,前端实现

发布时间:2019-12-09 15:19编辑:Web前端浏览(76)

    利用 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 = DomUPortofinoL.createObjectU景逸SUVL(blob卡塔尔(قطر‎; var svgWidth = document.querySelector('#kity_svg').getAttribute('width'); var svgHeight = document.querySelector('#kity_svg'卡塔尔(英语:State of Qatar).getAttribute('height'卡塔尔(英语:State of Qatar); // 分片的肥瘦和冲天,可依附浏览器做适配 var w0 = 8192; var h0 = 8192; // 每行和每列能兼容的分片数 var M = Math.ceil(svgWidth / w0卡塔尔(英语:State of Qatar); var N = Math.ceil(svgHeight / h0卡塔尔; var idx = 0; loadImage(svgUrl卡塔尔(قطر‎.then(function(img卡塔尔(英语:State of Qatar) { while(idx < M * N卡塔尔(英语:State of Qatar) { // 要分开的面片在 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卡塔尔(英语:State of Qatar) : 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卡塔尔(英语:State of Qatar); console.log('now it is ' + idx卡塔尔国; // 希图在前端下载 var a = document.createElement('a'卡塔尔国; a.download = 'naotu-' + idx + '.png'; a.href = canvas.toDataU智跑L('image/png'卡塔尔(英语:State of Qatar); var clickEvent = new Mouse伊夫nt('click', { 'view': window, 'bubbles': true, 'cancelable': false }卡塔尔国; a.dispatch伊芙nt(clickEvent卡塔尔(英语:State of Qatar); idx++; } }, function(err卡塔尔 { console.log(err卡塔尔(قطر‎; }卡塔尔; // 加载 image function loadImage(url卡塔尔国 { return new Promise(function(resolve, reject卡塔尔(قطر‎ { var image = new Image(卡塔尔(英语:State of Qatar); image.src = url; image.crossOrigin = 'Anonymous'; image.onload = function(卡塔尔国 { resolve(this卡塔尔(قطر‎; }; image.onerror = function(err卡塔尔国 { reject(err卡塔尔(قطر‎; }; }卡塔尔(英语:State of Qatar); }

    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 个像素,则填在 1000 x 1 的图样里。

    但假如有 10000 像素,就不可行了。因为 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卡塔尔(英语:State of Qatar); 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 = DomUENCOREL.createObjectU奥迪Q7L(blob卡塔尔(قطر‎; var svgWidth = document.querySelector('#kity_svg').getAttribute('width'); var svgHeight = document.querySelector('#kity_svg').getAttribute('height'); var embededImages = document.querySelectorAll('#kity_svg image'卡塔尔(英语:State of Qatar); // 由 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'卡塔尔(英语:State of Qatar); return loadImage(url卡塔尔(قطر‎.then(function( sImg卡塔尔(英语:State of Qatar) { ctx.drawImage(sImg, 0, 0, sImg.width, sImg.height, dX, dY, dWidth, dHeight卡塔尔(英语:State of Qatar); }, function(err卡塔尔 { console.log(err卡塔尔(英语:State of Qatar); }卡塔尔(قطر‎; }, function(err卡塔尔 { console.log(err卡塔尔国; }卡塔尔(英语:State of Qatar); }, Promise.resolve(卡塔尔(قطر‎卡塔尔(英语:State of Qatar).then(function(卡塔尔(英语:State of Qatar) { // 希图在前端下载 var a = document.createElement("a"卡塔尔(قطر‎; a.download = 'download.png'; a.href = canvas.toDataUQashqaiL("image/png"卡塔尔国; var clickEvent = new Mouse伊芙nt("click", { "view": window, "bubbles": true, "cancelable": false }卡塔尔国; a.dispatchEvent(click伊夫nt卡塔尔(英语:State of Qatar); }卡塔尔国; }, 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 却更糟了。

    Fire福克斯 有个别许的提拔,压缩率仍然是最高的。

    图片 4

    一律遗憾的是,固然全体图片并未选拔 Alpha 通道,但调换的 PNG 仍为 32个人的。

    並且,也心有余而力不足设置压缩品级,使得这种压缩方式,功能并不高。

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

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

    同不时候 Flash 生成的是通用格式,后端解码时,使用标准库就能够。

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

    因此,现实中依然开始的一段时期利用 Flash,本文只是开脑洞而已。

    实质上用场

    可是这种措施,实际依旧平价到过。用在一个很大日志上传的场面(何况不可能用 Flash)。

    因为后端并不分析,仅仅储存而已。所以,能够将日志对应的 PNG 下回地面,在协会者自身计算机上剖判。

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

    这么,既收缩了宽带,也节约存款和储蓄空间。

    3 赞 4 收藏 1 评论

    图片 5

    本文由澳门新葡8455最新网站发布于Web前端,转载请注明出处:实现数据压缩,前端实现

    关键词:

上一篇:没有了

下一篇:Web质量优化类别