Beispiel #1
0
        /// <summary>
        /// This version handles any integral sampling ratios.
        /// This is not used for typical JPEG files, so it need not be fast.
        /// Nor, for that matter, is it particularly accurate: the algorithm is
        /// simple replication of the input pixel onto the corresponding output
        /// pixels.  The hi-falutin sampling literature refers to this as a
        /// "box filter".  A box filter tends to introduce visible artifacts,
        /// so if you are actually going to use 3:1 or 4:1 sampling ratios
        /// you would be well advised to improve this code.
        /// </summary>
        private void int_upsample(ref ComponentBuffer input_data)
        {
            ComponentBuffer output_data = m_color_buf[m_currentComponent];
            int             h_expand    = m_h_expand[m_currentComponent];
            int             v_expand    = m_v_expand[m_currentComponent];

            int inrow  = 0;
            int outrow = 0;

            while (outrow < m_cinfo.m_max_v_samp_factor)
            {
                /* Generate one output row with proper horizontal expansion */
                int row = m_upsampleRowOffset + inrow;
                for (int col = 0; col < m_cinfo.m_output_width; col++)
                {
                    byte invalue  = input_data[row][col]; /* don't need GETJSAMPLE() here */
                    int  outIndex = 0;
                    for (int h = h_expand; h > 0; h--)
                    {
                        output_data[outrow][outIndex] = invalue;
                        outIndex++;
                    }
                }

                /* Generate any additional output rows by duplicating the first one */
                if (v_expand > 1)
                {
                    JpegUtils.jcopy_sample_rows(output_data, outrow, output_data,
                                                outrow + 1, v_expand - 1, m_cinfo.m_output_width);
                }

                inrow++;
                outrow += v_expand;
            }
        }
Beispiel #2
0
        public jpeg_d_coef_controller(jpeg_decompress_struct cinfo, bool need_full_buffer)
        {
            m_cinfo = cinfo;

            /* Create the coefficient buffer. */
            if (need_full_buffer)
            {
                /* Allocate a full-image virtual array for each component, */
                /* padded to a multiple of samp_factor DCT blocks in each direction. */
                /* Note we ask for a pre-zeroed array. */
                for (int ci = 0; ci < cinfo.m_num_components; ci++)
                {
                    m_whole_image[ci] = jpeg_common_struct.CreateBlocksArray(
                        JpegUtils.jround_up(cinfo.Comp_info[ci].Width_in_blocks, cinfo.Comp_info[ci].H_samp_factor),
                        JpegUtils.jround_up(cinfo.Comp_info[ci].height_in_blocks, cinfo.Comp_info[ci].V_samp_factor));
                    m_whole_image[ci].ErrorProcessor = cinfo;
                }

                m_useDummyConsumeData = false;
                m_decompressor        = DecompressorType.Ordinary;
                m_coef_arrays         = m_whole_image; /* link to virtual arrays */
            }
            else
            {
                /* We only need a single-MCU buffer. */
                for (int i = 0; i < JpegConstants.D_MAX_BLOCKS_IN_MCU; i++)
                {
                    m_MCU_buffer[i] = new JBLOCK();
                }

                m_useDummyConsumeData = true;
                m_decompressor        = DecompressorType.OnePass;
                m_coef_arrays         = null; /* flag for no virtual arrays */
            }
        }
        /**************** YCbCr -> RGB conversion: most common case **************/

        /*
         * YCbCr is defined per CCIR 601-1, except that Cb and Cr are
         * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
         * The conversion equations to be implemented are therefore
         *  R = Y                + 1.40200 * Cr
         *  G = Y - 0.34414 * Cb - 0.71414 * Cr
         *  B = Y + 1.77200 * Cb
         * where Cb and Cr represent the incoming values less CENTERJSAMPLE.
         * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
         *
         * To avoid floating-point arithmetic, we represent the fractional constants
         * as integers scaled up by 2^16 (about 4 digits precision); we have to divide
         * the products by 2^16, with appropriate rounding, to get the correct answer.
         * Notice that Y, being an integral input, does not contribute any fraction
         * so it need not participate in the rounding.
         *
         * For even more speed, we avoid doing any multiplications in the inner loop
         * by precalculating the constants times Cb and Cr for all possible values.
         * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
         * for 12-bit samples it is still acceptable.  It's not very reasonable for
         * 16-bit samples, but if you want lossless storage you shouldn't be changing
         * colorspace anyway.
         * The Cr=>R and Cb=>B values can be rounded to integers in advance; the
         * values for the G calculation are left scaled up, since we must add them
         * together before rounding.
         */

        /// <summary>
        /// Initialize tables for YCC->RGB colorspace conversion.
        /// </summary>
        private void build_ycc_rgb_table()
        {
            m_Cr_r_tab = new int[JpegConstants.MAXJSAMPLE + 1];
            m_Cb_b_tab = new int[JpegConstants.MAXJSAMPLE + 1];
            m_Cr_g_tab = new int[JpegConstants.MAXJSAMPLE + 1];
            m_Cb_g_tab = new int[JpegConstants.MAXJSAMPLE + 1];

            for (int i = 0, x = -JpegConstants.CENTERJSAMPLE; i <= JpegConstants.MAXJSAMPLE; i++, x++)
            {
                /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
                /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
                /* Cr=>R value is nearest int to 1.40200 * x */
                m_Cr_r_tab[i] = JpegUtils.RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS);

                /* Cb=>B value is nearest int to 1.77200 * x */
                m_Cb_b_tab[i] = JpegUtils.RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS);

                /* Cr=>G value is scaled-up -0.71414 * x */
                m_Cr_g_tab[i] = (-FIX(0.71414)) * x;

                /* Cb=>G value is scaled-up -0.34414 * x */
                /* We also add in ONE_HALF so that need not do it in inner loop */
                m_Cb_g_tab[i] = (-FIX(0.34414)) * x + ONE_HALF;
            }
        }
        private int m_next_row;                   /* index of next row to fill/empty in strip */

        /// <summary>
        /// Initialize postprocessing controller.
        /// </summary>
        public jpeg_d_post_controller(jpeg_decompress_struct cinfo, bool need_full_buffer)
        {
            m_cinfo = cinfo;

            /* Create the quantization buffer, if needed */
            if (cinfo.m_quantize_colors)
            {
                /* The buffer strip height is max_v_samp_factor, which is typically
                 * an efficient number of rows for upsampling to return.
                 * (In the presence of output rescaling, we might want to be smarter?)
                 */
                m_strip_height = cinfo.m_max_v_samp_factor;

                if (need_full_buffer)
                {
                    /* Two-pass color quantization: need full-image storage. */
                    /* We round up the number of rows to a multiple of the strip height. */
                    m_whole_image = jpeg_common_struct.CreateSamplesArray(
                        cinfo.m_output_width * cinfo.m_out_color_components,
                        JpegUtils.jround_up(cinfo.m_output_height, m_strip_height));
                    m_whole_image.ErrorProcessor = cinfo;
                }
                else
                {
                    /* One-pass color quantization: just make a strip buffer. */
                    m_buffer = jpeg_common_struct.AllocJpegSamples(
                        cinfo.m_output_width * cinfo.m_out_color_components, m_strip_height);
                }
            }
        }
 /// <summary>
 /// Expand an image vertically from height input_rows to height output_rows,
 /// by duplicating the bottom row.
 /// </summary>
 private static void expand_bottom_edge(byte[][] image_data, int rowsOffset, int num_cols, int input_rows, int output_rows)
 {
     for (int row = input_rows; row < output_rows; row++)
     {
         JpegUtils.jcopy_sample_rows(image_data, rowsOffset + input_rows - 1, image_data, row, 1, num_cols);
     }
 }
Beispiel #6
0
        /// <summary>
        /// Fast processing for the common case of 2:1 horizontal and 2:1 vertical.
        /// It's still a box filter.
        /// </summary>
        private void h2v2_upsample(ref ComponentBuffer input_data)
        {
            ComponentBuffer output_data = m_color_buf[m_currentComponent];

            int inrow  = 0;
            int outrow = 0;

            while (outrow < m_cinfo.m_max_v_samp_factor)
            {
                int row      = m_upsampleRowOffset + inrow;
                int outIndex = 0;

                for (int col = 0; outIndex < m_cinfo.m_output_width; col++)
                {
                    byte invalue = input_data[row][col]; /* don't need GETJSAMPLE() here */
                    output_data[outrow][outIndex] = invalue;
                    outIndex++;
                    output_data[outrow][outIndex] = invalue;
                    outIndex++;
                }

                JpegUtils.jcopy_sample_rows(output_data, outrow, output_data, outrow + 1, 1, m_cinfo.m_output_width);
                inrow++;
                outrow += 2;
            }
        }
Beispiel #7
0
        /// <summary>
        /// Multiply a DCTELEM variable by an int constant, and immediately
        /// descale to yield a DCTELEM result.
        /// </summary>
        private static int FAST_INTEGER_MULTIPLY(int var, int c)
        {
#if !USE_ACCURATE_ROUNDING
            return(JpegUtils.RIGHT_SHIFT((var) * (c), FAST_INTEGER_CONST_BITS));
#else
            return(JpegUtils.DESCALE((var) * (c), FAST_INTEGER_CONST_BITS));
#endif
        }
Beispiel #8
0
        /// <summary>
        /// Downsample pixel values of a single component.
        /// This version handles the special case of a full-size component,
        /// without smoothing.
        /// </summary>
        private void fullsize_downsample(int componentIndex, byte[][] input_data, int startInputRow, byte[][] output_data, int startOutRow)
        {
            /* Copy the data */
            JpegUtils.jcopy_sample_rows(input_data, startInputRow, output_data, startOutRow, m_cinfo.m_max_v_samp_factor, m_cinfo.m_image_width);

            /* Edge-expand */
            expand_right_edge(output_data, startOutRow, m_cinfo.m_max_v_samp_factor, m_cinfo.m_image_width, m_cinfo.Component_info[componentIndex].Width_in_blocks * JpegConstants.DCTSIZE);
        }
        /// <summary>
        /// Control routine to do upsampling (and color conversion).
        /// The control routine just handles the row buffering considerations.
        /// 2:1 vertical sampling case: may need a spare row.
        /// </summary>
        private void merged_2v_upsample(ComponentBuffer[] input_buf, ref int in_row_group_ctr, byte[][] output_buf, ref int out_row_ctr, int out_rows_avail)
        {
            int num_rows;        /* number of rows returned to caller */

            if (m_spare_full)
            {
                /* If we have a spare row saved from a previous cycle, just return it. */
                byte[][] temp = new byte[1][];
                temp[0] = m_spare_row;
                JpegUtils.jcopy_sample_rows(temp, 0, output_buf, out_row_ctr, 1, m_out_row_width);
                num_rows     = 1;
                m_spare_full = false;
            }
            else
            {
                /* Figure number of rows to return to caller. */
                num_rows = 2;

                /* Not more than the distance to the end of the image. */
                if (num_rows > m_rows_to_go)
                {
                    num_rows = m_rows_to_go;
                }

                /* And not more than what the client can accept: */
                out_rows_avail -= out_row_ctr;
                if (num_rows > out_rows_avail)
                {
                    num_rows = out_rows_avail;
                }

                /* Create output pointer array for upsampler. */
                byte[][] work_ptrs = new byte[2][];
                work_ptrs[0] = output_buf[out_row_ctr];
                if (num_rows > 1)
                {
                    work_ptrs[1] = output_buf[out_row_ctr + 1];
                }
                else
                {
                    work_ptrs[1] = m_spare_row;
                    m_spare_full = true;
                }

                /* Now do the upsampling. */
                h2v2_merged_upsample(input_buf, in_row_group_ctr, work_ptrs);
            }

            /* Adjust counts */
            out_row_ctr  += num_rows;
            m_rows_to_go -= num_rows;

            /* When the buffer is emptied, declare this input row group consumed */
            if (!m_spare_full)
            {
                in_row_group_ctr++;
            }
        }
        /*
         * These are the routines invoked by the control routines to do
         * the actual upsampling/conversion.  One row group is processed per call.
         *
         * Note: since we may be writing directly into application-supplied buffers,
         * we have to be honest about the output width; we can't assume the buffer
         * has been rounded up to an even width.
         */

        /// <summary>
        /// Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical.
        /// </summary>
        private void h2v1_merged_upsample(ComponentBuffer[] input_buf, int in_row_group_ctr, byte[][] output_buf, int outRow)
        {
            int inputIndex0 = 0;
            int inputIndex1 = 0;
            int inputIndex2 = 0;
            int outputIndex = 0;

            byte[] limit       = m_cinfo.m_sample_range_limit;
            int    limitOffset = m_cinfo.m_sampleRangeLimitOffset;

            /* Loop for each pair of output pixels */
            for (int col = m_cinfo.m_output_width >> 1; col > 0; col--)
            {
                /* Do the chroma part of the calculation */
                int cb = input_buf[1][in_row_group_ctr][inputIndex1];
                inputIndex1++;

                int cr = input_buf[2][in_row_group_ctr][inputIndex2];
                inputIndex2++;

                int cred   = m_Cr_r_tab[cr];
                int cgreen = JpegUtils.RIGHT_SHIFT(m_Cb_g_tab[cb] + m_Cr_g_tab[cr], SCALEBITS);
                int cblue  = m_Cb_b_tab[cb];

                /* Fetch 2 Y values and emit 2 pixels */
                int y = input_buf[0][in_row_group_ctr][inputIndex0];
                inputIndex0++;

                output_buf[outRow][outputIndex + JpegConstants.RGB_RED]   = limit[limitOffset + y + cred];
                output_buf[outRow][outputIndex + JpegConstants.RGB_GREEN] = limit[limitOffset + y + cgreen];
                output_buf[outRow][outputIndex + JpegConstants.RGB_BLUE]  = limit[limitOffset + y + cblue];
                outputIndex += JpegConstants.RGB_PIXELSIZE;

                y = input_buf[0][in_row_group_ctr][inputIndex0];
                inputIndex0++;

                output_buf[outRow][outputIndex + JpegConstants.RGB_RED]   = limit[limitOffset + y + cred];
                output_buf[outRow][outputIndex + JpegConstants.RGB_GREEN] = limit[limitOffset + y + cgreen];
                output_buf[outRow][outputIndex + JpegConstants.RGB_BLUE]  = limit[limitOffset + y + cblue];
                outputIndex += JpegConstants.RGB_PIXELSIZE;
            }

            /* If image width is odd, do the last output column separately */
            if ((m_cinfo.m_output_width & 1) != 0)
            {
                int cb     = input_buf[1][in_row_group_ctr][inputIndex1];
                int cr     = input_buf[2][in_row_group_ctr][inputIndex2];
                int cred   = m_Cr_r_tab[cr];
                int cgreen = JpegUtils.RIGHT_SHIFT(m_Cb_g_tab[cb] + m_Cr_g_tab[cr], SCALEBITS);
                int cblue  = m_Cb_b_tab[cb];

                int y = input_buf[0][in_row_group_ctr][inputIndex0];
                output_buf[outRow][outputIndex + JpegConstants.RGB_RED]   = limit[limitOffset + y + cred];
                output_buf[outRow][outputIndex + JpegConstants.RGB_GREEN] = limit[limitOffset + y + cgreen];
                output_buf[outRow][outputIndex + JpegConstants.RGB_BLUE]  = limit[limitOffset + y + cblue];
            }
        }
Beispiel #11
0
        public my_c_coef_controller(jpeg_compress_struct cinfo, bool need_full_buffer)
        {
            m_cinfo = cinfo;

            /* Create the coefficient buffer. */
            if (need_full_buffer)
            {
                /* Allocate a full-image virtual array for each component, */
                /* padded to a multiple of samp_factor DCT blocks in each direction. */
                for (int ci = 0; ci < cinfo.m_num_components; ci++)
                {
                    m_whole_image[ci] = jpeg_common_struct.CreateBlocksArray(
                        JpegUtils.jround_up(cinfo.Component_info[ci].Width_in_blocks, cinfo.Component_info[ci].H_samp_factor),
                        JpegUtils.jround_up(cinfo.Component_info[ci].height_in_blocks, cinfo.Component_info[ci].V_samp_factor));
                    m_whole_image[ci].ErrorProcessor = cinfo;
                }
            }
            else
            {
                /* We only need a single-MCU buffer. */
                JBLOCK[] buffer = new JBLOCK[JpegConstants.C_MAX_BLOCKS_IN_MCU];
                for (int i = 0; i < JpegConstants.C_MAX_BLOCKS_IN_MCU; i++)
                {
                    buffer[i] = new JBLOCK();
                }

                for (int i = 0; i < JpegConstants.C_MAX_BLOCKS_IN_MCU; i++)
                {
                    m_MCU_buffer[i] = new JBLOCK[JpegConstants.C_MAX_BLOCKS_IN_MCU - i];
                    for (int j = i; j < JpegConstants.C_MAX_BLOCKS_IN_MCU; j++)
                    {
                        m_MCU_buffer[i][j - i] = buffer[j];
                    }
                }

                /* flag for no virtual arrays */
                m_whole_image[0] = null;
            }
        }
        /// <summary>
        /// Process some data in the context case.
        /// </summary>
        private void pre_process_context(byte[][] input_buf, ref int in_row_ctr, int in_rows_avail, byte[][][] output_buf, ref int out_row_group_ctr, int out_row_groups_avail)
        {
            while (out_row_group_ctr < out_row_groups_avail)
            {
                if (in_row_ctr < in_rows_avail)
                {
                    /* Do color conversion to fill the conversion buffer. */
                    int inrows  = in_rows_avail - in_row_ctr;
                    int numrows = m_next_buf_stop - m_next_buf_row;
                    numrows = Math.Min(numrows, inrows);
                    m_cinfo.m_cconvert.color_convert(input_buf, in_row_ctr, m_color_buf, m_colorBufRowsOffset + m_next_buf_row, numrows);

                    /* Pad at top of image, if first time through */
                    if (m_rows_to_go == m_cinfo.m_image_height)
                    {
                        for (int ci = 0; ci < m_cinfo.m_num_components; ci++)
                        {
                            for (int row = 1; row <= m_cinfo.m_max_v_samp_factor; row++)
                            {
                                JpegUtils.jcopy_sample_rows(m_color_buf[ci], m_colorBufRowsOffset, m_color_buf[ci], m_colorBufRowsOffset - row, 1, m_cinfo.m_image_width);
                            }
                        }
                    }

                    in_row_ctr     += numrows;
                    m_next_buf_row += numrows;
                    m_rows_to_go   -= numrows;
                }
                else
                {
                    /* Return for more data, unless we are at the bottom of the image. */
                    if (m_rows_to_go != 0)
                    {
                        break;
                    }

                    /* When at bottom of image, pad to fill the conversion buffer. */
                    if (m_next_buf_row < m_next_buf_stop)
                    {
                        for (int ci = 0; ci < m_cinfo.m_num_components; ci++)
                        {
                            expand_bottom_edge(m_color_buf[ci], m_colorBufRowsOffset, m_cinfo.m_image_width, m_next_buf_row, m_next_buf_stop);
                        }

                        m_next_buf_row = m_next_buf_stop;
                    }
                }

                /* If we've gotten enough data, downsample a row group. */
                if (m_next_buf_row == m_next_buf_stop)
                {
                    m_cinfo.m_downsample.downsample(m_color_buf, m_colorBufRowsOffset + m_this_row_group, output_buf, out_row_group_ctr);
                    out_row_group_ctr++;

                    /* Advance pointers with wraparound as necessary. */
                    m_this_row_group += m_cinfo.m_max_v_samp_factor;
                    int buf_height = m_cinfo.m_max_v_samp_factor * 3;

                    if (m_this_row_group >= buf_height)
                    {
                        m_this_row_group = 0;
                    }

                    if (m_next_buf_row >= buf_height)
                    {
                        m_next_buf_row = 0;
                    }

                    m_next_buf_stop = m_next_buf_row + m_cinfo.m_max_v_samp_factor;
                }
            }
        }
Beispiel #13
0
        /// <summary>
        /// Routines to calculate various quantities related to the size of the image.
        /// Called once, when first SOS marker is reached
        /// </summary>
        private void initial_setup()
        {
            /* Make sure image isn't bigger than I can handle */
            if (m_cinfo.m_image_height > JpegConstants.JPEG_MAX_DIMENSION ||
                m_cinfo.m_image_width > JpegConstants.JPEG_MAX_DIMENSION)
            {
                m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_IMAGE_TOO_BIG, (int)JpegConstants.JPEG_MAX_DIMENSION);
            }

            /* Only 8 to 12 bits data precision are supported for DCT based JPEG */
            if (m_cinfo.m_data_precision < 8 || m_cinfo.m_data_precision > 12)
            {
                m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_BAD_PRECISION, m_cinfo.m_data_precision);
            }

            /* Check that number of components won't exceed internal array sizes */
            if (m_cinfo.m_num_components > JpegConstants.MAX_COMPONENTS)
            {
                m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_COMPONENT_COUNT, m_cinfo.m_num_components, JpegConstants.MAX_COMPONENTS);
            }

            /* Compute maximum sampling factors; check factor validity */
            m_cinfo.m_max_h_samp_factor = 1;
            m_cinfo.m_max_v_samp_factor = 1;

            for (int ci = 0; ci < m_cinfo.m_num_components; ci++)
            {
                if (m_cinfo.Comp_info[ci].H_samp_factor <= 0 || m_cinfo.Comp_info[ci].H_samp_factor > JpegConstants.MAX_SAMP_FACTOR ||
                    m_cinfo.Comp_info[ci].V_samp_factor <= 0 || m_cinfo.Comp_info[ci].V_samp_factor > JpegConstants.MAX_SAMP_FACTOR)
                {
                    m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_BAD_SAMPLING);
                }

                m_cinfo.m_max_h_samp_factor = Math.Max(m_cinfo.m_max_h_samp_factor, m_cinfo.Comp_info[ci].H_samp_factor);
                m_cinfo.m_max_v_samp_factor = Math.Max(m_cinfo.m_max_v_samp_factor, m_cinfo.Comp_info[ci].V_samp_factor);
            }

            /* Derive block_size, natural_order, and lim_Se */
            if (m_cinfo.is_baseline || (m_cinfo.m_progressive_mode && m_cinfo.m_comps_in_scan != 0))
            {
                /* no pseudo SOS marker */
                m_cinfo.block_size    = JpegConstants.DCTSIZE;
                m_cinfo.natural_order = JpegUtils.jpeg_natural_order;
                m_cinfo.lim_Se        = JpegConstants.DCTSIZE2 - 1;
            }
            else
            {
                switch (m_cinfo.m_Se)
                {
                case (1 * 1 - 1):
                    m_cinfo.block_size    = 1;
                    m_cinfo.natural_order = JpegUtils.jpeg_natural_order;     /* not needed */
                    m_cinfo.lim_Se        = m_cinfo.m_Se;
                    break;

                case (2 * 2 - 1):
                    m_cinfo.block_size    = 2;
                    m_cinfo.natural_order = JpegUtils.jpeg_natural_order2;
                    m_cinfo.lim_Se        = m_cinfo.m_Se;
                    break;

                case (3 * 3 - 1):
                    m_cinfo.block_size    = 3;
                    m_cinfo.natural_order = JpegUtils.jpeg_natural_order3;
                    m_cinfo.lim_Se        = m_cinfo.m_Se;
                    break;

                case (4 * 4 - 1):
                    m_cinfo.block_size    = 4;
                    m_cinfo.natural_order = JpegUtils.jpeg_natural_order4;
                    m_cinfo.lim_Se        = m_cinfo.m_Se;
                    break;

                case (5 * 5 - 1):
                    m_cinfo.block_size    = 5;
                    m_cinfo.natural_order = JpegUtils.jpeg_natural_order5;
                    m_cinfo.lim_Se        = m_cinfo.m_Se;
                    break;

                case (6 * 6 - 1):
                    m_cinfo.block_size    = 6;
                    m_cinfo.natural_order = JpegUtils.jpeg_natural_order6;
                    m_cinfo.lim_Se        = m_cinfo.m_Se;
                    break;

                case (7 * 7 - 1):
                    m_cinfo.block_size    = 7;
                    m_cinfo.natural_order = JpegUtils.jpeg_natural_order7;
                    m_cinfo.lim_Se        = m_cinfo.m_Se;
                    break;

                case (8 * 8 - 1):
                    m_cinfo.block_size    = 8;
                    m_cinfo.natural_order = JpegUtils.jpeg_natural_order;
                    m_cinfo.lim_Se        = JpegConstants.DCTSIZE2 - 1;
                    break;

                case (9 * 9 - 1):
                    m_cinfo.block_size    = 9;
                    m_cinfo.natural_order = JpegUtils.jpeg_natural_order;
                    m_cinfo.lim_Se        = JpegConstants.DCTSIZE2 - 1;
                    break;

                case (10 * 10 - 1):
                    m_cinfo.block_size    = 10;
                    m_cinfo.natural_order = JpegUtils.jpeg_natural_order;
                    m_cinfo.lim_Se        = JpegConstants.DCTSIZE2 - 1;
                    break;

                case (11 * 11 - 1):
                    m_cinfo.block_size    = 11;
                    m_cinfo.natural_order = JpegUtils.jpeg_natural_order;
                    m_cinfo.lim_Se        = JpegConstants.DCTSIZE2 - 1;
                    break;

                case (12 * 12 - 1):
                    m_cinfo.block_size    = 12;
                    m_cinfo.natural_order = JpegUtils.jpeg_natural_order;
                    m_cinfo.lim_Se        = JpegConstants.DCTSIZE2 - 1;
                    break;

                case (13 * 13 - 1):
                    m_cinfo.block_size    = 13;
                    m_cinfo.natural_order = JpegUtils.jpeg_natural_order;
                    m_cinfo.lim_Se        = JpegConstants.DCTSIZE2 - 1;
                    break;

                case (14 * 14 - 1):
                    m_cinfo.block_size    = 14;
                    m_cinfo.natural_order = JpegUtils.jpeg_natural_order;
                    m_cinfo.lim_Se        = JpegConstants.DCTSIZE2 - 1;
                    break;

                case (15 * 15 - 1):
                    m_cinfo.block_size    = 15;
                    m_cinfo.natural_order = JpegUtils.jpeg_natural_order;
                    m_cinfo.lim_Se        = JpegConstants.DCTSIZE2 - 1;
                    break;

                case (16 * 16 - 1):
                    m_cinfo.block_size    = 16;
                    m_cinfo.natural_order = JpegUtils.jpeg_natural_order;
                    m_cinfo.lim_Se        = JpegConstants.DCTSIZE2 - 1;
                    break;

                default:
                    m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_BAD_PROGRESSION,
                                    m_cinfo.m_Ss, m_cinfo.m_Se, m_cinfo.m_Ah, m_cinfo.m_Al);
                    break;
                }
            }

            /* We initialize DCT_scaled_size and min_DCT_scaled_size to block_size.
             * In the full decompressor,
             * this will be overridden by jpeg_calc_output_dimensions in jdmaster.c;
             * but in the transcoder,
             * jpeg_calc_output_dimensions is not used, so we must do it here.
             */
            m_cinfo.min_DCT_h_scaled_size = m_cinfo.block_size;
            m_cinfo.min_DCT_v_scaled_size = m_cinfo.block_size;

            /* Compute dimensions of components */
            for (int ci = 0; ci < m_cinfo.m_num_components; ci++)
            {
                jpeg_component_info compptr = m_cinfo.Comp_info[ci];
                compptr.DCT_h_scaled_size = m_cinfo.block_size;
                compptr.DCT_v_scaled_size = m_cinfo.block_size;

                /* Size in DCT blocks */
                compptr.Width_in_blocks = (int)JpegUtils.jdiv_round_up(
                    m_cinfo.m_image_width * compptr.H_samp_factor,
                    m_cinfo.m_max_h_samp_factor * m_cinfo.block_size);

                compptr.height_in_blocks = (int)JpegUtils.jdiv_round_up(
                    m_cinfo.m_image_height * compptr.V_samp_factor,
                    m_cinfo.m_max_v_samp_factor * m_cinfo.block_size);

                /* downsampled_width and downsampled_height will also be overridden by
                 * jpeg_decomp_master if we are doing full decompression.  The transcoder library
                 * doesn't use these values, but the calling application might.
                 */
                /* Size in samples */
                compptr.downsampled_width = (int)JpegUtils.jdiv_round_up(
                    m_cinfo.m_image_width * compptr.H_samp_factor,
                    m_cinfo.m_max_h_samp_factor);

                compptr.downsampled_height = (int)JpegUtils.jdiv_round_up(
                    m_cinfo.m_image_height * compptr.V_samp_factor,
                    m_cinfo.m_max_v_samp_factor);

                /* Mark component needed, until color conversion says otherwise */
                compptr.component_needed = true;

                /* Mark no quantization table yet saved for component */
                compptr.quant_table = null;
            }

            /* Compute number of fully interleaved MCU rows. */
            m_cinfo.m_total_iMCU_rows = (int)JpegUtils.jdiv_round_up(
                m_cinfo.m_image_height, m_cinfo.m_max_v_samp_factor * m_cinfo.block_size);

            /* Decide whether file contains multiple scans */
            if (m_cinfo.m_comps_in_scan < m_cinfo.m_num_components || m_cinfo.m_progressive_mode)
            {
                m_cinfo.m_inputctl.m_has_multiple_scans = true;
            }
            else
            {
                m_cinfo.m_inputctl.m_has_multiple_scans = false;
            }
        }
 /// <summary>
 /// Color conversion for grayscale: just copy the data.
 /// This also works for YCbCr -> grayscale conversion, in which
 /// we just copy the Y (luminance) component and ignore chrominance.
 /// </summary>
 private void grayscale_convert(ComponentBuffer[] input_buf, int input_row, byte[][] output_buf, int output_row, int num_rows)
 {
     JpegUtils.jcopy_sample_rows(input_buf[0], input_row + m_perComponentOffsets[0], output_buf, output_row, num_rows, m_cinfo.m_output_width);
 }
        /**************** Cases other than YCbCr -> RGB **************/

        /// <summary>
        /// Adobe-style YCCK->CMYK conversion.
        /// We convert YCbCr to R=1-C, G=1-M, and B=1-Y using the same
        /// conversion as above, while passing K (black) unchanged.
        /// We assume build_ycc_rgb_table has been called.
        /// </summary>
        private void ycck_cmyk_convert(ComponentBuffer[] input_buf, int input_row, byte[][] output_buf, int output_row, int num_rows)
        {
            int component0RowOffset = m_perComponentOffsets[0];
            int component1RowOffset = m_perComponentOffsets[1];
            int component2RowOffset = m_perComponentOffsets[2];
            int component3RowOffset = m_perComponentOffsets[3];

            byte[] limit       = m_cinfo.m_sample_range_limit;
            int    limitOffset = m_cinfo.m_sampleRangeLimitOffset;

            int num_cols = m_cinfo.m_output_width;

            for (int row = 0; row < num_rows; row++)
            {
                int columnOffset = 0;
                for (int col = 0; col < num_cols; col++)
                {
                    int y  = input_buf[0][input_row + component0RowOffset][col];
                    int cb = input_buf[1][input_row + component1RowOffset][col];
                    int cr = input_buf[2][input_row + component2RowOffset][col];

                    /* Range-limiting is essential due to noise introduced by DCT losses. */
                    output_buf[output_row + row][columnOffset]     = limit[limitOffset + JpegConstants.MAXJSAMPLE - (y + m_Cr_r_tab[cr])];                                                    /* red */
                    output_buf[output_row + row][columnOffset + 1] = limit[limitOffset + JpegConstants.MAXJSAMPLE - (y + JpegUtils.RIGHT_SHIFT(m_Cb_g_tab[cb] + m_Cr_g_tab[cr], SCALEBITS))]; /* green */
                    output_buf[output_row + row][columnOffset + 2] = limit[limitOffset + JpegConstants.MAXJSAMPLE - (y + m_Cb_b_tab[cb])];                                                    /* blue */

                    /* K passes through unchanged */
                    /* don't need GETJSAMPLE here */
                    output_buf[output_row + row][columnOffset + 3] = input_buf[3][input_row + component3RowOffset][col];
                    columnOffset += 4;
                }

                input_row++;
            }
        }
        private void ycc_rgb_convert(ComponentBuffer[] input_buf, int input_row, byte[][] output_buf, int output_row, int num_rows)
        {
            int component0RowOffset = m_perComponentOffsets[0];
            int component1RowOffset = m_perComponentOffsets[1];
            int component2RowOffset = m_perComponentOffsets[2];

            byte[] limit       = m_cinfo.m_sample_range_limit;
            int    limitOffset = m_cinfo.m_sampleRangeLimitOffset;

            for (int row = 0; row < num_rows; row++)
            {
                int columnOffset = 0;
                for (int col = 0; col < m_cinfo.m_output_width; col++)
                {
                    int y  = input_buf[0][input_row + component0RowOffset][col];
                    int cb = input_buf[1][input_row + component1RowOffset][col];
                    int cr = input_buf[2][input_row + component2RowOffset][col];

                    /* Range-limiting is essential due to noise introduced by DCT losses. */
                    output_buf[output_row + row][columnOffset + JpegConstants.RGB_RED]   = limit[limitOffset + y + m_Cr_r_tab[cr]];
                    output_buf[output_row + row][columnOffset + JpegConstants.RGB_GREEN] = limit[limitOffset + y + JpegUtils.RIGHT_SHIFT(m_Cb_g_tab[cb] + m_Cr_g_tab[cr], SCALEBITS)];
                    output_buf[output_row + row][columnOffset + JpegConstants.RGB_BLUE]  = limit[limitOffset + y + m_Cb_b_tab[cb]];
                    columnOffset += JpegConstants.RGB_PIXELSIZE;
                }

                input_row++;
            }
        }
Beispiel #17
0
        /// <summary>
        /// Map some rows of pixels to the output colormapped representation.
        /// General case, with Floyd-Steinberg dithering
        /// </summary>
        private void quantize_fs_dither(byte[][] input_buf, int in_row, byte[][] output_buf, int out_row, int num_rows)
        {
            int nc    = m_cinfo.m_out_color_components;
            int width = m_cinfo.m_output_width;

            byte[] limit       = m_cinfo.m_sample_range_limit;
            int    limitOffset = m_cinfo.m_sampleRangeLimitOffset;

            for (int row = 0; row < num_rows; row++)
            {
                /* Initialize output values to 0 so can process components separately */
                Array.Clear(output_buf[out_row + row], 0, width);

                for (int ci = 0; ci < nc; ci++)
                {
                    int inRow   = in_row + row;
                    int inIndex = ci;

                    int outIndex = 0;
                    int outRow   = out_row + row;

                    int errorIndex = 0;
                    int dir;            /* 1 for left-to-right, -1 for right-to-left */
                    if (m_on_odd_row)
                    {
                        /* work right to left in this row */
                        inIndex   += (width - 1) * nc; /* so point to rightmost pixel */
                        outIndex  += width - 1;
                        dir        = -1;
                        errorIndex = width + 1; /* => entry after last column */
                    }
                    else
                    {
                        /* work left to right in this row */
                        dir        = 1;
                        errorIndex = 0; /* => entry before first column */
                    }
                    int dirnc = dir * nc;

                    /* Preset error values: no error propagated to first pixel from left */
                    int cur = 0;
                    /* and no error propagated to row below yet */
                    int belowerr = 0;
                    int bpreverr = 0;

                    for (int col = width; col > 0; col--)
                    {
                        /* cur holds the error propagated from the previous pixel on the
                         * current line.  Add the error propagated from the previous line
                         * to form the complete error correction term for this pixel, and
                         * round the error term (which is expressed * 16) to an integer.
                         * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct
                         * for either sign of the error value.
                         * Note: errorIndex is for *previous* column's array entry.
                         */
                        cur = JpegUtils.RIGHT_SHIFT(cur + m_fserrors[ci][errorIndex + dir] + 8, 4);

                        /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
                         * The maximum error is +- MAXJSAMPLE; this sets the required size
                         * of the range_limit array.
                         */
                        cur += input_buf[inRow][inIndex];
                        cur  = limit[limitOffset + cur];

                        /* Select output value, accumulate into output code for this pixel */
                        int pixcode = m_colorindex[ci][m_colorindexOffset[ci] + cur];
                        output_buf[outRow][outIndex] += (byte)pixcode;

                        /* Compute actual representation error at this pixel */
                        /* Note: we can do this even though we don't have the final */
                        /* pixel code, because the colormap is orthogonal. */
                        cur -= m_sv_colormap[ci][pixcode];

                        /* Compute error fractions to be propagated to adjacent pixels.
                         * Add these into the running sums, and simultaneously shift the
                         * next-line error sums left by 1 column.
                         */
                        int bnexterr = cur;
                        int delta    = cur * 2;
                        cur += delta;       /* form error * 3 */
                        m_fserrors[ci][errorIndex + 0] = (short)(bpreverr + cur);
                        cur     += delta;   /* form error * 5 */
                        bpreverr = belowerr + cur;
                        belowerr = bnexterr;
                        cur     += delta;   /* form error * 7 */

                        /* At this point cur contains the 7/16 error value to be propagated
                         * to the next pixel on the current line, and all the errors for the
                         * next line have been shifted over. We are therefore ready to move on.
                         */
                        inIndex    += dirnc; /* advance input to next column */
                        outIndex   += dir;   /* advance output to next column */
                        errorIndex += dir;   /* advance errorIndex to current column */
                    }

                    /* Post-loop cleanup: we must unload the final error value into the
                     * final fserrors[] entry.  Note we need not unload belowerr because
                     * it is for the dummy column before or after the actual array.
                     */
                    m_fserrors[ci][errorIndex + 0] = (short)bpreverr;  /* unload prev err into array */
                }

                m_on_odd_row = (m_on_odd_row ? false : true);
            }
        }
Beispiel #18
0
        /// <summary>
        /// Do computations that are needed before processing a JPEG scan
        /// cinfo.comps_in_scan and cinfo.cur_comp_info[] were set from SOS marker
        /// </summary>
        private void per_scan_setup()
        {
            if (m_cinfo.m_comps_in_scan == 1)
            {
                /* Noninterleaved (single-component) scan */
                jpeg_component_info componentInfo = m_cinfo.Comp_info[m_cinfo.m_cur_comp_info[0]];

                /* Overall image size in MCUs */
                m_cinfo.m_MCUs_per_row     = componentInfo.Width_in_blocks;
                m_cinfo.m_MCU_rows_in_scan = componentInfo.height_in_blocks;

                /* For noninterleaved scan, always one block per MCU */
                componentInfo.MCU_width        = 1;
                componentInfo.MCU_height       = 1;
                componentInfo.MCU_blocks       = 1;
                componentInfo.MCU_sample_width = componentInfo.DCT_scaled_size;
                componentInfo.last_col_width   = 1;

                /* For noninterleaved scans, it is convenient to define last_row_height
                 * as the number of block rows present in the last iMCU row.
                 */
                int tmp = componentInfo.height_in_blocks % componentInfo.V_samp_factor;
                if (tmp == 0)
                {
                    tmp = componentInfo.V_samp_factor;
                }
                componentInfo.last_row_height = tmp;
                m_cinfo.Comp_info[m_cinfo.m_cur_comp_info[0]] = componentInfo;

                /* Prepare array describing MCU composition */
                m_cinfo.m_blocks_in_MCU     = 1;
                m_cinfo.m_MCU_membership[0] = 0;
            }
            else
            {
                /* Interleaved (multi-component) scan */
                if (m_cinfo.m_comps_in_scan <= 0 || m_cinfo.m_comps_in_scan > JpegConstants.MAX_COMPS_IN_SCAN)
                {
                    m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_COMPONENT_COUNT, m_cinfo.m_comps_in_scan, JpegConstants.MAX_COMPS_IN_SCAN);
                }

                /* Overall image size in MCUs */
                m_cinfo.m_MCUs_per_row = JpegUtils.jdiv_round_up(
                    m_cinfo.m_image_width, m_cinfo.m_max_h_samp_factor * JpegConstants.DCTSIZE);

                m_cinfo.m_MCU_rows_in_scan = JpegUtils.jdiv_round_up(
                    m_cinfo.m_image_height, m_cinfo.m_max_v_samp_factor * JpegConstants.DCTSIZE);

                m_cinfo.m_blocks_in_MCU = 0;

                for (int ci = 0; ci < m_cinfo.m_comps_in_scan; ci++)
                {
                    jpeg_component_info componentInfo = m_cinfo.Comp_info[m_cinfo.m_cur_comp_info[ci]];

                    /* Sampling factors give # of blocks of component in each MCU */
                    componentInfo.MCU_width        = componentInfo.H_samp_factor;
                    componentInfo.MCU_height       = componentInfo.V_samp_factor;
                    componentInfo.MCU_blocks       = componentInfo.MCU_width * componentInfo.MCU_height;
                    componentInfo.MCU_sample_width = componentInfo.MCU_width * componentInfo.DCT_scaled_size;

                    /* Figure number of non-dummy blocks in last MCU column & row */
                    int tmp = componentInfo.Width_in_blocks % componentInfo.MCU_width;
                    if (tmp == 0)
                    {
                        tmp = componentInfo.MCU_width;
                    }
                    componentInfo.last_col_width = tmp;

                    tmp = componentInfo.height_in_blocks % componentInfo.MCU_height;
                    if (tmp == 0)
                    {
                        tmp = componentInfo.MCU_height;
                    }
                    componentInfo.last_row_height = tmp;

                    /* Prepare array describing MCU composition */
                    int mcublks = componentInfo.MCU_blocks;
                    if (m_cinfo.m_blocks_in_MCU + mcublks > JpegConstants.D_MAX_BLOCKS_IN_MCU)
                    {
                        m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_BAD_MCU_SIZE);
                    }

                    m_cinfo.Comp_info[m_cinfo.m_cur_comp_info[ci]] = componentInfo;

                    while (mcublks-- > 0)
                    {
                        m_cinfo.m_MCU_membership[m_cinfo.m_blocks_in_MCU++] = ci;
                    }
                }
            }
        }
Beispiel #19
0
        /*
         * Compute output image dimensions and related values.
         * NOTE: this is exported for possible use by application.
         * Hence it mustn't do anything that can't be done twice.
         */
        /* Do computations that are needed before master selection phase.
         * This function is used for transcoding and full decompression.
         */
        public void jpeg_core_output_dimensions()
        {
            /* Compute actual output image dimensions and DCT scaling choices. */
            if (m_cinfo.m_scale_num * m_cinfo.block_size <= m_cinfo.m_scale_denom)
            {
                /* Provide 1/block_size scaling */
                m_cinfo.m_output_width = (int)
                                         JpegUtils.jdiv_round_up((long)m_cinfo.m_image_width, (long)m_cinfo.block_size);
                m_cinfo.m_output_height = (int)
                                          JpegUtils.jdiv_round_up((long)m_cinfo.m_image_height, (long)m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 1;
                m_cinfo.min_DCT_v_scaled_size = 1;
            }
            else if (m_cinfo.m_scale_num * m_cinfo.block_size <= m_cinfo.m_scale_denom * 2)
            {
                /* Provide 2/block_size scaling */
                m_cinfo.m_output_width = (int)
                                         JpegUtils.jdiv_round_up((long)m_cinfo.m_image_width * 2L, (long)m_cinfo.block_size);
                m_cinfo.m_output_height = (int)
                                          JpegUtils.jdiv_round_up((long)m_cinfo.m_image_height * 2L, (long)m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 2;
                m_cinfo.min_DCT_v_scaled_size = 2;
            }
            else if (m_cinfo.m_scale_num * m_cinfo.block_size <= m_cinfo.m_scale_denom * 3)
            {
                /* Provide 3/block_size scaling */
                m_cinfo.m_output_width = (int)
                                         JpegUtils.jdiv_round_up((long)m_cinfo.m_image_width * 3L, (long)m_cinfo.block_size);
                m_cinfo.m_output_height = (int)
                                          JpegUtils.jdiv_round_up((long)m_cinfo.m_image_height * 3L, (long)m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 3;
                m_cinfo.min_DCT_v_scaled_size = 3;
            }
            else if (m_cinfo.m_scale_num * m_cinfo.block_size <= m_cinfo.m_scale_denom * 4)
            {
                /* Provide 4/block_size scaling */
                m_cinfo.m_output_width = (int)
                                         JpegUtils.jdiv_round_up((long)m_cinfo.m_image_width * 4L, (long)m_cinfo.block_size);
                m_cinfo.m_output_height = (int)
                                          JpegUtils.jdiv_round_up((long)m_cinfo.m_image_height * 4L, (long)m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 4;
                m_cinfo.min_DCT_v_scaled_size = 4;
            }
            else if (m_cinfo.m_scale_num * m_cinfo.block_size <= m_cinfo.m_scale_denom * 5)
            {
                /* Provide 5/block_size scaling */
                m_cinfo.m_output_width = (int)
                                         JpegUtils.jdiv_round_up((long)m_cinfo.m_image_width * 5L, (long)m_cinfo.block_size);
                m_cinfo.m_output_height = (int)
                                          JpegUtils.jdiv_round_up((long)m_cinfo.m_image_height * 5L, (long)m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 5;
                m_cinfo.min_DCT_v_scaled_size = 5;
            }
            else if (m_cinfo.m_scale_num * m_cinfo.block_size <= m_cinfo.m_scale_denom * 6)
            {
                /* Provide 6/block_size scaling */
                m_cinfo.m_output_width = (int)
                                         JpegUtils.jdiv_round_up((long)m_cinfo.m_image_width * 6L, (long)m_cinfo.block_size);
                m_cinfo.m_output_height = (int)
                                          JpegUtils.jdiv_round_up((long)m_cinfo.m_image_height * 6L, (long)m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 6;
                m_cinfo.min_DCT_v_scaled_size = 6;
            }
            else if (m_cinfo.m_scale_num * m_cinfo.block_size <= m_cinfo.m_scale_denom * 7)
            {
                /* Provide 7/block_size scaling */
                m_cinfo.m_output_width = (int)
                                         JpegUtils.jdiv_round_up((long)m_cinfo.m_image_width * 7L, (long)m_cinfo.block_size);
                m_cinfo.m_output_height = (int)
                                          JpegUtils.jdiv_round_up((long)m_cinfo.m_image_height * 7L, (long)m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 7;
                m_cinfo.min_DCT_v_scaled_size = 7;
            }
            else if (m_cinfo.m_scale_num * m_cinfo.block_size <= m_cinfo.m_scale_denom * 8)
            {
                /* Provide 8/block_size scaling */
                m_cinfo.m_output_width = (int)
                                         JpegUtils.jdiv_round_up((long)m_cinfo.m_image_width * 8L, (long)m_cinfo.block_size);
                m_cinfo.m_output_height = (int)
                                          JpegUtils.jdiv_round_up((long)m_cinfo.m_image_height * 8L, (long)m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 8;
                m_cinfo.min_DCT_v_scaled_size = 8;
            }
            else if (m_cinfo.m_scale_num * m_cinfo.block_size <= m_cinfo.m_scale_denom * 9)
            {
                /* Provide 9/block_size scaling */
                m_cinfo.m_output_width = (int)
                                         JpegUtils.jdiv_round_up((long)m_cinfo.m_image_width * 9L, (long)m_cinfo.block_size);
                m_cinfo.m_output_height = (int)
                                          JpegUtils.jdiv_round_up((long)m_cinfo.m_image_height * 9L, (long)m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 9;
                m_cinfo.min_DCT_v_scaled_size = 9;
            }
            else if (m_cinfo.m_scale_num * m_cinfo.block_size <= m_cinfo.m_scale_denom * 10)
            {
                /* Provide 10/block_size scaling */
                m_cinfo.m_output_width = (int)
                                         JpegUtils.jdiv_round_up((long)m_cinfo.m_image_width * 10L, (long)m_cinfo.block_size);
                m_cinfo.m_output_height = (int)
                                          JpegUtils.jdiv_round_up((long)m_cinfo.m_image_height * 10L, (long)m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 10;
                m_cinfo.min_DCT_v_scaled_size = 10;
            }
            else if (m_cinfo.m_scale_num * m_cinfo.block_size <= m_cinfo.m_scale_denom * 11)
            {
                /* Provide 11/block_size scaling */
                m_cinfo.m_output_width = (int)
                                         JpegUtils.jdiv_round_up((long)m_cinfo.m_image_width * 11L, (long)m_cinfo.block_size);
                m_cinfo.m_output_height = (int)
                                          JpegUtils.jdiv_round_up((long)m_cinfo.m_image_height * 11L, (long)m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 11;
                m_cinfo.min_DCT_v_scaled_size = 11;
            }
            else if (m_cinfo.m_scale_num * m_cinfo.block_size <= m_cinfo.m_scale_denom * 12)
            {
                /* Provide 12/block_size scaling */
                m_cinfo.m_output_width = (int)
                                         JpegUtils.jdiv_round_up((long)m_cinfo.m_image_width * 12L, (long)m_cinfo.block_size);
                m_cinfo.m_output_height = (int)
                                          JpegUtils.jdiv_round_up((long)m_cinfo.m_image_height * 12L, (long)m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 12;
                m_cinfo.min_DCT_v_scaled_size = 12;
            }
            else if (m_cinfo.m_scale_num * m_cinfo.block_size <= m_cinfo.m_scale_denom * 13)
            {
                /* Provide 13/block_size scaling */
                m_cinfo.m_output_width = (int)
                                         JpegUtils.jdiv_round_up((long)m_cinfo.m_image_width * 13L, (long)m_cinfo.block_size);
                m_cinfo.m_output_height = (int)
                                          JpegUtils.jdiv_round_up((long)m_cinfo.m_image_height * 13L, (long)m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 13;
                m_cinfo.min_DCT_v_scaled_size = 13;
            }
            else if (m_cinfo.m_scale_num * m_cinfo.block_size <= m_cinfo.m_scale_denom * 14)
            {
                /* Provide 14/block_size scaling */
                m_cinfo.m_output_width = (int)
                                         JpegUtils.jdiv_round_up((long)m_cinfo.m_image_width * 14L, (long)m_cinfo.block_size);
                m_cinfo.m_output_height = (int)
                                          JpegUtils.jdiv_round_up((long)m_cinfo.m_image_height * 14L, (long)m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 14;
                m_cinfo.min_DCT_v_scaled_size = 14;
            }
            else if (m_cinfo.m_scale_num * m_cinfo.block_size <= m_cinfo.m_scale_denom * 15)
            {
                /* Provide 15/block_size scaling */
                m_cinfo.m_output_width = (int)
                                         JpegUtils.jdiv_round_up((long)m_cinfo.m_image_width * 15L, (long)m_cinfo.block_size);
                m_cinfo.m_output_height = (int)
                                          JpegUtils.jdiv_round_up((long)m_cinfo.m_image_height * 15L, (long)m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 15;
                m_cinfo.min_DCT_v_scaled_size = 15;
            }
            else
            {
                /* Provide 16/block_size scaling */
                m_cinfo.m_output_width = (int)
                                         JpegUtils.jdiv_round_up((long)m_cinfo.m_image_width * 16L, (long)m_cinfo.block_size);
                m_cinfo.m_output_height = (int)
                                          JpegUtils.jdiv_round_up((long)m_cinfo.m_image_height * 16L, (long)m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 16;
                m_cinfo.min_DCT_v_scaled_size = 16;
            }

            /* Recompute dimensions of components */
            for (int ci = 0; ci < m_cinfo.m_num_components; ci++)
            {
                jpeg_component_info compptr = m_cinfo.Comp_info[ci];
                compptr.DCT_h_scaled_size = m_cinfo.min_DCT_h_scaled_size;
                compptr.DCT_v_scaled_size = m_cinfo.min_DCT_v_scaled_size;
            }
        }
Beispiel #20
0
        /// <summary>
        /// Perform the forward DCT on one block of samples.
        /// NOTE: this code only copes with 8x8 DCTs.
        ///
        /// A slow-but-accurate integer implementation of the
        /// forward DCT (Discrete Cosine Transform).
        ///
        /// A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT
        /// on each column.  Direct algorithms are also available, but they are
        /// much more complex and seem not to be any faster when reduced to code.
        ///
        /// This implementation is based on an algorithm described in
        /// C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT
        /// Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics,
        /// Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991.
        /// The primary algorithm described there uses 11 multiplies and 29 adds.
        /// We use their alternate method with 12 multiplies and 32 adds.
        /// The advantage of this method is that no data path contains more than one
        /// multiplication; this allows a very simple and accurate implementation in
        /// scaled fixed-point arithmetic, with a minimal number of shifts.
        ///
        /// The poop on this scaling stuff is as follows:
        ///
        /// Each 1-D DCT step produces outputs which are a factor of sqrt(N)
        /// larger than the true DCT outputs.  The final outputs are therefore
        /// a factor of N larger than desired; since N=8 this can be cured by
        /// a simple right shift at the end of the algorithm.  The advantage of
        /// this arrangement is that we save two multiplications per 1-D DCT,
        /// because the y0 and y4 outputs need not be divided by sqrt(N).
        /// In the IJG code, this factor of 8 is removed by the quantization
        /// step, NOT here.
        ///
        /// We have to do addition and subtraction of the integer inputs, which
        /// is no problem, and multiplication by fractional constants, which is
        /// a problem to do in integer arithmetic.  We multiply all the constants
        /// by CONST_SCALE and convert them to integer constants (thus retaining
        /// SLOW_INTEGER_CONST_BITS bits of precision in the constants).  After doing a
        /// multiplication we have to divide the product by CONST_SCALE, with proper
        /// rounding, to produce the correct output.  This division can be done
        /// cheaply as a right shift of SLOW_INTEGER_CONST_BITS bits.  We postpone shifting
        /// as long as possible so that partial sums can be added together with
        /// full fractional precision.
        ///
        /// The outputs of the first pass are scaled up by SLOW_INTEGER_PASS1_BITS bits so that
        /// they are represented to better-than-integral precision.  These outputs
        /// require BITS_IN_JSAMPLE + SLOW_INTEGER_PASS1_BITS + 3 bits; this fits in a 16-bit word
        /// with the recommended scaling.  (For 12-bit sample data, the intermediate
        /// array is int anyway.)
        ///
        /// To avoid overflow of the 32-bit intermediate results in pass 2, we must
        /// have BITS_IN_JSAMPLE + SLOW_INTEGER_CONST_BITS + SLOW_INTEGER_PASS1_BITS &lt;= 26.  Error analysis
        /// shows that the values given below are the most effective.
        /// </summary>
        private static void jpeg_fdct_islow(int[] data)
        {
            /* Pass 1: process rows. */
            /* Note results are scaled up by sqrt(8) compared to a true DCT; */
            /* furthermore, we scale the results by 2**SLOW_INTEGER_PASS1_BITS. */
            int dataIndex = 0;

            for (int ctr = JpegConstants.DCTSIZE - 1; ctr >= 0; ctr--)
            {
                int tmp0 = data[dataIndex + 0] + data[dataIndex + 7];
                int tmp7 = data[dataIndex + 0] - data[dataIndex + 7];
                int tmp1 = data[dataIndex + 1] + data[dataIndex + 6];
                int tmp6 = data[dataIndex + 1] - data[dataIndex + 6];
                int tmp2 = data[dataIndex + 2] + data[dataIndex + 5];
                int tmp5 = data[dataIndex + 2] - data[dataIndex + 5];
                int tmp3 = data[dataIndex + 3] + data[dataIndex + 4];
                int tmp4 = data[dataIndex + 3] - data[dataIndex + 4];

                /* Even part per LL&M figure 1 --- note that published figure is faulty;
                 * rotator "sqrt(2)*c1" should be "sqrt(2)*c6".
                 */

                int tmp10 = tmp0 + tmp3;
                int tmp13 = tmp0 - tmp3;
                int tmp11 = tmp1 + tmp2;
                int tmp12 = tmp1 - tmp2;

                data[dataIndex + 0] = (tmp10 + tmp11) << SLOW_INTEGER_PASS1_BITS;
                data[dataIndex + 4] = (tmp10 - tmp11) << SLOW_INTEGER_PASS1_BITS;

                int z1 = (tmp12 + tmp13) * SLOW_INTEGER_FIX_0_541196100;
                data[dataIndex + 2] = JpegUtils.DESCALE(z1 + tmp13 * SLOW_INTEGER_FIX_0_765366865,
                                                        SLOW_INTEGER_CONST_BITS - SLOW_INTEGER_PASS1_BITS);
                data[dataIndex + 6] = JpegUtils.DESCALE(z1 + tmp12 * (-SLOW_INTEGER_FIX_1_847759065),
                                                        SLOW_INTEGER_CONST_BITS - SLOW_INTEGER_PASS1_BITS);

                /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
                 * cK represents cos(K*pi/16).
                 * i0..i3 in the paper are tmp4..tmp7 here.
                 */

                z1 = tmp4 + tmp7;
                int z2 = tmp5 + tmp6;
                int z3 = tmp4 + tmp6;
                int z4 = tmp5 + tmp7;
                int z5 = (z3 + z4) * SLOW_INTEGER_FIX_1_175875602; /* sqrt(2) * c3 */

                tmp4 = tmp4 * SLOW_INTEGER_FIX_0_298631336;        /* sqrt(2) * (-c1+c3+c5-c7) */
                tmp5 = tmp5 * SLOW_INTEGER_FIX_2_053119869;        /* sqrt(2) * ( c1+c3-c5+c7) */
                tmp6 = tmp6 * SLOW_INTEGER_FIX_3_072711026;        /* sqrt(2) * ( c1+c3+c5-c7) */
                tmp7 = tmp7 * SLOW_INTEGER_FIX_1_501321110;        /* sqrt(2) * ( c1+c3-c5-c7) */
                z1   = z1 * (-SLOW_INTEGER_FIX_0_899976223);       /* sqrt(2) * (c7-c3) */
                z2   = z2 * (-SLOW_INTEGER_FIX_2_562915447);       /* sqrt(2) * (-c1-c3) */
                z3   = z3 * (-SLOW_INTEGER_FIX_1_961570560);       /* sqrt(2) * (-c3-c5) */
                z4   = z4 * (-SLOW_INTEGER_FIX_0_390180644);       /* sqrt(2) * (c5-c3) */

                z3 += z5;
                z4 += z5;

                data[dataIndex + 7] = JpegUtils.DESCALE(tmp4 + z1 + z3, SLOW_INTEGER_CONST_BITS - SLOW_INTEGER_PASS1_BITS);
                data[dataIndex + 5] = JpegUtils.DESCALE(tmp5 + z2 + z4, SLOW_INTEGER_CONST_BITS - SLOW_INTEGER_PASS1_BITS);
                data[dataIndex + 3] = JpegUtils.DESCALE(tmp6 + z2 + z3, SLOW_INTEGER_CONST_BITS - SLOW_INTEGER_PASS1_BITS);
                data[dataIndex + 1] = JpegUtils.DESCALE(tmp7 + z1 + z4, SLOW_INTEGER_CONST_BITS - SLOW_INTEGER_PASS1_BITS);

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

            /* Pass 2: process columns.
             * We remove the SLOW_INTEGER_PASS1_BITS scaling, but leave the results scaled up
             * by an overall factor of 8.
             */

            dataIndex = 0;
            for (int ctr = JpegConstants.DCTSIZE - 1; ctr >= 0; ctr--)
            {
                int tmp0 = data[dataIndex + JpegConstants.DCTSIZE * 0] + data[dataIndex + JpegConstants.DCTSIZE * 7];
                int tmp7 = data[dataIndex + JpegConstants.DCTSIZE * 0] - data[dataIndex + JpegConstants.DCTSIZE * 7];
                int tmp1 = data[dataIndex + JpegConstants.DCTSIZE * 1] + data[dataIndex + JpegConstants.DCTSIZE * 6];
                int tmp6 = data[dataIndex + JpegConstants.DCTSIZE * 1] - data[dataIndex + JpegConstants.DCTSIZE * 6];
                int tmp2 = data[dataIndex + JpegConstants.DCTSIZE * 2] + data[dataIndex + JpegConstants.DCTSIZE * 5];
                int tmp5 = data[dataIndex + JpegConstants.DCTSIZE * 2] - data[dataIndex + JpegConstants.DCTSIZE * 5];
                int tmp3 = data[dataIndex + JpegConstants.DCTSIZE * 3] + data[dataIndex + JpegConstants.DCTSIZE * 4];
                int tmp4 = data[dataIndex + JpegConstants.DCTSIZE * 3] - data[dataIndex + JpegConstants.DCTSIZE * 4];

                /* Even part per LL&M figure 1 --- note that published figure is faulty;
                 * rotator "sqrt(2)*c1" should be "sqrt(2)*c6".
                 */

                int tmp10 = tmp0 + tmp3;
                int tmp13 = tmp0 - tmp3;
                int tmp11 = tmp1 + tmp2;
                int tmp12 = tmp1 - tmp2;

                data[dataIndex + JpegConstants.DCTSIZE * 0] = JpegUtils.DESCALE(tmp10 + tmp11, SLOW_INTEGER_PASS1_BITS);
                data[dataIndex + JpegConstants.DCTSIZE * 4] = JpegUtils.DESCALE(tmp10 - tmp11, SLOW_INTEGER_PASS1_BITS);

                int z1 = (tmp12 + tmp13) * SLOW_INTEGER_FIX_0_541196100;
                data[dataIndex + JpegConstants.DCTSIZE * 2] = JpegUtils.DESCALE(z1 + tmp13 * SLOW_INTEGER_FIX_0_765366865,
                                                                                SLOW_INTEGER_CONST_BITS + SLOW_INTEGER_PASS1_BITS);
                data[dataIndex + JpegConstants.DCTSIZE * 6] = JpegUtils.DESCALE(z1 + tmp12 * (-SLOW_INTEGER_FIX_1_847759065),
                                                                                SLOW_INTEGER_CONST_BITS + SLOW_INTEGER_PASS1_BITS);

                /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
                 * cK represents cos(K*pi/16).
                 * i0..i3 in the paper are tmp4..tmp7 here.
                 */

                z1 = tmp4 + tmp7;
                int z2 = tmp5 + tmp6;
                int z3 = tmp4 + tmp6;
                int z4 = tmp5 + tmp7;
                int z5 = (z3 + z4) * SLOW_INTEGER_FIX_1_175875602; /* sqrt(2) * c3 */

                tmp4 = tmp4 * SLOW_INTEGER_FIX_0_298631336;        /* sqrt(2) * (-c1+c3+c5-c7) */
                tmp5 = tmp5 * SLOW_INTEGER_FIX_2_053119869;        /* sqrt(2) * ( c1+c3-c5+c7) */
                tmp6 = tmp6 * SLOW_INTEGER_FIX_3_072711026;        /* sqrt(2) * ( c1+c3+c5-c7) */
                tmp7 = tmp7 * SLOW_INTEGER_FIX_1_501321110;        /* sqrt(2) * ( c1+c3-c5-c7) */
                z1   = z1 * (-SLOW_INTEGER_FIX_0_899976223);       /* sqrt(2) * (c7-c3) */
                z2   = z2 * (-SLOW_INTEGER_FIX_2_562915447);       /* sqrt(2) * (-c1-c3) */
                z3   = z3 * (-SLOW_INTEGER_FIX_1_961570560);       /* sqrt(2) * (-c3-c5) */
                z4   = z4 * (-SLOW_INTEGER_FIX_0_390180644);       /* sqrt(2) * (c5-c3) */

                z3 += z5;
                z4 += z5;

                data[dataIndex + JpegConstants.DCTSIZE * 7] = JpegUtils.DESCALE(tmp4 + z1 + z3, SLOW_INTEGER_CONST_BITS + SLOW_INTEGER_PASS1_BITS);
                data[dataIndex + JpegConstants.DCTSIZE * 5] = JpegUtils.DESCALE(tmp5 + z2 + z4, SLOW_INTEGER_CONST_BITS + SLOW_INTEGER_PASS1_BITS);
                data[dataIndex + JpegConstants.DCTSIZE * 3] = JpegUtils.DESCALE(tmp6 + z2 + z3, SLOW_INTEGER_CONST_BITS + SLOW_INTEGER_PASS1_BITS);
                data[dataIndex + JpegConstants.DCTSIZE * 1] = JpegUtils.DESCALE(tmp7 + z1 + z4, SLOW_INTEGER_CONST_BITS + SLOW_INTEGER_PASS1_BITS);

                dataIndex++;          /* advance pointer to next column */
            }
        }
Beispiel #21
0
        /// <summary>
        /// Initialize for a processing pass.
        /// Verify that all referenced Q-tables are present, and set up
        /// the divisor table for each one.
        /// In the current implementation, DCT of all components is done during
        /// the first pass, even if only some components will be output in the
        /// first scan.  Hence all components should be examined here.
        /// </summary>
        public virtual void start_pass()
        {
            for (int ci = 0; ci < m_cinfo.m_num_components; ci++)
            {
                int qtblno = m_cinfo.Component_info[ci].Quant_tbl_no;

                /* Make sure specified quantization table is present */
                if (qtblno < 0 || qtblno >= JpegConstants.NUM_QUANT_TBLS || m_cinfo.m_quant_tbl_ptrs[qtblno] == null)
                {
                    m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_NO_QUANT_TABLE, qtblno);
                }

                JQUANT_TBL qtbl = m_cinfo.m_quant_tbl_ptrs[qtblno];

                /* Compute divisors for this quant table */
                /* We may do this more than once for same table, but it's not a big deal */
                int i = 0;
                switch (m_cinfo.m_dct_method)
                {
                case J_DCT_METHOD.JDCT_ISLOW:
                    /* For LL&M IDCT method, divisors are equal to raw quantization
                     * coefficients multiplied by 8 (to counteract scaling).
                     */
                    if (m_divisors[qtblno] == null)
                    {
                        m_divisors[qtblno] = new int [JpegConstants.DCTSIZE2];
                    }

                    for (i = 0; i < JpegConstants.DCTSIZE2; i++)
                    {
                        m_divisors[qtblno][i] = ((int)qtbl.quantval[i]) << 3;
                    }

                    break;

                case J_DCT_METHOD.JDCT_IFAST:
                    if (m_divisors[qtblno] == null)
                    {
                        m_divisors[qtblno] = new int [JpegConstants.DCTSIZE2];
                    }

                    for (i = 0; i < JpegConstants.DCTSIZE2; i++)
                    {
                        m_divisors[qtblno][i] = JpegUtils.DESCALE((int)qtbl.quantval[i] * (int)aanscales[i], CONST_BITS - 3);
                    }
                    break;

                case J_DCT_METHOD.JDCT_FLOAT:
                    if (m_float_divisors[qtblno] == null)
                    {
                        m_float_divisors[qtblno] = new float [JpegConstants.DCTSIZE2];
                    }

                    float[] fdtbl = m_float_divisors[qtblno];
                    i = 0;
                    for (int row = 0; row < JpegConstants.DCTSIZE; row++)
                    {
                        for (int col = 0; col < JpegConstants.DCTSIZE; col++)
                        {
                            fdtbl[i] = (float)(1.0 / (((double)qtbl.quantval[i] * aanscalefactor[row] * aanscalefactor[col] * 8.0)));
                            i++;
                        }
                    }
                    break;

                default:
                    m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_NOT_COMPILED);
                    break;
                }
            }
        }
Beispiel #22
0
        /// <summary>
        /// Do computations that are needed before processing a JPEG scan
        /// cinfo.comps_in_scan and cinfo.cur_comp_info[] are already set
        /// </summary>
        private void per_scan_setup()
        {
            if (m_cinfo.m_comps_in_scan == 1)
            {
                /* Noninterleaved (single-component) scan */
                int compIndex = m_cinfo.m_cur_comp_info[0];

                /* Overall image size in MCUs */
                m_cinfo.m_MCUs_per_row     = m_cinfo.Component_info[compIndex].Width_in_blocks;
                m_cinfo.m_MCU_rows_in_scan = m_cinfo.Component_info[compIndex].height_in_blocks;

                /* For noninterleaved scan, always one block per MCU */
                m_cinfo.Component_info[compIndex].MCU_width        = 1;
                m_cinfo.Component_info[compIndex].MCU_height       = 1;
                m_cinfo.Component_info[compIndex].MCU_blocks       = 1;
                m_cinfo.Component_info[compIndex].MCU_sample_width = JpegConstants.DCTSIZE;
                m_cinfo.Component_info[compIndex].last_col_width   = 1;

                /* For noninterleaved scans, it is convenient to define last_row_height
                 * as the number of block rows present in the last iMCU row.
                 */
                int tmp = m_cinfo.Component_info[compIndex].height_in_blocks % m_cinfo.Component_info[compIndex].V_samp_factor;
                if (tmp == 0)
                {
                    tmp = m_cinfo.Component_info[compIndex].V_samp_factor;
                }
                m_cinfo.Component_info[compIndex].last_row_height = tmp;

                /* Prepare array describing MCU composition */
                m_cinfo.m_blocks_in_MCU     = 1;
                m_cinfo.m_MCU_membership[0] = 0;
            }
            else
            {
                /* Interleaved (multi-component) scan */
                if (m_cinfo.m_comps_in_scan <= 0 || m_cinfo.m_comps_in_scan > JpegConstants.MAX_COMPS_IN_SCAN)
                {
                    m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_COMPONENT_COUNT, m_cinfo.m_comps_in_scan, JpegConstants.MAX_COMPS_IN_SCAN);
                }

                /* Overall image size in MCUs */
                m_cinfo.m_MCUs_per_row = JpegUtils.jdiv_round_up(
                    m_cinfo.m_image_width, m_cinfo.m_max_h_samp_factor * JpegConstants.DCTSIZE);

                m_cinfo.m_MCU_rows_in_scan = JpegUtils.jdiv_round_up(m_cinfo.m_image_height,
                                                                     m_cinfo.m_max_v_samp_factor * JpegConstants.DCTSIZE);

                m_cinfo.m_blocks_in_MCU = 0;

                for (int ci = 0; ci < m_cinfo.m_comps_in_scan; ci++)
                {
                    int compIndex = m_cinfo.m_cur_comp_info[ci];

                    /* Sampling factors give # of blocks of component in each MCU */
                    m_cinfo.Component_info[compIndex].MCU_width        = m_cinfo.Component_info[compIndex].H_samp_factor;
                    m_cinfo.Component_info[compIndex].MCU_height       = m_cinfo.Component_info[compIndex].V_samp_factor;
                    m_cinfo.Component_info[compIndex].MCU_blocks       = m_cinfo.Component_info[compIndex].MCU_width * m_cinfo.Component_info[compIndex].MCU_height;
                    m_cinfo.Component_info[compIndex].MCU_sample_width = m_cinfo.Component_info[compIndex].MCU_width * JpegConstants.DCTSIZE;

                    /* Figure number of non-dummy blocks in last MCU column & row */
                    int tmp = m_cinfo.Component_info[compIndex].Width_in_blocks % m_cinfo.Component_info[compIndex].MCU_width;
                    if (tmp == 0)
                    {
                        tmp = m_cinfo.Component_info[compIndex].MCU_width;
                    }
                    m_cinfo.Component_info[compIndex].last_col_width = tmp;

                    tmp = m_cinfo.Component_info[compIndex].height_in_blocks % m_cinfo.Component_info[compIndex].MCU_height;
                    if (tmp == 0)
                    {
                        tmp = m_cinfo.Component_info[compIndex].MCU_height;
                    }
                    m_cinfo.Component_info[compIndex].last_row_height = tmp;

                    /* Prepare array describing MCU composition */
                    int mcublks = m_cinfo.Component_info[compIndex].MCU_blocks;
                    if (m_cinfo.m_blocks_in_MCU + mcublks > JpegConstants.C_MAX_BLOCKS_IN_MCU)
                    {
                        m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_BAD_MCU_SIZE);
                    }

                    while (mcublks-- > 0)
                    {
                        m_cinfo.m_MCU_membership[m_cinfo.m_blocks_in_MCU++] = ci;
                    }
                }
            }

            /* Convert restart specified in rows to actual MCU count. */
            /* Note that count must fit in 16 bits, so we provide limiting. */
            if (m_cinfo.m_restart_in_rows > 0)
            {
                int nominal = m_cinfo.m_restart_in_rows * m_cinfo.m_MCUs_per_row;
                m_cinfo.m_restart_interval = Math.Min(nominal, 65535);
            }
        }
        /// <summary>
        /// Process some data in the context case.
        /// </summary>
        private void PreProcessContext(byte[][] input_buf, ref int in_row_ctr, int in_rows_avail, byte[][][] output_buf, ref int out_row_group_ctr, int out_row_groups_avail)
        {
            while (out_row_group_ctr < out_row_groups_avail)
            {
                if (in_row_ctr < in_rows_avail)
                {
                    /* Do color conversion to fill the conversion buffer. */
                    var inrows  = in_rows_avail - in_row_ctr;
                    var numrows = nextBufStop - nextBufRow;
                    numrows = Math.Min(numrows, inrows);
                    cinfo.m_cconvert.color_convert(input_buf, in_row_ctr, colorBuf, colorBufRowsOffset + nextBufRow, numrows);

                    /* Pad at top of image, if first time through */
                    if (rowsToGo == cinfo.m_image_height)
                    {
                        for (var ci = 0; ci < cinfo.m_num_components; ci++)
                        {
                            for (var row = 1; row <= cinfo.m_max_v_samp_factor; row++)
                            {
                                JpegUtils.jcopy_sample_rows(colorBuf[ci], colorBufRowsOffset, colorBuf[ci], colorBufRowsOffset - row, 1, cinfo.m_image_width);
                            }
                        }
                    }

                    in_row_ctr += numrows;
                    nextBufRow += numrows;
                    rowsToGo   -= numrows;
                }
                else
                {
                    /* Return for more data, unless we are at the bottom of the image. */
                    if (rowsToGo != 0)
                    {
                        break;
                    }

                    /* When at bottom of image, pad to fill the conversion buffer. */
                    if (nextBufRow < nextBufStop)
                    {
                        for (var ci = 0; ci < cinfo.m_num_components; ci++)
                        {
                            ExpandBottomEdge(colorBuf[ci], colorBufRowsOffset, cinfo.m_image_width, nextBufRow, nextBufStop);
                        }

                        nextBufRow = nextBufStop;
                    }
                }

                /* If we've gotten enough data, downsample a row group. */
                if (nextBufRow == nextBufStop)
                {
                    cinfo.m_downsample.Downsample(colorBuf, colorBufRowsOffset + thisRowGroup, output_buf, out_row_group_ctr);
                    out_row_group_ctr++;

                    /* Advance pointers with wraparound as necessary. */
                    thisRowGroup += cinfo.m_max_v_samp_factor;
                    var buf_height = cinfo.m_max_v_samp_factor * 3;

                    if (thisRowGroup >= buf_height)
                    {
                        thisRowGroup = 0;
                    }

                    if (nextBufRow >= buf_height)
                    {
                        nextBufRow = 0;
                    }

                    nextBufStop = nextBufRow + cinfo.m_max_v_samp_factor;
                }
            }
        }
Beispiel #24
0
        /// <summary>
        /// Routines to calculate various quantities related to the size of the image.
        /// Called once, when first SOS marker is reached
        /// </summary>
        private void initial_setup()
        {
            /* Make sure image isn't bigger than I can handle */
            if (m_cinfo.m_image_height > JpegConstants.JPEG_MAX_DIMENSION ||
                m_cinfo.m_image_width > JpegConstants.JPEG_MAX_DIMENSION)
            {
                m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_IMAGE_TOO_BIG, (int)JpegConstants.JPEG_MAX_DIMENSION);
            }

            /* For now, precision must match compiled-in value... */
            if (m_cinfo.m_data_precision != JpegConstants.BITS_IN_JSAMPLE)
            {
                m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_BAD_PRECISION, m_cinfo.m_data_precision);
            }

            /* Check that number of components won't exceed internal array sizes */
            if (m_cinfo.m_num_components > JpegConstants.MAX_COMPONENTS)
            {
                m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_COMPONENT_COUNT, m_cinfo.m_num_components, JpegConstants.MAX_COMPONENTS);
            }

            /* Compute maximum sampling factors; check factor validity */
            m_cinfo.m_max_h_samp_factor = 1;
            m_cinfo.m_max_v_samp_factor = 1;

            for (int ci = 0; ci < m_cinfo.m_num_components; ci++)
            {
                if (m_cinfo.Comp_info[ci].H_samp_factor <= 0 || m_cinfo.Comp_info[ci].H_samp_factor > JpegConstants.MAX_SAMP_FACTOR ||
                    m_cinfo.Comp_info[ci].V_samp_factor <= 0 || m_cinfo.Comp_info[ci].V_samp_factor > JpegConstants.MAX_SAMP_FACTOR)
                {
                    m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_BAD_SAMPLING);
                }

                m_cinfo.m_max_h_samp_factor = Math.Max(m_cinfo.m_max_h_samp_factor, m_cinfo.Comp_info[ci].H_samp_factor);
                m_cinfo.m_max_v_samp_factor = Math.Max(m_cinfo.m_max_v_samp_factor, m_cinfo.Comp_info[ci].V_samp_factor);
            }

            /* We initialize DCT_scaled_size and min_DCT_scaled_size to DCTSIZE.
             * In the full decompressor, this will be overridden jpeg_decomp_master;
             * but in the transcoder, jpeg_decomp_master is not used, so we must do it here.
             */
            m_cinfo.m_min_DCT_scaled_size = JpegConstants.DCTSIZE;

            /* Compute dimensions of components */
            for (int ci = 0; ci < m_cinfo.m_num_components; ci++)
            {
                m_cinfo.Comp_info[ci].DCT_scaled_size = JpegConstants.DCTSIZE;

                /* Size in DCT blocks */
                m_cinfo.Comp_info[ci].Width_in_blocks = JpegUtils.jdiv_round_up(
                    m_cinfo.m_image_width * m_cinfo.Comp_info[ci].H_samp_factor,
                    m_cinfo.m_max_h_samp_factor * JpegConstants.DCTSIZE);

                m_cinfo.Comp_info[ci].height_in_blocks = JpegUtils.jdiv_round_up(
                    m_cinfo.m_image_height * m_cinfo.Comp_info[ci].V_samp_factor,
                    m_cinfo.m_max_v_samp_factor * JpegConstants.DCTSIZE);

                /* downsampled_width and downsampled_height will also be overridden by
                 * jpeg_decomp_master if we are doing full decompression.  The transcoder library
                 * doesn't use these values, but the calling application might.
                 */
                /* Size in samples */
                m_cinfo.Comp_info[ci].downsampled_width = JpegUtils.jdiv_round_up(
                    m_cinfo.m_image_width * m_cinfo.Comp_info[ci].H_samp_factor,
                    m_cinfo.m_max_h_samp_factor);

                m_cinfo.Comp_info[ci].downsampled_height = JpegUtils.jdiv_round_up(
                    m_cinfo.m_image_height * m_cinfo.Comp_info[ci].V_samp_factor,
                    m_cinfo.m_max_v_samp_factor);

                /* Mark component needed, until color conversion says otherwise */
                m_cinfo.Comp_info[ci].component_needed = true;

                /* Mark no quantization table yet saved for component */
                m_cinfo.Comp_info[ci].quant_table = null;
            }

            /* Compute number of fully interleaved MCU rows. */
            m_cinfo.m_total_iMCU_rows = JpegUtils.jdiv_round_up(
                m_cinfo.m_image_height, m_cinfo.m_max_v_samp_factor * JpegConstants.DCTSIZE);

            /* Decide whether file contains multiple scans */
            if (m_cinfo.m_comps_in_scan < m_cinfo.m_num_components || m_cinfo.m_progressive_mode)
            {
                m_cinfo.m_inputctl.m_has_multiple_scans = true;
            }
            else
            {
                m_cinfo.m_inputctl.m_has_multiple_scans = false;
            }
        }
Beispiel #25
0
        public my_upsampler(jpeg_decompress_struct cinfo)
        {
            m_cinfo             = cinfo;
            m_need_context_rows = false;  /* until we find out differently */

            if (cinfo.m_CCIR601_sampling) /* this isn't supported */
            {
                cinfo.ERREXIT(J_MESSAGE_CODE.JERR_CCIR601_NOTIMPL);
            }

            /* jpeg_d_main_controller doesn't support context rows when min_DCT_scaled_size = 1,
             * so don't ask for it.
             */
            bool do_fancy = cinfo.m_do_fancy_upsampling && cinfo.m_min_DCT_scaled_size > 1;

            /* Verify we can handle the sampling factors, select per-component methods,
             * and create storage as needed.
             */
            for (int ci = 0; ci < cinfo.m_num_components; ci++)
            {
                jpeg_component_info componentInfo = cinfo.Comp_info[ci];

                /* Compute size of an "input group" after IDCT scaling.  This many samples
                 * are to be converted to max_h_samp_factor * max_v_samp_factor pixels.
                 */
                int h_in_group  = (componentInfo.H_samp_factor * componentInfo.DCT_scaled_size) / cinfo.m_min_DCT_scaled_size;
                int v_in_group  = (componentInfo.V_samp_factor * componentInfo.DCT_scaled_size) / cinfo.m_min_DCT_scaled_size;
                int h_out_group = cinfo.m_max_h_samp_factor;
                int v_out_group = cinfo.m_max_v_samp_factor;

                /* save for use later */
                m_rowgroup_height[ci] = v_in_group;
                bool need_buffer = true;
                if (!componentInfo.component_needed)
                {
                    /* Don't bother to upsample an uninteresting component. */
                    m_upsampleMethods[ci] = ComponentUpsampler.noop_upsampler;
                    need_buffer           = false;
                }
                else if (h_in_group == h_out_group && v_in_group == v_out_group)
                {
                    /* Fullsize components can be processed without any work. */
                    m_upsampleMethods[ci] = ComponentUpsampler.fullsize_upsampler;
                    need_buffer           = false;
                }
                else if (h_in_group * 2 == h_out_group && v_in_group == v_out_group)
                {
                    /* Special cases for 2h1v upsampling */
                    if (do_fancy && componentInfo.downsampled_width > 2)
                    {
                        m_upsampleMethods[ci] = ComponentUpsampler.h2v1_fancy_upsampler;
                    }
                    else
                    {
                        m_upsampleMethods[ci] = ComponentUpsampler.h2v1_upsampler;
                    }
                }
                else if (h_in_group * 2 == h_out_group && v_in_group * 2 == v_out_group)
                {
                    /* Special cases for 2h2v upsampling */
                    if (do_fancy && componentInfo.downsampled_width > 2)
                    {
                        m_upsampleMethods[ci] = ComponentUpsampler.h2v2_fancy_upsampler;
                        m_need_context_rows   = true;
                    }
                    else
                    {
                        m_upsampleMethods[ci] = ComponentUpsampler.h2v2_upsampler;
                    }
                }
                else if ((h_out_group % h_in_group) == 0 && (v_out_group % v_in_group) == 0)
                {
                    /* Generic integral-factors upsampling method */
                    m_upsampleMethods[ci] = ComponentUpsampler.int_upsampler;
                    m_h_expand[ci]        = (byte)(h_out_group / h_in_group);
                    m_v_expand[ci]        = (byte)(v_out_group / v_in_group);
                }
                else
                {
                    cinfo.ERREXIT(J_MESSAGE_CODE.JERR_FRACT_SAMPLE_NOTIMPL);
                }

                if (need_buffer)
                {
                    ComponentBuffer cb = new ComponentBuffer();
                    cb.SetBuffer(jpeg_common_struct.AllocJpegSamples(JpegUtils.jround_up(cinfo.m_output_width,
                                                                                         cinfo.m_max_h_samp_factor), cinfo.m_max_v_samp_factor), null, 0);

                    m_color_buf[ci] = cb;
                }
            }
        }
Beispiel #26
0
        /*
         * Compute output image dimensions and related values.
         * NOTE: this is exported for possible use by application.
         * Hence it mustn't do anything that can't be done twice.
         */
        /* Do computations that are needed before master selection phase.
         * This function is used for transcoding and full decompression.
         */
        public void JpegCoreOutputDimensions()
        {
            /* Compute actual output image dimensions and DCT scaling choices. */
            if (m_cinfo.scaleNum * m_cinfo.block_size <= m_cinfo.scaleDenom)
            {
                /* Provide 1/block_size scaling */
                m_cinfo.outputWidth = (int)
                                      JpegUtils.jdiv_round_up(m_cinfo.imageWidth, m_cinfo.block_size);
                m_cinfo.outputHeight = (int)
                                       JpegUtils.jdiv_round_up(m_cinfo.imageHeight, m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 1;
                m_cinfo.min_DCT_v_scaled_size = 1;
            }
            else if (m_cinfo.scaleNum * m_cinfo.block_size <= m_cinfo.scaleDenom * 2)
            {
                /* Provide 2/block_size scaling */
                m_cinfo.outputWidth = (int)
                                      JpegUtils.jdiv_round_up(m_cinfo.imageWidth * 2L, m_cinfo.block_size);
                m_cinfo.outputHeight = (int)
                                       JpegUtils.jdiv_round_up(m_cinfo.imageHeight * 2L, m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 2;
                m_cinfo.min_DCT_v_scaled_size = 2;
            }
            else if (m_cinfo.scaleNum * m_cinfo.block_size <= m_cinfo.scaleDenom * 3)
            {
                /* Provide 3/block_size scaling */
                m_cinfo.outputWidth = (int)
                                      JpegUtils.jdiv_round_up(m_cinfo.imageWidth * 3L, m_cinfo.block_size);
                m_cinfo.outputHeight = (int)
                                       JpegUtils.jdiv_round_up(m_cinfo.imageHeight * 3L, m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 3;
                m_cinfo.min_DCT_v_scaled_size = 3;
            }
            else if (m_cinfo.scaleNum * m_cinfo.block_size <= m_cinfo.scaleDenom * 4)
            {
                /* Provide 4/block_size scaling */
                m_cinfo.outputWidth = (int)
                                      JpegUtils.jdiv_round_up(m_cinfo.imageWidth * 4L, m_cinfo.block_size);
                m_cinfo.outputHeight = (int)
                                       JpegUtils.jdiv_round_up(m_cinfo.imageHeight * 4L, m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 4;
                m_cinfo.min_DCT_v_scaled_size = 4;
            }
            else if (m_cinfo.scaleNum * m_cinfo.block_size <= m_cinfo.scaleDenom * 5)
            {
                /* Provide 5/block_size scaling */
                m_cinfo.outputWidth = (int)
                                      JpegUtils.jdiv_round_up(m_cinfo.imageWidth * 5L, m_cinfo.block_size);
                m_cinfo.outputHeight = (int)
                                       JpegUtils.jdiv_round_up(m_cinfo.imageHeight * 5L, m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 5;
                m_cinfo.min_DCT_v_scaled_size = 5;
            }
            else if (m_cinfo.scaleNum * m_cinfo.block_size <= m_cinfo.scaleDenom * 6)
            {
                /* Provide 6/block_size scaling */
                m_cinfo.outputWidth = (int)
                                      JpegUtils.jdiv_round_up(m_cinfo.imageWidth * 6L, m_cinfo.block_size);
                m_cinfo.outputHeight = (int)
                                       JpegUtils.jdiv_round_up(m_cinfo.imageHeight * 6L, m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 6;
                m_cinfo.min_DCT_v_scaled_size = 6;
            }
            else if (m_cinfo.scaleNum * m_cinfo.block_size <= m_cinfo.scaleDenom * 7)
            {
                /* Provide 7/block_size scaling */
                m_cinfo.outputWidth = (int)
                                      JpegUtils.jdiv_round_up(m_cinfo.imageWidth * 7L, m_cinfo.block_size);
                m_cinfo.outputHeight = (int)
                                       JpegUtils.jdiv_round_up(m_cinfo.imageHeight * 7L, m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 7;
                m_cinfo.min_DCT_v_scaled_size = 7;
            }
            else if (m_cinfo.scaleNum * m_cinfo.block_size <= m_cinfo.scaleDenom * 8)
            {
                /* Provide 8/block_size scaling */
                m_cinfo.outputWidth = (int)
                                      JpegUtils.jdiv_round_up(m_cinfo.imageWidth * 8L, m_cinfo.block_size);
                m_cinfo.outputHeight = (int)
                                       JpegUtils.jdiv_round_up(m_cinfo.imageHeight * 8L, m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 8;
                m_cinfo.min_DCT_v_scaled_size = 8;
            }
            else if (m_cinfo.scaleNum * m_cinfo.block_size <= m_cinfo.scaleDenom * 9)
            {
                /* Provide 9/block_size scaling */
                m_cinfo.outputWidth = (int)
                                      JpegUtils.jdiv_round_up(m_cinfo.imageWidth * 9L, m_cinfo.block_size);
                m_cinfo.outputHeight = (int)
                                       JpegUtils.jdiv_round_up(m_cinfo.imageHeight * 9L, m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 9;
                m_cinfo.min_DCT_v_scaled_size = 9;
            }
            else if (m_cinfo.scaleNum * m_cinfo.block_size <= m_cinfo.scaleDenom * 10)
            {
                /* Provide 10/block_size scaling */
                m_cinfo.outputWidth = (int)
                                      JpegUtils.jdiv_round_up(m_cinfo.imageWidth * 10L, m_cinfo.block_size);
                m_cinfo.outputHeight = (int)
                                       JpegUtils.jdiv_round_up(m_cinfo.imageHeight * 10L, m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 10;
                m_cinfo.min_DCT_v_scaled_size = 10;
            }
            else if (m_cinfo.scaleNum * m_cinfo.block_size <= m_cinfo.scaleDenom * 11)
            {
                /* Provide 11/block_size scaling */
                m_cinfo.outputWidth = (int)
                                      JpegUtils.jdiv_round_up(m_cinfo.imageWidth * 11L, m_cinfo.block_size);
                m_cinfo.outputHeight = (int)
                                       JpegUtils.jdiv_round_up(m_cinfo.imageHeight * 11L, m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 11;
                m_cinfo.min_DCT_v_scaled_size = 11;
            }
            else if (m_cinfo.scaleNum * m_cinfo.block_size <= m_cinfo.scaleDenom * 12)
            {
                /* Provide 12/block_size scaling */
                m_cinfo.outputWidth = (int)
                                      JpegUtils.jdiv_round_up(m_cinfo.imageWidth * 12L, m_cinfo.block_size);
                m_cinfo.outputHeight = (int)
                                       JpegUtils.jdiv_round_up(m_cinfo.imageHeight * 12L, m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 12;
                m_cinfo.min_DCT_v_scaled_size = 12;
            }
            else if (m_cinfo.scaleNum * m_cinfo.block_size <= m_cinfo.scaleDenom * 13)
            {
                /* Provide 13/block_size scaling */
                m_cinfo.outputWidth = (int)
                                      JpegUtils.jdiv_round_up(m_cinfo.imageWidth * 13L, m_cinfo.block_size);
                m_cinfo.outputHeight = (int)
                                       JpegUtils.jdiv_round_up(m_cinfo.imageHeight * 13L, m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 13;
                m_cinfo.min_DCT_v_scaled_size = 13;
            }
            else if (m_cinfo.scaleNum * m_cinfo.block_size <= m_cinfo.scaleDenom * 14)
            {
                /* Provide 14/block_size scaling */
                m_cinfo.outputWidth = (int)
                                      JpegUtils.jdiv_round_up(m_cinfo.imageWidth * 14L, m_cinfo.block_size);
                m_cinfo.outputHeight = (int)
                                       JpegUtils.jdiv_round_up(m_cinfo.imageHeight * 14L, m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 14;
                m_cinfo.min_DCT_v_scaled_size = 14;
            }
            else if (m_cinfo.scaleNum * m_cinfo.block_size <= m_cinfo.scaleDenom * 15)
            {
                /* Provide 15/block_size scaling */
                m_cinfo.outputWidth = (int)
                                      JpegUtils.jdiv_round_up(m_cinfo.imageWidth * 15L, m_cinfo.block_size);
                m_cinfo.outputHeight = (int)
                                       JpegUtils.jdiv_round_up(m_cinfo.imageHeight * 15L, m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 15;
                m_cinfo.min_DCT_v_scaled_size = 15;
            }
            else
            {
                /* Provide 16/block_size scaling */
                m_cinfo.outputWidth = (int)
                                      JpegUtils.jdiv_round_up(m_cinfo.imageWidth * 16L, m_cinfo.block_size);
                m_cinfo.outputHeight = (int)
                                       JpegUtils.jdiv_round_up(m_cinfo.imageHeight * 16L, m_cinfo.block_size);
                m_cinfo.min_DCT_h_scaled_size = 16;
                m_cinfo.min_DCT_v_scaled_size = 16;
            }

            /* Recompute dimensions of components */
            for (var ci = 0; ci < m_cinfo.numComponents; ci++)
            {
                var compptr = m_cinfo.CompInfo[ci];
                compptr.DCT_h_scaled_size = m_cinfo.min_DCT_h_scaled_size;
                compptr.DCT_v_scaled_size = m_cinfo.min_DCT_v_scaled_size;
            }
        }