Implementação de JavaScript do Gzip [fechado]

208

Estou escrevendo um aplicativo Web que precisa armazenar dados JSON em um cache pequeno e de tamanho fixo do servidor via AJAX (pense em: cotas Opensocial ). Eu não tenho controle sobre o servidor.

Preciso reduzir o tamanho dos dados armazenados para permanecer dentro de uma cota do lado do servidor e esperava poder compactar o JSON com string no navegador antes de enviá-lo ao servidor.

No entanto, não consigo encontrar muita coisa nas implementações de JavaScript do Gzip. Alguma sugestão de como posso compactar os dados no lado do cliente antes de enviá-los?

David Citron
fonte
6
Você está enviando- se ao servidor. É por isso que existem as noções de "upload" e "download". Talvez seja por isso que você esteja recebendo respostas que digam "o servidor pode fazer isso".
Tomalak
3
Uma implementação adequada disso é provavelmente complicada, pois o javascript é de thread único. Provavelmente, seria necessário compactar em lotes, usando setTimeout (), para que a interface do usuário não seja bloqueada durante a compactação.
August Lilleaas 15/09/09
talvez você poderia escrever seu próprio algoritmo de compressão
Capitão Kuro
3
@AugustLilleaas agora você pode usar WebWorkers para fazer isso :)
Capitão Óbvio

Respostas:

138

Editar Parece haver uma solução LZW melhor que lida com seqüências de caracteres Unicode corretamente em http://pieroxy.net/blog/pages/lz-string/index.html (Agradecimentos a pieroxy nos comentários).


Não conheço nenhuma implementação gzip, mas a biblioteca jsolait (o site parece ter desaparecido) tem funções para compactação / descompactação LZW. O código é coberto pela LGPL .

// LZW-compress a string
function lzw_encode(s) {
    var dict = {};
    var data = (s + "").split("");
    var out = [];
    var currChar;
    var phrase = data[0];
    var code = 256;
    for (var i=1; i<data.length; i++) {
        currChar=data[i];
        if (dict[phrase + currChar] != null) {
            phrase += currChar;
        }
        else {
            out.push(phrase.length > 1 ? dict[phrase] : phrase.charCodeAt(0));
            dict[phrase + currChar] = code;
            code++;
            phrase=currChar;
        }
    }
    out.push(phrase.length > 1 ? dict[phrase] : phrase.charCodeAt(0));
    for (var i=0; i<out.length; i++) {
        out[i] = String.fromCharCode(out[i]);
    }
    return out.join("");
}

// Decompress an LZW-encoded string
function lzw_decode(s) {
    var dict = {};
    var data = (s + "").split("");
    var currChar = data[0];
    var oldPhrase = currChar;
    var out = [currChar];
    var code = 256;
    var phrase;
    for (var i=1; i<data.length; i++) {
        var currCode = data[i].charCodeAt(0);
        if (currCode < 256) {
            phrase = data[i];
        }
        else {
           phrase = dict[currCode] ? dict[currCode] : (oldPhrase + currChar);
        }
        out.push(phrase);
        currChar = phrase.charAt(0);
        dict[code] = oldPhrase + currChar;
        code++;
        oldPhrase = phrase;
    }
    return out.join("");
}
Matthew Crumley
fonte
11
Segundo a Wikipedia, as patentes expiraram alguns anos atrás. Pode ser uma boa ideia verificar isso.
Matthew Crumley
3
O LZW é muito antigo para ser patenteado. As últimas patentes acabaram em 2003 ou mais. Existem muitas implementações gratuitas.
ypnos
5
Vejo pelo menos dois problemas com o código acima: 1) tente compactar "Teste para compactar esses caracteres não ascii.", 2) Nenhum erro será relatado se o código> 65535.
alguns
5
Aqui estão implementações em 21 idiomas diferentes. Rosettacode.org/wiki/LZW_compression está escrito que está em domínio público a partir de 2004.
jcubic
5
@some I acaba de lançar um pequeno lib corrigir exatamente os problemas que você está apontando aqui: pieroxy.net/blog/pages/lz-string/index.html
pieroxy
53

Eu tive outro problema, não queria codificar dados no gzip, mas decodificar dados compactados . Estou executando o código javascript fora do navegador, por isso preciso decodificá-lo usando javascript puro .

Levei algum tempo, mas descobri que na biblioteca JSXGraph existe uma maneira de ler dados compactados em gzip.

Aqui é onde eu encontrei a biblioteca: http://jsxgraph.uni-bayreuth.de/wp/2009/09/29/jsxcompressor-zlib-compressed-javascript-code/ Existe até um utilitário independente que pode fazer isso, JSXCompressor , e o código é licenciado pela LGPL.

Basta incluir o arquivo jsxcompressor.js no seu projeto e, em seguida, você poderá ler os dados compactados em gzip codificados na base 64:

<!doctype html>
</head>
<title>Test gzip decompression page</title>
<script src="jsxcompressor.js"></script>
</head>
<body>
<script>
    document.write(JXG.decompress('<?php 
        echo base64_encode(gzencode("Try not. Do, or do not. There is no try.")); 
    ?>'));
</script>
</html>

Entendo que não era o que você queria, mas ainda respondo aqui porque suspeito que isso ajude algumas pessoas.

pcans
fonte
3
Muito obrigado por compartilhar ainda. Isso é exatamente o que eu precisava. Você provavelmente me salvou horas de pesquisas malsucedidas que eu realmente não posso poupar. +1
Kiruse
1
Eu me pergunto por que diabos é chamado de "compressor" quando é um descompressor. lol
Matteo
1
quase 5 anos depois, ainda é útil. obrigado. Estou despejando um JSON grande diretamente na página, em vez de fazer o AJAX. pré-compactando-o com PHP e descompactando-o novamente no lado do cliente do JavaScript - estou economizando parte da sobrecarga.
Precisamos do <?php..bit? .. Estou perguntando porque é passado para o decompressmétodo.
precisa saber é
Eu recebo14:16:28.512 TypeError: e.replace is not a function[Weitere Informationen] jsxcompressor.min.js:19:12201
Bluscream
40

Acabamos de lançar o pako https://github.com/nodeca/pako , port of zlib para javascript. Eu acho que agora é a implementação js mais rápida de deflate / inflate / gzip / ungzip. Além disso, possui licença democrática do MIT. Pako suporta todas as opções zlib e seus resultados são binários iguais.

Exemplo:

var inflate = require('pako/lib/inflate').inflate; 
var text = inflate(zipped, {to: 'string'});
Vitaly
fonte
7
Forneça um exemplo do lado do cliente para decodificar seqüências de caracteres compactadas com gzip.
Redsandro 26/03
2
var inflate = require('pako/lib/inflate').inflate; var text = inflate(zipped, {to: 'string'});@Redsandro aqui está como eu uso pako.
forresto
Esse exemplo do lado do cliente lançaincorrect header check
duhaime
17

Portamos uma implementação do LZMA de um módulo GWT para JavaScript autônomo. Chama -se LZMA-JS .


fonte
1
você tem um módulo php compatível?
Sirber 7/09/10
que url é 404, e eu não posso encontrá-lo no github.com/nmrugg quer
hanshenrik
Desculpe, o link foi alterado. Aqui está o novo: lzma-js.github.io/LZMA-JS
14

Aqui estão alguns outros algoritmos de compactação implementados em Javascript:

Mauricio Scheffer
fonte
esta implementação LZMA requer BrowserPlus (uma extensão do navegador) e não parece ser puro Javascript
Piotr Findeisen
essa implementação do LZ77 não está mais disponível e pelo menos sua versão do Python (publicada na mesma página) estava incorreta para entradas bastante simples.
Piotr Findeisen
geocities mortas, vai atualizar o link
Mauricio Scheffer
Isso é bem próximo do que eu quero. coisas do Google também serão atualizadas aqui
Theofanis Pantelides
8

Não testei, mas há uma implementação em javascript do ZIP, chamada JSZip:

http://jszip.stuartk.co.uk/

https://stuk.github.io/jszip/

Sirber
fonte
1
É zip, não gzip, e usa pako sob o capô. A diferença é que o zip possui metadados de informações do arquivo.
Vitaly
0

Eu acho que uma implementação genérica de compactação JavaScript do lado do cliente seria uma operação muito cara em termos de tempo de processamento, em oposição ao tempo de transferência de mais alguns pacotes HTTP com carga útil não compactada.

Você fez algum teste que lhe desse uma idéia de quanto tempo resta para economizar? Quero dizer, a economia de largura de banda não pode ser o que você procura, ou pode?

Tomalak
fonte
Preciso manter o tamanho total dos dados dentro de uma certa cota - o tamanho é mais importante que o tempo.
David Citron
Hm ... Por que o limite? Apenas curioso.
Tomalak
Bem, aqui está a opinião do Google: code.google.com/apis/opensocial/articles/… - As cotas opensociais típicas são de cerca de 10 mil.
David Citron
Entendo, obrigado pelo esclarecimento.
Tomalak
1
Dependendo da intensidade da compactação, você pode usar trabalhadores da Web para executar a tarefa nos bastidores.
zachleat
-3

A maioria dos navegadores pode descomprimir o gzip em tempo real. Essa pode ser uma opção melhor do que uma implementação de javascript.


fonte
20
Sim, mas eu preciso para comprimir os dados no lado do cliente antes de enviá-lo para baixo ...
David Citron
-4

Você pode usar um applet Java de 1 pixel por 1 pixel incorporado na página e usá-lo para compactação.

Não é JavaScript e os clientes precisarão de um tempo de execução Java, mas farão o que você precisa.

Bogdan
fonte
7
Interessante, mas prefiro evitar a inclusão de um applet, se possível.
David Citron
Gostaria de adicionar os casos de uso reais
cmc
1
Não é uma boa solução, pois adiciona uma dependência ao Java. Além disso, nem todo mundo se preocupou em instalar o java - o site não funcionará para algumas pessoas. Pessoalmente, tenho o java instalado, pois precisava dele há muito tempo, mas prefiro visitar sites que não usam java.
Onkelborg 11/02