@Override
    public boolean forward(SliceIntArray source, SliceIntArray destination)
    {
        int srcIdx = source.index;
        int dstIdx = destination.index;
        final int[] src = source.array;
        final int[] dst = destination.array;
        final int w0 = this.width >> this.levels;
        final int h0 = this.height >> this.levels;
        
        this.quantize(src, srcIdx, this.quantizers);

        if (this.minClusterSize > 0)
            this.filter(src, srcIdx);

        // Process LL band
        for (int j=0, offset=srcIdx; j<h0; j++)
        {
            for (int i=0; i<w0; i++)
                dst[dstIdx++] = src[offset+i];

            offset += this.width;
        }

        // Reorder the coefficients and remove those under leaves
        int start = srcIdx;
        WaveletBandScanner sc = new WaveletBandScanner(this.width,
                this.height, WaveletBandScanner.ALL_BANDS, this.levels);
        
        final int w = this.width;
        int count = 0;

        // Process sub-bands
        while (count < sc.getSize())
        {
            final int len = sc.getIndexes(this.buffer, this.buffer.length, count);
            count += len;

            for (int i=0; i<len; i++, srcIdx++)
            {
                final int idx = start + this.buffer[i];

                if (src[idx] != IS_LEAF)
                {
                    dst[dstIdx++] = src[idx];
                    continue;
                }

                // Check if the parent coefficient is a leaf, if so skip
                final int x = (idx % w) >> 1;
                final int y = (idx / w) >> 1;

                if ((x < w0) && (y < h0))
                {
                    dst[dstIdx++] = IS_LEAF;
                }
                else if (src[start+(y*w)+x] != IS_LEAF)
                {
                    dst[dstIdx++] = IS_LEAF;
                }
            }
        }

        source.index = srcIdx;
        destination.index = dstIdx;
        return true;
    }