コード例 #1
0
        /// <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);
        }