Compressed file in jszip is bigger than uncompressed content
Asked Answered
H

1

6

Can somebody explain, how is it possible, that jszip is not compressing files? I am trying to use compression and the compressed zip file size is bigger than file size of uncompressed files inside. Am I doing something wrong?

var fs = require("fs");
var JSZip = require("jszip");

var zip = new JSZip();
zip.file('try.txt', 'Hello World ');

zip.generateNodeStream({type:'nodebuffer',streamFiles:true}).pipe(fs.createWriteStream('out.zip')).on('finish', function () {
    // JSZip generates a readable stream with a "end" event,
    // but is piped here in a writable stream which emits a "finish" event.
    console.log("out.zip written.");
});

I see the issue also on the official page when downloading example. https://stuk.github.io/jszip/

As I can see, the file is the same usually as uncompressed file and it is doing no compression at all.

Handmade answered 10/9, 2019 at 7:44 Comment(2)
Try an example with a larger and more obviously compress-able value like '11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111' or maybe 20x as many as that and see if that results in a smaller value. zip has some overhead that the uncompressed file won't, and it's quite probable that the "compressed" file will actually be larger for very short examplesTerpstra
I did, it doesn't work either, it returns zip file with same size as decompressed file inside. I have to be missing something (most probably documentation does).Handmade
T
9

Ok, I took a look at the example on their website as you suggested. I made an obviously compressable file like I suggested in my comment (and you followed up on), download a 100KB file, obviously uncompressed. I then unzipped that and rezipped it using both windows and 7zip and resulted in a ~1KB file instead. You're definitely right, jszip's own example is creating an uncompressed zip.

For the case on their website, generate_async() doesn't compress by default, you have to pass compression options like so, and adjusting the call on their website does work, like so:

var zip = new JSZip();
zip.file("Hello.txt", "11111111 I had a bunch more 1s that I removed\n");
var img = zip.folder("images");
img.file("smile.gif", imgData, {base64: true});
zip.generateAsync({type:"blob",
    /* NOTE THESE ADDED COMPRESSION OPTIONS */
    /* deflate is the name of the compression algorithm used */
    compression: "DEFLATE",
    compressionOptions: {
         /* compression level ranges from 1 (best speed) to 9 (best compression) */
        level: 9
    }})
.then(function(content) {
    // see FileSaver.js
    saveAs(content, "example.zip");
});

Similarly, for your call I believe adding similar options should resolve it based on the generateNodeStream() documentation:

zip.generateNodeStream(
    {type:'nodebuffer',streamFiles:true,compression: "DEFLATE", compressionOptions: {level: 9}}
).pipe(fs.createWriteStream('out.zip')).on('finish', function () {
    // JSZip generates a readable stream with a "end" event,
    // but is piped here in a writable stream which emits a "finish" event.
    console.log("out.zip written.");
});

Also, you're not the first to have this issue. Here's another user on their github who fell into the same trap: https://github.com/Stuk/jszip/issues/503 I commented on that issue suggesting they change the examples to default to using compression to help avoid this problem. I didn't create a separate issue for it, but if you were passionate about it you could do so.

Terpstra answered 10/9, 2019 at 13:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.