/// If the size of the code is larger than two, we must transmit the length /// of every symbol in the code. To save space, the lengths are themselves /// Huffman-coded with a length code, so the lengths of the length code must /// be stored first. static void WriteNormalCodeLengths(BitWriter b, List <Huffman.Code> codes) { var encodedLengths = EncodeCodeLengths(codes); var lengthHisto = new Histogram(19); for (int i = 0; i < encodedLengths.Count; ++i) { int sym = encodedLengths[i]; lengthHisto.Hit(sym); if (sym >= 16) { i += 1; } } var lengthCodes = Huffman.BuildCodes(lengthHisto, 7); int lengthCodeCount = 0; for (int i = 0; i < 19; ++i) { if (lengthHisto[CODE_LENGTH_ORDER[i]] > 0) { lengthCodeCount = i + 1; } } if (lengthCodeCount < 4) { lengthCodeCount = 4; } b.WriteBits(0, 1); b.WriteBits(lengthCodeCount - 4, 4); for (int i = 0; i < lengthCodeCount; ++i) { b.WriteBits(lengthCodes[CODE_LENGTH_ORDER[i]].Length, 3); } b.WriteBits(0, 1); for (int i = 0; i < encodedLengths.Count; ++i) { int sym = encodedLengths[i]; b.WriteCode(lengthCodes[sym]); if (sym == 16) { b.WriteBits(encodedLengths[++i], 2); } else if (sym == 17) { b.WriteBits(encodedLengths[++i], 3); } else if (sym == 18) { b.WriteBits(encodedLengths[++i], 7); } } }
/// Encodes the image into entropy-coded bitstream. The isRecursive flag /// must be true iff the data represents the main ARGB image. internal static void WriteImageData(BitWriter b, Image image, bool isRecursive, int colorCacheBits = 0) { if (colorCacheBits > 0) { if (colorCacheBits > 11) { throw new ArgumentException("Too many color cache bits"); } b.WriteBits(1, 1); b.WriteBits(colorCacheBits, 4); } else { b.WriteBits(0, 1); } if (isRecursive) { b.WriteBits(0, 1); // no meta-Huffman image } var encoded = EncodeImageData(image, colorCacheBits); var histos = new List <Histogram> { new Histogram(256 + 24 + (colorCacheBits > 0 ? (1 << colorCacheBits) : 0)), new Histogram(256), new Histogram(256), new Histogram(256), new Histogram(40), }; for (int i = 0; i < encoded.Count; ++i) { histos[0].Hit(encoded[i]); if (encoded[i] < 256) { histos[1].Hit(encoded[i + 1]); histos[2].Hit(encoded[i + 2]); histos[3].Hit(encoded[i + 3]); i += 3; } else if (encoded[i] < 256 + 24) { histos[4].Hit(encoded[i + 2]); i += 3; } } var codess = new List <List <Huffman.Code> >(); for (int i = 0; i < 5; ++i) { var codes = Huffman.BuildCodes(histos[i], 16); CodeLengths.WriteCodeLengths(b, codes); codess.Add(codes); } for (int i = 0; i < encoded.Count; ++i) { b.WriteCode(codess[0][encoded[i]]); if (encoded[i] < 256) { b.WriteCode(codess[1][encoded[i + 1]]); b.WriteCode(codess[2][encoded[i + 2]]); b.WriteCode(codess[3][encoded[i + 3]]); i += 3; } else if (encoded[i] < 256 + 24) { b.WriteBits(encoded[i + 1], ExtraBitsCount(encoded[i] - 256)); b.WriteCode(codess[4][encoded[i + 2]]); b.WriteBits(encoded[i + 3], ExtraBitsCount(encoded[i + 2])); i += 3; } } }