jcopy_sample_rows() public static method

public static jcopy_sample_rows ( ComponentBuffer input_array, int source_row, ComponentBuffer output_array, int dest_row, int num_rows, int num_cols ) : void
input_array ComponentBuffer
source_row int
output_array ComponentBuffer
dest_row int
num_rows int
num_cols int
return void
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;
            }
        }
 /// <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 #3
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 #4
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++;
            }
        }
        /// <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;
                }
            }
        }
 /// <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);
 }
        /// <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;
                }
            }
        }