/// <summary>
        /// Uses an integer long (32 bits) buffer to store the Huffman encoded bits
        /// and sends them to outStream by the byte.
        /// </summary>
        private void bufferIt(EndianBinaryWriter writer, int code, int size)
        {
            int PutBuffer = code;
            int PutBits = this.bufferPutBits;

            PutBuffer &= (1 << size) - 1;
            PutBits += size;
            PutBuffer <<= 24 - PutBits;
            PutBuffer |= this.bufferPutBuffer;

            while (PutBits >= 8)
            {
                int c = (PutBuffer >> 16) & 0xFF;
                writer.Write((byte)c);

                // FF must be escaped
                if (c == 0xFF)
                {
                    writer.Write(0);
                }

                PutBuffer <<= 8;
                PutBits -= 8;
            }

            this.bufferPutBuffer = PutBuffer;
            this.bufferPutBits = PutBits;
        }
        public void FlushBuffer(EndianBinaryWriter writer)
        {
            int PutBuffer = this.bufferPutBuffer;
            int PutBits = this.bufferPutBits;
            while (PutBits >= 8)
            {
                int c = (PutBuffer >> 16) & 0xFF;
                writer.Write((byte)c);

                // FF must be escaped
                if (c == 0xFF) writer.Write(0);

                PutBuffer <<= 8;
                PutBits -= 8;
            }

            if (PutBits > 0)
            {
                int c = (PutBuffer >> 16) & 0xFF;
                writer.Write((byte)c);
            }
        }
        /// <summary>
        /// Figure F.16 - Reads the huffman code bit-by-bit.
        /// </summary>
        /// <param name="writer">The writer.</param>
        /// <param name="zigzag">The zigzag.</param>
        /// <param name="prec">The prec.</param>
        /// <param name="DCcode">The D Ccode.</param>
        /// <param name="ACcode">The A Ccode.</param>
        /// <summary>
        /// HuffmanBlockEncoder run length encodes and Huffman encodes the quantized data.
        /// </summary>
        internal void HuffmanBlockEncoder(EndianBinaryWriter writer, int[] zigzag, int prec, int DCcode, int ACcode)
        {
            int temp, temp2, nbits, k, r, i;

            this.NumOfDCTables = 2;
            this.NumOfACTables = 2;

            // The DC portion
            temp = temp2 = zigzag[0] - prec;
            if (temp < 0)
            {
                temp = -temp;
                temp2--;
            }

            nbits = 0;
            while (temp != 0)
            {
                nbits++;
                temp >>= 1;
            }

            // TODO: Why would this happen?
            //if (nbits > 11) nbits = 11;

            this.bufferIt(writer, this.DC_matrix[DCcode][nbits, 0], this.DC_matrix[DCcode][nbits, 1]);

            // The arguments in bufferIt are code and size.
            if (nbits != 0)
            {
                this.bufferIt(writer, 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)
                    {
                        this.bufferIt(writer, this.AC_matrix[ACcode][0xF0, 0], this.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;
                    this.bufferIt(writer, this.AC_matrix[ACcode][i, 0], this.AC_matrix[ACcode][i, 1]);
                    this.bufferIt(writer, temp2, nbits);

                    r = 0;
                }
            }

            if (r > 0)
            {
                this.bufferIt(writer, this.AC_matrix[ACcode][0, 0], this.AC_matrix[ACcode][0, 1]);
            }
        }