public void Extract(Stream input)
        {
            int[] coeff;
            int i, n, k, hash, code;

            using (HuffmanDecode hd = new HuffmanDecode(input))
            {
                 coeff = hd.Decode();
            }

            logger.Info("Permutation starts");
            Permutation permutation = new Permutation(coeff.Length, this.random);
            logger.Info(coeff.Length + " indices shuffled");

            // extract length information
            CalcEmbeddedLength(permutation, coeff);
            k = (this.extractedFileLength >> 24) % 32;
            n = (1 << k) - 1;
            this.extractedFileLength &= 0x007fffff;

            logger.Info("Length of embedded file: " + extractedFileLength + " bytes");

            if (n > 0)
            {
                while (true)
                {
                    hash = 0;
                    code = 1;
                    while (code <= n)
                    {
                        this.pos++;
                        if (this.pos >= coeff.Length)
                            goto leaveContext;
                        this.shuffledIndex = permutation.GetShuffled(this.pos);
                        this.extractedBit = ExtractBit(coeff);
                        if (this.extractedBit == -1)
                            continue;
                        else if (this.extractedBit == 1)
                            hash ^= code;
                        code++;
                    }

                    for (i = 0; i < k; i++)
                    {
                        this.extractedByte |= (hash >> i & 1) << this.availableExtractedBits++;
                        if (this.availableExtractedBits == 8)
                        {
                            WriteExtractedByte();
                            // check for pending end of embedded data
                            if (this.nBytesExtracted == this.extractedFileLength)
                                goto leaveContext;
                        }
                    }
                }
            }
            else
            {
                while (++this.pos < coeff.Length && this.pos < permutation.Length)
                {
                    this.shuffledIndex = permutation.GetShuffled(this.pos);
                    this.extractedBit = ExtractBit(coeff);
                    if (this.extractedBit == -1)
                        continue;
                    this.extractedByte |= this.extractedBit << this.availableExtractedBits++;
                    if (this.availableExtractedBits == 8)
                    {
                        WriteExtractedByte();
                        if (this.nBytesExtracted == extractedFileLength)
                            break;
                    }
                }
            }
            leaveContext: ;
            if (this.nBytesExtracted < this.extractedFileLength)
            {
                logger.Warn("Incomplete file: only " + this.nBytesExtracted +
                    " of " + this.extractedFileLength + " bytes extracted");
            }
        }
        /// <summary>
        /// This method controls the compression of the image. Starting at the
        /// upper left of the image, it compresses 8x8 blocks of data until the
        /// entire image has been compressed.
        /// </summary>
        /// <param name="out"></param>
        private void WriteCompressedData()
        {
            // This initial setting of MinBlockWidth and MinBlockHeight is done to
            // ensure they start with values larger than will actually be the case.
            int MinBlockWidth = this.imageWidth % 8 != 0 ? (int)(Math.Floor(this.imageWidth / 8.0) + 1) * 8 : this.imageWidth;
            int MinBlockHeight = this.imageHeight % 8 != 0 ? (int)(Math.Floor(this.imageHeight / 8.0) + 1) * 8 : this.imageHeight;
            int comp, shuffledIndex;
            for (comp = 0; comp < JpegInfo.NumberOfComponents; comp++)
            {
                MinBlockWidth = Math.Min(MinBlockWidth, this.JpegObj.BlockWidth[comp]);
                MinBlockHeight = Math.Min(MinBlockHeight, this.JpegObj.BlockHeight[comp]);
            }

            int[] lastDCvalue = new int[JpegInfo.NumberOfComponents];
            int[] emptyArray = new int[64];
            int[] coeff = GetCoeff(MinBlockWidth, MinBlockHeight);
            int coeffCount = coeff.Length;
            int i, j, r, c;
            int _changed = 0;
            int _embedded = 0;
            int _examined = 0;
            int _expected = 0;
            int _one = 0;
            int _large = 0;
            int _thrown = 0;
            int _zero = 0;

            logger.Info("got " + coeffCount + " DCT AC/DC coefficients");
            for (i = 0; i < coeffCount; i++)
            {
                if (i % 64 == 0)
                    continue;
                else if (coeff[i] == 1 || coeff[i] == -1)
                    _one++;
                else if (coeff[i] == 0)
                    _zero++;
            }
            _large = coeffCount - _zero - _one - coeffCount / 64;
            _expected = _large + (int)(0.49 * _one);
            //

            logger.Info("one=" + _one);
            logger.Info("large=" + _large);
            //
            logger.Info("expected capacity: " + _expected + " bits");
            logger.Info("expected capacity with");

            for (i = 1; i < 8; i++)
            {
                int usable, changed, n;
                n = (1 << i) - 1;
                usable = _expected * i / n - _expected * i / n % n;
                changed = coeffCount - _zero - coeffCount / 64;
                changed = changed * i / n - changed * i / n % n;
                changed = n * changed / (n + 1) / i;
                //
                changed = _large - _large % (n + 1);
                changed = (changed + _one + _one / 2 - _one / (n + 1)) / (n + 1);
                usable /= 8;
                if (usable == 0)
                    break;
                if (i == 1)
                    logger.Info("default");
                else
                    logger.Info("(1, " + n + ", " + i + ")");
                logger.Info(" code: " + usable + " bytes (efficiency: " + usable * 8 / changed + "." +
                    usable * 80 / changed % 10 + " bits per change)");
            }

            // westfeld
            if (this.embeddedData != null)
            {
                // Now we embed the secret data in the permutated sequence.
                logger.Info("Permutation starts");
                F5Random random = new F5Random(Encoding.ASCII.GetBytes(this.password));
                Permutation permutation = new Permutation(coeffCount, random);
                int nextBitToEmbed = 0;
                int byteToEmbed = Convert.ToInt32(this.embeddedData.Length);
                int availableBitsToEmbed = 0;
                // We start with the length information. Well,
                // the length information it is more than one
                // byte, so this first "byte" is 32 bits long.

                /*try {
                    byteToEmbed = this.embeddedData.available();
                } catch (final Exception e) {
                    e.printStackTrace();
                }*/

                logger.Info("Embedding of " + (byteToEmbed * 8 + 32) + " bits (" + byteToEmbed + "+4 bytes) ");
                // We use the most significant byte for the 1 of n
                // code, and reserve one extra bit for future use.
                if (byteToEmbed > 0x007fffff)
                {
                    byteToEmbed = 0x007fffff;
                }
                // We calculate n now
                for (i = 1; i < 8; i++)
                {
                    int usable;
                    this.n = (1 << i) - 1;
                    usable = _expected * i / this.n - _expected * i / this.n % this.n;
                    usable /= 8;
                    if (usable == 0)
                    {
                        break;
                    }
                    if (usable < byteToEmbed + 4)
                    {
                        break;
                    }
                }
                int k = i - 1;
                this.n = (1 << k) - 1;
                switch (this.n)
                {
                    case 0:
                        logger.Info("using default code, file will not fit");
                        this.n++;
                        break;
                    case 1:
                        logger.Info("using default code");
                        break;
                    default:
                        logger.Info("using (1, " + this.n + ", " + k + ") code");
                        break;
                }
                byteToEmbed |= k << 24; // store k in the status word
                // Since shuffling cannot hide the distribution, the
                // distribution of all bits to embed is unified by
                // adding a pseudo random bit-string. We continue the random
                // we used for Permutation, initially seeked with password.
                byteToEmbed ^= random.GetNextByte();
                byteToEmbed ^= random.GetNextByte() << 8;
                byteToEmbed ^= random.GetNextByte() << 16;
                byteToEmbed ^= random.GetNextByte() << 24;
                nextBitToEmbed = byteToEmbed & 1;
                byteToEmbed >>= 1;
                availableBitsToEmbed = 31;
                _embedded++;

                for (i = 0; i < permutation.Length; i++)
                {
                    int shuffled_index = permutation.GetShuffled(i);

                    if (shuffled_index % 64 == 0 || coeff[shuffled_index] == 0)
                        continue;

                    var cc = coeff[shuffled_index];
                    _examined += 1;

                    if (cc > 0 && (cc & 1) != nextBitToEmbed)
                    {
                        coeff[shuffled_index]--;
                        _changed++;
                    }
                    else if (cc < 0 && (cc & 1) == nextBitToEmbed)
                    {
                        coeff[shuffled_index]++;
                        _changed++;
                    }

                    if (coeff[shuffled_index] != 0)
                    {
                        if (availableBitsToEmbed == 0)
                        {
                            if (n > 1 || embeddedData.Available == 1)
                                break;

                            byteToEmbed = embeddedData.Read();
                            byteToEmbed ^= random.GetNextByte();
                            availableBitsToEmbed = 8;
                        }
                        nextBitToEmbed = byteToEmbed & 1;
                        byteToEmbed >>= 1;
                        availableBitsToEmbed--;
                        _embedded++;
                    }
                    else
                        _thrown++;
                }

                if (n > 1)
                {
                    bool isLastByte = false;
                    FilteredCollection filtered_index = permutation.Filter(coeff, i + 1);
                    while (!isLastByte)
                    {
                        int kBitsToEmbed = 0;
                        for (i = 0; i < k; i++)
                        {
                            if (availableBitsToEmbed == 0)
                            {
                                if (embeddedData.Available == 0)
                                {
                                    isLastByte = true;
                                    break;
                                }
                                byteToEmbed = embeddedData.Read();
                                byteToEmbed ^= random.GetNextByte();
                                availableBitsToEmbed = 8;
                            }
                            nextBitToEmbed = byteToEmbed & 1;
                            byteToEmbed >>= 1;
                            availableBitsToEmbed--;
                            kBitsToEmbed |= nextBitToEmbed << i;
                            _embedded++;
                        }

                        List<int> codeWord = filtered_index.Offer(this.n);
                        int extractedBit;
                        while (true)
                        {
                            int vhash = 0;
                            int count = codeWord.Count;
                            for (i = 0; i < count; i++)
                            {
                                int index = codeWord[i];
                                extractedBit = coeff[index] > 0 ? coeff[index] & 1 : (1 - (coeff[index] & 1));
                                if (extractedBit == 1)
                                {
                                    vhash ^= i + 1;
                                }
                            }
                            i = vhash ^ kBitsToEmbed;
                            if (i == 0)
                                break;
                            i--;

                            if (coeff[codeWord[i]] < 0)
                                coeff[codeWord[i]]++;
                            else
                                coeff[codeWord[i]]--;
                            _changed++;

                            if (coeff[codeWord[i]] == 0)
                            {
                                _thrown++;
                                codeWord.RemoveAt(i);
                                codeWord.Add(filtered_index.Offer());
                            }
                        }
                    }
                }
            }

            logger.Info("Starting Huffman Encoding.");
            shuffledIndex = 0;
            for (r = 0; r < MinBlockHeight; r++)
            {
                for (c = 0; c < MinBlockWidth; c++)
                {
                    for (comp = 0; comp < JpegInfo.NumberOfComponents; comp++)
                    {
                        for (i = 0; i < JpegObj.VsampFactor[comp]; i++)
                        {
                            for (j = 0; j < JpegObj.HsampFactor[comp]; j++)
                            {
                                Array.Copy(coeff, shuffledIndex, emptyArray, 0, 64);
                                this.huffman.HuffmanBlockEncoder(this.output, emptyArray, lastDCvalue[comp],
                                    this.JpegObj.DCtableNumber[comp], this.JpegObj.ACtableNumber[comp]);
                                lastDCvalue[comp] = emptyArray[0];
                                shuffledIndex += 64;
                            }
                        }
                    }
                }
            }
            this.huffman.FlushBuffer(this.output);
        }
        /// <summary>
        /// extract length information
        /// </summary>
        private void CalcEmbeddedLength(Permutation permutation, int[] coeff)
        {
            this.extractedFileLength = 0;
            this.pos = -1;

            int i = 0;
            while (i < 32 && ++this.pos < coeff.Length)
            {
                this.shuffledIndex = permutation.GetShuffled(this.pos);
                this.extractedBit = ExtractBit(coeff);
                if (this.extractedBit == -1)
                    continue;
                this.extractedFileLength |= this.extractedBit << i++;
            }

            // remove pseudo random pad
            this.extractedFileLength ^= this.random.GetNextByte();
            this.extractedFileLength ^= this.random.GetNextByte() << 8;
            this.extractedFileLength ^= this.random.GetNextByte() << 16;
            this.extractedFileLength ^= this.random.GetNextByte() << 24;
        }