Beispiel #1
0
        /// <summary>
        /// Create a copy by value.
        /// </summary>
        /// <returns>
        /// The newly created copy
        /// </returns>
        public InterWaveBlock Duplicate()
        {
            InterWaveBlock retval = null;

            try
            {
                short[][][] pdata = (short[][][])this._PData.Clone();

                for (int i = 0; i < pdata.Length; i++)
                {
                    if (pdata[i] != null)
                    {
                        pdata[i] = (short[][])pdata[i].Clone();

                        for (int j = 0; j < pdata[i].Length; j++)
                        {
                            if (pdata[i][j] != null)
                            {
                                pdata[i][j] = new short[pdata[i][j].Length];
                                pdata[i][j].CopyTo(pdata[i][j], 0);
                            }
                        }
                    }
                }

                retval = new InterWaveBlock {
                    PData = pdata
                };
            }
            catch
            {
            }

            return(retval);
        }
Beispiel #2
0
        public InterWaveMap(int width, int height)
        {
            Width       = width;
            Height      = height;
            BlockWidth  = ((width + 0x20) - 1) & unchecked ((int)0xffffffe0);
            BlockHeight = ((height + 0x20) - 1) & unchecked ((int)0xffffffe0);
            BlockNumber = (BlockWidth * BlockHeight) / 1024;
            Blocks      = new InterWaveBlock[BlockNumber];

            for (int i = 0; i < Blocks.Length; i++)
            {
                Blocks[i] = new InterWaveBlock();
            }
        }
Beispiel #3
0
        /// <summary>
        /// Estimates image quality in dB.
        /// </summary>
        /// <param name="frac"></param>
        /// <returns></returns>
        public unsafe float EstimateDecibel(float frac)
        {
            int    i, j;
            float *q;

            // Fill norm arrays
            float[] normLo = new float[16];
            float[] normHi = new float[10];

            GCHandle iw = GCHandle.Alloc(iw_norm, GCHandleType.Pinned);

            // -- lo coefficients
            q = (float *)iw.AddrOfPinnedObject();

            for (i = j = 0; i < 4; j++)
            {
                normLo[i++] = *q++;
            }

            for (j = 0; j < 4; j++)
            {
                normLo[i++] = *q;
            }

            q += 1;
            for (j = 0; j < 4; j++)
            {
                normLo[i++] = *q;
            }

            q += 1;
            for (j = 0; j < 4; j++)
            {
                normLo[i++] = *q;
            }

            q += 1;

            // -- hi coefficients
            normHi[0] = 0;
            for (j = 1; j < 10; j++)
            {
                normHi[j] = *q++;
            }

            float[] xMse = new float[_Map.BlockNumber];

            for (int blockno = 0; blockno < _Map.BlockNumber; blockno++)
            {
                float vMse = 0.0f;

                // Iterate over bands
                for (int bandno = 0; bandno < 10; bandno++)
                {
                    int            fbucket = _BandBuckets[bandno].Start;
                    int            nbucket = _BandBuckets[bandno].Size;
                    InterWaveBlock blk     = _Map.Blocks[blockno];
                    InterWaveBlock eblk    = _EMap.Blocks[blockno];

                    float norm = normHi[bandno];

                    for (int buckno = 0; buckno < nbucket; buckno++)
                    {
                        short[] pcoeff  = blk.GetBlock(fbucket + buckno);
                        short[] epcoeff = eblk.GetBlock(fbucket + buckno);

                        if (pcoeff != null)
                        {
                            if (epcoeff != null)
                            {
                                for (i = 0; i < 16; i++)
                                {
                                    if (bandno == 0)
                                    {
                                        norm = normLo[i];
                                    }
                                    float delta = (float)(pcoeff[i] < 0 ? -pcoeff[i] : pcoeff[i]);
                                    delta = delta - epcoeff[i];
                                    vMse  = vMse + norm * delta * delta;
                                }
                            }
                            else
                            {
                                for (i = 0; i < 16; i++)
                                {
                                    if (bandno == 0)
                                    {
                                        norm = normLo[i];
                                    }
                                    float delta = (float)(pcoeff[i]);
                                    vMse = vMse + norm * delta * delta;
                                }
                            }
                        }
                    }
                }
                xMse[blockno] = vMse / 1024;
            }

            // Compute partition point
            int n = 0;
            int m = _Map.BlockNumber - 1;
            int p = (int)Math.Floor(m * (1.0 - frac) + 0.5);

            p = (p > m ? m : (p < 0 ? 0 : p));
            float pivot = 0;

            // Partition array
            while (n < p)
            {
                int l = n;
                int h = m;
                if (xMse[l] > xMse[h])
                {
                    float tmp = xMse[l];
                    xMse[l] = xMse[h];
                    xMse[h] = tmp;
                }

                pivot = xMse[(l + h) / 2];

                if (pivot < xMse[l])
                {
                    float tmp = pivot;
                    pivot   = xMse[l];
                    xMse[l] = tmp;
                }

                if (pivot > xMse[h])
                {
                    float tmp = pivot;
                    pivot   = xMse[h];
                    xMse[h] = tmp;
                }

                while (l < h)
                {
                    if (xMse[l] > xMse[h])
                    {
                        float tmp = xMse[l];
                        xMse[l] = xMse[h];
                        xMse[h] = tmp;
                    }

                    while (xMse[l] < pivot || (xMse[l] == pivot && l < h))
                    {
                        l++;
                    }

                    while (xMse[h] > pivot)
                    {
                        h--;
                    }
                }

                if (p >= l)
                {
                    n = l;
                }
                else
                {
                    m = l - 1;
                }
            }

            // Compute average mse
            float mse = 0;

            for (i = p; i < _Map.BlockNumber; i++)
            {
                mse = mse + xMse[i];
            }

            mse = mse / (_Map.BlockNumber - p);

            // Return
            float factor  = 255 << iw_shift;
            float decibel = (float)(10.0 * Math.Log(factor * factor / mse) / 2.302585125);

            return(decibel);
        }
Beispiel #4
0
        /// <summary>
        /// Encodes a sequence of buckets in a given block.
        /// </summary>
        /// <param name="zp"></param>
        /// <param name="bit"></param>
        /// <param name="band"></param>
        /// <param name="blk"></param>
        /// <param name="eblk"></param>
        /// <param name="fbucket"></param>
        /// <param name="nbucket"></param>
        public void EncodeBuckets(IDataCoder zp, int bit, int band,
                                  InterWaveBlock blk, InterWaveBlock eblk, int fbucket, int nbucket)
        {
            // compute state of all coefficients in all buckets
            int bbstate = EncodePrepare(band, fbucket, nbucket, blk, eblk);

            // code root bit
            if ((nbucket < 16) || (bbstate & Active) != 0)
            {
                bbstate |= New;
            }
            else if ((bbstate & Unk) != 0)
            {
                zp.Encoder((bbstate & New) != 0 ? 1 : 0, ref _CtxRoot);
            }

            // code bucket bits
            if ((bbstate & New) != 0)
            {
                for (int buckno = 0; buckno < nbucket; buckno++)
                {
                    // Code bucket bit
                    if ((_BucketState[buckno] & Unk) != 0)
                    {
                        // Context
                        int ctx = 0;
                        if (band > 0)
                        {
                            int     k = (fbucket + buckno) << 2;
                            short[] b = eblk.GetBlock(k >> 4);

                            if (b != null)
                            {
                                k = k & 0xf;
                                if (b[k] != 0)
                                {
                                    ctx += 1;
                                }
                                if (b[k + 1] != 0)
                                {
                                    ctx += 1;
                                }
                                if (b[k + 2] != 0)
                                {
                                    ctx += 1;
                                }
                                if (ctx < 3 && b[k + 3] != 0)
                                {
                                    ctx += 1;
                                }
                            }
                        }

                        if ((bbstate & Active) != 0)
                        {
                            ctx |= 4;
                        }

                        // Code
                        zp.Encoder((_BucketState[buckno] & New) != 0 ? 1 : 0, ref _CtxBucket[band][ctx]);
                    }
                }
            }

            // code new active coefficient (with their sign)
            if ((bbstate & New) != 0)
            {
                int     thres  = _QuantHigh[band];
                sbyte[] cstate = _CoefficientState;

                for (int buckno = 0, cidx = 0; buckno < nbucket; buckno++, cidx += 16)
                {
                    if ((_BucketState[buckno] & New) != 0)
                    {
                        int       i;
                        int       gotcha    = 0;
                        const int maxgotcha = 7;

                        for (i = 0; i < 16; i++)
                        {
                            if ((cstate[i + cidx] & Unk) != 0)
                            {
                                gotcha += 1;
                            }
                        }

                        short[] pcoeff  = blk.GetBlock(fbucket + buckno);
                        short[] epcoeff = eblk.GetInitializedBlock(fbucket + buckno);

                        // iterate within bucket
                        for (i = 0; i < 16; i++)
                        {
                            if ((cstate[i] & Unk) != 0)
                            {
                                // Prepare context
                                int ctx = 0;

                                if (gotcha >= maxgotcha)
                                {
                                    ctx = maxgotcha;
                                }
                                else
                                {
                                    ctx = gotcha;
                                }

                                if ((_BucketState[buckno] & Active) != 0)
                                {
                                    ctx |= 8;
                                }

                                // Code
                                zp.Encoder((cstate[i] & New) != 0 ? 1 : 0, ref _CtxStart[ctx]);

                                if ((cstate[i] & New) != 0)
                                {
                                    // Code sign
                                    zp.IWEncoder((pcoeff[i] < 0) ? true : false);

                                    // Set encoder state
                                    if (band == 0)
                                    {
                                        thres = _QuantLow[i];
                                    }

                                    epcoeff[i] = (short)(thres + (thres >> 1));
                                }

                                if ((cstate[i] & New) != 0)
                                {
                                    gotcha = 0;
                                }
                                else if (gotcha > 0)
                                {
                                    gotcha -= 1;
                                }
                            }
                        }
                    }
                }
            }

            // code mantissa bits
            if ((bbstate & Active) != 0)
            {
                int     thres  = _QuantHigh[band];
                sbyte[] cstate = _CoefficientState;

                for (int buckno = 0, cidx = 0; buckno < nbucket; buckno++, cidx += 16)
                {
                    if ((_BucketState[buckno] & Active) != 0)
                    {
                        short[] pcoeff  = blk.GetBlock(fbucket + buckno);
                        short[] epcoeff = eblk.GetInitializedBlock(fbucket + buckno);

                        for (int i = 0; i < 16; i++)
                        {
                            if ((cstate[i] & Active) != 0)
                            {
                                // get coefficient
                                int coeff  = pcoeff[i];
                                int ecoeff = epcoeff[i];
                                if (coeff < 0)
                                {
                                    coeff = -coeff;
                                }

                                // get band zero thresholds
                                if (band == 0)
                                {
                                    thres = _QuantLow[i];
                                }

                                // compute mantissa bit
                                int pix = 0;
                                if (coeff >= ecoeff)
                                {
                                    pix = 1;
                                }

                                // encode second or lesser mantissa bit
                                if (ecoeff <= 3 * thres)
                                {
                                    zp.Encoder(pix, ref _CtxMant);
                                }
                                else
                                {
                                    zp.IWEncoder(!!(pix != 0));
                                }

                                // adjust epcoeff
                                epcoeff[i] = (short)(ecoeff - (pix != 0 ? 0 : thres) + (thres >> 1));
                            }
                        }
                    }
                }
            }
        }
Beispiel #5
0
        /// <summary>
        /// Function computes the states prior to encoding the buckets
        /// </summary>
        /// <param name="band"></param>
        /// <param name="fbucket"></param>
        /// <param name="nbucket"></param>
        /// <param name="blk"></param>
        /// <param name="eblk"></param>
        /// <returns></returns>
        public unsafe int EncodePrepare(int band, int fbucket, int nbucket, InterWaveBlock blk, InterWaveBlock eblk)
        {
            int bbstate = 0;

            // compute state of all coefficients in all buckets
            if (band != 0)
            {
                // Band other than zero
                int      thres       = _QuantHigh[band];
                GCHandle hCoeffState = GCHandle.Alloc(_CoefficientState, GCHandleType.Pinned);
                sbyte *  cstate      = (sbyte *)hCoeffState.AddrOfPinnedObject();

                for (int buckno = 0; buckno < nbucket; buckno++, cstate += 16)
                {
                    short[] pcoeff    = blk.GetBlock(fbucket + buckno);
                    short[] epcoeff   = eblk.GetBlock(fbucket + buckno);
                    int     bstatetmp = 0;
                    if (null != pcoeff)
                    {
                        bstatetmp = Unk;
                        // cstate[i] is not used and does not need initialization
                    }
                    else if (null != epcoeff)
                    {
                        for (int i = 0; i < 16; i++)
                        {
                            int cstatetmp = Unk;
                            if ((int)(pcoeff[i]) >= thres || (int)(pcoeff[i]) <= -thres)
                            {
                                cstatetmp = New | Unk;
                            }

                            cstate[i]  = (sbyte)cstatetmp;
                            bstatetmp |= cstatetmp;
                        }
                    }
                    else
                    {
                        for (int i = 0; i < 16; i++)
                        {
                            int cstatetmp = Unk;

                            if (epcoeff[i] != 0)
                            {
                                cstatetmp = Active;
                            }
                            else if ((int)(pcoeff[i]) >= thres || (int)(pcoeff[i]) <= -thres)
                            {
                                cstatetmp = New | Unk;
                            }
                            cstate[i]  = (sbyte)cstatetmp;
                            bstatetmp |= cstatetmp;
                        }
                    }
                    _BucketState[buckno] = (sbyte)bstatetmp;
                    bbstate |= bstatetmp;
                }
            }
            else
            {
                // Band zero ( fbucket==0 implies band==zero and nbucket==1 )
                short[] pcoeff  = blk.GetInitializedBlock(0);
                short[] epcoeff = eblk.GetInitializedBlock(0);

                sbyte[] cstate = _CoefficientState;

                for (int i = 0; i < 16; i++)
                {
                    int thres     = _QuantLow[i];
                    int cstatetmp = cstate[i];
                    if (cstatetmp != Zero)
                    {
                        cstatetmp = Unk;
                        if (epcoeff[i] != 0)
                        {
                            cstatetmp = Active;
                        }
                        else if ((int)(pcoeff[i]) >= thres || (int)(pcoeff[i]) <= -thres)
                        {
                            cstatetmp = New | Unk;
                        }
                    }
                    cstate[i] = (sbyte)cstatetmp;
                    bbstate  |= cstatetmp;
                }
                _BucketState[0] = (sbyte)bbstate;
            }
            return(bbstate);
        }
Beispiel #6
0
        public void DecodeBuckets(IDataCoder coder, int bit, int band,
                                  InterWaveBlock blk, int fbucket, int nbucket)
        {
            int thres   = _QuantHigh[band];
            int bbstate = 0;

            sbyte[] cstate = _CoefficientState;
            int     cidx   = 0;

            for (int buckno = 0; buckno < nbucket; buckno++, cidx += 16)
            {
                int     bstatetmp = 0;
                short[] pcoeff    = blk.GetBlock(fbucket + buckno);

                if (pcoeff == null)
                {
                    bstatetmp = 8;
                }
                else
                {
                    for (int i = 0; i < 16; i++)
                    {
                        int cstatetmp = cstate[cidx + i] & 1;

                        if (cstatetmp == 0)
                        {
                            if (pcoeff[i] != 0)
                            {
                                cstatetmp |= 2;
                            }
                            else
                            {
                                cstatetmp |= 8;
                            }
                        }

                        cstate[cidx + i] = (sbyte)cstatetmp;
                        bstatetmp       |= cstatetmp;
                    }
                }

                _BucketState[buckno] = (sbyte)bstatetmp;
                bbstate |= bstatetmp;
            }

            if (nbucket < 16 || (bbstate & 2) != 0)
            {
                bbstate |= 4;
            }
            else if ((bbstate & 8) != 0)
            {
                if (coder.Decoder(ref _CtxRoot) != 0)
                {
                    bbstate |= 4;
                }
            }

            if ((bbstate & 4) != 0)
            {
                for (int buckno = 0; buckno < nbucket; buckno++)
                {
                    if ((_BucketState[buckno] & 8) != 0)
                    {
                        int ctx = 0;

                        //if (!DjVuOptions.NOCTX_BUCKET_UPPER && (band > 0))
                        if ((band > 0))
                        {
                            int     k = (fbucket + buckno) << 2;
                            short[] b = blk.GetBlock(k >> 4);

                            if (b != null)
                            {
                                k &= 0xf;

                                if (b[k] != 0)
                                {
                                    ctx++;
                                }

                                if (b[k + 1] != 0)
                                {
                                    ctx++;
                                }

                                if (b[k + 2] != 0)
                                {
                                    ctx++;
                                }

                                if ((ctx < 3) && (b[k + 3] != 0))
                                {
                                    ctx++;
                                }
                            }
                        }

                        //if (!DjVuOptions.NOCTX_BUCKET_ACTIVE && ((bbstate & 2) != 0))
                        if ((bbstate & 2) != 0)
                        {
                            ctx |= 4;
                        }

                        if (coder.Decoder(ref _CtxBucket[band][ctx]) != 0)
                        {
                            _BucketState[buckno] |= 4;
                        }
                    }
                }
            }

            if ((bbstate & 4) != 0)
            {
                cstate = _CoefficientState;
                cidx   = 0;

                for (int buckno = 0; buckno < nbucket; buckno++, cidx += 16)
                {
                    if ((_BucketState[buckno] & 4) != 0)
                    {
                        short[] pcoeff = blk.GetBlock(fbucket + buckno);

                        if (pcoeff == null)
                        {
                            pcoeff = blk.GetInitializedBlock(fbucket + buckno);

                            for (int i = 0; i < 16; i++)
                            {
                                if ((cstate[cidx + i] & 1) == 0)
                                {
                                    cstate[cidx + i] = 8;
                                }
                            }
                        }

                        int gotcha    = 0;
                        int maxgotcha = 7;

                        //if (!DjVuOptions.NOCTX_EXPECT)
                        {
                            for (int i = 0; i < 16; i++)
                            {
                                if ((cstate[cidx + i] & 8) != 0)
                                {
                                    gotcha++;
                                }
                            }
                        }

                        for (int i = 0; i < 16; i++)
                        {
                            if ((cstate[cidx + i] & 8) != 0)
                            {
                                if (band == 0)
                                {
                                    thres = _QuantLow[i];
                                }

                                int ctx = 0;

                                //if (!DjVuOptions.NOCTX_EXPECT)
                                {
                                    if (gotcha >= maxgotcha)
                                    {
                                        ctx = maxgotcha;
                                    }
                                    else
                                    {
                                        ctx = gotcha;
                                    }
                                }

                                //if (!DjVuOptions.NOCTX_ACTIVE && ((bucketstate[buckno] & 2) != 0))
                                if (((_BucketState[buckno] & 2) != 0))
                                {
                                    ctx |= 8;
                                }

                                if (coder.Decoder(ref _CtxStart[ctx]) != 0)
                                {
                                    cstate[cidx + i] |= 4;

                                    int halfthres = thres >> 1;
                                    int coeff     = (thres + halfthres) - (halfthres >> 2);

                                    if (coder.IWDecoder() != 0)
                                    {
                                        pcoeff[i] = (short)(-coeff);
                                    }
                                    else
                                    {
                                        pcoeff[i] = (short)coeff;
                                    }
                                }

                                //if (!DjVuOptions.NOCTX_EXPECT)
                                {
                                    if ((cstate[cidx + i] & 4) != 0)
                                    {
                                        gotcha = 0;
                                    }
                                    else if (gotcha > 0)
                                    {
                                        gotcha--;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if ((bbstate & 2) != 0)
            {
                cstate = _CoefficientState;
                cidx   = 0;

                for (int buckno = 0; buckno < nbucket; buckno++, cidx += 16)
                {
                    if ((_BucketState[buckno] & 2) != 0)
                    {
                        short[] pcoeff = blk.GetBlock(fbucket + buckno);

                        for (int i = 0; i < 16; i++)
                        {
                            if ((cstate[cidx + i] & 2) != 0)
                            {
                                int coeff = pcoeff[i];

                                if (coeff < 0)
                                {
                                    coeff = -coeff;
                                }

                                if (band == 0)
                                {
                                    thres = _QuantLow[i];
                                }

                                if (coeff <= (3 * thres))
                                {
                                    coeff += (thres >> 2);

                                    if (coder.Decoder(ref _CtxMant) != 0)
                                    {
                                        coeff += (thres >> 1);
                                    }
                                    else
                                    {
                                        coeff = (coeff - thres) + (thres >> 1);
                                    }
                                }
                                else
                                {
                                    if (coder.IWDecoder() != 0)
                                    {
                                        coeff += (thres >> 1);
                                    }
                                    else
                                    {
                                        coeff = (coeff - thres) + (thres >> 1);
                                    }
                                }

                                if (pcoeff[i] > 0)
                                {
                                    pcoeff[i] = (short)coeff;
                                }
                                else
                                {
                                    pcoeff[i] = (short)(-coeff);
                                }
                            }
                        } // end for (int i = 0 ...
                    }
                }         // end for (int buckno = 0 ....
            }
        }
Beispiel #7
0
        /// <summary>
        /// Add docs
        /// </summary>
        /// <param name="subsample"></param>
        /// <param name="rect"></param>
        /// <param name="index"></param>
        /// <param name="img8"></param>
        /// <param name="rowsize"></param>
        /// <param name="pixsep"></param>
        /// <param name="fast"></param>
        public void Image(int subsample, Rectangle rect, int index, sbyte[] img8, int rowsize, int pixsep, bool fast)
        {
            int nlevel = 0;

            while ((nlevel < 5) && ((32 >> nlevel) > subsample))
            {
                nlevel++;
            }

            int boxsize = 1 << nlevel;

            if (subsample != (32 >> nlevel))
            {
                throw new DjvuArgumentOutOfRangeException("Unsupported subsampling factor");
            }

            if (rect.Empty)
            {
                throw new DjvuArgumentException("Rectangle is empty", nameof(rect));
            }

            Rectangle irect = new Rectangle(
                0, 0, ((Width + subsample) - 1) / subsample, ((Height + subsample) - 1) / subsample);

            if ((rect.Right < 0) || (rect.Bottom < 0) || (rect.Left > irect.Left) || (rect.Top > irect.Top))
            {
                throw new DjvuArgumentException(
                          "Rectangle is out of bounds: " + rect.Right + "," + rect.Bottom +
                          "," + rect.Left + "," + rect.Top + "," + irect.Left + "," + irect.Top, nameof(rect));
            }

            Rectangle[] needed = new Rectangle[8];
            Rectangle[] recomp = new Rectangle[8];

            for (int i = 0; i < 8;)
            {
                needed[i]   = new Rectangle();
                recomp[i++] = new Rectangle();
            }

            int r = 1;

            needed[nlevel] = (Rectangle)rect.Duplicate();
            recomp[nlevel] = (Rectangle)rect.Duplicate();

            for (int i = nlevel - 1; i >= 0; i--)
            {
                needed[i] = recomp[i + 1];
                needed[i].Inflate(3 * r, 3 * r);
                needed[i].Intersect(needed[i], irect);
                r += r;
                recomp[i].Right  = ((needed[i].Right + r) - 1) & ~(r - 1);
                recomp[i].Left   = needed[i].Left & ~(r - 1);
                recomp[i].Bottom = ((needed[i].Bottom + r) - 1) & ~(r - 1);
                recomp[i].Top    = needed[i].Top & ~(r - 1);
            }

            Rectangle work = new Rectangle();

            work.Right  = needed[0].Right & ~(boxsize - 1);
            work.Bottom = needed[0].Bottom & ~(boxsize - 1);
            work.Left   = ((needed[0].Left - 1) & ~(boxsize - 1)) + boxsize;
            work.Top    = ((needed[0].Top - 1) & ~(boxsize - 1)) + boxsize;

            int dataw = work.Width;

            short[] data   = new short[dataw * work.Height];
            int     blkw   = BlockWidth >> 5;
            int     lblock = ((work.Bottom >> nlevel) * blkw) + (work.Right >> nlevel);

            short[] liftblock = new short[1024];

            for (int by = work.Bottom, ldata = 0;
                 by < work.Top;
                 by += boxsize, ldata += (dataw << nlevel), lblock += blkw)
            {
                for (int bx = work.Right, bidx = lblock, rdata = ldata;
                     bx < work.Left;
                     bx += boxsize, bidx++, rdata += boxsize)
                {
                    InterWaveBlock block  = Blocks[bidx];
                    int            mlevel = nlevel;

                    if ((nlevel > 2) &&
                        (((bx + 31) < needed[2].Right) || (bx > needed[2].Left) || ((by + 31) < needed[2].Bottom) ||
                         (by > needed[2].Top)))
                    {
                        mlevel = 2;
                    }

                    int bmax   = ((1 << (mlevel + mlevel)) + 15) >> 4;
                    int ppinc  = 1 << (nlevel - mlevel);
                    int ppmod1 = dataw << (nlevel - mlevel);
                    int ttmod0 = 32 >> mlevel;
                    int ttmod1 = ttmod0 << 5;

                    // liftblock should contain zeros only
                    block.WriteLiftBlock(liftblock, 0, bmax);

                    for (int ii = 0, tt = 0, pp = rdata; ii < boxsize; ii += ppinc, pp += ppmod1, tt += (ttmod1 - 32))
                    {
                        for (int jj = 0; jj < boxsize; jj += ppinc, tt += ttmod0)
                        {
                            data[pp + jj] = liftblock[tt];
                        }
                    }
                }
            }

            r = boxsize;

            for (int i = 0; i < nlevel; i++)
            {
                Rectangle comp = needed[i];
                comp.Right  = comp.Right & ~(r - 1);
                comp.Bottom = comp.Bottom & ~(r - 1);
                comp.Translate(-work.Right, -work.Bottom);

                if (fast && (i >= 4))
                {
                    for (int ii = comp.Bottom, pp = (comp.Bottom * dataw); ii < comp.Top; ii += 2, pp += (dataw + dataw))
                    {
                        for (int jj = comp.Right; jj < comp.Left; jj += 2)
                        {
                            data[pp + jj + dataw] = data[pp + jj + dataw + 1] = data[pp + jj + 1] = data[pp + jj];
                        }
                    }

                    break;
                }

                Backward(data, (comp.Bottom * dataw) + comp.Right, comp.Width, comp.Height, dataw, r, r >> 1);
                r >>= 1;
            }

            Rectangle nrect = rect.Duplicate();

            nrect.Translate(-work.Right, -work.Bottom);

            for (int i = nrect.Bottom, pidx = (nrect.Bottom * dataw), ridx = index;
                 i++ < nrect.Top;
                 ridx += rowsize, pidx += dataw)
            {
                for (int j = nrect.Right, pixidx = ridx; j < nrect.Left; j++, pixidx += pixsep)
                {
                    int x = (data[pidx + j] + 32) >> 6;

                    if (x < -128)
                    {
                        x = -128;
                    }
                    else if (x > 127)
                    {
                        x = 127;
                    }

                    img8[pixidx] = (sbyte)x;
                }
            }
        }