Beispiel #1
0
        // Downsample pixel values of a single component.
        // One row group is processed per call.
        // This version handles arbitrary integral sampling ratios, without smoothing.
        // Note that this version is not actually used for customary sampling ratios.
        static void int_downsample(jpeg_compress cinfo, jpeg_component_info compptr, byte[][] input_data, uint in_row_index, byte[][] output_data, uint out_row_index)
        {
            uint output_cols = compptr.width_in_blocks * cinfo.DCT_size;
            int  h_expand    = cinfo.max_h_samp_factor / compptr.h_samp_factor;
            int  v_expand    = cinfo.max_v_samp_factor / compptr.v_samp_factor;
            int  numpix      = h_expand * v_expand;
            int  numpix2     = numpix / 2;

            // Expand input data enough to let all the output samples be generated
            // by the standard loop. Special-casing padded output would be more
            // efficient.
            expand_right_edge(input_data, in_row_index, cinfo.max_v_samp_factor, cinfo.image_width, (uint)(output_cols * h_expand));

            int inrow = (int)in_row_index;

            for (int outrow = 0; outrow < compptr.v_samp_factor; outrow++)
            {
                byte[] outptr = output_data[out_row_index + outrow];
                for (uint outcol = 0, outcol_h = 0; outcol < output_cols; outcol++, outcol_h += (uint)h_expand)
                {
                    byte[] inptr;
                    int    outvalue = 0;
                    for (int v = 0; v < v_expand; v++)
                    {
                        inptr = input_data[inrow + v];
                        for (int h = 0; h < h_expand; h++)
                        {
                            outvalue += (int)inptr[outcol_h + h];
                        }
                    }
                    outptr[outcol] = (byte)((outvalue + numpix2) / numpix);
                }
                inrow += v_expand;
            }
        }
Beispiel #2
0
        // Downsample pixel values of a single component.
        // This version handles the standard case of 2:1 horizontal and 2:1 vertical,
        // without smoothing.
        static void h2v2_downsample(jpeg_compress cinfo, jpeg_component_info compptr, byte[][] input_data, uint in_row_index, byte[][] output_data, uint out_row_index)
        {
            uint output_cols = compptr.width_in_blocks * cinfo.DCT_size;

            // Expand input data enough to let all the output samples be generated
            // by the standard loop. Special-casing padded output would be more
            // efficient.
            expand_right_edge(input_data, in_row_index, cinfo.max_v_samp_factor, cinfo.image_width, output_cols * 2);

            int inrow = (int)in_row_index;

            for (int outrow = 0; outrow < compptr.v_samp_factor; outrow++)
            {
                byte[] outptr = output_data[out_row_index + outrow];
                byte[] inptr0 = input_data[inrow];
                byte[] inptr1 = input_data[inrow + 1];
                int    bias   = 1;          // bias = 1,2,1,2,... for successive samples
                for (uint outcol = 0, ind = 0; outcol < output_cols; outcol++, ind += 2)
                {
                    outptr[outcol] = (byte)((inptr0[ind] + inptr0[ind + 1] + inptr1[ind] + inptr1[ind + 1] + bias) >> 2);
                    bias          ^= 3;          // 1=>2, 2=>1
                }
                inrow += 2;
            }
        }
Beispiel #3
0
        // These are the routines invoked by sep_upsample to upsample pixel values
        // of a single component. One row group is processed per call.

        // For full-size components, we just make color_buf[ci] point at the
        // input buffer, and thus avoid copying any data. Note that this is
        // safe only because sep_upsample doesn't declare the input row group
        // "consumed" until we are done color converting and emitting it.
        static void fullsize_upsample(jpeg_decompress cinfo, jpeg_component_info compptr, byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int output_data_offset)
        {
            for (int i = 0; i < cinfo.max_v_samp_factor; i++)
            {
                output_data_ptr[output_data_offset][i] = input_data[input_data_offset++];
            }
        }
Beispiel #4
0
        // Fancy processing for the common case of 2:1 horizontal and 1:1 vertical.
        //
        // The upsampling algorithm is linear interpolation between pixel centers,
        // also known as a "triangle filter". This is a good compromise between
        // speed and visual quality. The centers of the output pixels are 1/4 and 3/4
        // of the way between input pixel centers.
        //
        // A note about the "bias" calculations: when rounding fractional values to
        // integer, we do not want to always round 0.5 up to the next integer.
        // If we did that, we'd introduce a noticeable bias towards larger values.
        // Instead, this code is arranged so that 0.5 will be rounded up or down at
        // alternate pixel locations (a simple ordered dither pattern).
#if !USE_UNSAFE_STUFF
        static void h2v1_fancy_upsample(jpeg_decompress cinfo, jpeg_component_info compptr, byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int output_data_offset)
        {
            byte[][] output_data = output_data_ptr[output_data_offset];

            for (int inrow = 0; inrow < cinfo.max_v_samp_factor; inrow++)
            {
                byte[] inptr      = input_data[input_data_offset++];
                uint   inptr_ind  = 0;
                byte[] outptr     = output_data[inrow];
                uint   outptr_ind = 0;

                // Special case for first column
                int invalue = inptr[inptr_ind++];
                outptr[outptr_ind++] = (byte)invalue;
                outptr[outptr_ind++] = (byte)((invalue * 3 + inptr[inptr_ind] + 2) >> 2);

                for (uint colctr = compptr.downsampled_width - 2; colctr > 0; colctr--)
                {
                    // General case: 3/4 * nearer pixel + 1/4 * further pixel
                    invalue = inptr[inptr_ind++] * 3;
                    outptr[outptr_ind++] = (byte)((invalue + inptr[inptr_ind - 2] + 1) >> 2);
                    outptr[outptr_ind++] = (byte)((invalue + inptr[inptr_ind] + 2) >> 2);
                }

                // Special case for last column
                invalue = inptr[inptr_ind];
                outptr[outptr_ind++] = (byte)((invalue * 3 + inptr[inptr_ind - 1] + 1) >> 2);
                outptr[outptr_ind]   = (byte)invalue;
            }
        }
Beispiel #5
0
        // Fast processing for the common case of 2:1 horizontal and 2:1 vertical.
        // It's still a box filter.
        static void h2v2_upsample(jpeg_decompress cinfo, jpeg_component_info compptr, byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int output_data_offset)
        {
            byte[][] output_data = output_data_ptr[output_data_offset];

            int  outrow = 0;
            uint outend = cinfo.output_width;

            while (outrow < cinfo.max_v_samp_factor)
            {
                byte[] inptr      = input_data[input_data_offset];
                uint   inptr_ind  = 0;
                byte[] outptr     = output_data[outrow];
                uint   outptr_ind = 0;
                while (outptr_ind < outend)
                {
                    byte invalue = inptr[inptr_ind++];
                    outptr[outptr_ind++] = invalue;
                    outptr[outptr_ind++] = invalue;
                }

                Array.Copy(output_data[outrow], output_data[outrow + 1], cinfo.output_width);
                input_data_offset++;
                outrow += 2;
            }
        }
Beispiel #6
0
        static void h2v2_fancy_upsample(jpeg_decompress cinfo, jpeg_component_info compptr, byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int output_data_offset)
        {
            unsafe
            {
                if (!compptr.notFirst)
                {
                    input_data[0].CopyTo(input_data[input_data.Length - 1], 0);
                    compptr.notFirst = true;
                }

                byte[][] output_data = output_data_ptr[output_data_offset];

                int inrow = 0, outrow = 0;
                while (outrow < cinfo.max_v_samp_factor)
                {
                    // inptr0 points to nearest input row
                    fixed(byte *inptr0_ = input_data[input_data_offset + inrow])
                    {
                        // inptr1 points to next nearest
                        int nextnearestrow = input_data_offset == 0?input_data.Length - 1:input_data_offset + inrow - 1;               // next nearest is row above

                        for (int v = 0; v < 2; v++)
                        {
                            fixed(byte *inptr1_ = input_data[nextnearestrow], outptr_ = output_data[outrow++])
                            {
                                byte *inptr0 = inptr0_, inptr1 = inptr1_, outptr = outptr_;

                                // Special case for first column
                                int thiscolsum = *(inptr0++) * 3 + *(inptr1++);
                                int nextcolsum = *(inptr0++) * 3 + *(inptr1++);

                                *(outptr++) = (byte)((thiscolsum * 4 + 8) >> 4);
                                *(outptr++) = (byte)((thiscolsum * 3 + nextcolsum + 7) >> 4);
                                int lastcolsum = thiscolsum;

                                thiscolsum = nextcolsum;

                                for (uint colctr = compptr.downsampled_width - 2; colctr > 0; colctr--)
                                {
                                    // General case: 3/4 * nearer pixel + 1/4 * further pixel in each
                                    // dimension, thus 9/16, 3/16, 3/16, 1/16 overall
                                    nextcolsum  = *(inptr0++) * 3 + *(inptr1++);
                                    *(outptr++) = (byte)((thiscolsum * 3 + lastcolsum + 8) >> 4);
                                    *(outptr++) = (byte)((thiscolsum * 3 + nextcolsum + 7) >> 4);
                                    lastcolsum  = thiscolsum; thiscolsum = nextcolsum;
                                }

                                // Special case for last column
                                *(outptr++) = (byte)((thiscolsum * 3 + lastcolsum + 8) >> 4);
                                *(outptr++) = (byte)((thiscolsum * 4 + 7) >> 4);
                            }

                            nextnearestrow = (input_data_offset + inrow + 1) % input_data.Length;                     // next nearest is row below
                        }
                    }

                    inrow++;
                }
            }
        }
Beispiel #7
0
        static void h2v1_fancy_upsample(jpeg_decompress cinfo, jpeg_component_info compptr, byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int output_data_offset)
        {
            unsafe
            {
                byte[][] output_data = output_data_ptr[output_data_offset];

                for (int inrow = 0; inrow < cinfo.max_v_samp_factor; inrow++)
                {
                    fixed(byte *inptr_ = input_data[input_data_offset++], outptr_ = output_data[inrow])
                    {
                        byte *inptr  = inptr_;
                        byte *outptr = outptr_;

                        // Special case for first column
                        int invalue = *(inptr++);

                        *(outptr++) = (byte)invalue;
                        *(outptr++) = (byte)((invalue * 3 + *inptr + 2) >> 2);

                        for (uint colctr = compptr.downsampled_width - 2; colctr > 0; colctr--)
                        {
                            // General case: 3/4 * nearer pixel + 1/4 * further pixel
                            invalue     = *(inptr++) * 3;
                            *(outptr++) = (byte)((invalue + inptr[-2] + 1) >> 2);
                            *(outptr++) = (byte)((invalue + *inptr + 2) >> 2);
                        }

                        // Special case for last column
                        invalue     = *inptr;
                        *(outptr++) = (byte)((invalue * 3 + inptr[-1] + 1) >> 2);
                        *outptr = (byte)invalue;
                    }
                }
            }
        }
Beispiel #8
0
        // Allocate downsampled-data buffers needed for downsampled I/O.
        // We use values computed in jpeg_start_compress or jpeg_start_decompress.
        // We use libjpeg's allocator so that buffers will be released automatically
        // when done with strip/tile.
        // This is also a handy place to compute samplesperclump, bytesperline.
        static bool alloc_downsampled_buffers(TIFF tif, jpeg_component_info[] comp_info, int num_components)
        {
            JPEGState sp=tif.tif_data as JPEGState;

            byte[][] buf;
            int samples_per_clump=0;

            for(int ci=0; ci<num_components; ci++)
            {
                jpeg_component_info compptr=comp_info[ci];

                samples_per_clump+=compptr.h_samp_factor*compptr.v_samp_factor;
                try
                {
                    buf=TIFFjpeg_alloc_sarray(sp, compptr.width_in_blocks*libjpeg.DCTSIZE, (uint)compptr.v_samp_factor*libjpeg.DCTSIZE);
                }
                catch
                {
                    return false;
                }

                sp.ds_buffer[ci]=buf;
            }

            sp.samplesperclump=samples_per_clump;
            return true;
        }
Beispiel #9
0
        // Create the wrapped-around downsampling input buffer needed for context mode.
        static void create_context_buffer(jpeg_compress cinfo)
        {
            my_prep_controller prep = (my_prep_controller)cinfo.prep;
            int rgroup_height       = cinfo.max_v_samp_factor;

            for (int ci = 0; ci < cinfo.num_components; ci++)
            {
                jpeg_component_info compptr = cinfo.comp_info[ci];

                // Grab enough space for fake row pointers;
                // we need five row groups' worth of pointers for each component.
                byte[][] fake_buffer = new byte[5 * rgroup_height][];

                // Allocate the actual buffer space (3 row groups) for this component.
                // We make the buffer wide enough to allow the downsampler to edge-expand
                // horizontally within the buffer, if it so chooses.
                byte[][] true_buffer = alloc_sarray(cinfo,
                                                    (uint)(((int)compptr.width_in_blocks * cinfo.DCT_size * cinfo.max_h_samp_factor) / compptr.h_samp_factor),
                                                    (uint)(3 * rgroup_height));

                // Copy true buffer row pointers into the middle of the fake row array
                Array.Copy(true_buffer, 0, fake_buffer, rgroup_height, 3 * rgroup_height);

                // Fill in the above and below wraparound pointers
                for (int i = 0; i < rgroup_height; i++)
                {
                    fake_buffer[i] = true_buffer[2 * rgroup_height + i];
                    fake_buffer[4 * rgroup_height + i] = true_buffer[i];
                }
                prep.color_buf[ci] = fake_buffer;
            }
        }
Beispiel #10
0
        // Downsample pixel values of a single component.
        // This version handles the special case of a full-size component,
        // without smoothing.
        static void fullsize_downsample(jpeg_compress cinfo, jpeg_component_info compptr, byte[][] input_data, uint in_row_index, byte[][] output_data, uint out_row_index)
        {
            // Copy the data
            jcopy_sample_rows(input_data, (int)in_row_index, output_data, (int)out_row_index, cinfo.max_v_samp_factor, cinfo.image_width);

            // Edge-expand
            expand_right_edge(output_data, out_row_index, cinfo.max_v_samp_factor, cinfo.image_width, compptr.width_in_blocks * cinfo.DCT_size);
        }
Beispiel #11
0
        // Fast processing for the common case of 2:1 horizontal and 2:1 vertical.
        // It's still a box filter.
#if !USE_UNSAFE_STUFF
        static void h2v2_fancy_upsample(jpeg_decompress cinfo, jpeg_component_info compptr, byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int output_data_offset)
        {
            if (!compptr.notFirst)
            {
                input_data[0].CopyTo(input_data[input_data.Length - 1], 0);
                compptr.notFirst = true;
            }

            byte[][] output_data = output_data_ptr[output_data_offset];

            int inrow = 0, outrow = 0;

            while (outrow < cinfo.max_v_samp_factor)
            {
                for (int v = 0; v < 2; v++)
                {
                    // inptr0 points to nearest input row, inptr1 points to next nearest
                    byte[] inptr0 = input_data[input_data_offset + inrow];
                    byte[] inptr1 = null;
                    if (v == 0)
                    {
                        inptr1 = input_data[input_data_offset == 0?input_data.Length - 1:input_data_offset + inrow - 1];                // next nearest is row above
                    }
                    else
                    {
                        inptr1 = input_data[(input_data_offset + inrow + 1) % input_data.Length];                       // next nearest is row below
                    }
                    uint intptr_ind = 0;

                    byte[] outptr     = output_data[outrow++];
                    uint   outptr_ind = 0;

                    // Special case for first column
                    int thiscolsum = inptr0[intptr_ind] * 3 + inptr1[intptr_ind]; intptr_ind++;
                    int nextcolsum = inptr0[intptr_ind] * 3 + inptr1[intptr_ind]; intptr_ind++;
                    outptr[outptr_ind++] = (byte)((thiscolsum * 4 + 8) >> 4);
                    outptr[outptr_ind++] = (byte)((thiscolsum * 3 + nextcolsum + 7) >> 4);
                    int lastcolsum = thiscolsum;
                    thiscolsum = nextcolsum;

                    for (uint colctr = compptr.downsampled_width - 2; colctr > 0; colctr--)
                    {
                        // General case: 3/4 * nearer pixel + 1/4 * further pixel in each
                        // dimension, thus 9/16, 3/16, 3/16, 1/16 overall
                        nextcolsum           = inptr0[intptr_ind] * 3 + inptr1[intptr_ind]; intptr_ind++;
                        outptr[outptr_ind++] = (byte)((thiscolsum * 3 + lastcolsum + 8) >> 4);
                        outptr[outptr_ind++] = (byte)((thiscolsum * 3 + nextcolsum + 7) >> 4);
                        lastcolsum           = thiscolsum; thiscolsum = nextcolsum;
                    }

                    // Special case for last column
                    outptr[outptr_ind++] = (byte)((thiscolsum * 3 + lastcolsum + 8) >> 4);
                    outptr[outptr_ind++] = (byte)((thiscolsum * 4 + 7) >> 4);
                }
                inrow++;
            }
        }
Beispiel #12
0
        // Downsample pixel values of a single component.
        // This version handles the special case of a full-size component,
        // with smoothing. One row of context is required.
        static void fullsize_smooth_downsample(jpeg_compress cinfo, jpeg_component_info compptr, byte[][] input_data, uint in_row_index, byte[][] output_data, uint out_row_index)
        {
            uint output_cols = compptr.width_in_blocks * cinfo.DCT_size;

            // Expand input data enough to let all the output samples be generated
            // by the standard loop. Special-casing padded output would be more
            // efficient.
            expand_right_edge(input_data, in_row_index - 1, cinfo.max_v_samp_factor + 2, cinfo.image_width, output_cols);

            // Each of the eight neighbor pixels contributes a fraction SF to the
            // smoothed pixel, while the main pixel contributes (1-8*SF). In order
            // to use integer arithmetic, these factors are multiplied by 2^16 = 65536.
            // Also recall that SF = smoothing_factor / 1024.
            int memberscale = 65536 - cinfo.smoothing_factor * 512; // scaled 1-8*SF
            int neighscale  = cinfo.smoothing_factor * 64;          // scaled SF

            int membersum, neighsum;
            int colsum, lastcolsum, nextcolsum;

            for (int outrow = 0; outrow < compptr.v_samp_factor; outrow++)
            {
                byte[] outptr    = output_data[out_row_index + outrow];
                byte[] inptr     = input_data[in_row_index + outrow];
                byte[] above_ptr = input_data[in_row_index + outrow - 1];
                byte[] below_ptr = input_data[in_row_index + outrow + 1];

                int iind = 0, aind = 0, bind = 0, oind = 0;

                // Special case for first column
                colsum         = above_ptr[aind++] + below_ptr[bind++] + inptr[iind];
                membersum      = inptr[iind++];
                nextcolsum     = above_ptr[aind] + below_ptr[bind] + inptr[iind];
                neighsum       = colsum + (colsum - membersum) + nextcolsum;
                membersum      = membersum * memberscale + neighsum * neighscale;
                outptr[oind++] = (byte)((membersum + 32768) >> 16);
                lastcolsum     = colsum; colsum = nextcolsum;

                for (uint colctr = output_cols - 2; colctr > 0; colctr--)
                {
                    membersum      = inptr[iind++];
                    nextcolsum     = above_ptr[aind++] + below_ptr[bind++] + inptr[iind];
                    neighsum       = lastcolsum + (colsum - membersum) + nextcolsum;
                    membersum      = membersum * memberscale + neighsum * neighscale;
                    outptr[oind++] = (byte)((membersum + 32768) >> 16);
                    lastcolsum     = colsum; colsum = nextcolsum;
                }

                // Special case for last column
                membersum    = inptr[iind];
                neighsum     = lastcolsum + (colsum - membersum) + colsum;
                membersum    = membersum * memberscale + neighsum * neighscale;
                outptr[oind] = (byte)((membersum + 32768) >> 16);
            }
        }
Beispiel #13
0
        static void SET_COMP(jpeg_compress cinfo, int index, int id, int hsamp, int vsamp, int quant, int dctbl, int actbl)
        {
            jpeg_component_info compptr = cinfo.comp_info[index];

            compptr.component_id  = id;
            compptr.h_samp_factor = hsamp;
            compptr.v_samp_factor = vsamp;
            compptr.quant_tbl_no  = quant;
            compptr.dc_tbl_no     = dctbl;
            compptr.ac_tbl_no     = actbl;
        }
Beispiel #14
0
        // Initialize for a Huffman-compressed scan.
        static void start_pass_lhuff_decoder(jpeg_decompress cinfo)
        {
            jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef;
            lhuff_entropy_decoder entropy = (lhuff_entropy_decoder)losslsd.entropy_private;

            for (int ci = 0; ci < cinfo.comps_in_scan; ci++)
            {
                jpeg_component_info compptr = cinfo.cur_comp_info[ci];
                int dctbl = compptr.dc_tbl_no;

                // Make sure requested tables are present
                if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS ||
                    cinfo.dc_huff_tbl_ptrs[dctbl] == null)
                {
                    ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_NO_HUFF_TABLE, dctbl);
                }

                // Compute derived values for Huffman tables
                // We may do this more than once for a table, but it's not expensive
                jpeg_make_d_derived_tbl(cinfo, true, dctbl, ref entropy.derived_tbls[dctbl]);
            }

            // Precalculate decoding info for each sample in an MCU of this scan
            int ptrn = 0;

            for (int sampn = 0; sampn < cinfo.blocks_in_MCU;)
            {
                jpeg_component_info compptr = cinfo.cur_comp_info[cinfo.MCU_membership[sampn]];
                int ci = compptr.component_index;
                for (int yoffset = 0; yoffset < compptr.MCU_height; yoffset++, ptrn++)
                {
                    // Precalculate the setup info for each output pointer
                    entropy.output_ptr_info[ptrn].ci        = ci;
                    entropy.output_ptr_info[ptrn].yoffset   = yoffset;
                    entropy.output_ptr_info[ptrn].MCU_width = compptr.MCU_width;
                    for (int xoffset = 0; xoffset < compptr.MCU_width; xoffset++, sampn++)
                    {
                        // Precalculate the output pointer index for each sample
                        entropy.output_ptr_index[sampn] = ptrn;

                        // Precalculate which table to use for each sample
                        entropy.cur_tbls[sampn] = entropy.derived_tbls[compptr.dc_tbl_no];
                    }
                }
            }
            entropy.num_output_ptrs = ptrn;

            // Initialize bitread state variables
            entropy.bitstate.bits_left  = 0;
            entropy.bitstate.get_buffer = 0;           // unnecessary, but keeps Purify quiet
            entropy.insufficient_data   = false;
        }
Beispiel #15
0
        // Control routine to do upsampling (and color conversion).
        //
        // In this version we upsample each component independently.
        // We upsample one row group into the conversion buffer, then apply
        // color conversion a row at a time.
        static void sep_upsample(jpeg_decompress cinfo, byte[][][] input_buf, ref uint in_row_group_ctr, uint in_row_groups_avail, byte[][] output_buf, uint output_buf_offset, ref uint out_row_ctr, uint out_rows_avail)
        {
            my_upsampler upsample = (my_upsampler)cinfo.upsample;

            // Fill the conversion buffer, if it's empty
            if (upsample.next_row_out >= cinfo.max_v_samp_factor)
            {
                for (int ci = 0; ci < cinfo.num_components; ci++)
                {
                    jpeg_component_info compptr = cinfo.comp_info[ci];

                    // Invoke per-component upsample method. Notice we pass a POINTER
                    // to color_buf[ci], so that fullsize_upsample can change it.
                    upsample.methods[ci](cinfo, compptr, input_buf[ci], (int)(in_row_group_ctr * upsample.rowgroup_height[ci]), upsample.color_buf, ci);
                }
                upsample.next_row_out = 0;
            }

            // Color-convert and emit rows

            // How many we have in the buffer:
            uint num_rows = (uint)(cinfo.max_v_samp_factor - upsample.next_row_out);

            // Not more than the distance to the end of the image. Need this test
            // in case the image height is not a multiple of max_v_samp_factor:
            if (num_rows > upsample.rows_to_go)
            {
                num_rows = upsample.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;
            }

            cinfo.cconvert.color_convert(cinfo, upsample.color_buf, (uint)upsample.next_row_out, output_buf, output_buf_offset + out_row_ctr, (int)num_rows);

            // Adjust counts
            out_row_ctr           += num_rows;
            upsample.rows_to_go   -= num_rows;
            upsample.next_row_out += (int)num_rows;

            // When the buffer is emptied, declare this input row group consumed
            if (upsample.next_row_out >= cinfo.max_v_samp_factor)
            {
                in_row_group_ctr++;
            }
        }
Beispiel #16
0
        // Output some data from the full-image buffer sample in the multi-pass case.
        // Always attempts to emit one fully interleaved MCU row ("iMCU" row).
        // Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
        //
        // NB: output_buf contains a plane for each component in image.
        static CONSUME_INPUT output_data_d_diff(jpeg_decompress cinfo, byte[][][] output_buf)
        {
            jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef;
            d_diff_controller     diff    = (d_diff_controller)losslsd.diff_private;
            uint last_iMCU_row            = cinfo.total_iMCU_rows - 1;

            // Force some input to be done if we are getting ahead of the input.
            while (cinfo.input_scan_number < cinfo.output_scan_number || (cinfo.input_scan_number == cinfo.output_scan_number && cinfo.input_iMCU_row <= cinfo.output_iMCU_row))
            {
                if (cinfo.inputctl.consume_input(cinfo) == CONSUME_INPUT.JPEG_SUSPENDED)
                {
                    return(CONSUME_INPUT.JPEG_SUSPENDED);
                }
            }

            // OK, output from the arrays.
            for (int ci = 0; ci < cinfo.num_components; ci++)
            {
                jpeg_component_info compptr = cinfo.comp_info[ci];

                // Align the buffer for this component.
                byte[][] buffer = diff.whole_image[ci];

                int samp_rows;
                if (cinfo.output_iMCU_row < last_iMCU_row)
                {
                    samp_rows = compptr.v_samp_factor;
                }
                else
                {
                    // NB: can't use last_row_height here; it is input-side-dependent!
                    samp_rows = (int)(compptr.height_in_blocks % compptr.v_samp_factor);
                    if (samp_rows == 0)
                    {
                        samp_rows = compptr.v_samp_factor;
                    }
                }

                for (int row = 0; row < samp_rows; row++)
                {
                    Array.Copy(buffer[cinfo.output_iMCU_row * compptr.v_samp_factor + row], output_buf[ci][row], compptr.width_in_blocks);
                }
            }

            if (++(cinfo.output_iMCU_row) < cinfo.total_iMCU_rows)
            {
                return(CONSUME_INPUT.JPEG_ROW_COMPLETED);
            }
            return(CONSUME_INPUT.JPEG_SCAN_COMPLETED);
        }
Beispiel #17
0
        // Initialize difference buffer controller.
        static void jinit_d_diff_controller(jpeg_decompress cinfo, bool need_full_buffer)
        {
            jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef;
            d_diff_controller     diff    = null;

            try
            {
                diff = new d_diff_controller();
            }
            catch
            {
                ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
            }
            losslsd.diff_private          = diff;
            losslsd.diff_start_input_pass = start_input_pass_d_diff;
            losslsd.start_output_pass     = start_output_pass_d_diff;

            // Create the [un]difference buffers.
            for (int ci = 0; ci < cinfo.num_components; ci++)
            {
                jpeg_component_info compptr = cinfo.comp_info[ci];
                diff.diff_buf[ci]   = alloc_darray(cinfo, (uint)jround_up(compptr.width_in_blocks, compptr.h_samp_factor), (uint)compptr.v_samp_factor);
                diff.undiff_buf[ci] = alloc_darray(cinfo, (uint)jround_up(compptr.width_in_blocks, compptr.h_samp_factor), (uint)compptr.v_samp_factor);
            }

            if (need_full_buffer)
            {
#if D_MULTISCAN_FILES_SUPPORTED
                // Allocate a full-image array for each component.
                for (int ci = 0; ci < cinfo.num_components; ci++)
                {
                    jpeg_component_info compptr = cinfo.comp_info[ci];
                    diff.whole_image[ci] = alloc_sarray(cinfo, (uint)jround_up(compptr.width_in_blocks, compptr.h_samp_factor), (uint)jround_up(compptr.height_in_blocks, compptr.v_samp_factor));
                }
                losslsd.consume_data    = consume_data_d_diff;
                losslsd.decompress_data = output_data_d_diff;
#else
                ERREXIT(cinfo, J_MESSAGE_CODE.JERR_NOT_COMPILED);
#endif
            }
            else
            {
                losslsd.consume_data    = dummy_consume_data_d_diff;
                losslsd.decompress_data = decompress_data_d_diff;
                diff.whole_image[0]     = null;           // flag for no arrays
            }
        }
Beispiel #18
0
        // Initialize preprocessing controller.
        static void jinit_c_prep_controller(jpeg_compress cinfo, bool need_full_buffer)
        {
            if (need_full_buffer)
            {
                ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_BUFFER_MODE);                              // safety check
            }
            my_prep_controller prep = null;

            try
            {
                prep = new my_prep_controller();
            }
            catch
            {
                ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
            }
            cinfo.prep      = prep;
            prep.start_pass = start_pass_prep;

            // Allocate the color conversion buffer.
            // We make the buffer wide enough to allow the downsampler to edge-expand
            // horizontally within the buffer, if it so chooses.
            if (cinfo.downsample.need_context_rows)
            {
                // Set up to provide context rows
#if CONTEXT_ROWS_SUPPORTED
                prep.pre_process_data = pre_process_context;
                create_context_buffer(cinfo);
#else
                ERREXIT(cinfo, J_MESSAGE_CODE.JERR_NOT_COMPILED);
#endif
            }
            else
            {
                // No context, just make it tall enough for one row group
                prep.pre_process_data = pre_process_data;
                for (int ci = 0; ci < cinfo.num_components; ci++)
                {
                    jpeg_component_info compptr = cinfo.comp_info[ci];
                    prep.color_buf[ci] = alloc_sarray(cinfo,
                                                      (uint)(((int)compptr.width_in_blocks * cinfo.DCT_size * cinfo.max_h_samp_factor) / compptr.h_samp_factor),
                                                      (uint)cinfo.max_v_samp_factor);
                }
            }
        }
Beispiel #19
0
        // Process some data in the simple no-context case.
        //
        // Preprocessor output data is counted in "row groups". A row group
        // is defined to be v_samp_factor sample rows of each component.
        // Downsampling will produce this much data from each max_v_samp_factor input rows.
        static void pre_process_data(jpeg_compress cinfo, byte[][] input_buf, ref uint in_row_ctr, uint in_rows_avail, byte[][][] output_buf, ref uint out_row_group_ctr, uint out_row_groups_avail)
        {
            my_prep_controller prep = (my_prep_controller)cinfo.prep;

            while (in_row_ctr < in_rows_avail && out_row_group_ctr < out_row_groups_avail)
            {
                // Do color conversion to fill the conversion buffer.
                uint inrows  = in_rows_avail - in_row_ctr;
                int  numrows = cinfo.max_v_samp_factor - prep.next_buf_row;
                numrows = (int)Math.Min((uint)numrows, inrows);
                cinfo.cconvert.color_convert(cinfo, input_buf, in_row_ctr, prep.color_buf, (uint)prep.next_buf_row, numrows);
                in_row_ctr        += (uint)numrows;
                prep.next_buf_row += numrows;
                prep.rows_to_go   -= (uint)numrows;
                // If at bottom of image, pad to fill the conversion buffer.
                if (prep.rows_to_go == 0 && prep.next_buf_row < cinfo.max_v_samp_factor)
                {
                    for (int ci = 0; ci < cinfo.num_components; ci++)
                    {
                        expand_bottom_edge(prep.color_buf[ci], cinfo.image_width, prep.next_buf_row, cinfo.max_v_samp_factor);
                    }
                    prep.next_buf_row = cinfo.max_v_samp_factor;
                }
                // If we've filled the conversion buffer, empty it.
                if (prep.next_buf_row == cinfo.max_v_samp_factor)
                {
                    cinfo.downsample.downsample(cinfo, prep.color_buf, 0, output_buf, out_row_group_ctr);
                    prep.next_buf_row = 0;
                    out_row_group_ctr++;
                }
                // If at bottom of image, pad the output to a full iMCU height.
                // Note we assume the caller is providing a one-iMCU-height output buffer!
                if (prep.rows_to_go == 0 && out_row_group_ctr < out_row_groups_avail)
                {
                    for (int ci = 0; ci < cinfo.num_components; ci++)
                    {
                        jpeg_component_info compptr = cinfo.comp_info[ci];
                        expand_bottom_edge(output_buf[ci], compptr.width_in_blocks * cinfo.DCT_size, (int)(out_row_group_ctr * compptr.v_samp_factor), (int)(out_row_groups_avail * compptr.v_samp_factor));
                    }
                    out_row_group_ctr = out_row_groups_avail;
                    break; // can exit outer loop without test
                }
            }              // while(...)
        }
Beispiel #20
0
        // Process some data in the first pass of a multi-pass case.
        // We process the equivalent of one fully interleaved MCU row ("iMCU" row)
        // per call, ie, v_samp_factor rows for each component in the image.
        // This amount of data is read from the source buffer and saved into the arrays.
        //
        // We must also emit the data to the compressor. This is conveniently
        // done by calling compress_output_diff() after we've loaded the current strip
        // of the arrays.
        //
        // NB: input_buf contains a plane for each component in image. All components
        // are loaded into the arrays in this pass. However, it may be that
        // only a subset of the components are emitted to the compressor during
        // this first pass; be careful about looking at the scan-dependent variables
        // (MCU dimensions, etc).
        static bool compress_first_pass_diff(jpeg_compress cinfo, byte[][][] input_buf)
        {
            jpeg_lossless_c_codec losslsc = (jpeg_lossless_c_codec)cinfo.coef;
            c_diff_controller     diff    = (c_diff_controller)losslsc.diff_private;

            uint last_iMCU_row = cinfo.total_iMCU_rows - 1;

            for (int ci = 0; ci < cinfo.num_components; ci++)
            {
                jpeg_component_info compptr = cinfo.comp_info[ci];

                // Count non-dummy sample rows in this iMCU row.
                int samp_rows;
                if (diff.iMCU_row_num < last_iMCU_row)
                {
                    samp_rows = compptr.v_samp_factor;
                }
                else
                {
                    // NB: can't use last_row_height here, since may not be set!
                    samp_rows = (int)(compptr.height_in_blocks % compptr.v_samp_factor);
                    if (samp_rows == 0)
                    {
                        samp_rows = compptr.v_samp_factor;
                    }
                }

                uint samps_across = compptr.width_in_blocks;

                // Perform point transform scaling and prediction/differencing for all
                // non-dummy rows in this iMCU row. Each call on these functions
                // process a complete row of samples.
                for (int samp_row = 0; samp_row < samp_rows; samp_row++)
                {
                    Array.Copy(input_buf[ci][samp_row], diff.whole_image[ci][samp_row + diff.iMCU_row_num * compptr.v_samp_factor], samps_across);
                }
            }

            // NB: compress_output will increment iMCU_row_num if successful.
            // A suspension return will result in redoing all the work above next time.

            // Emit data to the compressor, sharing code with subsequent passes
            return(compress_output_diff(cinfo, input_buf));
        }
Beispiel #21
0
        // Consume input data and store it in the full-image sample buffer.
        // We read as much as one fully interleaved MCU row ("iMCU" row) per call,
        // ie, v_samp_factor rows for each component in the scan.
        // Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
        static CONSUME_INPUT consume_data_d_diff(jpeg_decompress cinfo)
        {
            jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef;
            d_diff_controller     diff    = (d_diff_controller)losslsd.diff_private;
            uint last_iMCU_row            = cinfo.total_iMCU_rows - 1;

            byte[][][] buffer     = new byte[MAX_COMPS_IN_SCAN][][];
            int[]      buffer_ind = new int[MAX_COMPS_IN_SCAN];

            // Align the buffers for the components used in this scan.
            for (int comp = 0; comp < cinfo.comps_in_scan; comp++)
            {
                jpeg_component_info compptr = cinfo.cur_comp_info[comp];
                int ci = compptr.component_index;
                buffer[ci]     = diff.whole_image[ci];
                buffer_ind[ci] = (int)cinfo.input_iMCU_row * compptr.v_samp_factor;
            }

            return(decompress_data_d_diff(cinfo, buffer, buffer_ind));
        }
Beispiel #22
0
        // Fast processing for the common case of 2:1 horizontal and 1:1 vertical.
        // It's still a box filter.
        static void h2v1_upsample(jpeg_decompress cinfo, jpeg_component_info compptr, byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int output_data_offset)
        {
            byte[][] output_data = output_data_ptr[output_data_offset];

            uint outend = cinfo.output_width;

            for (int outrow = 0; outrow < cinfo.max_v_samp_factor; outrow++)
            {
                byte[] inptr      = input_data[input_data_offset++];
                uint   inptr_ind  = 0;
                byte[] outptr     = output_data[outrow];
                uint   outptr_ind = 0;
                while (outptr_ind < outend)
                {
                    byte invalue = inptr[inptr_ind++];
                    outptr[outptr_ind++] = invalue;
                    outptr[outptr_ind++] = invalue;
                }
            }
        }
Beispiel #23
0
        // Process some data in subsequent passes of a multi-pass case.
        // We process the equivalent of one fully interleaved MCU row ("iMCU" row)
        // per call, ie, v_samp_factor rows for each component in the scan.
        // The data is obtained from the arrays and fed to the compressor.
        // Returns true if the iMCU row is completed, false if suspended.
        //
        // NB: input_buf is ignored; it is likely to be a null pointer.
        static bool compress_output_diff(jpeg_compress cinfo, byte[][][] input_buf)
        {
            jpeg_lossless_c_codec losslsc = (jpeg_lossless_c_codec)cinfo.coef;
            c_diff_controller     diff    = (c_diff_controller)losslsc.diff_private;

            byte[][][] buffer     = new byte[MAX_COMPONENTS][][];
            int[]      buffer_ind = new int[MAX_COMPONENTS];

            // Align the buffers for the components used in this scan.
            // NB: during first pass, this is safe only because the buffers will
            // already be aligned properly, so jmemmgr.cs won't need to do any I/O.
            for (int comp = 0; comp < cinfo.comps_in_scan; comp++)
            {
                jpeg_component_info compptr = cinfo.cur_comp_info[comp];
                int ci = compptr.component_index;
                buffer[ci]     = diff.whole_image[ci];
                buffer_ind[ci] = (int)diff.iMCU_row_num * compptr.v_samp_factor;
            }

            return(compress_data_diff(cinfo, buffer, buffer_ind));
        }
Beispiel #24
0
        // 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.
        static void int_upsample(jpeg_decompress cinfo, jpeg_component_info compptr, byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int output_data_offset)
        {
            my_upsampler upsample = (my_upsampler)cinfo.upsample;

            byte[][] output_data = output_data_ptr[output_data_offset];

            int h_expand = upsample.h_expand[compptr.component_index];
            int v_expand = upsample.v_expand[compptr.component_index];

            int  outrow = 0;
            uint outend = cinfo.output_width;

            while (outrow < cinfo.max_v_samp_factor)
            {
                // Generate one output row with proper horizontal expansion
                byte[] inptr      = input_data[input_data_offset];
                uint   inptr_ind  = 0;
                byte[] outptr     = output_data[outrow];
                uint   outptr_ind = 0;
                while (outptr_ind < outend)
                {
                    byte invalue = inptr[inptr_ind++];
                    for (int h = h_expand; h > 0; h--)
                    {
                        outptr[outptr_ind++] = invalue;
                    }
                }

                // Generate any additional output rows by duplicating the first one
                if (v_expand > 1)
                {
                    jcopy_sample_rows(output_data, outrow, output_data, outrow + 1, v_expand - 1, cinfo.output_width);
                }
                input_data_offset++;
                outrow += v_expand;
            }
        }
Beispiel #25
0
		// Downsample pixel values of a single component.
		// One row group is processed per call.
		// This version handles arbitrary integral sampling ratios, without smoothing.
		// Note that this version is not actually used for customary sampling ratios.
		static void int_downsample(jpeg_compress cinfo, jpeg_component_info compptr, byte[][] input_data, uint in_row_index, byte[][] output_data, uint out_row_index)
		{
			uint output_cols=compptr.width_in_blocks*cinfo.DCT_size;
			int h_expand=cinfo.max_h_samp_factor/compptr.h_samp_factor;
			int v_expand=cinfo.max_v_samp_factor/compptr.v_samp_factor;
			int numpix=h_expand*v_expand;
			int numpix2=numpix/2;

			// Expand input data enough to let all the output samples be generated
			// by the standard loop. Special-casing padded output would be more
			// efficient.
			expand_right_edge(input_data, in_row_index, cinfo.max_v_samp_factor, cinfo.image_width, (uint)(output_cols*h_expand));

			int inrow=(int)in_row_index;
			for(int outrow=0; outrow<compptr.v_samp_factor; outrow++)
			{
				byte[] outptr=output_data[out_row_index+outrow];
				for(uint outcol=0, outcol_h=0; outcol<output_cols; outcol++, outcol_h+=(uint)h_expand)
				{
					byte[] inptr;
					int outvalue=0;
					for(int v=0; v<v_expand; v++)
					{
						inptr=input_data[inrow+v];
						for(int h=0; h<h_expand; h++) outvalue+=(int)inptr[outcol_h+h];
					}
					outptr[outcol]=(byte)((outvalue+numpix2)/numpix);
				}
				inrow+=v_expand;
			}
		}
Beispiel #26
0
        // Routines to calculate various quantities related to the size of the image.

        // Called once, when first SOS marker is reached
        static void initial_setup_d_input(jpeg_decompress cinfo)
        {
            // Make sure image isn't bigger than I can handle
            if ((int)cinfo.image_height > JPEG_MAX_DIMENSION || (int)cinfo.image_width > JPEG_MAX_DIMENSION)
            {
                ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_IMAGE_TOO_BIG, JPEG_MAX_DIMENSION);
            }

            if (cinfo.process == J_CODEC_PROCESS.JPROC_LOSSLESS)
            {
                // If precision > compiled-in value, we must downscale
                if (cinfo.data_precision > BITS_IN_JSAMPLE)
                {
                    WARNMS2(cinfo, J_MESSAGE_CODE.JWRN_MUST_DOWNSCALE, cinfo.data_precision, BITS_IN_JSAMPLE);
                }
            }
            else
            {             // Lossy processes
                // For now, precision must match compiled-in value...
                if (cinfo.data_precision != BITS_IN_JSAMPLE)
                {
                    ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_BAD_PRECISION, cinfo.data_precision);
                }
            }

            // Check that number of components won't exceed internal array sizes
            if (cinfo.num_components > MAX_COMPONENTS)
            {
                ERREXIT2(cinfo, J_MESSAGE_CODE.JERR_COMPONENT_COUNT, cinfo.num_components, MAX_COMPONENTS);
            }

            // Compute maximum sampling factors; check factor validity
            cinfo.max_h_samp_factor = 1;
            cinfo.max_v_samp_factor = 1;
            for (int ci = 0; ci < cinfo.num_components; ci++)
            {
                jpeg_component_info compptr = cinfo.comp_info[ci];
                if (compptr.h_samp_factor <= 0 || compptr.h_samp_factor > MAX_SAMP_FACTOR || compptr.v_samp_factor <= 0 || compptr.v_samp_factor > MAX_SAMP_FACTOR)
                {
                    ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_SAMPLING);
                }
                cinfo.max_h_samp_factor = Math.Max(cinfo.max_h_samp_factor, compptr.h_samp_factor);
                cinfo.max_v_samp_factor = Math.Max(cinfo.max_v_samp_factor, compptr.v_samp_factor);
            }

            // We initialize DCT_scaled_size and min_DCT_scaled_size to DCTSIZE.
            // In the full decompressor, this will be overridden by jdmaster.cs;
            // but in the transcoder, jdmaster.cs is not used, so we must do it here.
            cinfo.min_DCT_scaled_size = cinfo.DCT_size;

            // Compute dimensions of components
            for (int ci = 0; ci < cinfo.num_components; ci++)
            {
                jpeg_component_info compptr = cinfo.comp_info[ci];
                compptr.DCT_scaled_size = (uint)cinfo.DCT_size;

                // Size in data units
                compptr.width_in_blocks  = (uint)jdiv_round_up(cinfo.image_width * compptr.h_samp_factor, cinfo.max_h_samp_factor * cinfo.DCT_size);
                compptr.height_in_blocks = (uint)jdiv_round_up(cinfo.image_height * compptr.v_samp_factor, cinfo.max_v_samp_factor * cinfo.DCT_size);
                // downsampled_width and downsampled_height will also be overridden by
                // jdmaster.cs 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  = (uint)jdiv_round_up(cinfo.image_width * compptr.h_samp_factor, cinfo.max_h_samp_factor);
                compptr.downsampled_height = (uint)jdiv_round_up(cinfo.image_height * compptr.v_samp_factor, cinfo.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.
            cinfo.total_iMCU_rows = (uint)jdiv_round_up(cinfo.image_height, cinfo.max_v_samp_factor * cinfo.DCT_size);

            // Decide whether file contains multiple scans
            if (cinfo.comps_in_scan < cinfo.num_components || cinfo.process == J_CODEC_PROCESS.JPROC_PROGRESSIVE)
            {
                cinfo.inputctl.has_multiple_scans = true;
            }
            else
            {
                cinfo.inputctl.has_multiple_scans = false;
            }
        }
Beispiel #27
0
		// Downsample pixel values of a single component.
		// This version handles the standard case of 2:1 horizontal and 2:1 vertical,
		// without smoothing.
		static void h2v2_downsample(jpeg_compress cinfo, jpeg_component_info compptr, byte[][] input_data, uint in_row_index, byte[][] output_data, uint out_row_index)
		{
			uint output_cols=compptr.width_in_blocks*cinfo.DCT_size;

			// Expand input data enough to let all the output samples be generated
			// by the standard loop. Special-casing padded output would be more
			// efficient.
			expand_right_edge(input_data, in_row_index, cinfo.max_v_samp_factor, cinfo.image_width, output_cols*2);

			int inrow=(int)in_row_index;
			for(int outrow=0; outrow<compptr.v_samp_factor; outrow++)
			{
				byte[] outptr=output_data[out_row_index+outrow];
				byte[] inptr0=input_data[inrow];
				byte[] inptr1=input_data[inrow+1];
				int bias=1; // bias = 1,2,1,2,... for successive samples
				for(uint outcol=0, ind=0; outcol<output_cols; outcol++, ind+=2)
				{
					outptr[outcol]=(byte)((inptr0[ind]+inptr0[ind+1]+inptr1[ind]+inptr1[ind+1]+bias)>>2);
					bias^=3; // 1=>2, 2=>1
				}
				inrow+=2;
			}
		}
Beispiel #28
0
		// Downsample pixel values of a single component.
		// This version handles the special case of a full-size component,
		// without smoothing.
		static void fullsize_downsample(jpeg_compress cinfo, jpeg_component_info compptr, byte[][] input_data, uint in_row_index, byte[][] output_data, uint out_row_index)
		{
			// Copy the data
			jcopy_sample_rows(input_data, (int)in_row_index, output_data, (int)out_row_index, cinfo.max_v_samp_factor, cinfo.image_width);

			// Edge-expand
			expand_right_edge(output_data, out_row_index, cinfo.max_v_samp_factor, cinfo.image_width, compptr.width_in_blocks*cinfo.DCT_size);
		}
Beispiel #29
0
		// Fast processing for the common case of 2:1 horizontal and 2:1 vertical.
		// It's still a box filter.
#if! USE_UNSAFE_STUFF
		static void h2v2_fancy_upsample(jpeg_decompress cinfo, jpeg_component_info compptr, byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int output_data_offset)
		{
			if(!compptr.notFirst)
			{
				input_data[0].CopyTo(input_data[input_data.Length-1], 0);
				compptr.notFirst=true;
			}

			byte[][] output_data=output_data_ptr[output_data_offset];

			int inrow=0, outrow=0;
			while(outrow<cinfo.max_v_samp_factor)
			{
				for(int v=0; v<2; v++)
				{
					// inptr0 points to nearest input row, inptr1 points to next nearest
					byte[] inptr0=input_data[input_data_offset+inrow];
					byte[] inptr1=null;
					if(v==0)
					{
						inptr1=input_data[input_data_offset==0?input_data.Length-1:input_data_offset+inrow-1];	// next nearest is row above
					}
					else inptr1=input_data[(input_data_offset+inrow+1)%input_data.Length];		// next nearest is row below
					uint intptr_ind=0;

					byte[] outptr=output_data[outrow++];
					uint outptr_ind=0;

					// Special case for first column
					int thiscolsum=inptr0[intptr_ind]*3+inptr1[intptr_ind]; intptr_ind++;
					int nextcolsum=inptr0[intptr_ind]*3+inptr1[intptr_ind]; intptr_ind++;
					outptr[outptr_ind++]=(byte)((thiscolsum*4+8)>>4);
					outptr[outptr_ind++]=(byte)((thiscolsum*3+nextcolsum+7)>>4);
					int lastcolsum=thiscolsum;
					thiscolsum=nextcolsum;

					for(uint colctr=compptr.downsampled_width-2; colctr>0; colctr--)
					{
						// General case: 3/4 * nearer pixel + 1/4 * further pixel in each
						// dimension, thus 9/16, 3/16, 3/16, 1/16 overall
						nextcolsum=inptr0[intptr_ind]*3+inptr1[intptr_ind]; intptr_ind++;
						outptr[outptr_ind++]=(byte)((thiscolsum*3+lastcolsum+8)>>4);
						outptr[outptr_ind++]=(byte)((thiscolsum*3+nextcolsum+7)>>4);
						lastcolsum=thiscolsum; thiscolsum=nextcolsum;
					}

					// Special case for last column
					outptr[outptr_ind++]=(byte)((thiscolsum*3+lastcolsum+8)>>4);
					outptr[outptr_ind++]=(byte)((thiscolsum*4+7)>>4);
				}
				inrow++;
			}
		}
Beispiel #30
0
		// Downsample pixel values of a single component.
		// This version handles the standard case of 2:1 horizontal and 2:1 vertical,
		// with smoothing. One row of context is required.
		static void h2v2_smooth_downsample(jpeg_compress cinfo, jpeg_component_info compptr, byte[][] input_data, uint in_row_index, byte[][] output_data, uint out_row_index)
		{
			uint output_cols=compptr.width_in_blocks*cinfo.DCT_size;

			// Expand input data enough to let all the output samples be generated
			// by the standard loop. Special-casing padded output would be more efficient.
			expand_right_edge(input_data, in_row_index-1, cinfo.max_v_samp_factor+2, cinfo.image_width, output_cols*2);

			// We don't bother to form the individual "smoothed" input pixel values;
			// we can directly compute the output which is the average of the four
			// smoothed values. Each of the four member pixels contributes a fraction
			// (1-8*SF) to its own smoothed image and a fraction SF to each of the three
			// other smoothed pixels, therefore a total fraction (1-5*SF)/4 to the final
			// output. The four corner-adjacent neighbor pixels contribute a fraction
			// SF to just one smoothed pixel, or SF/4 to the final output; while the
			// eight edge-adjacent neighbors contribute SF to each of two smoothed
			// pixels, or SF/2 overall. In order to use integer arithmetic, these
			// factors are scaled by 2^16 = 65536.
			// Also recall that SF = smoothing_factor / 1024.
			int memberscale=16384-cinfo.smoothing_factor*80; // scaled (1-5*SF)/4
			int neighscale=cinfo.smoothing_factor*16; // scaled SF/4

			int inrow=(int)in_row_index;
			for(int outrow=0; outrow<compptr.v_samp_factor; outrow++)
			{
				byte[] outptr=output_data[out_row_index+outrow];
				byte[] inptr0=input_data[inrow];
				byte[] inptr1=input_data[inrow+1];
				byte[] above_ptr=input_data[inrow-1];
				byte[] below_ptr=input_data[inrow+2];

				// Special case for first column: pretend column -1 is same as column 0
				int membersum=inptr0[0]+inptr0[1]+inptr1[0]+inptr1[1];
				int neighsum=above_ptr[0]+above_ptr[1]+below_ptr[0]+below_ptr[1]+inptr0[0]+inptr0[2]+inptr1[0]+inptr1[2];
				neighsum+=neighsum;
				neighsum+=above_ptr[0]+above_ptr[2]+below_ptr[0]+below_ptr[2];
				membersum=membersum*memberscale+neighsum*neighscale;
				outptr[0]=(byte)((membersum+32768)>>16);
				int iind=2, oind=1;

				for(uint colctr=output_cols-2; colctr>0; colctr--)
				{
					// sum of pixels directly mapped to this output element
					membersum=inptr0[iind]+inptr0[iind+1]+inptr1[iind]+inptr1[iind+1];
					// sum of edge-neighbor pixels
					neighsum=above_ptr[iind]+above_ptr[iind+1]+below_ptr[iind]+below_ptr[iind+1]+inptr0[iind-1]+inptr0[iind+2]+inptr1[iind-1]+inptr1[iind+2];
					// The edge-neighbors count twice as much as corner-neighbors
					neighsum+=neighsum;
					// Add in the corner-neighbors
					neighsum+=above_ptr[iind-1]+above_ptr[iind+2]+below_ptr[iind-1]+below_ptr[iind+2];
					// form final output scaled up by 2^16
					membersum=membersum*memberscale+neighsum*neighscale;
					// round, descale and output it
					outptr[oind]=(byte)((membersum+32768)>>16);
					iind+=2;
					oind++;
				}

				// Special case for last column
				membersum=inptr0[iind]+inptr0[iind+1]+inptr1[iind]+inptr1[iind+1];
				neighsum=above_ptr[iind]+above_ptr[iind+1]+below_ptr[iind]+below_ptr[iind+1]+inptr0[iind-1]+inptr0[iind+1]+inptr1[iind-1]+inptr1[iind+1];
				neighsum+=neighsum;
				neighsum+=above_ptr[iind-1]+above_ptr[iind+1]+below_ptr[iind-1]+below_ptr[iind+1];
				membersum=membersum*memberscale+neighsum*neighscale;
				outptr[oind]=(byte)((membersum+32768)>>16);

				inrow+=2;
			}
		}
Beispiel #31
0
        static CONSUME_INPUT decompress_data_d_diff(jpeg_decompress cinfo, byte[][][] output_buf, int[] output_buf_ind)
        {
            jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef;
            d_diff_controller     diff    = (d_diff_controller)losslsd.diff_private;

            // Loop to process as much as one whole iMCU row
            for (uint yoffset = diff.MCU_vert_offset; yoffset < diff.MCU_rows_per_iMCU_row; yoffset++)
            {
                // Process restart marker if needed; may have to suspend
                if (cinfo.restart_interval != 0)
                {
                    if (diff.restart_rows_to_go == 0)
                    {
                        if (!process_restart_d_diff(cinfo))
                        {
                            return(CONSUME_INPUT.JPEG_SUSPENDED);
                        }
                    }
                }

                uint MCU_col_num = diff.MCU_ctr;               // index of current MCU within row

                // Try to fetch an MCU-row (or remaining portion of suspended MCU-row).
                uint MCU_count = losslsd.entropy_decode_mcus(cinfo, diff.diff_buf, yoffset, MCU_col_num, cinfo.MCUs_per_row - MCU_col_num);
                if (MCU_count != cinfo.MCUs_per_row - MCU_col_num)
                {
                    // Suspension forced; update state counters and exit
                    diff.MCU_vert_offset = yoffset;
                    diff.MCU_ctr        += MCU_count;
                    return(CONSUME_INPUT.JPEG_SUSPENDED);
                }

                // Account for restart interval (no-op if not using restarts)
                diff.restart_rows_to_go--;

                // Completed an MCU row, but perhaps not an iMCU row
                diff.MCU_ctr = 0;
            }

            uint last_iMCU_row = cinfo.total_iMCU_rows - 1;

            // Undifference and scale each scanline of the disassembled MCU-row
            // separately. We do not process dummy samples at the end of a scanline
            // or dummy rows at the end of the image.
            for (int comp = 0; comp < cinfo.comps_in_scan; comp++)
            {
                jpeg_component_info compptr = cinfo.cur_comp_info[comp];
                int ci   = compptr.component_index;
                int stop = cinfo.input_iMCU_row == last_iMCU_row?compptr.last_row_height:compptr.v_samp_factor;
                for (int row = 0, prev_row = compptr.v_samp_factor - 1; row < stop; prev_row = row, row++)
                {
                    losslsd.predict_undifference[ci](cinfo, ci, diff.diff_buf[ci][row], diff.undiff_buf[ci][prev_row], diff.undiff_buf[ci][row], compptr.width_in_blocks);
                    losslsd.scaler_scale(cinfo, diff.undiff_buf[ci][row], output_buf[ci][output_buf_ind[ci] + row], compptr.width_in_blocks);
                }
            }

            // Completed the iMCU row, advance counters for next one.
            //
            // NB: output_data will increment output_iMCU_row.
            // This counter is not needed for the single-pass case
            // or the input side of the multi-pass case.
            if (++(cinfo.input_iMCU_row) < cinfo.total_iMCU_rows)
            {
                start_iMCU_row_d_diff(cinfo);
                return(CONSUME_INPUT.JPEG_ROW_COMPLETED);
            }

            // Completed the scan
            cinfo.inputctl.finish_input_pass(cinfo);
            return(CONSUME_INPUT.JPEG_SCAN_COMPLETED);
        }
Beispiel #32
0
		static void h2v2_fancy_upsample(jpeg_decompress cinfo, jpeg_component_info compptr, byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int output_data_offset)
		{
			unsafe
			{
				if(!compptr.notFirst)
				{
					input_data[0].CopyTo(input_data[input_data.Length-1], 0);
					compptr.notFirst=true;
				}

				byte[][] output_data=output_data_ptr[output_data_offset];

				int inrow=0, outrow=0;
				while(outrow<cinfo.max_v_samp_factor)
				{
					// inptr0 points to nearest input row
					fixed(byte* inptr0_=input_data[input_data_offset+inrow])
					{
						// inptr1 points to next nearest
						int nextnearestrow=input_data_offset==0?input_data.Length-1:input_data_offset+inrow-1; // next nearest is row above

						for(int v=0; v<2; v++)
						{
							fixed(byte* inptr1_=input_data[nextnearestrow], outptr_=output_data[outrow++])
							{
								byte* inptr0=inptr0_, inptr1=inptr1_, outptr=outptr_;

								// Special case for first column
								int thiscolsum=*(inptr0++)*3+*(inptr1++);
								int nextcolsum=*(inptr0++)*3+*(inptr1++);
								*(outptr++)=(byte)((thiscolsum*4+8)>>4);
								*(outptr++)=(byte)((thiscolsum*3+nextcolsum+7)>>4);
								int lastcolsum=thiscolsum;
								thiscolsum=nextcolsum;

								for(uint colctr=compptr.downsampled_width-2; colctr>0; colctr--)
								{
									// General case: 3/4 * nearer pixel + 1/4 * further pixel in each
									// dimension, thus 9/16, 3/16, 3/16, 1/16 overall
									nextcolsum=*(inptr0++)*3+*(inptr1++);
									*(outptr++)=(byte)((thiscolsum*3+lastcolsum+8)>>4);
									*(outptr++)=(byte)((thiscolsum*3+nextcolsum+7)>>4);
									lastcolsum=thiscolsum; thiscolsum=nextcolsum;
								}

								// Special case for last column
								*(outptr++)=(byte)((thiscolsum*3+lastcolsum+8)>>4);
								*(outptr++)=(byte)((thiscolsum*4+7)>>4);
							}

							nextnearestrow=(input_data_offset+inrow+1)%input_data.Length; // next nearest is row below
						}
					}
					inrow++;
				}
			}
		}
Beispiel #33
0
        // Module initialization routine for downsampling.
        // Note that we must select a routine for each component.
        static void jinit_downsampler(jpeg_compress cinfo)
        {
            my_downsampler downsample = null;

            try
            {
                downsample = new my_downsampler();
            }
            catch
            {
                ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
            }

            cinfo.downsample             = downsample;
            downsample.start_pass        = start_pass_downsample;
            downsample.downsample        = sep_downsample;
            downsample.need_context_rows = false;

            if (cinfo.CCIR601_sampling)
            {
                ERREXIT(cinfo, J_MESSAGE_CODE.JERR_CCIR601_NOTIMPL);
            }

            bool smoothok = true;

            // Verify we can handle the sampling factors, and set up method pointers
            for (int ci = 0; ci < cinfo.num_components; ci++)
            {
                jpeg_component_info compptr = cinfo.comp_info[ci];
                if (compptr.h_samp_factor == cinfo.max_h_samp_factor && compptr.v_samp_factor == cinfo.max_v_samp_factor)
                {
#if INPUT_SMOOTHING_SUPPORTED
                    if (cinfo.smoothing_factor != 0)
                    {
                        downsample.methods[ci]       = fullsize_smooth_downsample;
                        downsample.need_context_rows = true;
                    }
                    else
#endif
                    downsample.methods[ci] = fullsize_downsample;
                }
                else if (compptr.h_samp_factor * 2 == cinfo.max_h_samp_factor && compptr.v_samp_factor == cinfo.max_v_samp_factor)
                {
                    smoothok = false;
                    downsample.methods[ci] = h2v1_downsample;
                }
                else if (compptr.h_samp_factor * 2 == cinfo.max_h_samp_factor && compptr.v_samp_factor * 2 == cinfo.max_v_samp_factor)
                {
#if INPUT_SMOOTHING_SUPPORTED
                    if (cinfo.smoothing_factor != 0)
                    {
                        downsample.methods[ci]       = h2v2_smooth_downsample;
                        downsample.need_context_rows = true;
                    }
                    else
#endif
                    downsample.methods[ci] = h2v2_downsample;
                }
                else if ((cinfo.max_h_samp_factor % compptr.h_samp_factor) == 0 && (cinfo.max_v_samp_factor % compptr.v_samp_factor) == 0)
                {
                    smoothok = false;
                    downsample.methods[ci] = int_downsample;
                }
                else
                {
                    ERREXIT(cinfo, J_MESSAGE_CODE.JERR_FRACT_SAMPLE_NOTIMPL);
                }
            }

#if INPUT_SMOOTHING_SUPPORTED
            if (cinfo.smoothing_factor != 0 && !smoothok)
            {
                TRACEMS(cinfo, 0, J_MESSAGE_CODE.JTRC_SMOOTH_NOTIMPL);
            }
#endif
        }
Beispiel #34
0
        // Module initialization routine for upsampling.
        public static void jinit_upsampler(jpeg_decompress cinfo)
        {
            my_upsampler upsample = null;
            bool         need_buffer;
            int          h_in_group, v_in_group, h_out_group, v_out_group;

            try
            {
                upsample = new my_upsampler();
            }
            catch
            {
                ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
            }
            cinfo.upsample      = upsample;
            upsample.start_pass = start_pass_upsample;
            upsample.upsample   = sep_upsample;
#if UPSCALING_CONTEXT
            upsample.need_context_rows = false;           // until we find out differently
#endif

            if (cinfo.CCIR601_sampling)
            {
                ERREXIT(cinfo, J_MESSAGE_CODE.JERR_CCIR601_NOTIMPL);                                    // this isn't supported
            }
            // jdmainct.cs doesn't support context rows when min_DCT_scaled_size = 1,
            // so don't ask for it.
            bool do_fancy = cinfo.do_fancy_upsampling && cinfo.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.num_components; ci++)
            {
                jpeg_component_info compptr = 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.
                h_in_group  = (int)(compptr.h_samp_factor * compptr.DCT_scaled_size) / cinfo.min_DCT_scaled_size;
                v_in_group  = (int)(compptr.v_samp_factor * compptr.DCT_scaled_size) / cinfo.min_DCT_scaled_size;
                h_out_group = cinfo.max_h_samp_factor;
                v_out_group = cinfo.max_v_samp_factor;
                upsample.rowgroup_height[ci] = v_in_group;               // save for use later
                need_buffer = true;
                if (!compptr.component_needed)
                {
                    // Don't bother to upsample an uninteresting component.
                    upsample.methods[ci] = noop_upsample;
                    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.
                    upsample.methods[ci]   = fullsize_upsample;
                    need_buffer            = false;
                    upsample.color_buf[ci] = new byte[cinfo.max_v_samp_factor][];
                }
                else if (h_in_group * 2 == h_out_group && v_in_group == v_out_group)
                {
                    // Special cases for 2h1v upsampling
                    if (do_fancy && compptr.downsampled_width > 2)
                    {
                        upsample.methods[ci] = h2v1_fancy_upsample;
                    }
                    else
                    {
                        upsample.methods[ci] = h2v1_upsample;
                    }
                }
                else if (h_in_group * 2 == h_out_group && v_in_group * 2 == v_out_group)
                {
                    // Special cases for 2h2v upsampling
#if UPSCALING_CONTEXT
                    if (do_fancy && compptr.downsampled_width > 2)
                    {
                        upsample.methods[ci]       = h2v2_fancy_upsample;
                        upsample.need_context_rows = true;
                        compptr.doContext          = true;
                    }
                    else
#endif
                    upsample.methods[ci] = h2v2_upsample;
                }
                else if ((h_out_group % h_in_group) == 0 && (v_out_group % v_in_group) == 0)
                {
                    // Generic integral-factors upsampling method
                    upsample.methods[ci]  = int_upsample;
                    upsample.h_expand[ci] = (byte)(h_out_group / h_in_group);
                    upsample.v_expand[ci] = (byte)(v_out_group / v_in_group);
                }
                else
                {
                    ERREXIT(cinfo, J_MESSAGE_CODE.JERR_FRACT_SAMPLE_NOTIMPL);
                }

                if (need_buffer)
                {
                    upsample.color_buf[ci] = alloc_sarray(cinfo, (uint)jround_up((int)cinfo.output_width, (int)cinfo.max_h_samp_factor), (uint)cinfo.max_v_samp_factor);
                }
            }
        }
Beispiel #35
0
		// These are the routines invoked by sep_upsample to upsample pixel values
		// of a single component. One row group is processed per call.

		// For full-size components, we just make color_buf[ci] point at the
		// input buffer, and thus avoid copying any data. Note that this is
		// safe only because sep_upsample doesn't declare the input row group
		// "consumed" until we are done color converting and emitting it.
		static void fullsize_upsample(jpeg_decompress cinfo, jpeg_component_info compptr, byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int output_data_offset)
		{		
			for(int i=0; i<cinfo.max_v_samp_factor; i++) output_data_ptr[output_data_offset][i]=input_data[input_data_offset++];
		}
Beispiel #36
0
        // Downsample pixel values of a single component.
        // This version handles the standard case of 2:1 horizontal and 2:1 vertical,
        // with smoothing. One row of context is required.
        static void h2v2_smooth_downsample(jpeg_compress cinfo, jpeg_component_info compptr, byte[][] input_data, uint in_row_index, byte[][] output_data, uint out_row_index)
        {
            uint output_cols = compptr.width_in_blocks * cinfo.DCT_size;

            // Expand input data enough to let all the output samples be generated
            // by the standard loop. Special-casing padded output would be more efficient.
            expand_right_edge(input_data, in_row_index - 1, cinfo.max_v_samp_factor + 2, cinfo.image_width, output_cols * 2);

            // We don't bother to form the individual "smoothed" input pixel values;
            // we can directly compute the output which is the average of the four
            // smoothed values. Each of the four member pixels contributes a fraction
            // (1-8*SF) to its own smoothed image and a fraction SF to each of the three
            // other smoothed pixels, therefore a total fraction (1-5*SF)/4 to the final
            // output. The four corner-adjacent neighbor pixels contribute a fraction
            // SF to just one smoothed pixel, or SF/4 to the final output; while the
            // eight edge-adjacent neighbors contribute SF to each of two smoothed
            // pixels, or SF/2 overall. In order to use integer arithmetic, these
            // factors are scaled by 2^16 = 65536.
            // Also recall that SF = smoothing_factor / 1024.
            int memberscale = 16384 - cinfo.smoothing_factor * 80; // scaled (1-5*SF)/4
            int neighscale  = cinfo.smoothing_factor * 16;         // scaled SF/4

            int inrow = (int)in_row_index;

            for (int outrow = 0; outrow < compptr.v_samp_factor; outrow++)
            {
                byte[] outptr    = output_data[out_row_index + outrow];
                byte[] inptr0    = input_data[inrow];
                byte[] inptr1    = input_data[inrow + 1];
                byte[] above_ptr = input_data[inrow - 1];
                byte[] below_ptr = input_data[inrow + 2];

                // Special case for first column: pretend column -1 is same as column 0
                int membersum = inptr0[0] + inptr0[1] + inptr1[0] + inptr1[1];
                int neighsum  = above_ptr[0] + above_ptr[1] + below_ptr[0] + below_ptr[1] + inptr0[0] + inptr0[2] + inptr1[0] + inptr1[2];
                neighsum += neighsum;
                neighsum += above_ptr[0] + above_ptr[2] + below_ptr[0] + below_ptr[2];
                membersum = membersum * memberscale + neighsum * neighscale;
                outptr[0] = (byte)((membersum + 32768) >> 16);
                int iind = 2, oind = 1;

                for (uint colctr = output_cols - 2; colctr > 0; colctr--)
                {
                    // sum of pixels directly mapped to this output element
                    membersum = inptr0[iind] + inptr0[iind + 1] + inptr1[iind] + inptr1[iind + 1];
                    // sum of edge-neighbor pixels
                    neighsum = above_ptr[iind] + above_ptr[iind + 1] + below_ptr[iind] + below_ptr[iind + 1] + inptr0[iind - 1] + inptr0[iind + 2] + inptr1[iind - 1] + inptr1[iind + 2];
                    // The edge-neighbors count twice as much as corner-neighbors
                    neighsum += neighsum;
                    // Add in the corner-neighbors
                    neighsum += above_ptr[iind - 1] + above_ptr[iind + 2] + below_ptr[iind - 1] + below_ptr[iind + 2];
                    // form final output scaled up by 2^16
                    membersum = membersum * memberscale + neighsum * neighscale;
                    // round, descale and output it
                    outptr[oind] = (byte)((membersum + 32768) >> 16);
                    iind        += 2;
                    oind++;
                }

                // Special case for last column
                membersum    = inptr0[iind] + inptr0[iind + 1] + inptr1[iind] + inptr1[iind + 1];
                neighsum     = above_ptr[iind] + above_ptr[iind + 1] + below_ptr[iind] + below_ptr[iind + 1] + inptr0[iind - 1] + inptr0[iind + 1] + inptr1[iind - 1] + inptr1[iind + 1];
                neighsum    += neighsum;
                neighsum    += above_ptr[iind - 1] + above_ptr[iind + 1] + below_ptr[iind - 1] + below_ptr[iind + 1];
                membersum    = membersum * memberscale + neighsum * neighscale;
                outptr[oind] = (byte)((membersum + 32768) >> 16);

                inrow += 2;
            }
        }
Beispiel #37
0
		// This is a no-op version used for "uninteresting" components.
		// These components will not be referenced by color conversion.
		static void noop_upsample(jpeg_decompress cinfo, jpeg_component_info compptr, byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int output_data_offset)
		{
			output_data_ptr[output_data_offset]=null; // safety check
		}
Beispiel #38
0
		// 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.
		static void int_upsample(jpeg_decompress cinfo, jpeg_component_info compptr, byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int output_data_offset)
		{
			my_upsampler upsample=(my_upsampler)cinfo.upsample;
			byte[][] output_data=output_data_ptr[output_data_offset];

			int h_expand=upsample.h_expand[compptr.component_index];
			int v_expand=upsample.v_expand[compptr.component_index];

			int outrow=0;
			uint outend=cinfo.output_width;
			while(outrow<cinfo.max_v_samp_factor)
			{
				// Generate one output row with proper horizontal expansion
				byte[] inptr=input_data[input_data_offset];
				uint inptr_ind=0;
				byte[] outptr=output_data[outrow];
				uint outptr_ind=0;
				while(outptr_ind<outend)
				{
					byte invalue=inptr[inptr_ind++];
					for(int h=h_expand; h>0; h--) outptr[outptr_ind++]=invalue;
				}

				// Generate any additional output rows by duplicating the first one
				if(v_expand>1) jcopy_sample_rows(output_data, outrow, output_data, outrow+1, v_expand-1, cinfo.output_width);
				input_data_offset++;
				outrow+=v_expand;
			}
		}
Beispiel #39
0
		// Fast processing for the common case of 2:1 horizontal and 1:1 vertical.
		// It's still a box filter.
		static void h2v1_upsample(jpeg_decompress cinfo, jpeg_component_info compptr, byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int output_data_offset)
		{
			byte[][] output_data=output_data_ptr[output_data_offset];

			uint outend=cinfo.output_width;
			for(int outrow=0; outrow<cinfo.max_v_samp_factor; outrow++)
			{
				byte[] inptr=input_data[input_data_offset++];
				uint inptr_ind=0;
				byte[] outptr=output_data[outrow];
				uint outptr_ind=0;
				while(outptr_ind<outend)
				{
					byte invalue=inptr[inptr_ind++];
					outptr[outptr_ind++]=invalue;
					outptr[outptr_ind++]=invalue;
				}
			}
		}
Beispiel #40
0
        // Do computations that are needed before processing a JPEG scan
        // cinfo.comps_in_scan and cinfo.cur_comp_info[] were set from SOS marker
        static void per_scan_setup_d_input(jpeg_decompress cinfo)
        {
            if (cinfo.comps_in_scan == 1)
            {
                // Noninterleaved (single-component) scan
                jpeg_component_info compptr = cinfo.cur_comp_info[0];

                // Overall image size in MCUs
                cinfo.MCUs_per_row     = compptr.width_in_blocks;
                cinfo.MCU_rows_in_scan = compptr.height_in_blocks;

                // For noninterleaved scan, always one block per MCU
                compptr.MCU_width        = 1;
                compptr.MCU_height       = 1;
                compptr.MCU_blocks       = 1;
                compptr.MCU_sample_width = (int)compptr.DCT_scaled_size;
                compptr.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 = (int)(compptr.height_in_blocks % compptr.v_samp_factor);
                if (tmp == 0)
                {
                    tmp = compptr.v_samp_factor;
                }
                compptr.last_row_height = tmp;

                // Prepare array describing MCU composition
                cinfo.blocks_in_MCU     = 1;
                cinfo.MCU_membership[0] = 0;
            }
            else
            {
                // Interleaved (multi-component) scan
                if (cinfo.comps_in_scan <= 0 || cinfo.comps_in_scan > MAX_COMPS_IN_SCAN)
                {
                    ERREXIT2(cinfo, J_MESSAGE_CODE.JERR_COMPONENT_COUNT, cinfo.comps_in_scan, MAX_COMPS_IN_SCAN);
                }

                // Overall image size in MCUs
                cinfo.MCUs_per_row     = (uint)jdiv_round_up(cinfo.image_width, cinfo.max_h_samp_factor * cinfo.DCT_size);
                cinfo.MCU_rows_in_scan = (uint)jdiv_round_up(cinfo.image_height, cinfo.max_v_samp_factor * cinfo.DCT_size);

                cinfo.blocks_in_MCU = 0;

                for (int ci = 0; ci < cinfo.comps_in_scan; ci++)
                {
                    jpeg_component_info compptr = cinfo.cur_comp_info[ci];

                    // Sampling factors give # of blocks of component in each MCU
                    compptr.MCU_width        = compptr.h_samp_factor;
                    compptr.MCU_height       = compptr.v_samp_factor;
                    compptr.MCU_blocks       = (uint)(compptr.MCU_width * compptr.MCU_height);
                    compptr.MCU_sample_width = (int)(compptr.MCU_width * compptr.DCT_scaled_size);

                    // Figure number of non-dummy blocks in last MCU column & row
                    int tmp = (int)(compptr.width_in_blocks % compptr.MCU_width);
                    if (tmp == 0)
                    {
                        tmp = compptr.MCU_width;
                    }
                    compptr.last_col_width = tmp;
                    tmp = (int)(compptr.height_in_blocks % compptr.MCU_height);
                    if (tmp == 0)
                    {
                        tmp = compptr.MCU_height;
                    }
                    compptr.last_row_height = tmp;

                    // Prepare array describing MCU composition
                    int mcublks = (int)compptr.MCU_blocks;
                    if (cinfo.blocks_in_MCU + mcublks > D_MAX_BLOCKS_IN_MCU)
                    {
                        ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_MCU_SIZE);
                    }
                    while ((mcublks--) > 0)
                    {
                        cinfo.MCU_membership[cinfo.blocks_in_MCU++] = ci;
                    }
                }
            }
        }
Beispiel #41
0
		static void h2v1_fancy_upsample(jpeg_decompress cinfo, jpeg_component_info compptr, byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int output_data_offset)
		{
			unsafe
			{
				byte[][] output_data=output_data_ptr[output_data_offset];

				for(int inrow=0; inrow<cinfo.max_v_samp_factor; inrow++)
				{
					fixed(byte* inptr_=input_data[input_data_offset++], outptr_=output_data[inrow])
					{
						byte* inptr=inptr_;
						byte* outptr=outptr_;

						// Special case for first column
						int invalue=*(inptr++);
						*(outptr++)=(byte)invalue;
						*(outptr++)=(byte)((invalue*3+*inptr+2)>>2);

						for(uint colctr=compptr.downsampled_width-2; colctr>0; colctr--)
						{
							// General case: 3/4 * nearer pixel + 1/4 * further pixel
							invalue=*(inptr++)*3;
							*(outptr++)=(byte)((invalue+inptr[-2]+1)>>2);
							*(outptr++)=(byte)((invalue+*inptr+2)>>2);
						}

						// Special case for last column
						invalue=*inptr;
						*(outptr++)=(byte)((invalue*3+inptr[-1]+1)>>2);
						*outptr=(byte)invalue;
					}
				}
			}
		}
Beispiel #42
0
		// Downsample pixel values of a single component.
		// This version handles the special case of a full-size component,
		// with smoothing. One row of context is required.
		static void fullsize_smooth_downsample(jpeg_compress cinfo, jpeg_component_info compptr, byte[][] input_data, uint in_row_index, byte[][] output_data, uint out_row_index)
		{
			uint output_cols=compptr.width_in_blocks*cinfo.DCT_size;

			// Expand input data enough to let all the output samples be generated
			// by the standard loop. Special-casing padded output would be more
			// efficient.
			expand_right_edge(input_data, in_row_index-1, cinfo.max_v_samp_factor+2, cinfo.image_width, output_cols);

			// Each of the eight neighbor pixels contributes a fraction SF to the
			// smoothed pixel, while the main pixel contributes (1-8*SF). In order
			// to use integer arithmetic, these factors are multiplied by 2^16 = 65536.
			// Also recall that SF = smoothing_factor / 1024.
			int memberscale=65536-cinfo.smoothing_factor*512; // scaled 1-8*SF
			int neighscale=cinfo.smoothing_factor*64; // scaled SF

			int membersum, neighsum;
			int colsum, lastcolsum, nextcolsum;

			for(int outrow=0; outrow<compptr.v_samp_factor; outrow++)
			{
				byte[] outptr=output_data[out_row_index+outrow];
				byte[] inptr=input_data[in_row_index+outrow];
				byte[] above_ptr=input_data[in_row_index+outrow-1];
				byte[] below_ptr=input_data[in_row_index+outrow+1];

				int iind=0, aind=0, bind=0, oind=0;

				// Special case for first column
				colsum=above_ptr[aind++]+below_ptr[bind++]+inptr[iind];
				membersum=inptr[iind++];
				nextcolsum=above_ptr[aind]+below_ptr[bind]+inptr[iind];
				neighsum=colsum+(colsum-membersum)+nextcolsum;
				membersum=membersum*memberscale+neighsum*neighscale;
				outptr[oind++]=(byte)((membersum+32768)>>16);
				lastcolsum=colsum; colsum=nextcolsum;

				for(uint colctr=output_cols-2; colctr>0; colctr--)
				{
					membersum=inptr[iind++];
					nextcolsum=above_ptr[aind++]+below_ptr[bind++]+inptr[iind];
					neighsum=lastcolsum+(colsum-membersum)+nextcolsum;
					membersum=membersum*memberscale+neighsum*neighscale;
					outptr[oind++]=(byte)((membersum+32768)>>16);
					lastcolsum=colsum; colsum=nextcolsum;
				}

				// Special case for last column
				membersum=inptr[iind];
				neighsum=lastcolsum+(colsum-membersum)+colsum;
				membersum=membersum*memberscale+neighsum*neighscale;
				outptr[oind]=(byte)((membersum+32768)>>16);
			}
		}
Beispiel #43
0
		// Fast processing for the common case of 2:1 horizontal and 2:1 vertical.
		// It's still a box filter.
		static void h2v2_upsample(jpeg_decompress cinfo, jpeg_component_info compptr, byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int output_data_offset)
		{
			byte[][] output_data=output_data_ptr[output_data_offset];

			int outrow=0;
			uint outend=cinfo.output_width;
			while(outrow<cinfo.max_v_samp_factor)
			{
				byte[] inptr=input_data[input_data_offset];
				uint inptr_ind=0;
				byte[] outptr=output_data[outrow];
				uint outptr_ind=0;
				while(outptr_ind<outend)
				{
					byte invalue=inptr[inptr_ind++];
					outptr[outptr_ind++]=invalue;
					outptr[outptr_ind++]=invalue;
				}

				Array.Copy(output_data[outrow], output_data[outrow+1], cinfo.output_width);
				input_data_offset++;
				outrow+=2;
			}
		}
Beispiel #44
0
 // This is a no-op version used for "uninteresting" components.
 // These components will not be referenced by color conversion.
 static void noop_upsample(jpeg_decompress cinfo, jpeg_component_info compptr, byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int output_data_offset)
 {
     output_data_ptr[output_data_offset] = null;           // safety check
 }
Beispiel #45
0
		// Fancy processing for the common case of 2:1 horizontal and 1:1 vertical.
		//
		// The upsampling algorithm is linear interpolation between pixel centers,
		// also known as a "triangle filter". This is a good compromise between
		// speed and visual quality. The centers of the output pixels are 1/4 and 3/4
		// of the way between input pixel centers.
		//
		// A note about the "bias" calculations: when rounding fractional values to
		// integer, we do not want to always round 0.5 up to the next integer.
		// If we did that, we'd introduce a noticeable bias towards larger values.
		// Instead, this code is arranged so that 0.5 will be rounded up or down at
		// alternate pixel locations (a simple ordered dither pattern).
#if! USE_UNSAFE_STUFF
		static void h2v1_fancy_upsample(jpeg_decompress cinfo, jpeg_component_info compptr, byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int output_data_offset)
		{
			byte[][] output_data=output_data_ptr[output_data_offset];

			for(int inrow=0; inrow<cinfo.max_v_samp_factor; inrow++)
			{
				byte[] inptr=input_data[input_data_offset++];
				uint inptr_ind=0;
				byte[] outptr=output_data[inrow];
				uint outptr_ind=0;

				// Special case for first column
				int invalue=inptr[inptr_ind++];
				outptr[outptr_ind++]=(byte)invalue;
				outptr[outptr_ind++]=(byte)((invalue*3+inptr[inptr_ind]+2)>>2);

				for(uint colctr=compptr.downsampled_width-2; colctr>0; colctr--)
				{
					// General case: 3/4 * nearer pixel + 1/4 * further pixel
					invalue=inptr[inptr_ind++]*3;
					outptr[outptr_ind++]=(byte)((invalue+inptr[inptr_ind-2]+1)>>2);
					outptr[outptr_ind++]=(byte)((invalue+inptr[inptr_ind]+2)>>2);
				}

				// Special case for last column
				invalue=inptr[inptr_ind];
				outptr[outptr_ind++]=(byte)((invalue*3+inptr[inptr_ind-1]+1)>>2);
				outptr[outptr_ind]=(byte)invalue;
			}
		}