/// Copyright (c) 2008 Jeffrey Powers for Fluxcapacity Open Source. /// Under the MIT License, details: License.txt. // Partially derives from a Java encoder, JpegEncoder.java by James R Weeks. // Implements Baseline JPEG Encoding http://www.opennet.ru/docs/formats/jpeg.txt using System; using FluxJpeg.Core.IO; using System.IO; using System.Collections.Generic; namespace FluxJpeg.Core { internal class HuffmanTable { public static int HUFFMAN_MAX_TABLES = 4; private short[] huffcode = new short[256]; private short[] huffsize = new short[256]; private short[] valptr = new short[16]; private short[] mincode = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,-1,-1}; private short[] maxcode = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; private short[] huffval; private short[] bits; int bufferPutBits, bufferPutBuffer; internal int ImageHeight; internal int ImageWidth; internal int[,] DC_matrix0; internal int[,] AC_matrix0; internal int[,] DC_matrix1; internal int[,] AC_matrix1; internal int[][,] DC_matrix; internal int[][,] AC_matrix; internal int NumOfDCTables; internal int NumOfACTables; public List bitsList; public List val; public static byte JPEG_DC_TABLE = 0; public static byte JPEG_AC_TABLE = 1; private short lastk = 0; internal HuffmanTable(JpegHuffmanTable table) { if (table != null) { huffval = table.Values; bits = table.Lengths; GenerateSizeTable(); GenerateCodeTable(); GenerateDecoderTables(); } else { // Encode initialization bitsList = new List(); bitsList.Add(JpegHuffmanTable.StdDCLuminance.Lengths); bitsList.Add(JpegHuffmanTable.StdACLuminance.Lengths); bitsList.Add(JpegHuffmanTable.StdDCChrominance.Lengths); bitsList.Add(JpegHuffmanTable.StdACChrominance.Lengths); val = new List(); val.Add(JpegHuffmanTable.StdDCLuminance.Values); val.Add(JpegHuffmanTable.StdACLuminance.Values); val.Add(JpegHuffmanTable.StdDCChrominance.Values); val.Add(JpegHuffmanTable.StdACChrominance.Values); initHuf(); } } /// See Figure C.1 private void GenerateSizeTable() { short index = 0; for (short i = 0; i < bits.Length; i++) { for (short j = 0; j < bits[i]; j++) { huffsize[index] = (short)(i + 1); index++; } } lastk = index; } /// See Figure C.2 private void GenerateCodeTable() { short k = 0; short si = huffsize[0]; short code = 0; for (short i = 0; i < huffsize.Length; i++) { while (huffsize[k] == si) { huffcode[k] = code; code++; k++; } code <<= 1; si++; } } /// See figure F.15 private void GenerateDecoderTables() { short bitcount = 0; for (int i = 0; i < 16; i++) { if (bits[i] != 0) valptr[i] = bitcount; for (int j = 0; j < bits[i]; j++) { if (huffcode[j + bitcount] < mincode[i] || mincode[i] == -1) mincode[i] = huffcode[j + bitcount]; if (huffcode[j + bitcount] > maxcode[i]) maxcode[i] = huffcode[j + bitcount]; } if (mincode[i] != -1) valptr[i] = (short)(valptr[i] - mincode[i]); bitcount += bits[i]; } } /// Figure F.12 public static int Extend(int diff, int t) { // here we use bitshift to implement 2^ ... // NOTE: Math.Pow returns 0 for negative powers, which occassionally happen here! int Vt = 1 << t - 1; // WAS: int Vt = (int)Math.Pow(2, (t - 1)); if (diff < Vt) { Vt = (-1 << t) + 1; diff = diff + Vt; } return diff; } /// Figure F.16 - Reads the huffman code bit-by-bit. /*public int Decode(JPEGBinaryReader JPEGStream) { int i = 0; short code = (short)JPEGStream.ReadBits(1); while (code > maxcode[i]) { i++; code <<= 1; code |= (short)JPEGStream.ReadBits(1); } int val = huffval[code + (valptr[i])]; if (val < 0) val = 256 + val; return val; }*/ /// /// HuffmanBlockEncoder run length encodes and Huffman encodes the quantized data. /// internal void HuffmanBlockEncoder(Stream outStream, int[] zigzag, int prec, int DCcode, int ACcode) { int temp, temp2, nbits, k, r, i; NumOfDCTables = 2; NumOfACTables = 2; // The DC portion temp = temp2 = zigzag[0] - prec; if (temp < 0) { temp = -temp; temp2--; } nbits = 0; while (temp != 0) { nbits++; temp >>= 1; } // if (nbits > 11) nbits = 11; bufferIt(outStream, DC_matrix[DCcode][nbits, 0], DC_matrix[DCcode][nbits, 1]); // The arguments in bufferIt are code and size. if (nbits != 0) { bufferIt(outStream, temp2, nbits); } // The AC portion r = 0; for (k = 1; k < 64; k++) { if ((temp = zigzag[ ZigZag.ZigZagMap[k] ]) == 0) { r++; } else { while (r > 15) { bufferIt(outStream, AC_matrix[ACcode][0xF0, 0], AC_matrix[ACcode][0xF0, 1]); r -= 16; } temp2 = temp; if (temp < 0) { temp = -temp; temp2--; } nbits = 1; while ((temp >>= 1) != 0) { nbits++; } i = (r << 4) + nbits; bufferIt(outStream, AC_matrix[ACcode][i, 0], AC_matrix[ACcode][i, 1]); bufferIt(outStream, temp2, nbits); r = 0; } } if (r > 0) { bufferIt(outStream, AC_matrix[ACcode][0, 0], AC_matrix[ACcode][0, 1]); } } /// /// Uses an integer long (32 bits) buffer to store the Huffman encoded bits /// and sends them to outStream by the byte. /// void bufferIt(Stream outStream, int code, int size) { int PutBuffer = code; int PutBits = bufferPutBits; PutBuffer &= (1 << size) - 1; PutBits += size; PutBuffer <<= 24 - PutBits; PutBuffer |= bufferPutBuffer; while (PutBits >= 8) { int c = ((PutBuffer >> 16) & 0xFF); outStream.WriteByte((byte)c); // FF must be escaped if (c == 0xFF) outStream.WriteByte(0); PutBuffer <<= 8; PutBits -= 8; } bufferPutBuffer = PutBuffer; bufferPutBits = PutBits; } public void FlushBuffer(Stream outStream) { int PutBuffer = bufferPutBuffer; int PutBits = bufferPutBits; while (PutBits >= 8) { int c = ((PutBuffer >> 16) & 0xFF); outStream.WriteByte((byte)c); // FF must be escaped if (c == 0xFF) outStream.WriteByte(0); PutBuffer <<= 8; PutBits -= 8; } if (PutBits > 0) { int c = ((PutBuffer >> 16) & 0xFF); outStream.WriteByte((byte)c); } } /// /// Initialisation of the Huffman codes for Luminance and Chrominance. /// This code results in the same tables created in the IJG Jpeg-6a /// library. /// public void initHuf() { DC_matrix0 = new int[12, 2]; DC_matrix1 = new int[12, 2]; AC_matrix0 = new int[255, 2]; AC_matrix1 = new int[255, 2]; DC_matrix = new int[2][,]; AC_matrix = new int[2][,]; int p, l, i, lastp, si, code; int[] huffsize = new int[257]; int[] huffcode = new int[257]; short[] bitsDCchrominance = JpegHuffmanTable.StdDCChrominance.Lengths; short[] bitsACchrominance = JpegHuffmanTable.StdACChrominance.Lengths; short[] bitsDCluminance = JpegHuffmanTable.StdDCLuminance.Lengths; short[] bitsACluminance = JpegHuffmanTable.StdACLuminance.Lengths; short[] valDCchrominance = JpegHuffmanTable.StdDCChrominance.Values; short[] valACchrominance = JpegHuffmanTable.StdACChrominance.Values; short[] valDCluminance = JpegHuffmanTable.StdDCLuminance.Values; short[] valACluminance = JpegHuffmanTable.StdACLuminance.Values; /* * init of the DC values for the chrominance * [,0] is the code [,1] is the number of bit */ p = 0; for (l = 0; l < 16; l++) { for (i = 1; i <= bitsDCchrominance[l]; i++) { huffsize[p++] = l+1; } } huffsize[p] = 0; lastp = p; code = 0; si = huffsize[0]; p = 0; while (huffsize[p] != 0) { while (huffsize[p] == si) { huffcode[p++] = code; code++; } code <<= 1; si++; } for (p = 0; p < lastp; p++) { DC_matrix1[valDCchrominance[p], 0] = huffcode[p]; DC_matrix1[valDCchrominance[p], 1] = huffsize[p]; } /* * Init of the AC hufmann code for the chrominance * matrix [,,0] is the code & matrix[,,1] is the number of bit needed */ p = 0; for (l = 0; l < 16; l++) { for (i = 1; i <= bitsACchrominance[l]; i++) { huffsize[p++] = l+1; } } huffsize[p] = 0; lastp = p; code = 0; si = huffsize[0]; p = 0; while (huffsize[p] != 0) { while (huffsize[p] == si) { huffcode[p++] = code; code++; } code <<= 1; si++; } for (p = 0; p < lastp; p++) { AC_matrix1[valACchrominance[p], 0] = huffcode[p]; AC_matrix1[valACchrominance[p], 1] = huffsize[p]; } /* * init of the DC values for the luminance * [,0] is the code [,1] is the number of bit */ p = 0; for (l = 0; l < 16; l++) { for (i = 1; i <= bitsDCluminance[l]; i++) { huffsize[p++] = l+1; } } huffsize[p] = 0; lastp = p; code = 0; si = huffsize[0]; p = 0; while (huffsize[p] != 0) { while (huffsize[p] == si) { huffcode[p++] = code; code++; } code <<= 1; si++; } for (p = 0; p < lastp; p++) { DC_matrix0[valDCluminance[p], 0] = huffcode[p]; DC_matrix0[valDCluminance[p], 1] = huffsize[p]; } /* * Init of the AC hufmann code for luminance * matrix [,,0] is the code & matrix[,,1] is the number of bit */ p = 0; for (l = 0; l < 16; l++) { for (i = 1; i <= bitsACluminance[l]; i++) { huffsize[p++] = l+1; } } huffsize[p] = 0; lastp = p; code = 0; si = huffsize[0]; p = 0; while (huffsize[p] != 0) { while (huffsize[p] == si) { huffcode[p++] = code; code++; } code <<= 1; si++; } for (int q = 0; q < lastp; q++) { AC_matrix0[valACluminance[q], 0] = huffcode[q]; AC_matrix0[valACluminance[q], 1] = huffsize[q]; } DC_matrix[0] = DC_matrix0; DC_matrix[1] = DC_matrix1; AC_matrix[0] = AC_matrix0; AC_matrix[1] = AC_matrix1; } } }