BitMiracle.LibJpeg.Classic.Internal.jpeg_inverse_dct.jpeg_idct_4x4 C# (CSharp) Method

jpeg_idct_4x4() private method

Inverse-DCT routines that produce reduced-size output: either 4x4, 2x2, or 1x1 pixels from an 8x8 DCT block. NOTE: this code only copes with 8x8 DCTs. The implementation is based on the Loeffler, Ligtenberg and Moschytz (LL&M) algorithm. We simply replace each 8-to-8 1-D IDCT step with an 8-to-4 step that produces the four averages of two adjacent outputs (or an 8-to-2 step producing two averages of four outputs, for 2x2 output). These steps were derived by computing the corresponding values at the end of the normal LL&M code, then simplifying as much as possible. 1x1 is trivial: just take the DC coefficient divided by 8. Perform dequantization and inverse DCT on one block of coefficients, producing a reduced-size 4x4 output block.
private jpeg_idct_4x4 ( int component_index, short coef_block, int output_row, int output_col ) : void
component_index int
coef_block short
output_row int
output_col int
return void
        private void jpeg_idct_4x4(int component_index, short[] coef_block, int output_row, int output_col)
        {
            /* buffers data between passes */
            int[] workspace = new int[JpegConstants.DCTSIZE * 4];

            /* Pass 1: process columns from input, store into work array. */
            int coefBlockIndex = 0;
            int workspaceIndex = 0;

            int[] quantTable = m_dctTables[component_index].int_array;
            int quantTableIndex = 0;

            for (int ctr = JpegConstants.DCTSIZE; ctr > 0; coefBlockIndex++, quantTableIndex++, workspaceIndex++, ctr--)
            {
                /* Don't bother to process column 4, because second pass won't use it */
                if (ctr == JpegConstants.DCTSIZE - 4)
                    continue;

                if (coef_block[coefBlockIndex + JpegConstants.DCTSIZE * 1] == 0 &&
                    coef_block[coefBlockIndex + JpegConstants.DCTSIZE * 2] == 0 &&
                    coef_block[coefBlockIndex + JpegConstants.DCTSIZE * 3] == 0 &&
                    coef_block[coefBlockIndex + JpegConstants.DCTSIZE * 5] == 0 &&
                    coef_block[coefBlockIndex + JpegConstants.DCTSIZE * 6] == 0 &&
                    coef_block[coefBlockIndex + JpegConstants.DCTSIZE * 7] == 0)
                {
                    /* AC terms all zero; we need not examine term 4 for 4x4 output */
                    int dcval = REDUCED_DEQUANTIZE(coef_block[coefBlockIndex + JpegConstants.DCTSIZE * 0],
                        quantTable[quantTableIndex + JpegConstants.DCTSIZE * 0]) << REDUCED_PASS1_BITS;

                    workspace[workspaceIndex + JpegConstants.DCTSIZE * 0] = dcval;
                    workspace[workspaceIndex + JpegConstants.DCTSIZE * 1] = dcval;
                    workspace[workspaceIndex + JpegConstants.DCTSIZE * 2] = dcval;
                    workspace[workspaceIndex + JpegConstants.DCTSIZE * 3] = dcval;

                    continue;
                }

                /* Even part */

                int tmp0 = REDUCED_DEQUANTIZE(coef_block[coefBlockIndex + JpegConstants.DCTSIZE * 0],
                    quantTable[quantTableIndex + JpegConstants.DCTSIZE * 0]);
                tmp0 <<= (REDUCED_CONST_BITS + 1);

                int z2 = REDUCED_DEQUANTIZE(coef_block[coefBlockIndex + JpegConstants.DCTSIZE * 2],
                    quantTable[quantTableIndex + JpegConstants.DCTSIZE * 2]);
                int z3 = REDUCED_DEQUANTIZE(coef_block[coefBlockIndex + JpegConstants.DCTSIZE * 6],
                    quantTable[quantTableIndex + JpegConstants.DCTSIZE * 6]);

                int tmp2 = z2 * REDUCED_FIX_1_847759065 + z3 * (-REDUCED_FIX_0_765366865);

                int tmp10 = tmp0 + tmp2;
                int tmp12 = tmp0 - tmp2;

                /* Odd part */

                int z1 = REDUCED_DEQUANTIZE(coef_block[coefBlockIndex + JpegConstants.DCTSIZE * 7],
                    quantTable[quantTableIndex + JpegConstants.DCTSIZE * 7]);
                z2 = REDUCED_DEQUANTIZE(coef_block[coefBlockIndex + JpegConstants.DCTSIZE * 5],
                    quantTable[quantTableIndex + JpegConstants.DCTSIZE * 5]);
                z3 = REDUCED_DEQUANTIZE(coef_block[coefBlockIndex + JpegConstants.DCTSIZE * 3],
                    quantTable[quantTableIndex + JpegConstants.DCTSIZE * 3]);
                int z4 = REDUCED_DEQUANTIZE(coef_block[coefBlockIndex + JpegConstants.DCTSIZE * 1],
                    quantTable[quantTableIndex + JpegConstants.DCTSIZE * 1]);

                tmp0 = z1 * (-REDUCED_FIX_0_211164243) /* sqrt(2) * (c3-c1) */ +
                       z2 * REDUCED_FIX_1_451774981 /* sqrt(2) * (c3+c7) */ +
                       z3 * (-REDUCED_FIX_2_172734803) /* sqrt(2) * (-c1-c5) */ +
                       z4 * REDUCED_FIX_1_061594337; /* sqrt(2) * (c5+c7) */

                tmp2 = z1 * (-REDUCED_FIX_0_509795579) /* sqrt(2) * (c7-c5) */ +
                       z2 * (-REDUCED_FIX_0_601344887) /* sqrt(2) * (c5-c1) */ +
                       z3 * REDUCED_FIX_0_899976223 /* sqrt(2) * (c3-c7) */ +
                       z4 * REDUCED_FIX_2_562915447; /* sqrt(2) * (c1+c3) */

                /* Final output stage */

                workspace[workspaceIndex + JpegConstants.DCTSIZE * 0] = JpegUtils.DESCALE(tmp10 + tmp2, REDUCED_CONST_BITS - REDUCED_PASS1_BITS + 1);
                workspace[workspaceIndex + JpegConstants.DCTSIZE * 3] = JpegUtils.DESCALE(tmp10 - tmp2, REDUCED_CONST_BITS - REDUCED_PASS1_BITS + 1);
                workspace[workspaceIndex + JpegConstants.DCTSIZE * 1] = JpegUtils.DESCALE(tmp12 + tmp0, REDUCED_CONST_BITS - REDUCED_PASS1_BITS + 1);
                workspace[workspaceIndex + JpegConstants.DCTSIZE * 2] = JpegUtils.DESCALE(tmp12 - tmp0, REDUCED_CONST_BITS - REDUCED_PASS1_BITS + 1);
            }

            /* Pass 2: process 4 rows from work array, store into output array. */
            byte[] limit = m_cinfo.m_sample_range_limit;
            int limitOffset = m_cinfo.m_sampleRangeLimitOffset - RANGE_SUBSET;

            workspaceIndex = 0;
            for (int ctr = 0; ctr < 4; ctr++)
            {
                int currentOutRow = output_row + ctr;
                /* It's not clear whether a zero row test is worthwhile here ... */

                if (workspace[workspaceIndex + 1] == 0 &&
                    workspace[workspaceIndex + 2] == 0 &&
                    workspace[workspaceIndex + 3] == 0 &&
                    workspace[workspaceIndex + 5] == 0 &&
                    workspace[workspaceIndex + 6] == 0 &&
                    workspace[workspaceIndex + 7] == 0)
                {
                    /* AC terms all zero */
                    byte dcval = limit[limitOffset + JpegUtils.DESCALE(workspace[workspaceIndex + 0], REDUCED_PASS1_BITS + 3) & RANGE_MASK];

                    m_componentBuffer[currentOutRow][output_col + 0] = dcval;
                    m_componentBuffer[currentOutRow][output_col + 1] = dcval;
                    m_componentBuffer[currentOutRow][output_col + 2] = dcval;
                    m_componentBuffer[currentOutRow][output_col + 3] = dcval;

                    workspaceIndex += JpegConstants.DCTSIZE;       /* advance pointer to next row */
                    continue;
                }

                /* Even part */

                int tmp0 = (workspace[workspaceIndex + 0]) << (REDUCED_CONST_BITS + 1);

                int tmp2 = workspace[workspaceIndex + 2] * REDUCED_FIX_1_847759065 + workspace[workspaceIndex + 6] * (-REDUCED_FIX_0_765366865);

                int tmp10 = tmp0 + tmp2;
                int tmp12 = tmp0 - tmp2;

                /* Odd part */

                int z1 = workspace[workspaceIndex + 7];
                int z2 = workspace[workspaceIndex + 5];
                int z3 = workspace[workspaceIndex + 3];
                int z4 = workspace[workspaceIndex + 1];

                tmp0 = z1 * (-REDUCED_FIX_0_211164243) /* sqrt(2) * (c3-c1) */ +
                       z2 * REDUCED_FIX_1_451774981 /* sqrt(2) * (c3+c7) */ +
                       z3 * (-REDUCED_FIX_2_172734803) /* sqrt(2) * (-c1-c5) */ +
                       z4 * REDUCED_FIX_1_061594337; /* sqrt(2) * (c5+c7) */

                tmp2 = z1 * (-REDUCED_FIX_0_509795579) /* sqrt(2) * (c7-c5) */ +
                       z2 * (-REDUCED_FIX_0_601344887) /* sqrt(2) * (c5-c1) */ +
                       z3 * REDUCED_FIX_0_899976223 /* sqrt(2) * (c3-c7) */ +
                       z4 * REDUCED_FIX_2_562915447; /* sqrt(2) * (c1+c3) */

                /* Final output stage */

                m_componentBuffer[currentOutRow][output_col + 0] = limit[limitOffset + JpegUtils.DESCALE(tmp10 + tmp2, REDUCED_CONST_BITS + REDUCED_PASS1_BITS + 3 + 1) & RANGE_MASK];
                m_componentBuffer[currentOutRow][output_col + 3] = limit[limitOffset + JpegUtils.DESCALE(tmp10 - tmp2, REDUCED_CONST_BITS + REDUCED_PASS1_BITS + 3 + 1) & RANGE_MASK];
                m_componentBuffer[currentOutRow][output_col + 1] = limit[limitOffset + JpegUtils.DESCALE(tmp12 + tmp0, REDUCED_CONST_BITS + REDUCED_PASS1_BITS + 3 + 1) & RANGE_MASK];
                m_componentBuffer[currentOutRow][output_col + 2] = limit[limitOffset + JpegUtils.DESCALE(tmp12 - tmp0, REDUCED_CONST_BITS + REDUCED_PASS1_BITS + 3 + 1) & RANGE_MASK];

                workspaceIndex += JpegConstants.DCTSIZE;       /* advance pointer to next row */
            }
        }