zopfli 0.0.5 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitmodules +1 -1
- data/.travis.yml +24 -0
- data/Gemfile +2 -0
- data/Rakefile +8 -10
- data/ext/extconf.rb +1 -0
- data/ext/zopfli.c +37 -17
- data/lib/zopfli/version.rb +1 -1
- data/smoke.sh +9 -0
- data/{test → spec}/fixtures/alice29.txt +0 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/zopfli_spec.rb +68 -0
- data/vendor/zopfli/src/zopfli/blocksplitter.c +34 -44
- data/vendor/zopfli/src/zopfli/blocksplitter.h +2 -6
- data/vendor/zopfli/src/zopfli/cache.c +3 -1
- data/vendor/zopfli/src/zopfli/deflate.c +351 -287
- data/vendor/zopfli/src/zopfli/deflate.h +8 -2
- data/vendor/zopfli/src/zopfli/gzip_container.c +54 -47
- data/vendor/zopfli/src/zopfli/hash.c +18 -10
- data/vendor/zopfli/src/zopfli/hash.h +6 -3
- data/vendor/zopfli/src/zopfli/katajainen.c +73 -62
- data/vendor/zopfli/src/zopfli/lz77.c +190 -42
- data/vendor/zopfli/src/zopfli/lz77.h +32 -19
- data/vendor/zopfli/src/zopfli/squeeze.c +75 -61
- data/vendor/zopfli/src/zopfli/squeeze.h +1 -0
- data/vendor/zopfli/src/zopfli/symbols.h +239 -0
- data/vendor/zopfli/src/zopfli/util.c +0 -178
- data/vendor/zopfli/src/zopfli/util.h +6 -23
- data/vendor/zopfli/src/zopfli/zlib_container.c +1 -1
- data/vendor/zopfli/src/zopfli/zopfli.h +1 -4
- data/vendor/zopfli/src/zopfli/zopfli_bin.c +11 -8
- data/zopfli.gemspec +8 -27
- metadata +13 -20
- data/test/test_zopfli_deflate.rb +0 -45
- data/vendor/zopfli/CONTRIBUTING.md +0 -24
- data/vendor/zopfli/CONTRIBUTORS +0 -8
- data/vendor/zopfli/Makefile +0 -42
- data/vendor/zopfli/README +0 -32
- data/vendor/zopfli/README.zopflipng +0 -35
- data/vendor/zopfli/src/zopflipng/lodepng/lodepng.cpp +0 -6252
- data/vendor/zopfli/src/zopflipng/lodepng/lodepng.h +0 -1716
- data/vendor/zopfli/src/zopflipng/lodepng/lodepng_util.cpp +0 -656
- data/vendor/zopfli/src/zopflipng/lodepng/lodepng_util.h +0 -151
- data/vendor/zopfli/src/zopflipng/zopflipng_bin.cc +0 -408
- data/vendor/zopfli/src/zopflipng/zopflipng_lib.cc +0 -492
- data/vendor/zopfli/src/zopflipng/zopflipng_lib.h +0 -134
@@ -30,21 +30,17 @@ ones that enhance it.
|
|
30
30
|
|
31
31
|
#include <stdlib.h>
|
32
32
|
|
33
|
+
#include "lz77.h"
|
33
34
|
#include "zopfli.h"
|
34
35
|
|
35
36
|
|
36
37
|
/*
|
37
38
|
Does blocksplitting on LZ77 data.
|
38
39
|
The output splitpoints are indices in the LZ77 data.
|
39
|
-
litlens: lz77 lit/lengths
|
40
|
-
dists: lz77 distances
|
41
|
-
llsize: size of litlens and dists
|
42
40
|
maxblocks: set a limit to the amount of blocks. Set to 0 to mean no limit.
|
43
41
|
*/
|
44
42
|
void ZopfliBlockSplitLZ77(const ZopfliOptions* options,
|
45
|
-
const
|
46
|
-
const unsigned short* dists,
|
47
|
-
size_t llsize, size_t maxblocks,
|
43
|
+
const ZopfliLZ77Store* lz77, size_t maxblocks,
|
48
44
|
size_t** splitpoints, size_t* npoints);
|
49
45
|
|
50
46
|
/*
|
@@ -32,7 +32,9 @@ void ZopfliInitCache(size_t blocksize, ZopfliLongestMatchCache* lmc) {
|
|
32
32
|
/* Rather large amount of memory. */
|
33
33
|
lmc->sublen = (unsigned char*)malloc(ZOPFLI_CACHE_LENGTH * 3 * blocksize);
|
34
34
|
if(lmc->sublen == NULL) {
|
35
|
-
fprintf(stderr,
|
35
|
+
fprintf(stderr,
|
36
|
+
"Error: Out of memory. Tried allocating %lu bytes of memory.\n",
|
37
|
+
ZOPFLI_CACHE_LENGTH * 3 * blocksize);
|
36
38
|
exit (EXIT_FAILURE);
|
37
39
|
}
|
38
40
|
|
@@ -24,8 +24,8 @@ Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala)
|
|
24
24
|
#include <stdlib.h>
|
25
25
|
|
26
26
|
#include "blocksplitter.h"
|
27
|
-
#include "lz77.h"
|
28
27
|
#include "squeeze.h"
|
28
|
+
#include "symbols.h"
|
29
29
|
#include "tree.h"
|
30
30
|
|
31
31
|
/*
|
@@ -294,8 +294,7 @@ Adds all lit/len and dist codes from the lists as huffman symbols. Does not add
|
|
294
294
|
end code 256. expected_data_size is the uncompressed block size, used for
|
295
295
|
assert, but you can set it to 0 to not do the assertion.
|
296
296
|
*/
|
297
|
-
static void AddLZ77Data(const
|
298
|
-
const unsigned short* dists,
|
297
|
+
static void AddLZ77Data(const ZopfliLZ77Store* lz77,
|
299
298
|
size_t lstart, size_t lend,
|
300
299
|
size_t expected_data_size,
|
301
300
|
const unsigned* ll_symbols, const unsigned* ll_lengths,
|
@@ -306,8 +305,8 @@ static void AddLZ77Data(const unsigned short* litlens,
|
|
306
305
|
size_t i;
|
307
306
|
|
308
307
|
for (i = lstart; i < lend; i++) {
|
309
|
-
unsigned dist = dists[i];
|
310
|
-
unsigned litlen = litlens[i];
|
308
|
+
unsigned dist = lz77->dists[i];
|
309
|
+
unsigned litlen = lz77->litlens[i];
|
311
310
|
if (dist == 0) {
|
312
311
|
assert(litlen < 256);
|
313
312
|
assert(ll_lengths[litlen] > 0);
|
@@ -343,29 +342,83 @@ static void GetFixedTree(unsigned* ll_lengths, unsigned* d_lengths) {
|
|
343
342
|
}
|
344
343
|
|
345
344
|
/*
|
346
|
-
|
345
|
+
Same as CalculateBlockSymbolSize, but for block size smaller than histogram
|
346
|
+
size.
|
347
347
|
*/
|
348
|
-
static size_t
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
size_t lstart, size_t lend) {
|
348
|
+
static size_t CalculateBlockSymbolSizeSmall(const unsigned* ll_lengths,
|
349
|
+
const unsigned* d_lengths,
|
350
|
+
const ZopfliLZ77Store* lz77,
|
351
|
+
size_t lstart, size_t lend) {
|
353
352
|
size_t result = 0;
|
354
353
|
size_t i;
|
355
354
|
for (i = lstart; i < lend; i++) {
|
356
|
-
|
357
|
-
|
355
|
+
assert(i < lz77->size);
|
356
|
+
assert(lz77->litlens[i] < 259);
|
357
|
+
if (lz77->dists[i] == 0) {
|
358
|
+
result += ll_lengths[lz77->litlens[i]];
|
358
359
|
} else {
|
359
|
-
|
360
|
-
|
361
|
-
result +=
|
362
|
-
result +=
|
360
|
+
int ll_symbol = ZopfliGetLengthSymbol(lz77->litlens[i]);
|
361
|
+
int d_symbol = ZopfliGetDistSymbol(lz77->dists[i]);
|
362
|
+
result += ll_lengths[ll_symbol];
|
363
|
+
result += d_lengths[d_symbol];
|
364
|
+
result += ZopfliGetLengthSymbolExtraBits(ll_symbol);
|
365
|
+
result += ZopfliGetDistSymbolExtraBits(d_symbol);
|
363
366
|
}
|
364
367
|
}
|
365
368
|
result += ll_lengths[256]; /*end symbol*/
|
366
369
|
return result;
|
367
370
|
}
|
368
371
|
|
372
|
+
/*
|
373
|
+
Same as CalculateBlockSymbolSize, but with the histogram provided by the caller.
|
374
|
+
*/
|
375
|
+
static size_t CalculateBlockSymbolSizeGivenCounts(const size_t* ll_counts,
|
376
|
+
const size_t* d_counts,
|
377
|
+
const unsigned* ll_lengths,
|
378
|
+
const unsigned* d_lengths,
|
379
|
+
const ZopfliLZ77Store* lz77,
|
380
|
+
size_t lstart, size_t lend) {
|
381
|
+
size_t result = 0;
|
382
|
+
size_t i;
|
383
|
+
if (lstart + ZOPFLI_NUM_LL * 3 > lend) {
|
384
|
+
return CalculateBlockSymbolSizeSmall(
|
385
|
+
ll_lengths, d_lengths, lz77, lstart, lend);
|
386
|
+
} else {
|
387
|
+
for (i = 0; i < 256; i++) {
|
388
|
+
result += ll_lengths[i] * ll_counts[i];
|
389
|
+
}
|
390
|
+
for (i = 257; i < 286; i++) {
|
391
|
+
result += ll_lengths[i] * ll_counts[i];
|
392
|
+
result += ZopfliGetLengthSymbolExtraBits(i) * ll_counts[i];
|
393
|
+
}
|
394
|
+
for (i = 0; i < 30; i++) {
|
395
|
+
result += d_lengths[i] * d_counts[i];
|
396
|
+
result += ZopfliGetDistSymbolExtraBits(i) * d_counts[i];
|
397
|
+
}
|
398
|
+
result += ll_lengths[256]; /*end symbol*/
|
399
|
+
return result;
|
400
|
+
}
|
401
|
+
}
|
402
|
+
|
403
|
+
/*
|
404
|
+
Calculates size of the part after the header and tree of an LZ77 block, in bits.
|
405
|
+
*/
|
406
|
+
static size_t CalculateBlockSymbolSize(const unsigned* ll_lengths,
|
407
|
+
const unsigned* d_lengths,
|
408
|
+
const ZopfliLZ77Store* lz77,
|
409
|
+
size_t lstart, size_t lend) {
|
410
|
+
if (lstart + ZOPFLI_NUM_LL * 3 > lend) {
|
411
|
+
return CalculateBlockSymbolSizeSmall(
|
412
|
+
ll_lengths, d_lengths, lz77, lstart, lend);
|
413
|
+
} else {
|
414
|
+
size_t ll_counts[ZOPFLI_NUM_LL];
|
415
|
+
size_t d_counts[ZOPFLI_NUM_D];
|
416
|
+
ZopfliLZ77GetHistogram(lz77, lstart, lend, ll_counts, d_counts);
|
417
|
+
return CalculateBlockSymbolSizeGivenCounts(
|
418
|
+
ll_counts, d_counts, ll_lengths, d_lengths, lz77, lstart, lend);
|
419
|
+
}
|
420
|
+
}
|
421
|
+
|
369
422
|
static size_t AbsDiff(size_t x, size_t y) {
|
370
423
|
if (x > y)
|
371
424
|
return x - y;
|
@@ -374,9 +427,9 @@ static size_t AbsDiff(size_t x, size_t y) {
|
|
374
427
|
}
|
375
428
|
|
376
429
|
/*
|
377
|
-
|
378
|
-
compression, especially its rle-part will be more likely to compress this data
|
379
|
-
more efficiently. length
|
430
|
+
Changes the population counts in a way that the consequent Huffman tree
|
431
|
+
compression, especially its rle-part, will be more likely to compress this data
|
432
|
+
more efficiently. length contains the size of the histogram.
|
380
433
|
*/
|
381
434
|
void OptimizeHuffmanForRle(int length, size_t* counts) {
|
382
435
|
int i, k, stride;
|
@@ -464,50 +517,151 @@ void OptimizeHuffmanForRle(int length, size_t* counts) {
|
|
464
517
|
free(good_for_rle);
|
465
518
|
}
|
466
519
|
|
520
|
+
/*
|
521
|
+
Tries out OptimizeHuffmanForRle for this block, if the result is smaller,
|
522
|
+
uses it, otherwise keeps the original. Returns size of encoded tree and data in
|
523
|
+
bits, not including the 3-bit block header.
|
524
|
+
*/
|
525
|
+
static double TryOptimizeHuffmanForRle(
|
526
|
+
const ZopfliLZ77Store* lz77, size_t lstart, size_t lend,
|
527
|
+
const size_t* ll_counts, const size_t* d_counts,
|
528
|
+
unsigned* ll_lengths, unsigned* d_lengths) {
|
529
|
+
size_t ll_counts2[ZOPFLI_NUM_LL];
|
530
|
+
size_t d_counts2[ZOPFLI_NUM_D];
|
531
|
+
unsigned ll_lengths2[ZOPFLI_NUM_LL];
|
532
|
+
unsigned d_lengths2[ZOPFLI_NUM_D];
|
533
|
+
double treesize;
|
534
|
+
double datasize;
|
535
|
+
double treesize2;
|
536
|
+
double datasize2;
|
537
|
+
|
538
|
+
treesize = CalculateTreeSize(ll_lengths, d_lengths);
|
539
|
+
datasize = CalculateBlockSymbolSizeGivenCounts(ll_counts, d_counts,
|
540
|
+
ll_lengths, d_lengths, lz77, lstart, lend);
|
541
|
+
|
542
|
+
memcpy(ll_counts2, ll_counts, sizeof(ll_counts2));
|
543
|
+
memcpy(d_counts2, d_counts, sizeof(d_counts2));
|
544
|
+
OptimizeHuffmanForRle(ZOPFLI_NUM_LL, ll_counts2);
|
545
|
+
OptimizeHuffmanForRle(ZOPFLI_NUM_D, d_counts2);
|
546
|
+
ZopfliCalculateBitLengths(ll_counts2, ZOPFLI_NUM_LL, 15, ll_lengths2);
|
547
|
+
ZopfliCalculateBitLengths(d_counts2, ZOPFLI_NUM_D, 15, d_lengths2);
|
548
|
+
PatchDistanceCodesForBuggyDecoders(d_lengths2);
|
549
|
+
|
550
|
+
treesize2 = CalculateTreeSize(ll_lengths2, d_lengths2);
|
551
|
+
datasize2 = CalculateBlockSymbolSizeGivenCounts(ll_counts, d_counts,
|
552
|
+
ll_lengths2, d_lengths2, lz77, lstart, lend);
|
553
|
+
|
554
|
+
if (treesize2 + datasize2 < treesize + datasize) {
|
555
|
+
memcpy(ll_lengths, ll_lengths2, sizeof(ll_lengths2));
|
556
|
+
memcpy(d_lengths, d_lengths2, sizeof(d_lengths2));
|
557
|
+
return treesize2 + datasize2;
|
558
|
+
}
|
559
|
+
return treesize + datasize;
|
560
|
+
}
|
561
|
+
|
467
562
|
/*
|
468
563
|
Calculates the bit lengths for the symbols for dynamic blocks. Chooses bit
|
469
564
|
lengths that give the smallest size of tree encoding + encoding of all the
|
470
565
|
symbols to have smallest output size. This are not necessarily the ideal Huffman
|
471
|
-
bit lengths.
|
566
|
+
bit lengths. Returns size of encoded tree and data in bits, not including the
|
567
|
+
3-bit block header.
|
472
568
|
*/
|
473
|
-
static
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
size_t
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
ZopfliCalculateBitLengths(ll_counts, 288, 15, ll_lengths);
|
484
|
-
ZopfliCalculateBitLengths(d_counts, 32, 15, d_lengths);
|
569
|
+
static double GetDynamicLengths(const ZopfliLZ77Store* lz77,
|
570
|
+
size_t lstart, size_t lend,
|
571
|
+
unsigned* ll_lengths, unsigned* d_lengths) {
|
572
|
+
size_t ll_counts[ZOPFLI_NUM_LL];
|
573
|
+
size_t d_counts[ZOPFLI_NUM_D];
|
574
|
+
|
575
|
+
ZopfliLZ77GetHistogram(lz77, lstart, lend, ll_counts, d_counts);
|
576
|
+
ll_counts[256] = 1; /* End symbol. */
|
577
|
+
ZopfliCalculateBitLengths(ll_counts, ZOPFLI_NUM_LL, 15, ll_lengths);
|
578
|
+
ZopfliCalculateBitLengths(d_counts, ZOPFLI_NUM_D, 15, d_lengths);
|
485
579
|
PatchDistanceCodesForBuggyDecoders(d_lengths);
|
580
|
+
return TryOptimizeHuffmanForRle(
|
581
|
+
lz77, lstart, lend, ll_counts, d_counts, ll_lengths, d_lengths);
|
486
582
|
}
|
487
583
|
|
488
|
-
double ZopfliCalculateBlockSize(const
|
489
|
-
const unsigned short* dists,
|
584
|
+
double ZopfliCalculateBlockSize(const ZopfliLZ77Store* lz77,
|
490
585
|
size_t lstart, size_t lend, int btype) {
|
491
|
-
unsigned ll_lengths[
|
492
|
-
unsigned d_lengths[
|
586
|
+
unsigned ll_lengths[ZOPFLI_NUM_LL];
|
587
|
+
unsigned d_lengths[ZOPFLI_NUM_D];
|
493
588
|
|
494
589
|
double result = 3; /* bfinal and btype bits */
|
495
590
|
|
496
|
-
|
497
|
-
|
498
|
-
|
591
|
+
if (btype == 0) {
|
592
|
+
size_t length = ZopfliLZ77GetByteRange(lz77, lstart, lend);
|
593
|
+
size_t rem = length % 65535;
|
594
|
+
size_t blocks = length / 65535 + (rem ? 1 : 0);
|
595
|
+
/* An uncompressed block must actually be split into multiple blocks if it's
|
596
|
+
larger than 65535 bytes long. Eeach block header is 5 bytes: 3 bits,
|
597
|
+
padding, LEN and NLEN (potential less padding for first one ignored). */
|
598
|
+
return blocks * 5 * 8 + length * 8;
|
599
|
+
} if (btype == 1) {
|
499
600
|
GetFixedTree(ll_lengths, d_lengths);
|
601
|
+
result += CalculateBlockSymbolSize(
|
602
|
+
ll_lengths, d_lengths, lz77, lstart, lend);
|
500
603
|
} else {
|
501
|
-
GetDynamicLengths(
|
502
|
-
result += CalculateTreeSize(ll_lengths, d_lengths);
|
604
|
+
result += GetDynamicLengths(lz77, lstart, lend, ll_lengths, d_lengths);
|
503
605
|
}
|
504
606
|
|
505
|
-
result += CalculateBlockSymbolSize(
|
506
|
-
ll_lengths, d_lengths, litlens, dists, lstart, lend);
|
507
|
-
|
508
607
|
return result;
|
509
608
|
}
|
510
609
|
|
610
|
+
double ZopfliCalculateBlockSizeAutoType(const ZopfliLZ77Store* lz77,
|
611
|
+
size_t lstart, size_t lend) {
|
612
|
+
double uncompressedcost = ZopfliCalculateBlockSize(lz77, lstart, lend, 0);
|
613
|
+
/* Don't do the expensive fixed cost calculation for larger blocks that are
|
614
|
+
unlikely to use it. */
|
615
|
+
double fixedcost = (lz77->size > 1000) ?
|
616
|
+
uncompressedcost : ZopfliCalculateBlockSize(lz77, lstart, lend, 1);
|
617
|
+
double dyncost = ZopfliCalculateBlockSize(lz77, lstart, lend, 2);
|
618
|
+
return (uncompressedcost < fixedcost && uncompressedcost < dyncost)
|
619
|
+
? uncompressedcost
|
620
|
+
: (fixedcost < dyncost ? fixedcost : dyncost);
|
621
|
+
}
|
622
|
+
|
623
|
+
/* Since an uncompressed block can be max 65535 in size, it actually adds
|
624
|
+
multible blocks if needed. */
|
625
|
+
static void AddNonCompressedBlock(const ZopfliOptions* options, int final,
|
626
|
+
const unsigned char* in, size_t instart,
|
627
|
+
size_t inend,
|
628
|
+
unsigned char* bp,
|
629
|
+
unsigned char** out, size_t* outsize) {
|
630
|
+
size_t pos = instart;
|
631
|
+
(void)options;
|
632
|
+
for (;;) {
|
633
|
+
size_t i;
|
634
|
+
unsigned short blocksize = 65535;
|
635
|
+
unsigned short nlen;
|
636
|
+
int currentfinal;
|
637
|
+
|
638
|
+
if (pos + blocksize > inend) blocksize = inend - pos;
|
639
|
+
currentfinal = pos + blocksize >= inend;
|
640
|
+
|
641
|
+
nlen = ~blocksize;
|
642
|
+
|
643
|
+
AddBit(final && currentfinal, bp, out, outsize);
|
644
|
+
/* BTYPE 00 */
|
645
|
+
AddBit(0, bp, out, outsize);
|
646
|
+
AddBit(0, bp, out, outsize);
|
647
|
+
|
648
|
+
/* Any bits of input up to the next byte boundary are ignored. */
|
649
|
+
*bp = 0;
|
650
|
+
|
651
|
+
ZOPFLI_APPEND_DATA(blocksize % 256, out, outsize);
|
652
|
+
ZOPFLI_APPEND_DATA((blocksize / 256) % 256, out, outsize);
|
653
|
+
ZOPFLI_APPEND_DATA(nlen % 256, out, outsize);
|
654
|
+
ZOPFLI_APPEND_DATA((nlen / 256) % 256, out, outsize);
|
655
|
+
|
656
|
+
for (i = 0; i < blocksize; i++) {
|
657
|
+
ZOPFLI_APPEND_DATA(in[pos + i], out, outsize);
|
658
|
+
}
|
659
|
+
|
660
|
+
if (currentfinal) break;
|
661
|
+
pos += blocksize;
|
662
|
+
}
|
663
|
+
}
|
664
|
+
|
511
665
|
/*
|
512
666
|
Adds a deflate block with the given LZ77 data to the output.
|
513
667
|
options: global program options
|
@@ -526,20 +680,27 @@ out: dynamic output array to append to
|
|
526
680
|
outsize: dynamic output array size
|
527
681
|
*/
|
528
682
|
static void AddLZ77Block(const ZopfliOptions* options, int btype, int final,
|
529
|
-
const
|
530
|
-
const unsigned short* dists,
|
683
|
+
const ZopfliLZ77Store* lz77,
|
531
684
|
size_t lstart, size_t lend,
|
532
685
|
size_t expected_data_size,
|
533
686
|
unsigned char* bp,
|
534
687
|
unsigned char** out, size_t* outsize) {
|
535
|
-
unsigned ll_lengths[
|
536
|
-
unsigned d_lengths[
|
537
|
-
unsigned ll_symbols[
|
538
|
-
unsigned d_symbols[
|
539
|
-
size_t detect_block_size;
|
688
|
+
unsigned ll_lengths[ZOPFLI_NUM_LL];
|
689
|
+
unsigned d_lengths[ZOPFLI_NUM_D];
|
690
|
+
unsigned ll_symbols[ZOPFLI_NUM_LL];
|
691
|
+
unsigned d_symbols[ZOPFLI_NUM_D];
|
692
|
+
size_t detect_block_size = *outsize;
|
540
693
|
size_t compressed_size;
|
541
694
|
size_t uncompressed_size = 0;
|
542
695
|
size_t i;
|
696
|
+
if (btype == 0) {
|
697
|
+
size_t length = ZopfliLZ77GetByteRange(lz77, lstart, lend);
|
698
|
+
size_t pos = lstart == lend ? 0 : lz77->pos[lstart];
|
699
|
+
size_t end = pos + length;
|
700
|
+
AddNonCompressedBlock(options, final,
|
701
|
+
lz77->data, pos, end, bp, out, outsize);
|
702
|
+
return;
|
703
|
+
}
|
543
704
|
|
544
705
|
AddBit(final, bp, out, outsize);
|
545
706
|
AddBit(btype & 1, bp, out, outsize);
|
@@ -553,7 +714,7 @@ static void AddLZ77Block(const ZopfliOptions* options, int btype, int final,
|
|
553
714
|
unsigned detect_tree_size;
|
554
715
|
assert(btype == 2);
|
555
716
|
|
556
|
-
GetDynamicLengths(
|
717
|
+
GetDynamicLengths(lz77, lstart, lend, ll_lengths, d_lengths);
|
557
718
|
|
558
719
|
detect_tree_size = *outsize;
|
559
720
|
AddDynamicTree(ll_lengths, d_lengths, bp, out, outsize);
|
@@ -562,18 +723,18 @@ static void AddLZ77Block(const ZopfliOptions* options, int btype, int final,
|
|
562
723
|
}
|
563
724
|
}
|
564
725
|
|
565
|
-
ZopfliLengthsToSymbols(ll_lengths,
|
566
|
-
ZopfliLengthsToSymbols(d_lengths,
|
726
|
+
ZopfliLengthsToSymbols(ll_lengths, ZOPFLI_NUM_LL, 15, ll_symbols);
|
727
|
+
ZopfliLengthsToSymbols(d_lengths, ZOPFLI_NUM_D, 15, d_symbols);
|
567
728
|
|
568
729
|
detect_block_size = *outsize;
|
569
|
-
AddLZ77Data(
|
730
|
+
AddLZ77Data(lz77, lstart, lend, expected_data_size,
|
570
731
|
ll_symbols, ll_lengths, d_symbols, d_lengths,
|
571
732
|
bp, out, outsize);
|
572
733
|
/* End symbol. */
|
573
734
|
AddHuffmanBits(ll_symbols[256], ll_lengths[256], bp, out, outsize);
|
574
735
|
|
575
736
|
for (i = lstart; i < lend; i++) {
|
576
|
-
uncompressed_size += dists[i] == 0 ? 1 : litlens[i];
|
737
|
+
uncompressed_size += lz77->dists[i] == 0 ? 1 : lz77->litlens[i];
|
577
738
|
}
|
578
739
|
compressed_size = *outsize - detect_block_size;
|
579
740
|
if (options->verbose) {
|
@@ -583,262 +744,165 @@ static void AddLZ77Block(const ZopfliOptions* options, int btype, int final,
|
|
583
744
|
}
|
584
745
|
}
|
585
746
|
|
586
|
-
static void
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
747
|
+
static void AddLZ77BlockAutoType(const ZopfliOptions* options, int final,
|
748
|
+
const ZopfliLZ77Store* lz77,
|
749
|
+
size_t lstart, size_t lend,
|
750
|
+
size_t expected_data_size,
|
751
|
+
unsigned char* bp,
|
752
|
+
unsigned char** out, size_t* outsize) {
|
753
|
+
double uncompressedcost = ZopfliCalculateBlockSize(lz77, lstart, lend, 0);
|
754
|
+
double fixedcost = ZopfliCalculateBlockSize(lz77, lstart, lend, 1);
|
755
|
+
double dyncost = ZopfliCalculateBlockSize(lz77, lstart, lend, 2);
|
756
|
+
|
757
|
+
/* Whether to perform the expensive calculation of creating an optimal block
|
758
|
+
with fixed huffman tree to check if smaller. Only do this for small blocks or
|
759
|
+
blocks which already are pretty good with fixed huffman tree. */
|
760
|
+
int expensivefixed = (lz77->size < 1000) || fixedcost <= dyncost * 1.1;
|
761
|
+
|
762
|
+
ZopfliLZ77Store fixedstore;
|
763
|
+
if (lstart == lend) {
|
764
|
+
/* Smallest empty block is represented by fixed block */
|
765
|
+
AddBits(final, 1, bp, out, outsize);
|
766
|
+
AddBits(1, 2, bp, out, outsize); /* btype 01 */
|
767
|
+
AddBits(0, 7, bp, out, outsize); /* end symbol has code 0000000 */
|
768
|
+
return;
|
769
|
+
}
|
770
|
+
ZopfliInitLZ77Store(lz77->data, &fixedstore);
|
771
|
+
if (expensivefixed) {
|
772
|
+
/* Recalculate the LZ77 with ZopfliLZ77OptimalFixed */
|
773
|
+
size_t instart = lz77->pos[lstart];
|
774
|
+
size_t inend = instart + ZopfliLZ77GetByteRange(lz77, lstart, lend);
|
775
|
+
|
776
|
+
ZopfliBlockState s;
|
777
|
+
ZopfliInitBlockState(options, instart, inend, 1, &s);
|
778
|
+
ZopfliLZ77OptimalFixed(&s, lz77->data, instart, inend, &fixedstore);
|
779
|
+
fixedcost = ZopfliCalculateBlockSize(&fixedstore, 0, fixedstore.size, 1);
|
780
|
+
ZopfliCleanBlockState(&s);
|
781
|
+
}
|
605
782
|
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
ZopfliInitLZ77Store(&fixedstore);
|
614
|
-
ZopfliLZ77OptimalFixed(&s, in, instart, inend, &fixedstore);
|
615
|
-
dyncost = ZopfliCalculateBlockSize(store.litlens, store.dists,
|
616
|
-
0, store.size, 2);
|
617
|
-
fixedcost = ZopfliCalculateBlockSize(fixedstore.litlens, fixedstore.dists,
|
618
|
-
0, fixedstore.size, 1);
|
619
|
-
if (fixedcost < dyncost) {
|
620
|
-
btype = 1;
|
621
|
-
ZopfliCleanLZ77Store(&store);
|
622
|
-
store = fixedstore;
|
783
|
+
if (uncompressedcost < fixedcost && uncompressedcost < dyncost) {
|
784
|
+
AddLZ77Block(options, 0, final, lz77, lstart, lend,
|
785
|
+
expected_data_size, bp, out, outsize);
|
786
|
+
} else if (fixedcost < dyncost) {
|
787
|
+
if (expensivefixed) {
|
788
|
+
AddLZ77Block(options, 1, final, &fixedstore, 0, fixedstore.size,
|
789
|
+
expected_data_size, bp, out, outsize);
|
623
790
|
} else {
|
624
|
-
|
791
|
+
AddLZ77Block(options, 1, final, lz77, lstart, lend,
|
792
|
+
expected_data_size, bp, out, outsize);
|
625
793
|
}
|
794
|
+
} else {
|
795
|
+
AddLZ77Block(options, 2, final, lz77, lstart, lend,
|
796
|
+
expected_data_size, bp, out, outsize);
|
626
797
|
}
|
627
798
|
|
628
|
-
|
629
|
-
store.litlens, store.dists, 0, store.size,
|
630
|
-
blocksize, bp, out, outsize);
|
631
|
-
|
632
|
-
#ifdef ZOPFLI_LONGEST_MATCH_CACHE
|
633
|
-
ZopfliCleanCache(s.lmc);
|
634
|
-
free(s.lmc);
|
635
|
-
#endif
|
636
|
-
ZopfliCleanLZ77Store(&store);
|
637
|
-
}
|
638
|
-
|
639
|
-
static void DeflateFixedBlock(const ZopfliOptions* options, int final,
|
640
|
-
const unsigned char* in,
|
641
|
-
size_t instart, size_t inend,
|
642
|
-
unsigned char* bp,
|
643
|
-
unsigned char** out, size_t* outsize) {
|
644
|
-
ZopfliBlockState s;
|
645
|
-
size_t blocksize = inend - instart;
|
646
|
-
ZopfliLZ77Store store;
|
647
|
-
|
648
|
-
ZopfliInitLZ77Store(&store);
|
649
|
-
|
650
|
-
s.options = options;
|
651
|
-
s.blockstart = instart;
|
652
|
-
s.blockend = inend;
|
653
|
-
#ifdef ZOPFLI_LONGEST_MATCH_CACHE
|
654
|
-
s.lmc = (ZopfliLongestMatchCache*)malloc(sizeof(ZopfliLongestMatchCache));
|
655
|
-
ZopfliInitCache(blocksize, s.lmc);
|
656
|
-
#endif
|
657
|
-
|
658
|
-
ZopfliLZ77OptimalFixed(&s, in, instart, inend, &store);
|
659
|
-
|
660
|
-
AddLZ77Block(s.options, 1, final, store.litlens, store.dists, 0, store.size,
|
661
|
-
blocksize, bp, out, outsize);
|
662
|
-
|
663
|
-
#ifdef ZOPFLI_LONGEST_MATCH_CACHE
|
664
|
-
ZopfliCleanCache(s.lmc);
|
665
|
-
free(s.lmc);
|
666
|
-
#endif
|
667
|
-
ZopfliCleanLZ77Store(&store);
|
799
|
+
ZopfliCleanLZ77Store(&fixedstore);
|
668
800
|
}
|
669
801
|
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
802
|
+
/*
|
803
|
+
Deflate a part, to allow ZopfliDeflate() to use multiple master blocks if
|
804
|
+
needed.
|
805
|
+
It is possible to call this function multiple times in a row, shifting
|
806
|
+
instart and inend to next bytes of the data. If instart is larger than 0, then
|
807
|
+
previous bytes are used as the initial dictionary for LZ77.
|
808
|
+
This function will usually output multiple deflate blocks. If final is 1, then
|
809
|
+
the final bit will be set on the last block.
|
810
|
+
*/
|
811
|
+
void ZopfliDeflatePart(const ZopfliOptions* options, int btype, int final,
|
812
|
+
const unsigned char* in, size_t instart, size_t inend,
|
813
|
+
unsigned char* bp, unsigned char** out,
|
814
|
+
size_t* outsize) {
|
675
815
|
size_t i;
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
AddBit(final, bp, out, outsize);
|
683
|
-
/* BTYPE 00 */
|
684
|
-
AddBit(0, bp, out, outsize);
|
685
|
-
AddBit(0, bp, out, outsize);
|
816
|
+
/* byte coordinates rather than lz77 index */
|
817
|
+
size_t* splitpoints_uncompressed = 0;
|
818
|
+
size_t npoints = 0;
|
819
|
+
size_t* splitpoints = 0;
|
820
|
+
double totalcost = 0;
|
821
|
+
ZopfliLZ77Store lz77;
|
686
822
|
|
687
|
-
/*
|
688
|
-
|
823
|
+
/* If btype=2 is specified, it tries all block types. If a lesser btype is
|
824
|
+
given, then however it forces that one. Neither of the lesser types needs
|
825
|
+
block splitting as they have no dynamic huffman trees. */
|
826
|
+
if (btype == 0) {
|
827
|
+
AddNonCompressedBlock(options, final, in, instart, inend, bp, out, outsize);
|
828
|
+
return;
|
829
|
+
} else if (btype == 1) {
|
830
|
+
ZopfliLZ77Store store;
|
831
|
+
ZopfliBlockState s;
|
832
|
+
ZopfliInitLZ77Store(in, &store);
|
833
|
+
ZopfliInitBlockState(options, instart, inend, 1, &s);
|
689
834
|
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
ZOPFLI_APPEND_DATA((nlen / 256) % 256, out, outsize);
|
835
|
+
ZopfliLZ77OptimalFixed(&s, in, instart, inend, &store);
|
836
|
+
AddLZ77Block(options, btype, final, &store, 0, store.size, 0,
|
837
|
+
bp, out, outsize);
|
694
838
|
|
695
|
-
|
696
|
-
|
839
|
+
ZopfliCleanBlockState(&s);
|
840
|
+
ZopfliCleanLZ77Store(&store);
|
841
|
+
return;
|
697
842
|
}
|
698
|
-
}
|
699
843
|
|
700
|
-
static void DeflateBlock(const ZopfliOptions* options,
|
701
|
-
int btype, int final,
|
702
|
-
const unsigned char* in, size_t instart, size_t inend,
|
703
|
-
unsigned char* bp,
|
704
|
-
unsigned char** out, size_t* outsize) {
|
705
|
-
if (btype == 0) {
|
706
|
-
DeflateNonCompressedBlock(
|
707
|
-
options, final, in, instart, inend, bp, out, outsize);
|
708
|
-
} else if (btype == 1) {
|
709
|
-
DeflateFixedBlock(options, final, in, instart, inend, bp, out, outsize);
|
710
|
-
} else {
|
711
|
-
assert (btype == 2);
|
712
|
-
DeflateDynamicBlock(options, final, in, instart, inend, bp, out, outsize);
|
713
|
-
}
|
714
|
-
}
|
715
844
|
|
716
|
-
|
717
|
-
Does squeeze strategy where first block splitting is done, then each block is
|
718
|
-
squeezed.
|
719
|
-
Parameters: see description of the ZopfliDeflate function.
|
720
|
-
*/
|
721
|
-
static void DeflateSplittingFirst(const ZopfliOptions* options,
|
722
|
-
int btype, int final,
|
723
|
-
const unsigned char* in,
|
724
|
-
size_t instart, size_t inend,
|
725
|
-
unsigned char* bp,
|
726
|
-
unsigned char** out, size_t* outsize) {
|
727
|
-
size_t i;
|
728
|
-
size_t* splitpoints = 0;
|
729
|
-
size_t npoints = 0;
|
730
|
-
if (btype == 0) {
|
731
|
-
ZopfliBlockSplitSimple(in, instart, inend, 65535, &splitpoints, &npoints);
|
732
|
-
} else if (btype == 1) {
|
733
|
-
/* If all blocks are fixed tree, splitting into separate blocks only
|
734
|
-
increases the total size. Leave npoints at 0, this represents 1 block. */
|
735
|
-
} else {
|
845
|
+
if (options->blocksplitting) {
|
736
846
|
ZopfliBlockSplit(options, in, instart, inend,
|
737
|
-
options->blocksplittingmax,
|
847
|
+
options->blocksplittingmax,
|
848
|
+
&splitpoints_uncompressed, &npoints);
|
849
|
+
splitpoints = (size_t*)malloc(sizeof(*splitpoints) * npoints);
|
738
850
|
}
|
739
851
|
|
852
|
+
ZopfliInitLZ77Store(in, &lz77);
|
853
|
+
|
740
854
|
for (i = 0; i <= npoints; i++) {
|
741
|
-
size_t start = i == 0 ? instart :
|
742
|
-
size_t end = i == npoints ? inend :
|
743
|
-
|
744
|
-
|
855
|
+
size_t start = i == 0 ? instart : splitpoints_uncompressed[i - 1];
|
856
|
+
size_t end = i == npoints ? inend : splitpoints_uncompressed[i];
|
857
|
+
ZopfliBlockState s;
|
858
|
+
ZopfliLZ77Store store;
|
859
|
+
ZopfliInitLZ77Store(in, &store);
|
860
|
+
ZopfliInitBlockState(options, start, end, 1, &s);
|
861
|
+
ZopfliLZ77Optimal(&s, in, start, end, options->numiterations, &store);
|
862
|
+
totalcost += ZopfliCalculateBlockSizeAutoType(&store, 0, store.size);
|
863
|
+
|
864
|
+
ZopfliAppendLZ77Store(&store, &lz77);
|
865
|
+
if (i < npoints) splitpoints[i] = lz77.size;
|
866
|
+
|
867
|
+
ZopfliCleanBlockState(&s);
|
868
|
+
ZopfliCleanLZ77Store(&store);
|
745
869
|
}
|
746
870
|
|
747
|
-
|
748
|
-
|
871
|
+
/* Second block splitting attempt */
|
872
|
+
if (options->blocksplitting && npoints > 1) {
|
873
|
+
size_t* splitpoints2 = 0;
|
874
|
+
size_t npoints2 = 0;
|
875
|
+
double totalcost2 = 0;
|
749
876
|
|
750
|
-
|
751
|
-
|
752
|
-
on that data, block splitting is done.
|
753
|
-
Parameters: see description of the ZopfliDeflate function.
|
754
|
-
*/
|
755
|
-
static void DeflateSplittingLast(const ZopfliOptions* options,
|
756
|
-
int btype, int final,
|
757
|
-
const unsigned char* in,
|
758
|
-
size_t instart, size_t inend,
|
759
|
-
unsigned char* bp,
|
760
|
-
unsigned char** out, size_t* outsize) {
|
761
|
-
size_t i;
|
762
|
-
ZopfliBlockState s;
|
763
|
-
ZopfliLZ77Store store;
|
764
|
-
size_t* splitpoints = 0;
|
765
|
-
size_t npoints = 0;
|
766
|
-
|
767
|
-
if (btype == 0) {
|
768
|
-
/* This function only supports LZ77 compression. DeflateSplittingFirst
|
769
|
-
supports the special case of noncompressed data. Punt it to that one. */
|
770
|
-
DeflateSplittingFirst(options, btype, final,
|
771
|
-
in, instart, inend,
|
772
|
-
bp, out, outsize);
|
773
|
-
}
|
774
|
-
assert(btype == 1 || btype == 2);
|
775
|
-
|
776
|
-
ZopfliInitLZ77Store(&store);
|
777
|
-
|
778
|
-
s.options = options;
|
779
|
-
s.blockstart = instart;
|
780
|
-
s.blockend = inend;
|
781
|
-
#ifdef ZOPFLI_LONGEST_MATCH_CACHE
|
782
|
-
s.lmc = (ZopfliLongestMatchCache*)malloc(sizeof(ZopfliLongestMatchCache));
|
783
|
-
ZopfliInitCache(inend - instart, s.lmc);
|
784
|
-
#endif
|
877
|
+
ZopfliBlockSplitLZ77(options, &lz77,
|
878
|
+
options->blocksplittingmax, &splitpoints2, &npoints2);
|
785
879
|
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
}
|
880
|
+
for (i = 0; i <= npoints2; i++) {
|
881
|
+
size_t start = i == 0 ? 0 : splitpoints2[i - 1];
|
882
|
+
size_t end = i == npoints2 ? lz77.size : splitpoints2[i];
|
883
|
+
totalcost2 += ZopfliCalculateBlockSizeAutoType(&lz77, start, end);
|
884
|
+
}
|
792
885
|
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
886
|
+
if (totalcost2 < totalcost) {
|
887
|
+
free(splitpoints);
|
888
|
+
splitpoints = splitpoints2;
|
889
|
+
npoints = npoints2;
|
890
|
+
} else {
|
891
|
+
free(splitpoints2);
|
892
|
+
}
|
799
893
|
}
|
800
894
|
|
801
895
|
for (i = 0; i <= npoints; i++) {
|
802
896
|
size_t start = i == 0 ? 0 : splitpoints[i - 1];
|
803
|
-
size_t end = i == npoints ?
|
804
|
-
|
805
|
-
|
806
|
-
|
897
|
+
size_t end = i == npoints ? lz77.size : splitpoints[i];
|
898
|
+
AddLZ77BlockAutoType(options, i == npoints && final,
|
899
|
+
&lz77, start, end, 0,
|
900
|
+
bp, out, outsize);
|
807
901
|
}
|
808
902
|
|
809
|
-
|
810
|
-
ZopfliCleanCache(s.lmc);
|
811
|
-
free(s.lmc);
|
812
|
-
#endif
|
813
|
-
|
814
|
-
ZopfliCleanLZ77Store(&store);
|
903
|
+
ZopfliCleanLZ77Store(&lz77);
|
815
904
|
free(splitpoints);
|
816
|
-
|
817
|
-
|
818
|
-
/*
|
819
|
-
Deflate a part, to allow ZopfliDeflate() to use multiple master blocks if
|
820
|
-
needed.
|
821
|
-
It is possible to call this function multiple times in a row, shifting
|
822
|
-
instart and inend to next bytes of the data. If instart is larger than 0, then
|
823
|
-
previous bytes are used as the initial dictionary for LZ77.
|
824
|
-
This function will usually output multiple deflate blocks. If final is 1, then
|
825
|
-
the final bit will be set on the last block.
|
826
|
-
*/
|
827
|
-
void ZopfliDeflatePart(const ZopfliOptions* options, int btype, int final,
|
828
|
-
const unsigned char* in, size_t instart, size_t inend,
|
829
|
-
unsigned char* bp, unsigned char** out,
|
830
|
-
size_t* outsize) {
|
831
|
-
if (options->blocksplitting) {
|
832
|
-
if (options->blocksplittinglast) {
|
833
|
-
DeflateSplittingLast(options, btype, final, in, instart, inend,
|
834
|
-
bp, out, outsize);
|
835
|
-
} else {
|
836
|
-
DeflateSplittingFirst(options, btype, final, in, instart, inend,
|
837
|
-
bp, out, outsize);
|
838
|
-
}
|
839
|
-
} else {
|
840
|
-
DeflateBlock(options, btype, final, in, instart, inend, bp, out, outsize);
|
841
|
-
}
|
905
|
+
free(splitpoints_uncompressed);
|
842
906
|
}
|
843
907
|
|
844
908
|
void ZopfliDeflate(const ZopfliOptions* options, int btype, int final,
|
@@ -849,19 +913,19 @@ void ZopfliDeflate(const ZopfliOptions* options, int btype, int final,
|
|
849
913
|
ZopfliDeflatePart(options, btype, final, in, 0, insize, bp, out, outsize);
|
850
914
|
#else
|
851
915
|
size_t i = 0;
|
852
|
-
|
916
|
+
do {
|
853
917
|
int masterfinal = (i + ZOPFLI_MASTER_BLOCK_SIZE >= insize);
|
854
918
|
int final2 = final && masterfinal;
|
855
919
|
size_t size = masterfinal ? insize - i : ZOPFLI_MASTER_BLOCK_SIZE;
|
856
920
|
ZopfliDeflatePart(options, btype, final2,
|
857
921
|
in, i, i + size, bp, out, outsize);
|
858
922
|
i += size;
|
859
|
-
}
|
923
|
+
} while (i < insize);
|
860
924
|
#endif
|
861
925
|
if (options->verbose) {
|
862
926
|
fprintf(stderr,
|
863
|
-
"Original Size: %
|
864
|
-
(
|
927
|
+
"Original Size: %lu, Deflate: %lu, Compression: %f%% Removed\n",
|
928
|
+
(unsigned long)insize, (unsigned long)(*outsize - offset),
|
865
929
|
100.0 * (double)(insize - (*outsize - offset)) / (double)insize);
|
866
930
|
}
|
867
931
|
}
|