Decompress gzip and zlib string in javascript

109,572

Solution 1

I can solve my problem by zlib . I fix my code as below

var base64Data = "eJztwTEBAAAAwqD1T20JT6AAAHgaCWAAAQ==";
var compressData = atob(base64Data);
var compressData = compressData.split('').map(function(e) {
    return e.charCodeAt(0);
});
var inflate = new Zlib.Inflate(compressData);
var output = inflate.decompress();

Solution 2

Pako is a full and modern Zlib port.

Here is a very simple example and you can work from there.

Get pako.js and you can decompress byteArray like so:

<html>
<head>
  <title>Gunzipping binary gzipped string</title>
  <script type="text/javascript" src="pako.js"></script>
  <script type="text/javascript">

    // Get datastream as Array, for example:
    var charData    = [31,139,8,0,0,0,0,0,0,3,5,193,219,13,0,16,16,4,192,86,214,151,102,52,33,110,35,66,108,226,60,218,55,147,164,238,24,173,19,143,241,18,85,27,58,203,57,46,29,25,198,34,163,193,247,106,179,134,15,50,167,173,148,48,0,0,0];

    // Turn number array into byte-array
    var binData     = new Uint8Array(charData);

    // Pako magic
    var data        = pako.inflate(binData);

    // Convert gunzipped byteArray back to ascii string:
    var strData     = String.fromCharCode.apply(null, new Uint16Array(data));

    // Output to console
    console.log(strData);

  </script>
</head>
<body>
    Open up the developer console.
</body>
</html>

Running example: http://jsfiddle.net/9yH7M/

Alternatively you can base64 encode the array before you send it over as the Array takes up a lot of overhead when sending as JSON or XML. Decode likewise:

// Get some base64 encoded binary data from the server. Imagine we got this:
var b64Data     = 'H4sIAAAAAAAAAwXB2w0AEBAEwFbWl2Y0IW4jQmziPNo3k6TuGK0Tj/ESVRs6yzkuHRnGIqPB92qzhg8yp62UMAAAAA==';

// Decode base64 (convert ascii to binary)
var strData     = atob(b64Data);

// Convert binary string to character-number array
var charData    = strData.split('').map(function(x){return x.charCodeAt(0);});

// Turn number array into byte-array
var binData     = new Uint8Array(charData);

// Pako magic
var data        = pako.inflate(binData);

// Convert gunzipped byteArray back to ascii string:
var strData     = String.fromCharCode.apply(null, new Uint16Array(data));

// Output to console
console.log(strData);

Running example: http://jsfiddle.net/9yH7M/1/

To go more advanced, here is the pako API documentation.

Solution 3

For anyone using Ruby on Rails, who wants to send compressed encoded data to the browser, then uncompress it via Javascript on the browser, I've combined both excellent answers above into the following solution. Here's the Rails server code in my application controller which compresses and encodes a string before sending it the browser via a @variable to a .html.erb file:

require 'zlib'
require 'base64'

    def compressor (some_string)
        Base64.encode64(Zlib::Deflate.deflate(some_string))
    end

Here's the Javascript function, which uses pako.min.js:

function uncompress(input_field){
    base64data = document.getElementById(input_field).innerText;
    compressData = atob(base64data);
    compressData = compressData.split('').map(function(e) {
        return e.charCodeAt(0);
    });
    binData = new Uint8Array(compressData);
    data = pako.inflate(binData);
    return String.fromCharCode.apply(null, new Uint16Array(data));
}

Here's a javascript call to that uncompress function, which wants to unencode and uncompress data stored inside a hidden HTML field:

my_answer = uncompress('my_hidden_field');

Here's the entry in the Rails application.js file to call pako.min.js, which is in the /vendor/assets/javascripts directory:

//= require pako.min

And I got the pako.min.js file from here:

https://github.com/nodeca/pako/tree/master/dist

All works at my end, anyway! :-)

Share:
109,572
Toan Nguyen
Author by

Toan Nguyen

Updated on February 09, 2020

Comments

  • Toan Nguyen
    Toan Nguyen about 4 years

    I want to get compress layer data from tmx file . Who knows libraries for decompress gzip and zlib string in javascript ? I try zlib but it doesn't work for me . Ex , layer data in tmx file is :

      <data encoding="base64" compression="zlib">
           eJztwTEBAAAAwqD1T20JT6AAAHgaCWAAAQ==
      </data>
    

    My javascript code is

    var base64Data = "eJztwTEBAAAAwqD1T20JT6AAAHgaCWAAAQ==";
    var compressData = atob(base64Data);
    var inflate = new Zlib.Inflate(compressData);
    var output = inflate.decompress();
    

    It runs with displays message error "unsupported compression method" . But I try decompress with online tool as http://i-tools.org/gzip , it returns correct string.

  • Quark
    Quark over 8 years
    The html example probably will not work as it is, because pako is not defined. The API has changed maybe, it uses require now.
  • Patrick
    Patrick about 8 years
    Note: String.fromCharCode.apply(null, new Uint16Array(data)) fails for long input (Maximum call stack size exceeded, JavaScript) This should work for longer arrays: stackoverflow.com/a/20604561/774398
  • Kamil Slowikowski
    Kamil Slowikowski over 5 years
    For long strings, use var string = new TextDecoder("utf-8").decode(data) as mentioned here: stackoverflow.com/questions/8936984/…
  • alan9uo
    alan9uo about 5 years
    I meet a problem.When I decompress use pako the english is okay, but when meet Chinese the Chinese string would become unreadable code.I don't know why.The gzip compression would remove the chart-set infomation??
  • Bekim Bacaj
    Bekim Bacaj almost 3 years
    I have a zip file in a normal JavaScript string retrieved over a network url - How do I decompress it so I can use its original 'text-plain' content?