<< Tomcat, Java and https | Home | lz-string: We'll try to make it faster >>

Just released: lz-string

lz-string is a compression program for JavaScript in the browser, based on LZW. It is fast, meant for localStorage or any other string-based storage in JavaScript, and is particularly efficient on short strings.

All can be read on the home page: https://pieroxy.net/blog/pages/lz-string/index.html And a demo can be found below for live compression: https://pieroxy.net/blog/pages/lz-string/demo.html

Lua decompress

I implemented the decompression algorithm in Lua 3.2, but it takes too long to complete the process. I do not understand why this happens. But data compression is extremely fast.

[Compress / Decompress] Python

[Decompress only] Lua 3.2

Data is compressed into Python, and decompressed on the Lua. I wanted to use lzstring in a communication network (RPC).
Avatar: pieroxy

Lua decompress

I don't know anything about Lua, I'll try to have a look anyways. My main question is: why would you want lz-string to do this? Lz-string is made to compress a string into another string. Both Python and Lua have byte arrays/streams which work with an existing large array of compression algorithms such as lzma, gzip, lz4 an plenty more both more performant and faster than mine.
Avatar: Charlie

Re: Just released: lz-string

This implementation/upgrade of LZW is genius!! Specially for Chrome since the localStorage stores every single byte as a word (2 bytes) occupying twice as much space hence instead of having 5MB of storage it gets reduced to 2.5MB.

C'est génial!

Avatar: pieroxy

Re: Just released: lz-string

 This is not specific to Chrome, but all browsers AFAIK. localStorage stores JavaScript Strings, which are UTF-16, meaning every character takes up 16bits of space. localStorage is limited effectively to 5MB, even on Chrome, it's just that Strings use a lot of memory in JavaScript. Note that this is not specific to JavaScript as it is the same in Java and C# for example.

The real issue I tried to solve in JavaScript is "how to represent a binary stream of data". The best answer I found is using Strings and using the 16-bits of all characters as storage.

Avatar: Anonymous

Re: Just released: lz-string

hi

Great job !!!

In my application I would like get from server compressed template data. Do you think about implementing this algorithm in java?

Avatar: pieroxy

Re: Just released: lz-string

 Just turn on gzip compression on your server and everything your server sends to the browser should be already gzip-compressed automatically, which is most likely much, much more efficient. You can see that if your server sends back a "Content-Encoding: gzip" into the http response to your browser. On Chrome, with the debugging tools turned on on the Network tab, you can see "Size/Content" for every request. Size is the actual number of bytes transferred while Content is the size of your uncompressed content.

Re: Just released: lz-string

FYI, I'm using LZString within a chrome-app (aka packaged app) and found that while using LZString.compress() to compress ~12MB of string before saving in chrome.storage.local, Chrome started suspending my chrome app unpredictably. Switching to LZString.compressToUTF16() fixed the suspend problem.

I suspect Chrome has some background storage checker that suspends extensions that store malformed data, like LZString compressed strings.

Avatar: pieroxy

Re: Just released: lz-string

 Thanks for the feedback. Thinking about it, LZString.compressToUTF16() seems much safer. Strings are sets of characters after all and who can predict what bugs an invalid character will trigger?

What is this chrome.storage.local you're using? If I read you correctly you store more than 5MB in it, so it must be something else than localStorage...

Re: Just released: lz-string

chrome.storage.local is storage API available to Chrome apps and extensions.

You can find documentation here: http://developer.chrome.com/apps/storage.html

Unlike localStorage, it's async. It's still limited to 5MB.

Good news is that I've managed to cut down my data to ~3.7M *characters* which,

using LZString compresses down to 10% (w00t). Bad news is, when I call

chrome.storage.local.getBytesInUse, returned number is ~2.5M *bytes* which,

if correct, suggests chrome.storage.local implementation doesn't just store what it

receives but transforms it somehow such that much of the compression magic gets

diffused. It could be that localStorage does the same.

Re: Just released: lz-string

I found myself needing a Java implementation of this for pre-compressing data from a Java program before putting it on a static web-server. I decided to not rely on the internal automatic compression of most web servers to reduce complexity.

I wrote one and put it on my github here if anyone is interested: https://github.com/ownaginatious/lz-string-java

Just a word of caution though; I haven't done a very extensive amount of testing.

Avatar: pieroxy

Re: Just released: lz-string

 Thanks for the effort. Just out of curiosity, why don't you rely on the webserver compression? That one is full fledge gzip which ought to compress a lot better than LZ-String...

 

Anyways, I'll link to your project from the documentation.

Re: Just released: lz-string

Hey, you can remove the link to my project (lz-string-java) from your website. I deleted it as it had too many problems and was confusing people. It looks as though someone implemented a better version. Thanks :)
Avatar: pieroxy

Re: Just released: lz-string

Just did it, thanks for the update.

Re: Just released: lz-string

Well, for my specific application it was crucial that data get compressed before being sent to clients. From what I understand, if I were to rely on the internal gzip of the webserver, there is a chance that some devices wouldn't support it and would request the uncompressed version, which would waste a lot of bandwidth. This kind of "guarantees" that the compression will always happen. The content I'm serving is already stored as files compressed using your algorithm :). I also wanted a method of sending compressed data back to a webserver, which from what I can tell isn't natively supported by many browsers.

I know that's an awfully specific purpose, but I figure someone else out there might find a clever use for a Java implementation :)

Also, I forgot to mention before - great library! Out of all the JS compression libraries I've looked through, yours is by far the easiest to use!

Avatar: Paul

lzString works ok, breaks Chrome debug tools

I am experimenting with lzString to store compressed data from javascript simulations

LZString seems to be working fine

But... when I bring up the debug tools, and click over to the Local Storage tab, it hangs and

the debug tools can not be dismissed with the X.

The website keeps working though.

Local storage with uncompressed data, even though it is pretty big (250K chars), does not

break the chrome Local Storage viewing tab in the dev tools.

This is probably  chromium's problem, not yours.  I have not yet tried other browsers.

Just thought you might want to be aware of it, and wondering what it might be....

Avatar: pieroxy

lzString works ok, breaks Chrome debug tools

 I have noticed this behavior with a localStorage full (5MB of packed strings) but it doesn't freeze, it just takes an awful lot of time rendering those weird strings. If you look at your task manager (or a top in a terminal) while trying to open the dev tools, you'll notice that one full core is crunching data for Chrome. This is the rendering part. while the rendering is done you can interact with your dev tools again.

Firebug exibits the same behavior 

This has to do (I think) with the handling of ultra-long strings coupled with the rendering of obscure UTF16 characters. With just a few kilobytes in localStorage everything is instantenuous.

Re: Just released: lz-string

 You're an absolute life saver, extremely easy to use and opens up lots of possibilities with cookies.

Re: Just released: lz-string

Hi! I just wanted to leave a comment to say thanks for writing and releasing this - as you found out yourself, there really isn't anything else comparable that is readily available! I wanted to be able to reduce the size of JSON data stored on the server and decompress it on the client and this has enabled me to do just that. I was hosting on NeoCities which has a limit on the size of hosted sites - so relying on gzip for transmission was no good as that compresses the content delivered over the wire but doesn't reduce the backend storage requirements. Shameless plug: I wrote about this at JavaScript Compression (Putting my JSON Search Indexes on a diet). But really I just wanted to say thanks. So thanks! :)

Avatar: Anonymous

nodejs error ?

I'm testing a node client <--> server chat program, and was wondering if your script was working for sending base64Strings.
It is working and it is not working :S ;)

A simple test gives me this:

var stringex = "This is my compression test.";
console.log("Size of sample is: " + stringex.length);

var compressed = Base64String.compress(stringex);
console.log("Size of compressed sample is: " + compressed.length);
string = Base64String.decompress(compressed);
console.log("Base64String Sample is: " + string);

var compressed3 = LZString.compressToUTF16(stringex);
console.log("Size of compressToUTF16 sample is: " + compressed3.length);
string = LZString.decompressFromUTF16(compressed3);
console.log("compressToUTF16 Sample is: " + string);

output:

Size of sample is: 28
Size of compressed sample is: 10
Base64String Sample is: ThisismycompressiontestA
Size of compressToUTF16 sample is: 17
compressToUTF16 Sample is: null

<div> </div>

 

Avatar: pieroxy

nodejs error ?

 So, I got around to it and I tested my lib on nodejs. 

Your first example (using Base64String.compress) cannot work as Base64String is meant to compress base64 encoded content. Your string ("This is my compression test.") is not a valid base64 string. So it doesn't work. Basically Base64String is meant to reencode Base64 content (usually images). The rationale is that base64 takes up a full character to store 6 bits, while compressToUTF16 stores 15 bits per characters.

Your second example is more useful in that really, it doesn't work. It looks as if your compressed test string triggers a bug in either compressToUTF16 or decompressToUTF16. I'm working on it as soon as I get home.

Avatar: pieroxy

nodejs error ?

I just released version 1.3.3. Version 1.3.2 was the result of a pull request that I obviously didn't test enough...

Avatar: Anonymous

nodejs error ?

 Oke thanks,

I will use is like this:

Serverside:
LZString.compressToUTF16(JSON.stringify({JSON:DATA}))

Clientside:
data = JSON.parse(LZString.decompressFromUTF16(data.compr));

Well test more later.

Avatar: pieroxy

nodejs error ?

 That's the idea. How will you get the resulting encoded string on the client side? Ajax.responseText ?

Avatar: Anonymous

nodejs error ?

Something like that, using http://socket.io/ but I can only send UTF-8 (and no binary) :S
compressToUTF16() works still, but maybe not for all messages... 

Maybe I can create a UTF16 detection
IF( ContainsUTF16Char( LZString.compressToUTF16(JSON.stringify(args[1])) )){
  nocompression
}


 

Avatar: pieroxy

nodejs error ?

I'm not worried about encoding problems here, but I am worried that a UTF-8 encoded string is going to be substantially bigger than the UTF-16 counterpart LZString is producing, resulting in wasted bandwidth. Your UTF16 detection is going to return true all the time : compressToUTF16 *is* generating UTF-16 characters as its name can tell.

The best way would probably be to generate ISO-(LATIN-1 for example) characters (all 256 of them being valid), or UTF-16. But for this to be "optimal" you need the content type to be set correctly. Do you have the hand on the content encoding of these requests? If yes, I suggest switching to "Content-Type: text/html; charset=utf-16" for a better bandwidth usage. 

If not, we'd need to write a compressToUTF8, using 7 bytes per character. Not quite hard.

The ideal solution would be for socket.io to be able to transfer byte arrays instead of strings. After all, we're trying to transmit binary data, not text.

 

Avatar: Anonymous

nodejs error ?

Haha thanks for the information, I don't know very mucht about UTF8 / UTF-16

Socket.io don't support binary yet :(
If you think its easy to create a compressToUTF8() than I say :)

I quick compression check gives me this

msg = {data:'I say hello'}
console.log('no compression',JSON.stringify(msg).length)
compr = LZString.LZString.compressToUTF16(JSON.stringify(msg));
console.log('compression',compr.length);

no compression 22
compression 17
 

msg = {data:'I say hello, I can say more and more text so this is big'}
console.log('no compression',JSON.stringify(msg).length)
compr = LZString.LZString.compressToUTF16(JSON.stringify(msg));
console.log('compression',compr.length);

<div> <div>no compression 67</div> <div>compression 37</div> <div> </div> <div>As you can see there is some compression.</div> <div> </div> <div>But if I understand you correct , you can make more compression using compressToUTF8() ?
 </div> </div>
Home