public override void Encode(IntField image, Stream output) { // Predictive transform image.ArgbTo4c(); image.PredictionEnTransformXor(Seer); // Convert to three fields' runlengths var fields = CodecUtil.FieldcodeRunlengthsEn2(image, RLE, this); SetCounter("rle|longer", (RLE as RunLength01LongShortCodec).Counter_Longers); SetCounter("rle|muchlonger", (RLE as RunLength01LongShortCodec).Counter_MuchLongers); // Write size DeltaTracker pos = new DeltaTracker(); output.WriteUInt32Optim((uint)image.Width); output.WriteUInt32Optim((uint)image.Height); SetCounter("bytes|size", pos.Next(output.Position)); // Write probs ulong[] probs = CodecUtil.CountValues(fields, RLE.MaxSymbol); CodecUtil.SaveFreqs(output, probs, TimwiCecCompressor.runLProbsProbs, ""); SetCounter("bytes|probs", pos.Next(output.Position)); // Write fields ArithmeticWriter aw = new ArithmeticWriter(output, probs); output.WriteUInt32Optim((uint)fields.Length); foreach (var sym in fields) { aw.WriteSymbol(sym); } aw.Flush(); SetCounter("bytes|fields", pos.Next(output.Position)); }
public static void TestData(int[] data, int symMax, int symDataMax, int rlStages, params int[] symRle) { //int[] trip; //RunLengthCodec enc = new RunLengthCodec(symMax, symDataMax, rlStages, symRle); //RunLengthCodec dec = new RunLengthCodec(symMax, symDataMax, rlStages, symRle); //trip = dec.Decode(enc.Encode(data)); //Assert.IsTrue(data.SequenceEqual(trip)); //ulong[] probs = CodecUtil.CountValues(data); //ArithmeticCodec enca = new ArithmeticCodec(probs); //ArithmeticCodec deca = new ArithmeticCodec(probs); //trip = deca.Decode(enca.Encode(data)); //Assert.IsTrue(data.SequenceEqual(trip)); if (symDataMax == 1) { //RunLength01Codec encz = new RunLength01Codec(); //RunLength01Codec decz = new RunLength01Codec(); //trip = decz.Decode(encz.Encode(data)); //Assert.IsTrue(data.SequenceEqual(trip)); //RunLength01MaxCodec enczm = new RunLength01MaxCodec(15); //RunLength01MaxCodec deczm = new RunLength01MaxCodec(15); //trip = deczm.Decode(enczm.Encode(data)); //Assert.IsTrue(data.SequenceEqual(trip)); //RunLength01MaxSmartCodec enczs = new RunLength01MaxSmartCodec(15); //RunLength01MaxSmartCodec deczs = new RunLength01MaxSmartCodec(15); //trip = deczs.Decode(enczs.Encode(data)); //Assert.IsTrue(data.SequenceEqual(trip)); } { ulong[] input = data.Select(val => (ulong)val).ToArray(); MemoryStream ms = new MemoryStream(); CodecUtil.SaveFreqs(ms, input, TimwiCecCompressor.runLProbsProbs, ""); ms.Position = 0; ulong[] freqs = CodecUtil.LoadFreqs(ms, TimwiCecCompressor.runLProbsProbs, data.Length); Assert.IsTrue(input.SequenceEqual(freqs)); } }
public override void Encode(IntField image, Stream output) { int blocksX = (image.Width + _blocksizeX - 1) / _blocksizeX; int blocksY = (image.Height + _blocksizeY - 1) / _blocksizeY; int blocks = blocksX * blocksY; int[] kinds = new int[blocks]; ulong[] blockHigh = new ulong[blocks]; ulong[] blockLow = new ulong[blocks]; var pixels = image.Data.Select(p => (uint)p).ToArray(); for (int i = 0; i < pixels.Length; i++) { int x = i % image.Width; uint p = pixels[i]; if (p != 0) { int blockIndex = ((i / image.Width) / _blocksizeY) * blocksX + x / _blocksizeX; kinds[blockIndex] |= 1 << (int)(p - 1); int indexInBlock = ((i / image.Width) % _blocksizeY) * _blocksizeX + x % _blocksizeX; if (indexInBlock < 32) { blockLow[blockIndex] |= (ulong)p << (2 * indexInBlock); } else { blockHigh[blockIndex] |= (ulong)p << (2 * (indexInBlock - 32)); } } } // Start writing to the file long pos = 0; output.WriteUInt32Optim((uint)image.Width); output.WriteUInt32Optim((uint)image.Height); SetCounter("bytes|size", output.Position - pos); pos = output.Position; // Some slight optimisations for (int i = 0; i < blocks; i++) { var k = kinds[i]; // If a kind-5 block is sandwiched between two kind-7s, it is worth setting to 7 to improve the run-length encoding if (k == 5 && i > 0 && i < blocks - 1 && kinds[i - 1] == 7 && kinds[i + 1] == 7) { k = kinds[i] = 7; } // Kinds 3 and 6 are the rarest. It is more common for a block to have its top or bottom half all black. // Therefore, redefine 3 and 6 to mean top and bottom half all black. // A block that has kind 5 should also be changed to 3 or 6 if it has one half all black, because // having kind 5 reduces the block's entropy by 1/3, but having one half all black by 1/2. if (k == 3 || k > 4) { kinds[i] = blockLow[i] == 0 ? 3 : blockHigh[i] == 0 ? 6 : k == 5 ? 5 : 7; } } // Encode the kinds as three planes of optim-encoded run lengths long pos2 = 0; var ms = new MemoryStream(); bool curRunData = false; uint curRunLength = 0; for (int c = 0; c < 3; c++) { for (int i = 0; i < blocks; i++) { if (curRunData ^ ((kinds[i] & (1 << c)) != 0)) { ms.WriteUInt32Optim(curRunLength); curRunData = !curRunData; curRunLength = 1; } else { curRunLength++; } } SetCounter("kinds-raw|" + c, ms.Position - pos2); pos2 = ms.Position; } ms.WriteUInt32Optim(curRunLength); ms.Close(); var kindsArr = ms.ToArray(); SetCounter("kinds-raw|error", kindsArr.Length - pos2); // Save the frequencies of each byte in the Optim-encoded run lengths ulong[] kFreq = new ulong[256]; for (int i = 0; i < kindsArr.Length; i++) { kFreq[kindsArr[i]]++; } CodecUtil.SaveFreqs(output, kFreq, kindProbsProbs, "kindProbsProbs"); SetCounter("bytes|kinds|probs", output.Position - pos); pos = output.Position; // Save the run lengths themselves MemoryStream kMaster = new MemoryStream(); var kAcw = new ArithmeticCodingWriter(kMaster, kFreq); foreach (var symb in kindsArr) { kAcw.WriteSymbol(symb); } kAcw.Close(false); var kArr = kMaster.ToArray(); output.WriteUInt32Optim((uint)kindsArr.Length); output.WriteUInt32Optim((uint)kArr.Length); output.Write(kArr, 0, kArr.Length); //Console.WriteLine("krl " + kArr.Length); SetCounter("bytes|kinds|data", output.Position - pos); pos = output.Position; /* * Bitmap bXor = PixelsToBitmap(newPixels, bw, bh); * bXor.Save(target + "-xor.png"); * Bitmap bBlocks = KindsToBitmap(kinds, blocksizeX, blocksizeY, bw, bh); * Graphics g = Graphics.FromImage(bXor); * GraphicsUtil.DrawImageAlpha(g, bBlocks, new Rectangle(0, 0, bw, bh), 0.5f); * bXor.Save(target + "-xor-blocks.png"); * /**/ // Create the sequence of symbols that represents the run lengths for the actual pixels ms = new MemoryStream(); int j = 0; ulong curLength = 0; var kind = kinds[0]; while (j < 3 * pixels.Length) { var c = j / pixels.Length; var i = j % pixels.Length; var x = i % image.Width; if (x % _blocksizeX == 0) { kind = kinds[((i / image.Width) / _blocksizeY) * blocksX + x / _blocksizeX]; } j++; if (kind == 3) { if (((i / image.Width) % _blocksizeY) * _blocksizeX + x % _blocksizeX < 32) { continue; } kind = 7; } else if (kind == 6) { if (((i / image.Width) % _blocksizeY) * _blocksizeX + x % _blocksizeX > 31) { continue; } kind = 7; } else if (((kind % 8) & (1 << c)) == 0) { continue; } if (pixels[i] == c + 1) { ms.WriteUInt64Optim(curLength); curLength = 0; } else if (pixels[i] == 0 || pixels[i] > c + 1) { curLength++; } } if (curLength > 0) { ms.WriteUInt64Optim(curLength); } ms.Close(); var runLengthsArr = ms.ToArray(); // Save the frequencies of each byte in the Optim-encoded run lengths ulong[] freq = new ulong[256]; for (int i = 0; i < runLengthsArr.Length; i++) { freq[runLengthsArr[i]]++; } CodecUtil.SaveFreqs(output, freq, runLProbsProbs, "runLProbsProbs"); SetCounter("bytes|runs|probs", output.Position - pos); pos = output.Position; // Save the run lengths themselves MemoryStream master = new MemoryStream(); master.WriteUInt32Optim((uint)runLengthsArr.Length); var acw = new ArithmeticCodingWriter(master, freq); foreach (var symb in runLengthsArr) { acw.WriteSymbol(symb); } acw.Close(false); var arr = master.ToArray(); output.Write(arr, 0, arr.Length); //Console.WriteLine("rl " + arr.Length); SetCounter("bytes|runs|data", output.Position - pos); pos = output.Position; output.Close(); }