static void ZopfliLZ77OptimalFixed(ZopfliBlockState s, byte[] InFile, ulong instart, ulong inend, ZopfliLZ77Store store) { /* Dist to get to here with smallest cost. */ ulong blocksize = inend - instart; ushort[] length_array = new ushort[blocksize + 1]; List <ushort> path = new List <ushort>(); path.Add(0); ZopfliHash h = new ZopfliHash(); float[] costs = new float[blocksize + 1]; SymbolStats stats = new SymbolStats(); s.blockstart = (int)instart; s.blockend = (int)inend; /* Shortest path for fixed tree This one should give the shortest possible * result for fixed tree, no repeated runs are needed since the tree is known. */ LZ77OptimalRun(s, InFile, (int)instart, (int)inend, path, length_array, stats, store, h, costs, true); }
static void ZopfliCopyLZ77Store( ZopfliLZ77Store source, ZopfliLZ77Store dest) { dest.ResetStore(source.data); dest.litlens = new List <ushort>(source.litlens); dest.ll_counts = new List <ulong>(source.ll_counts); dest.d_counts = new List <ulong>(source.d_counts); dest.ll_symbol = new List <ushort>(source.ll_symbol); dest.d_symbol = new List <ushort>(source.d_symbol); dest.pos = new List <ulong>(source.pos); dest.dists = new List <ushort>(source.dists); dest.size = source.size; }
/* * Does a single run for ZopfliLZ77Optimal. For good compression, repeated runs * with updated statistics should be performed. * s: the block state * in: the input data array * instart: where to start * inend: where to stop (not inclusive) * path: pointer to dynamically allocated memory to store the path * pathsize: pointer to the size of the dynamic path array * length_array: array of size (inend - instart) used to store lengths * costmodel: function to use as the cost model for this squeeze run * costcontext: abstract context for the costmodel function * store: place to output the LZ77 data * returns the cost that was, according to the costmodel, needed to get to the end. * This is not the actual cost. */ static double LZ77OptimalRun(ZopfliBlockState s, byte[] InFile, int instart, int inend, List <ushort> path, ushort[] length_array, SymbolStats stats, ZopfliLZ77Store store, ZopfliHash h, float[] costs, bool fixedcosts) { double cost = GetBestLengths(s, InFile, instart, inend, stats, length_array, h, costs, fixedcosts); ulong pathsize = 0; path.Clear(); TraceBackwards((ulong)(inend - instart), length_array, path, ref pathsize); FollowPath(s, InFile, instart, inend, path, pathsize, store, h); Debug.Assert(cost < ZOPFLI_LARGE_FLOAT); return(cost); }
/* Appends the symbol statistics from the store. */ static void GetStatistics(ZopfliLZ77Store store, SymbolStats stats) { ulong i; for (i = 0; i < store.size; i++) { if (store.dists[(int)i] == 0) { stats.litlens[store.litlens[(int)i]]++; } else { stats.litlens[Symbols.ZopfliGetLengthSymbol(store.litlens[(int)i])]++; stats.dists[Symbols.ZopfliGetDistSymbol(store.dists[(int)i])]++; } } stats.litlens[256] = 1; /* End symbol. */ stats.CalculateStatistics(); }
static void ZopfliLZ77Optimal(ZopfliBlockState s, byte[] InFile, int instart, int inend, int numiterations, ZopfliLZ77Store store) { /* Dist to get to here with smallest cost. */ int blocksize = inend - instart; ushort[] length_array = new ushort[blocksize + 1]; List <ushort> path = new List <ushort>(); ZopfliLZ77Store currentstore = new ZopfliLZ77Store(InFile); ZopfliHash h = new ZopfliHash(); SymbolStats stats = new SymbolStats(); SymbolStats beststats = new SymbolStats(); SymbolStats laststats = new SymbolStats(); int i; float[] costs = new float [blocksize + 1]; double cost; double bestcost = ZOPFLI_LARGE_FLOAT; double lastcost = 0; /* Try randomizing the costs a bit once the size stabilizes. */ RanState ran_state = new RanState(); int lastrandomstep = -1; /* Do regular deflate, then loop multiple shortest path runs, each time using * the statistics of the previous run. */ /* Initial run. */ ZopfliLZ77Greedy(s, InFile, instart, inend, currentstore, h); GetStatistics(currentstore, stats); /* Repeat statistics with each time the cost model from the previous stat * run. */ for (i = 0; i < numiterations; i++) { currentstore.ResetStore(InFile); LZ77OptimalRun(s, InFile, instart, inend, path, length_array, stats, currentstore, h, costs, false); cost = ZopfliCalculateBlockSize(currentstore, 0, currentstore.size, 2); if (Globals.verbose_more > 0 || (Globals.verbose > 0 && cost < bestcost)) { Console.WriteLine("Iteration " + i + ": " + cost + " bit"); } if (cost < bestcost) { /* Copy to the output store. */ ZopfliCopyLZ77Store(currentstore, store); CopyStats(stats, ref beststats); bestcost = cost; } CopyStats(stats, ref laststats); ClearStatFreqs(stats); GetStatistics(currentstore, stats); if (lastrandomstep != -1) { /* This makes it converge slower but better. Do it only once the * randomness kicks in so that if the user does few iterations, it gives a * better result sooner. */ AddWeighedStatFreqs(stats, 1.0, laststats, 0.5, stats); stats.CalculateStatistics(); } if (i > 5 && cost == lastcost) { CopyStats(beststats, ref stats); RandomizeStatFreqs(ran_state, stats); stats.CalculateStatistics(); lastrandomstep = i; } lastcost = cost; } }
static void FollowPath(ZopfliBlockState s, byte[] InFile, int instart, int inend, List <ushort> path, ulong pathsize, ZopfliLZ77Store store, ZopfliHash h) { int i, j, pos; int windowstart = instart > ZopfliHash.ZOPFLI_WINDOW_SIZE ? instart - ZopfliHash.ZOPFLI_WINDOW_SIZE : 0; ulong total_length_test = 0; if (instart == inend) { return; } h.ZopfliResetHash(); h.ZopfliWarmupHash(InFile, windowstart, inend); for (i = windowstart; i < instart; i++) { h.ZopfliUpdateHash(InFile, i, inend); } pos = instart; for (i = 0; i < (int)pathsize; i++) { ushort length = path[i]; ushort dummy_length = 0; ushort dist = 0; Debug.Assert(pos < inend); h.ZopfliUpdateHash(InFile, pos, inend); /* Add to output. */ if (length >= ZOPFLI_MIN_MATCH) { /* Get the distance by recalculating longest match. The found length * should match the length from the path. */ ZopfliFindLongestMatch(s, h, InFile, pos, inend, length, null, ref dist, ref dummy_length); Debug.Assert(!(dummy_length != length && length > 2 && dummy_length > 2)); ZopfliVerifyLenDist(InFile, inend, pos, dist, length); ZopfliStoreLitLenDist(length, dist, pos, store); total_length_test += length; } else { length = 1; ZopfliStoreLitLenDist(InFile[pos], 0, pos, store); total_length_test++; } Debug.Assert(pos + length <= inend); for (j = 1; j < length; j++) { h.ZopfliUpdateHash(InFile, pos + j, inend); } pos += length; } }