Пример #1
0
        // An additional method that can be provided by data source modules is the
        // resync_to_restart method for error recovery in the presence of RST markers.
        // For the moment, this source module just uses the default resync method
        // provided by the JPEG library. That method assumes that no backtracking
        // is possible.

        // Terminate source --- called by jpeg_finish_decompress
        // after all data has been read. Often a no-op.
        //
        // NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
        // application must deal with any cleanup that should happen even
        // for error exit.
        static void term_source(jpeg_decompress cinfo, bool readExtraBytes, out byte[] data)
        {
            if (!readExtraBytes)
            {
                data = null;

                // no work necessary here
                return;
            }

            my_source_mgr src = (my_source_mgr)cinfo.src;

            MemoryStream mem = new MemoryStream();

            mem.Write(src.input_bytes, (int)src.next_input_byte, (int)src.bytes_in_buffer);
            src.next_input_byte += (int)src.bytes_in_buffer;
            src.bytes_in_buffer  = 0;

            int nbytes = 0;

            while ((nbytes = src.infile.Read(src.buffer, 0, INPUT_BUF_SIZE)) != 0)
            {
                mem.Write(src.buffer, 0, nbytes);
            }

            data = mem.ToArray();
        }
Пример #2
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++];
            }
        }
Пример #3
0
        // Prepare for input from a stdio stream.
        // The caller must have already opened the stream, and is responsible
        // for closing it after finishing decompression.
        public static void jpeg_stdio_src(jpeg_decompress cinfo, Stream infile)
        {
            my_source_mgr src = null;

            // The source object and input buffer are made permanent so that a series
            // of JPEG images can be read from the same file by calling jpeg_stdio_src
            // only before the first one. (If we discarded the buffer at the end of
            // one image, we'd likely lose the start of the next one.)
            // This makes it unsafe to use this manager and a different source
            // manager serially with the same JPEG object. Caveat programmer.
            if (cinfo.src == null)
            {             // first time for this JPEG object?
                try
                {
                    src        = new my_source_mgr();
                    src.buffer = new byte[INPUT_BUF_SIZE];
                }
                catch
                {
                    ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
                }
                cinfo.src = src;
            }

            src                   = (my_source_mgr)cinfo.src;
            src.init_source       = init_source;
            src.fill_input_buffer = fill_input_buffer;
            src.skip_input_data   = skip_input_data;
            src.resync_to_restart = jpeg_resync_to_restart;           // use default method
            src.term_source       = term_source;
            src.infile            = infile;
            src.bytes_in_buffer   = 0;          // forces fill_input_buffer on first read
            src.input_bytes       = null;
            src.next_input_byte   = 0;          // until buffer loaded
        }
Пример #4
0
        // Create the color index table.
        static void create_colorindex(jpeg_decompress cinfo)
        {
            my_cquantizer1 cquantize = (my_cquantizer1)cinfo.cquantize;

            cquantize.colorindex = alloc_sarray(cinfo, (uint)(MAXJSAMPLE + 1), (uint)cinfo.out_color_components);

            // blksize is number of adjacent repeated entries for a component
            int blksize = cquantize.sv_actual;

            for (int i = 0; i < cinfo.out_color_components; i++)
            {
                // fill in colorindex entries for i'th color component
                int nci = cquantize.Ncolors[i];               // # of distinct values for this color
                blksize = blksize / nci;

                // in loop, val = index of current output value,
                // and k = largest j that maps to current val
                byte[] indexptr = cquantize.colorindex[i];
                int    val      = 0;
                int    k        = largest_input_value(cinfo, i, 0, nci - 1);
                for (int j = 0; j <= MAXJSAMPLE; j++)
                {
                    while (j > k)
                    {
                        k = largest_input_value(cinfo, i, ++val, nci - 1);                        // advance val if past boundary
                    }
                    // premultiply so that no multiplication needed in main processing
                    indexptr[j] = (byte)(val * blksize);
                }
            }
        }
Пример #5
0
        // Create an ordered-dither array for a component having ncolors
        // distinct output values.
        static int[,] make_odither_array(jpeg_decompress cinfo, int ncolors)
        {
            int[,] odither = null;

            try
            {
                odither = new int[ODITHER_SIZE, ODITHER_SIZE];
            }
            catch
            {
                ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
            }

            // The inter-value distance for this color is MAXJSAMPLE/(ncolors-1).
            // Hence the dither value for the matrix cell with fill order f
            // (f=0..N-1) should be (N-1-2*f)/(2*N) * MAXJSAMPLE/(ncolors-1).
            // On 16-bit-int machine, be careful to avoid overflow.
            int den = 2 * ODITHER_CELLS * ((int)(ncolors - 1));

            for (int j = 0; j < ODITHER_SIZE; j++)
            {
                for (int k = 0; k < ODITHER_SIZE; k++)
                {
                    int num = ((int)(ODITHER_CELLS - 1 - 2 * ((int)base_dither_matrix[j, k]))) * MAXJSAMPLE;
                    // Ensure round towards zero despite C's lack of consistency
                    // about rounding negative values in integer division...
                    odither[j, k] = (int)(num < 0?-((-num) / den):num / den);
                }
            }
            return(odither);
        }
Пример #6
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;
            }
        }
Пример #7
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;
            }
        }
Пример #8
0
        // Initialize the input controller module.
        // This is called only once, when the decompression object is created.
        public static void jinit_input_controller(jpeg_decompress cinfo)
        {
            my_input_controller inputctl = null;

            // Create subobject in pool
            try
            {
                inputctl = new my_input_controller();
            }
            catch
            {
                ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
            }
            cinfo.inputctl = inputctl;

            // Initialize method pointers
            inputctl.consume_input          = consume_markers_d_input;
            inputctl.reset_input_controller = reset_input_controller_d_input;
            inputctl.start_input_pass       = start_input_pass_d_input;
            inputctl.finish_input_pass      = finish_input_pass_d_input;

            // Initialize state: can't use reset_input_controller since we don't
            // want to try to reset other modules yet.
            inputctl.has_multiple_scans = false;           // "unknown" would be better
            inputctl.eoi_reached        = false;
            inputctl.inheaders          = 1;
        }
Пример #9
0
        //#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x))

        // Check for a restart marker & resynchronize decoder.
        // Returns false if must suspend.
        static bool process_restart_dlhuff(jpeg_decompress cinfo)
        {
            jpeg_lossless_d_codec losslsd = (jpeg_lossless_d_codec)cinfo.coef;
            lhuff_entropy_decoder entropy = (lhuff_entropy_decoder)losslsd.entropy_private;

            // Throw away any unused bits remaining in bit buffer;
            // include any full bytes in next_marker's count of discarded bytes
            cinfo.marker.discarded_bytes += (uint)(entropy.bitstate.bits_left / 8);
            entropy.bitstate.bits_left    = 0;

            // Advance past the RSTn marker
            if (!cinfo.marker.read_restart_marker(cinfo))
            {
                return(false);
            }

            // Reset out-of-data flag, unless read_restart_marker left us smack up
            // against a marker. In that case we will end up treating the next data
            // segment as empty, and we can avoid producing bogus output pixels by
            // leaving the flag set.
            if (cinfo.unread_marker == 0)
            {
                entropy.insufficient_data = false;
            }

            return(true);
        }
Пример #10
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;
                    }
                }
            }
        }
Пример #11
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++;
                }
            }
        }
Пример #12
0
        // Initialize tables for YCC->RGB colorspace conversion.
        // This is taken directly from jdcolor.cs; see that file for more info.
        static void build_ycc_rgb_table_upsample(jpeg_decompress cinfo)
        {
            my_upsampler_merge upsample = (my_upsampler_merge)cinfo.upsample;

            try
            {
                upsample.Cr_r_tab = new int[MAXJSAMPLE + 1];
                upsample.Cb_b_tab = new int[MAXJSAMPLE + 1];
                upsample.Cr_g_tab = new int[MAXJSAMPLE + 1];
                upsample.Cb_g_tab = new int[MAXJSAMPLE + 1];
            }
            catch
            {
                ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
            }

            for (int i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++)
            {
                // i is the actual input pixel value, in the range 0..MAXJSAMPLE
                // The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE
                // Cr=>R value is nearest int to 1.40200 * x
                upsample.Cr_r_tab[i] = (int)((FIX_140200 * x + ONE_HALF) >> SCALEBITS);
                // Cb=>B value is nearest int to 1.77200 * x
                upsample.Cb_b_tab[i] = (int)((FIX_177200 * x + ONE_HALF) >> SCALEBITS);
                // Cr=>G value is scaled-up -0.71414 * x
                upsample.Cr_g_tab[i] = (-FIX_071414) * x;
                // Cb=>G value is scaled-up -0.34414 * x
                // We also add in ONE_HALF so that need not do it in inner loop
                upsample.Cb_g_tab[i] = (-FIX_034414) * x + ONE_HALF;
            }
        }
Пример #13
0
        // Reset within-iMCU-row counters for a new row (input side)
        static void start_iMCU_row_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;

            // In an interleaved scan, an MCU row is the same as an iMCU row.
            // In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
            // But at the bottom of the image, process only what's left.
            if (cinfo.comps_in_scan > 1)
            {
                diff.MCU_rows_per_iMCU_row = 1;
            }
            else
            {
                if (cinfo.input_iMCU_row < (cinfo.total_iMCU_rows - 1))
                {
                    diff.MCU_rows_per_iMCU_row = (uint)cinfo.cur_comp_info[0].v_samp_factor;
                }
                else
                {
                    diff.MCU_rows_per_iMCU_row = (uint)cinfo.cur_comp_info[0].last_row_height;
                }
            }

            diff.MCU_ctr         = 0;
            diff.MCU_vert_offset = 0;
        }
Пример #14
0
		// Initialize tables for YCC->RGB colorspace conversion.
		// This is taken directly from jdcolor.cs; see that file for more info.
		static void build_ycc_rgb_table_upsample(jpeg_decompress cinfo)
		{
			my_upsampler_merge upsample=(my_upsampler_merge)cinfo.upsample;

			try
			{
				upsample.Cr_r_tab=new int[MAXJSAMPLE+1];
				upsample.Cb_b_tab=new int[MAXJSAMPLE+1];
				upsample.Cr_g_tab=new int[MAXJSAMPLE+1];
				upsample.Cb_g_tab=new int[MAXJSAMPLE+1];
			}
			catch
			{
				ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
			}

			for(int i=0, x=-CENTERJSAMPLE; i<=MAXJSAMPLE; i++, x++)
			{
				// i is the actual input pixel value, in the range 0..MAXJSAMPLE
				// The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE
				// Cr=>R value is nearest int to 1.40200 * x
				upsample.Cr_r_tab[i]=(int)((FIX_140200*x+ONE_HALF)>>SCALEBITS);
				// Cb=>B value is nearest int to 1.77200 * x
				upsample.Cb_b_tab[i]=(int)((FIX_177200*x+ONE_HALF)>>SCALEBITS);
				// Cr=>G value is scaled-up -0.71414 * x
				upsample.Cr_g_tab[i]=(-FIX_071414)*x;
				// Cb=>G value is scaled-up -0.34414 * x
				// We also add in ONE_HALF so that need not do it in inner loop
				upsample.Cb_g_tab[i]=(-FIX_034414)*x+ONE_HALF;
			}
		}
Пример #15
0
        // Fill the input buffer --- called whenever buffer is emptied.
        //
        // In typical applications, this should read fresh data into the buffer
        // (ignoring the current state of next_input_byte & bytes_in_buffer),
        // reset the pointer & count to the start of the buffer, and return true
        // indicating that the buffer has been reloaded. It is not necessary to
        // fill the buffer entirely, only to obtain at least one more byte.
        //
        // There is no such thing as an EOF return. If the end of the file has been
        // reached, the routine has a choice of ERREXIT() or inserting fake data into
        // the buffer. In most cases, generating a warning message and inserting a
        // fake EOI marker is the best course of action --- this will allow the
        // decompressor to output however much of the image is there. However,
        // the resulting error message is misleading if the real problem is an empty
        // input file, so we handle that case specially.
        //
        // In applications that need to be able to suspend compression due to input
        // not being available yet, a false return indicates that no more data can be
        // obtained right now, but more may be forthcoming later. In this situation,
        // the decompressor will return to its caller (with an indication of the
        // number of scanlines it has read, if any). The application should resume
        // decompression after it has loaded more data into the input buffer. Note
        // that there are substantial restrictions on the use of suspension --- see
        // the documentation.
        //
        // When suspending, the decompressor will back up to a convenient restart point
        // (typically the start of the current MCU). next_input_byte & bytes_in_buffer
        // indicate where the restart point will be if the current call returns false.
        // Data beyond this point must be rescanned after resumption, so move it to
        // the front of the buffer rather than discarding it.
        static bool fill_input_buffer(jpeg_decompress cinfo)
        {
            my_source_mgr src    = (my_source_mgr)cinfo.src;
            uint          nbytes = (uint)src.infile.Read(src.buffer, 0, INPUT_BUF_SIZE);

            if (nbytes <= 0)
            {
                if (src.start_of_file)
                {
                    ERREXIT(cinfo, J_MESSAGE_CODE.JERR_INPUT_EMPTY);                                    // Treat empty input file as fatal error
                }
                WARNMS(cinfo, J_MESSAGE_CODE.JWRN_JPEG_EOF);
                // Insert a fake EOI marker
                src.buffer[0] = (byte)0xFF;
                src.buffer[1] = (byte)JPEG_EOI;
                nbytes        = 2;
            }

            src.input_bytes     = src.buffer;
            src.next_input_byte = 0;
            src.bytes_in_buffer = nbytes;
            src.start_of_file   = false;

            return(true);
        }
Пример #16
0
 // Return j'th output value, where j will range from 0 to maxj
 // The output values must fall in 0..MAXJSAMPLE in increasing order
 static int output_value(jpeg_decompress cinfo, int ci, int j, int maxj)
 {
     // We always provide values 0 and MAXJSAMPLE for each component;
     // any additional values are equally spaced between these limits.
     // (Forcing the upper and lower values to the limits ensures that
     // dithering can't produce a color outside the selected gamut.)
     return((int)(((int)j * MAXJSAMPLE + maxj / 2) / maxj));
 }
Пример #17
0
        // Control routine to do upsampling (and color conversion).
        //
        // The control routine just handles the row buffering considerations.

        // 2:1 vertical sampling case: may need a spare row.
        static void merged_2v_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_merge upsample = (my_upsampler_merge)cinfo.upsample;

            byte[][] work_ptrs = new byte[2][];
            uint     num_rows;         // number of rows returned to caller

            if (upsample.spare_full)
            {
                // If we have a spare row saved from a previous cycle, just return it.
                Array.Copy(upsample.spare_row, output_buf[output_buf_offset + out_row_ctr], upsample.out_row_width);

                num_rows            = 1;
                upsample.spare_full = false;
            }
            else
            {
                // Figure number of rows to return to caller.
                num_rows = 2;

                // Not more than the distance to the end of the image.
                if (num_rows > 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;
                }

                // Create output pointer array for upsampler.
                work_ptrs[0] = output_buf[output_buf_offset + out_row_ctr];
                if (num_rows > 1)
                {
                    work_ptrs[1] = output_buf[output_buf_offset + out_row_ctr + 1];
                }
                else
                {
                    work_ptrs[1]        = upsample.spare_row;
                    upsample.spare_full = true;
                }

                // Now do the upsampling.
                upsample.upmethod(cinfo, input_buf, in_row_group_ctr, work_ptrs, 0);
            }

            // Adjust counts
            out_row_ctr         += num_rows;
            upsample.rows_to_go -= num_rows;
            // When the buffer is emptied, declare this input row group consumed
            if (!upsample.spare_full)
            {
                in_row_group_ctr++;
            }
        }
Пример #18
0
		const int INPUT_BUF_SIZE=4096; // choose an efficiently Read'able size

		// Initialize source --- called by jpeg_read_header
		// before any data is actually read.
		static void init_source(jpeg_decompress cinfo)
		{
			my_source_mgr src=(my_source_mgr)cinfo.src;

			// We reset the empty-input-file flag for each image,
			// but we don't clear the input buffer.
			// This is correct behavior for reading a series of images from one source.
			src.start_of_file=true;
		}
Пример #19
0
        // Initialize for an upsampling pass.
        static void start_pass_upsample(jpeg_decompress cinfo)
        {
            my_upsampler upsample = (my_upsampler)cinfo.upsample;

            // Mark the conversion buffer empty
            upsample.next_row_out = cinfo.max_v_samp_factor;
            // Initialize total-height counter for detecting bottom of image
            upsample.rows_to_go = cinfo.output_height;
        }
Пример #20
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++;
            }
        }
Пример #21
0
        const int INPUT_BUF_SIZE = 4096;       // choose an efficiently Read'able size

        // Initialize source --- called by jpeg_read_header
        // before any data is actually read.
        static void init_source(jpeg_decompress cinfo)
        {
            my_source_mgr src = (my_source_mgr)cinfo.src;

            // We reset the empty-input-file flag for each image,
            // but we don't clear the input buffer.
            // This is correct behavior for reading a series of images from one source.
            src.start_of_file = true;
        }
Пример #22
0
		// Initialize for an upsampling pass.
		static void start_pass_upsample(jpeg_decompress cinfo)
		{
			my_upsampler upsample=(my_upsampler)cinfo.upsample;

			// Mark the conversion buffer empty
			upsample.next_row_out=cinfo.max_v_samp_factor;
			// Initialize total-height counter for detecting bottom of image
			upsample.rows_to_go=cinfo.output_height;
		}
Пример #23
0
        // Initialize for an upsampling pass.
        static void start_pass_merged_upsample(jpeg_decompress cinfo)
        {
            my_upsampler_merge upsample = (my_upsampler_merge)cinfo.upsample;

            // Mark the spare buffer empty
            upsample.spare_full = false;

            // Initialize total-height counter for detecting bottom of image
            upsample.rows_to_go = cinfo.output_height;
        }
Пример #24
0
        // 1:1 vertical sampling case: much easier, never need a spare row.
        static void merged_1v_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_merge upsample = (my_upsampler_merge)cinfo.upsample;

            // Just do the upsampling.
            upsample.upmethod(cinfo, input_buf, in_row_group_ctr, output_buf, (int)(output_buf_offset + out_row_ctr));

            // Adjust counts
            out_row_ctr++;
            in_row_group_ctr++;
        }
Пример #25
0
        // These are the routines invoked by the control routines to do
        // the actual upsampling/conversion. One row group is processed per call.
        //
        // Note: since we may be writing directly into application-supplied buffers,
        // we have to be honest about the output width; we can't assume the buffer
        // has been rounded up to an even width.

        // Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical.
        static void h2v1_merged_upsample(jpeg_decompress cinfo, byte[][][] input_buf, uint in_row_group_ctr, byte[][] output_buf, int output_buf_offset)
        {
            my_upsampler_merge upsample = (my_upsampler_merge)cinfo.upsample;

            // copy these pointers into registers if possible
            int[] Crrtab = upsample.Cr_r_tab;
            int[] Cbbtab = upsample.Cb_b_tab;
            int[] Crgtab = upsample.Cr_g_tab;
            int[] Cbgtab = upsample.Cb_g_tab;

            byte[] inptr0 = input_buf[0][in_row_group_ctr];
            byte[] inptr1 = input_buf[1][in_row_group_ctr];
            byte[] inptr2 = input_buf[2][in_row_group_ctr];
            byte[] outptr = output_buf[output_buf_offset];
            int    inptr0_ind = 0, inptrX_ind = 0, outptr_ind = 0;

            // Loop for each pair of output pixels
            for (uint col = cinfo.output_width >> 1; col > 0; col--)
            {
                // Do the chroma part of the calculation
                int cb = inptr1[inptrX_ind];
                int cr = inptr2[inptrX_ind];
                inptrX_ind++;
                int cred   = Crrtab[cr];
                int cgreen = (int)((Cbgtab[cb] + Crgtab[cr]) >> SCALEBITS);
                int cblue  = Cbbtab[cb];

                // Fetch 2 Y values and emit 2 pixels
                int y   = inptr0[inptr0_ind++];
                int tmp = y + cred; outptr[outptr_ind + RGB_RED] = (byte)(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp));
                tmp         = y + cgreen; outptr[outptr_ind + RGB_GREEN] = (byte)(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp));
                tmp         = y + cblue; outptr[outptr_ind + RGB_BLUE] = (byte)(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp));
                outptr_ind += RGB_PIXELSIZE;
                y           = inptr0[inptr0_ind++];
                tmp         = y + cred; outptr[outptr_ind + RGB_RED] = (byte)(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp));
                tmp         = y + cgreen; outptr[outptr_ind + RGB_GREEN] = (byte)(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp));
                tmp         = y + cblue; outptr[outptr_ind + RGB_BLUE] = (byte)(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp));
                outptr_ind  = RGB_PIXELSIZE;
            }

            // If image width is odd, do the last output column separately
            if ((cinfo.output_width & 1) != 0)
            {
                int cb     = inptr1[inptrX_ind];
                int cr     = inptr2[inptrX_ind];
                int cred   = Crrtab[cr];
                int cgreen = (int)((Cbgtab[cb] + Crgtab[cr]) >> SCALEBITS);
                int cblue  = Cbbtab[cb];
                int y      = inptr0[inptr0_ind];
                int tmp    = y + cred; outptr[outptr_ind + RGB_RED] = (byte)(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp));
                tmp = y + cgreen; outptr[outptr_ind + RGB_GREEN] = (byte)(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp));
                tmp = y + cblue; outptr[outptr_ind + RGB_BLUE] = (byte)(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp));
            }
        }
Пример #26
0
        // Create the colormap.
        static void create_colormap(jpeg_decompress cinfo)
        {
            my_cquantizer1 cquantize = (my_cquantizer1)cinfo.cquantize;

            // Select number of colors for each component
            int total_colors = select_ncolors(cinfo, cquantize.Ncolors);           // Number of distinct output colors

            // Report selected color counts
            if (cinfo.out_color_components == 3)
            {
                TRACEMS4(cinfo, 1, J_MESSAGE_CODE.JTRC_QUANT_3_NCOLORS, total_colors, cquantize.Ncolors[0], cquantize.Ncolors[1], cquantize.Ncolors[2]);
            }
            else
            {
                TRACEMS1(cinfo, 1, J_MESSAGE_CODE.JTRC_QUANT_NCOLORS, total_colors);
            }

            // Allocate and fill in the colormap.
            // The colors are ordered in the map in standard row-major order,
            // i.e. rightmost (highest-indexed) color changes most rapidly.
            byte[][] colormap = alloc_sarray(cinfo, (uint)total_colors, (uint)cinfo.out_color_components);

            // blksize is number of adjacent repeated entries for a component
            // blkdist is distance between groups of identical entries for a component
            int blkdist = total_colors;

            for (int i = 0; i < cinfo.out_color_components; i++)
            {
                // fill in colormap entries for i'th color component
                int nci     = cquantize.Ncolors[i];           // # of distinct values for this color
                int blksize = blkdist / nci;
                for (int j = 0; j < nci; j++)
                {
                    // Compute j'th output value (out of nci) for component
                    int val = output_value(cinfo, i, j, nci - 1);
                    // Fill in all colormap entries that have this value of this component
                    for (int ptr = j * blksize; ptr < total_colors; ptr += blkdist)
                    {
                        // fill in blksize entries beginning at ptr
                        for (int k = 0; k < blksize; k++)
                        {
                            colormap[i][ptr + k] = (byte)val;
                        }
                    }
                }
                blkdist = blksize;               // blksize of this color is blkdist of next
            }

            // Save the colormap in private storage,
            // where it will survive color quantization mode changes.
            cquantize.sv_colormap = colormap;
            cquantize.sv_actual   = total_colors;
        }
Пример #27
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;
        }
Пример #28
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++;
            }
        }
Пример #29
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);
        }
Пример #30
0
		// Check for a restart marker & resynchronize decoder, undifferencer.
		// Returns false if must suspend.
		static bool process_restart_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;

			if(!losslsd.entropy_process_restart(cinfo)) return false;

			losslsd.predict_process_restart(cinfo);

			// Reset restart counter
			diff.restart_rows_to_go=cinfo.restart_interval/cinfo.MCUs_per_row;

			return true;
		}
Пример #31
0
		// Initialize for an input processing pass.
		static void start_input_pass_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;

			// Check that the restart interval is an integer multiple of the number 
			// of MCU in an MCU-row.
			if(cinfo.restart_interval%cinfo.MCUs_per_row!=0) ERREXIT2(cinfo, J_MESSAGE_CODE.JERR_BAD_RESTART, (int)cinfo.restart_interval, (int)cinfo.MCUs_per_row);

			// Initialize restart counter
			diff.restart_rows_to_go=cinfo.restart_interval/cinfo.MCUs_per_row;

			cinfo.input_iMCU_row=0;
			start_iMCU_row_d_diff(cinfo);
		}
Пример #32
0
        // Reset state to begin a fresh datastream.
        static void reset_input_controller_d_input(jpeg_decompress cinfo)
        {
            my_input_controller inputctl = (my_input_controller)cinfo.inputctl;

            inputctl.consume_input      = consume_markers_d_input;
            inputctl.has_multiple_scans = false;           // "unknown" would be better
            inputctl.eoi_reached        = false;
            inputctl.inheaders          = 1;

            // Reset other modules
            cinfo.err.reset_error_mgr(cinfo);
            cinfo.marker.reset_marker_reader(cinfo);

            // Reset progression state -- would be cleaner if entropy decoder did this
            cinfo.coef_bits = null;
        }
Пример #33
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
            }
        }
Пример #34
0
        // General case, with ordered dithering
        static void quantize_ord_dither(jpeg_decompress cinfo, byte[][] input_buf, uint input_row, byte[][] output_buf, uint output_row, int num_rows)
        {
            my_cquantizer1 cquantize = (my_cquantizer1)cinfo.cquantize;
            int            row_index;   // current indexes into dither matrix
            int            nc    = cinfo.out_color_components;
            uint           width = cinfo.output_width;

            for (int row = 0; row < num_rows; row++)
            {
                // Initialize output values to 0 so can process components separately
                for (int i = 0; i < width; i++)
                {
                    output_buf[output_row + row][i] = 0;
                }
                row_index = cquantize.row_index;

                for (int ci = 0; ci < nc; ci++)
                {
                    byte[] input_ptr     = input_buf[input_row + row];
                    int    iind          = ci;
                    byte[] output_ptr    = output_buf[output_row + row];
                    uint   oind          = 0;
                    byte[] colorindex_ci = cquantize.colorindex[ci];
                    int[,] dither = cquantize.odither[ci];                   // points to active row of dither matrix
                    int col_index = 0;

                    for (uint col = width; col > 0; col--)
                    {
                        // Form pixel value + dither, range-limit to 0..MAXJSAMPLE,
                        // select output value, accumulate into output code for this pixel.
                        // Range-limiting need not be done explicitly, as we have extended
                        // the colorindex table to produce the right answers for out-of-range
                        // inputs. The maximum dither is +- MAXJSAMPLE; this sets the
                        // required amount of padding.
                        int tmp = input_ptr[iind] + dither[row_index, col_index];
                        output_ptr[oind] += colorindex_ci[(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp))];
                        iind             += nc;
                        oind++;
                        col_index = (col_index + 1) & ODITHER_MASK;
                    }
                }

                // Advance row index for next row
                row_index           = (row_index + 1) & ODITHER_MASK;
                cquantize.row_index = row_index;
            }
        }
Пример #35
0
        // Check for a restart marker & resynchronize decoder, undifferencer.
        // Returns false if must suspend.
        static bool process_restart_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;

            if (!losslsd.entropy_process_restart(cinfo))
            {
                return(false);
            }

            losslsd.predict_process_restart(cinfo);

            // Reset restart counter
            diff.restart_rows_to_go = cinfo.restart_interval / cinfo.MCUs_per_row;

            return(true);
        }
Пример #36
0
		// Reset within-iMCU-row counters for a new row (input side)
		static void start_iMCU_row_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;

			// In an interleaved scan, an MCU row is the same as an iMCU row.
			// In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
			// But at the bottom of the image, process only what's left.
			if(cinfo.comps_in_scan>1) diff.MCU_rows_per_iMCU_row=1;
			else
			{
				if(cinfo.input_iMCU_row<(cinfo.total_iMCU_rows-1)) diff.MCU_rows_per_iMCU_row=(uint)cinfo.cur_comp_info[0].v_samp_factor;
				else diff.MCU_rows_per_iMCU_row=(uint)cinfo.cur_comp_info[0].last_row_height;
			}

			diff.MCU_ctr=0;
			diff.MCU_vert_offset=0;
		}
Пример #37
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++;
		}
Пример #38
0
		// Fill the input buffer --- called whenever buffer is emptied.
		//
		// In typical applications, this should read fresh data into the buffer
		// (ignoring the current state of next_input_byte & bytes_in_buffer),
		// reset the pointer & count to the start of the buffer, and return true
		// indicating that the buffer has been reloaded. It is not necessary to
		// fill the buffer entirely, only to obtain at least one more byte.
		//
		// There is no such thing as an EOF return. If the end of the file has been
		// reached, the routine has a choice of ERREXIT() or inserting fake data into
		// the buffer. In most cases, generating a warning message and inserting a
		// fake EOI marker is the best course of action --- this will allow the
		// decompressor to output however much of the image is there. However,
		// the resulting error message is misleading if the real problem is an empty
		// input file, so we handle that case specially.
		//
		// In applications that need to be able to suspend compression due to input
		// not being available yet, a false return indicates that no more data can be
		// obtained right now, but more may be forthcoming later. In this situation,
		// the decompressor will return to its caller (with an indication of the
		// number of scanlines it has read, if any). The application should resume
		// decompression after it has loaded more data into the input buffer. Note
		// that there are substantial restrictions on the use of suspension --- see
		// the documentation.
		//
		// When suspending, the decompressor will back up to a convenient restart point
		// (typically the start of the current MCU). next_input_byte & bytes_in_buffer
		// indicate where the restart point will be if the current call returns false.
		// Data beyond this point must be rescanned after resumption, so move it to
		// the front of the buffer rather than discarding it.
		static bool fill_input_buffer(jpeg_decompress cinfo)
		{
			my_source_mgr src=(my_source_mgr)cinfo.src;
			uint nbytes=(uint)src.infile.Read(src.buffer, 0, INPUT_BUF_SIZE);

			if(nbytes<=0)
			{
				if(src.start_of_file) ERREXIT(cinfo, J_MESSAGE_CODE.JERR_INPUT_EMPTY);	// Treat empty input file as fatal error
				WARNMS(cinfo, J_MESSAGE_CODE.JWRN_JPEG_EOF);
				// Insert a fake EOI marker
				src.buffer[0]=(byte)0xFF;
				src.buffer[1]=(byte)JPEG_EOI;
				nbytes=2;
			}

			src.input_bytes=src.buffer;
			src.next_input_byte=0;
			src.bytes_in_buffer=nbytes;
			src.start_of_file=false;

			return true;
		}
Пример #39
0
		// Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical.
		static void h2v2_merged_upsample(jpeg_decompress cinfo, byte[][][] input_buf, uint in_row_group_ctr, byte[][] output_buf, int output_buf_offset)
		{
			my_upsampler_merge upsample=(my_upsampler_merge)cinfo.upsample;

			// copy these pointers into registers if possible
			int[] Crrtab=upsample.Cr_r_tab;
			int[] Cbbtab=upsample.Cb_b_tab;
			int[] Crgtab=upsample.Cr_g_tab;
			int[] Cbgtab=upsample.Cb_g_tab;

			byte[] inptr00=input_buf[0][in_row_group_ctr*2];
			byte[] inptr01=input_buf[0][in_row_group_ctr*2+1];
			byte[] inptr1=input_buf[1][in_row_group_ctr];
			byte[] inptr2=input_buf[2][in_row_group_ctr];
			byte[] outptr0=output_buf[output_buf_offset];
			byte[] outptr1=output_buf[output_buf_offset+1];

			int inptr0_ind=0, inptrX_ind=0, outptr_ind=0;

			// Loop for each group of output pixels
			for(uint col=cinfo.output_width>>1; col>0; col--)
			{
				// Do the chroma part of the calculation
				int cb=inptr1[inptrX_ind];
				int cr=inptr2[inptrX_ind];
				inptrX_ind++;
				int cred=Crrtab[cr];
				int cgreen=(int)((Cbgtab[cb]+Crgtab[cr])>>SCALEBITS);
				int cblue=Cbbtab[cb];

				// Fetch 4 Y values and emit 4 pixels
				int y=inptr00[inptr0_ind];
				int tmp=y+cred; outptr0[outptr_ind+RGB_RED]=(byte)(tmp>=MAXJSAMPLE?MAXJSAMPLE:(tmp<0?0:tmp));
				tmp=y+cgreen; outptr0[outptr_ind+RGB_GREEN]=(byte)(tmp>=MAXJSAMPLE?MAXJSAMPLE:(tmp<0?0:tmp));
				tmp=y+cblue; outptr0[outptr_ind+RGB_BLUE]=(byte)(tmp>=MAXJSAMPLE?MAXJSAMPLE:(tmp<0?0:tmp));

				y=inptr01[inptr0_ind];
				tmp=y+cred; outptr1[outptr_ind+RGB_RED]=(byte)(tmp>=MAXJSAMPLE?MAXJSAMPLE:(tmp<0?0:tmp));
				tmp=y+cgreen; outptr1[outptr_ind+RGB_GREEN]=(byte)(tmp>=MAXJSAMPLE?MAXJSAMPLE:(tmp<0?0:tmp));
				tmp=y+cblue; outptr1[outptr_ind+RGB_BLUE]=(byte)(tmp>=MAXJSAMPLE?MAXJSAMPLE:(tmp<0?0:tmp));
				inptr0_ind++;
				outptr_ind+=RGB_PIXELSIZE;

				y=inptr00[inptr0_ind];
				tmp=y+cred; outptr0[outptr_ind+RGB_RED]=(byte)(tmp>=MAXJSAMPLE?MAXJSAMPLE:(tmp<0?0:tmp));
				tmp=y+cgreen; outptr0[outptr_ind+RGB_GREEN]=(byte)(tmp>=MAXJSAMPLE?MAXJSAMPLE:(tmp<0?0:tmp));
				tmp=y+cblue; outptr0[outptr_ind+RGB_BLUE]=(byte)(tmp>=MAXJSAMPLE?MAXJSAMPLE:(tmp<0?0:tmp));

				y=inptr01[inptr0_ind];
				tmp=y+cred; outptr1[outptr_ind+RGB_RED]=(byte)(tmp>=MAXJSAMPLE?MAXJSAMPLE:(tmp<0?0:tmp));
				tmp=y+cgreen; outptr1[outptr_ind+RGB_GREEN]=(byte)(tmp>=MAXJSAMPLE?MAXJSAMPLE:(tmp<0?0:tmp));
				tmp=y+cblue; outptr1[outptr_ind+RGB_BLUE]=(byte)(tmp>=MAXJSAMPLE?MAXJSAMPLE:(tmp<0?0:tmp));
				inptr0_ind++;
				outptr_ind+=RGB_PIXELSIZE;
			}

			// If image width is odd, do the last output column separately
			if((cinfo.output_width&1)!=0)
			{
				int cb=inptr1[inptrX_ind];
				int cr=inptr2[inptrX_ind];
				int cred=Crrtab[cr];
				int cgreen=(int)((Cbgtab[cb]+Crgtab[cr])>>SCALEBITS);
				int cblue=Cbbtab[cb];

				int y=inptr00[inptr0_ind];
				int tmp=y+cred; outptr0[outptr_ind+RGB_RED]=(byte)(tmp>=MAXJSAMPLE?MAXJSAMPLE:(tmp<0?0:tmp));
				tmp=y+cgreen; outptr0[outptr_ind+RGB_GREEN]=(byte)(tmp>=MAXJSAMPLE?MAXJSAMPLE:(tmp<0?0:tmp));
				tmp=y+cblue; outptr0[outptr_ind+RGB_BLUE]=(byte)(tmp>=MAXJSAMPLE?MAXJSAMPLE:(tmp<0?0:tmp));

				y=inptr01[inptr0_ind];
				tmp=y+cred; outptr1[outptr_ind+RGB_RED]=(byte)(tmp>=MAXJSAMPLE?MAXJSAMPLE:(tmp<0?0:tmp));
				tmp=y+cgreen; outptr1[outptr_ind+RGB_GREEN]=(byte)(tmp>=MAXJSAMPLE?MAXJSAMPLE:(tmp<0?0:tmp));
				tmp=y+cblue; outptr1[outptr_ind+RGB_BLUE]=(byte)(tmp>=MAXJSAMPLE?MAXJSAMPLE:(tmp<0?0:tmp));
			}
		}
Пример #40
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++];
		}
Пример #41
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;
			}
		}
Пример #42
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;
		}
Пример #43
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;
		}
Пример #44
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);
				}
			}
		}
Пример #45
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;
			}
		}
Пример #46
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++;
				}
			}
		}
Пример #47
0
		// Dummy consume-input routine for single-pass operation.
		static CONSUME_INPUT dummy_consume_data_d_diff(jpeg_decompress cinfo)
		{
			return CONSUME_INPUT.JPEG_SUSPENDED;	// Always indicate nothing was done
		}
Пример #48
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;
				}
			}
		}
Пример #49
0
		// Module initialization routine for merged upsampling/color conversion.
		//
		// NB: this is called under the conditions determined by use_merged_upsample()
		// in jdmaster.cs. That routine MUST correspond to the actual capabilities
		// of this module; no safety checks are made here.
		public static void jinit_merged_upsampler(jpeg_decompress cinfo)
		{
			my_upsampler_merge upsample=null;

			try
			{
				upsample=new my_upsampler_merge();
			}
			catch
			{
				ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
			}
			cinfo.upsample=upsample;
			upsample.start_pass=start_pass_merged_upsample;
#if UPSCALING_CONTEXT
			upsample.need_context_rows=false;
#endif

			upsample.out_row_width=(uint)(cinfo.output_width*cinfo.out_color_components);

			if(cinfo.max_v_samp_factor==2)
			{
				upsample.upsample=merged_2v_upsample;
				upsample.upmethod=h2v2_merged_upsample;

				// Allocate a spare row buffer
				try
				{
					upsample.spare_row=new byte[upsample.out_row_width];
				}
				catch
				{
					ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
				}
			}
			else
			{
				upsample.upsample=merged_1v_upsample;
				upsample.upmethod=h2v1_merged_upsample;

				// No spare row needed
				upsample.spare_row=null;
			}

			build_ycc_rgb_table_upsample(cinfo);
		}
Пример #50
0
		// Skip data --- used to skip over a potentially large amount of
		// uninteresting data (such as an APPn marker).
		//
		// Writers of suspendable-input applications must note that skip_input_data
		// is not granted the right to give a suspension return. If the skip extends
		// beyond the data currently in the buffer, the buffer can be marked empty so
		// that the next read will cause a fill_input_buffer call that can suspend.
		// Arranging for additional bytes to be discarded before reloading the input
		// buffer is the application writer's problem.
		static void skip_input_data(jpeg_decompress cinfo, int num_bytes)
		{
			my_source_mgr src=(my_source_mgr)cinfo.src;

			// Just a dumb implementation for now. Could use Seek() except
			// it doesn't work on pipes. Not clear that being smart is worth
			// any trouble anyway --- large skips are infrequent.
			if(num_bytes>0)
			{
				while(num_bytes>(int)src.bytes_in_buffer)
				{
					num_bytes-=(int)src.bytes_in_buffer;
					fill_input_buffer(cinfo);
					// note we assume that fill_input_buffer will never return false,
					// so suspension need not be handled.
				}
				src.next_input_byte+=num_bytes;
				src.bytes_in_buffer-=(uint)num_bytes;
			}
		}
Пример #51
0
		// Initialize for an output processing pass.
		static void start_output_pass_d_diff(jpeg_decompress cinfo)
		{
			cinfo.output_iMCU_row=0;
		}
Пример #52
0
		// An additional method that can be provided by data source modules is the
		// resync_to_restart method for error recovery in the presence of RST markers.
		// For the moment, this source module just uses the default resync method
		// provided by the JPEG library. That method assumes that no backtracking
		// is possible.

		// Terminate source --- called by jpeg_finish_decompress
		// after all data has been read. Often a no-op.
		//
		// NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
		// application must deal with any cleanup that should happen even
		// for error exit.
		static void term_source(jpeg_decompress cinfo, bool readExtraBytes, out byte[] data)
		{
			if(!readExtraBytes)
			{
				data=null;

				// no work necessary here
				return;
			}

			my_source_mgr src=(my_source_mgr)cinfo.src;

			MemoryStream mem=new MemoryStream();
			mem.Write(src.input_bytes, (int)src.next_input_byte, (int)src.bytes_in_buffer);
			src.next_input_byte+=(int)src.bytes_in_buffer;
			src.bytes_in_buffer=0;

			int nbytes=0;
			while((nbytes=src.infile.Read(src.buffer, 0, INPUT_BUF_SIZE))!=0) mem.Write(src.buffer, 0, nbytes);

			data=mem.ToArray();
		}
Пример #53
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
			}
		}
Пример #54
0
		// Prepare for input from a stdio stream.
		// The caller must have already opened the stream, and is responsible
		// for closing it after finishing decompression.
		public static void jpeg_stdio_src(jpeg_decompress cinfo, Stream infile)
		{
			my_source_mgr src=null;

			// The source object and input buffer are made permanent so that a series
			// of JPEG images can be read from the same file by calling jpeg_stdio_src
			// only before the first one. (If we discarded the buffer at the end of
			// one image, we'd likely lose the start of the next one.)
			// This makes it unsafe to use this manager and a different source
			// manager serially with the same JPEG object. Caveat programmer.
			if(cinfo.src==null)
			{ // first time for this JPEG object?
				try
				{
					src=new my_source_mgr();
					src.buffer=new byte[INPUT_BUF_SIZE];
				}
				catch
				{
					ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
				}
				cinfo.src=src;
			}

			src=(my_source_mgr)cinfo.src;
			src.init_source=init_source;
			src.fill_input_buffer=fill_input_buffer;
			src.skip_input_data=skip_input_data;
			src.resync_to_restart=jpeg_resync_to_restart; // use default method
			src.term_source=term_source;
			src.infile=infile;
			src.bytes_in_buffer=0;	// forces fill_input_buffer on first read
			src.input_bytes=null;
			src.next_input_byte=0;	// until buffer loaded
		}
Пример #55
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);
		}
Пример #56
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
		}
Пример #57
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;
					}
				}
			}
		}
Пример #58
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;
			}
		}
Пример #59
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++;
			}
		}
Пример #60
0
		// Initialize for an upsampling pass.
		static void start_pass_merged_upsample(jpeg_decompress cinfo)
		{
			my_upsampler_merge upsample=(my_upsampler_merge)cinfo.upsample;

			// Mark the spare buffer empty
			upsample.spare_full=false;

			// Initialize total-height counter for detecting bottom of image
			upsample.rows_to_go=cinfo.output_height;
		}