Beispiel #1
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);
                }
            }
        }
Beispiel #2
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;
        }
Beispiel #3
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;
            }
        }
Beispiel #4
0
        // Allocate workspace for Floyd-Steinberg errors.
        static void alloc_fs_workspace(jpeg_decompress cinfo)
        {
            my_cquantizer1 cquantize = (my_cquantizer1)cinfo.cquantize;

            try
            {
                uint arraysize = cinfo.output_width + 2;
                for (int i = 0; i < cinfo.out_color_components; i++)
                {
                    cquantize.fserrors[i] = new int[arraysize];
                }
            }
            catch
            {
                ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
            }
        }
Beispiel #5
0
        // Module initialization routine for 1-pass color quantization.
        public static void jinit_1pass_quantizer(jpeg_decompress cinfo)
        {
            my_cquantizer1 cquantize = null;

            try
            {
                cquantize = new my_cquantizer1();
            }
            catch
            {
                ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
            }
            cinfo.cquantize         = cquantize;
            cquantize.start_pass    = start_pass_1_quant;
            cquantize.finish_pass   = finish_pass_1_quant;
            cquantize.new_color_map = new_color_map_1_quant;
            cquantize.fserrors[0]   = null;         // Flag FS workspace not allocated
            cquantize.odither[0]    = null;         // Also flag odither arrays not allocated

            // Make sure my internal arrays won't overflow
            if (cinfo.out_color_components > MAX_Q_COMPS)
            {
                ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_QUANT_COMPONENTS, MAX_Q_COMPS);
            }

            // Make sure colormap indexes can be represented by bytes
            if (cinfo.desired_number_of_colors > (MAXJSAMPLE + 1))
            {
                ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_QUANT_MANY_COLORS, MAXJSAMPLE + 1);
            }

            // Create the colormap and color index table.
            create_colormap(cinfo);
            create_colorindex(cinfo);

            // Allocate Floyd-Steinberg workspace now if requested.
            // We do this now since it is storage and may effect the memory
            // manager's space calculations. If the user changes to FS dither
            // mode in a later pass, we will allocate the space then, and will
            // possibly overrun the max_memory_to_use setting.
            if (cinfo.dither_mode == J_DITHER_MODE.JDITHER_FS)
            {
                alloc_fs_workspace(cinfo);
            }
        }
Beispiel #6
0
        // Fast path for out_color_components==3, with ordered dithering
        static void quantize3_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;

            byte[] colorindex0 = cquantize.colorindex[0];
            byte[] colorindex1 = cquantize.colorindex[1];
            byte[] colorindex2 = cquantize.colorindex[2];
            uint   width       = cinfo.output_width;

            for (int row = 0; row < num_rows; row++)
            {
                int    row_index = cquantize.row_index;
                byte[] input_ptr = input_buf[input_row + row];
                byte[] output_ptr = output_buf[output_row + row];
                uint   iind = 0, oind = 0;
                int[,] dither0 = cquantize.odither[0];               // points to active row of dither matrix
                int[,] dither1 = cquantize.odither[1];
                int[,] dither2 = cquantize.odither[2];
                int col_index = 0;

                for (uint col = width; col > 0; col--)
                {
                    int tmp     = input_ptr[iind++] + dither0[row_index, col_index];
                    int pixcode = colorindex0[(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp))];

                    tmp      = input_ptr[iind++] + dither1[row_index, col_index];
                    pixcode += colorindex1[(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp))];

                    tmp      = input_ptr[iind++] + dither2[row_index, col_index];
                    pixcode += colorindex2[(tmp >= MAXJSAMPLE?MAXJSAMPLE:(tmp < 0?0:tmp))];

                    output_ptr[oind++] = (byte)pixcode;
                    col_index          = (col_index + 1) & ODITHER_MASK;
                }
                row_index           = (row_index + 1) & ODITHER_MASK;
                cquantize.row_index = row_index;
            }
        }
Beispiel #7
0
        // Fast path for out_color_components==3, no dithering
        static void color_quantize3(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;

            byte[] colorindex0 = cquantize.colorindex[0];
            byte[] colorindex1 = cquantize.colorindex[1];
            byte[] colorindex2 = cquantize.colorindex[2];
            uint   width       = cinfo.output_width;

            for (int row = 0; row < num_rows; row++)
            {
                byte[] ptrin = input_buf[input_row + row];
                byte[] ptrout = output_buf[output_row + row];
                uint   iind = 0, oind = 0;
                for (uint col = width; col > 0; col--)
                {
                    int pixcode = colorindex0[ptrin[iind++]];
                    pixcode       += colorindex1[ptrin[iind++]];
                    pixcode       += colorindex2[ptrin[iind++]];
                    ptrout[oind++] = (byte)pixcode;
                }
            }
        }
Beispiel #8
0
        // Create the ordered-dither tables.
        // Components having the same number of representative colors may
        // share a dither table.
        static void create_odither_tables(jpeg_decompress cinfo)
        {
            my_cquantizer1 cquantize = (my_cquantizer1)cinfo.cquantize;

            for (int i = 0; i < cinfo.out_color_components; i++)
            {
                int nci = cquantize.Ncolors[i];                 // # of distinct values for this color
                int[,] odither = null;                          // search for matching prior component
                for (int j = 0; j < i; j++)
                {
                    if (nci == cquantize.Ncolors[j])
                    {
                        odither = cquantize.odither[j];
                        break;
                    }
                }
                if (odither == null)
                {
                    odither = make_odither_array(cinfo, nci);                             // need a new table?
                }
                cquantize.odither[i] = odither;
            }
        }
Beispiel #9
0
        // Map some rows of pixels to the output colormapped representation.
        // General case, no dithering
        static void color_quantize(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;

            byte[][] colorindex = cquantize.colorindex;
            uint     width      = cinfo.output_width;
            int      nc         = cinfo.out_color_components;

            for (int row = 0; row < num_rows; row++)
            {
                byte[] ptrin = input_buf[input_row + row];
                byte[] ptrout = output_buf[output_row + row];
                uint   iind = 0, oind = 0;
                for (uint col = width; col > 0; col--)
                {
                    int pixcode = 0;
                    for (int ci = 0; ci < nc; ci++)
                    {
                        pixcode += colorindex[ci][ptrin[iind++]];
                    }
                    ptrout[oind++] = (byte)pixcode;
                }
            }
        }
Beispiel #10
0
        // Initialize for one-pass color quantization.
        static void start_pass_1_quant(jpeg_decompress cinfo, bool is_pre_scan)
        {
            my_cquantizer1 cquantize = (my_cquantizer1)cinfo.cquantize;

            // Install my colormap.
            cinfo.colormap = cquantize.sv_colormap;
            cinfo.actual_number_of_colors = cquantize.sv_actual;

            // Initialize for desired dithering mode.
            switch (cinfo.dither_mode)
            {
            case J_DITHER_MODE.JDITHER_NONE:
                if (cinfo.out_color_components == 3)
                {
                    cquantize.color_quantize = color_quantize3;
                }
                else
                {
                    cquantize.color_quantize = color_quantize;
                }
                break;

            case J_DITHER_MODE.JDITHER_ORDERED:
                if (cinfo.out_color_components == 3)
                {
                    cquantize.color_quantize = quantize3_ord_dither;
                }
                else
                {
                    cquantize.color_quantize = quantize_ord_dither;
                }
                cquantize.row_index = 0;                        // initialize state for ordered dither
                // Create ordered-dither tables if we didn't already.
                if (cquantize.odither[0] == null)
                {
                    create_odither_tables(cinfo);
                }
                break;

            case J_DITHER_MODE.JDITHER_FS:
                cquantize.color_quantize = quantize_fs_dither;
                cquantize.on_odd_row     = false;                   // initialize state for F-S dither

                // Allocate Floyd-Steinberg workspace if didn't already.
                if (cquantize.fserrors[0] == null)
                {
                    alloc_fs_workspace(cinfo);
                }

                // Initialize the propagated errors to zero.
                uint arraysize = cinfo.output_width + 2;
                for (int i = 0; i < cinfo.out_color_components; i++)
                {
                    for (int j = 0; j < arraysize; j++)
                    {
                        cquantize.fserrors[i][j] = 0;
                    }
                }
                break;

            default:
                ERREXIT(cinfo, J_MESSAGE_CODE.JERR_NOT_COMPILED);
                break;
            }
        }
Beispiel #11
0
        // General case, with Floyd-Steinberg dithering
        static void quantize_fs_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[] errorptr;             // => fserrors[] at column before current
            int   errorptr_ind;
            int   pixcode;
            int   nc = cinfo.out_color_components;
            int   dir;                                  // 1 for left-to-right, -1 for right-to-left
            int   dirnc;                                // dir * nc
            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;
                }

                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];
                    int    oind       = 0;
                    if (cquantize.on_odd_row)
                    {
                        // work right to left in this row
                        iind        += (int)(width - 1) * nc;            // so point to rightmost pixel
                        oind        += (int)width - 1;
                        dir          = -1;
                        dirnc        = -nc;
                        errorptr     = cquantize.fserrors[ci];
                        errorptr_ind = (int)(width + 1);                     // => entry after last column
                    }
                    else
                    {
                        // work left to right in this row
                        dir          = 1;
                        dirnc        = nc;
                        errorptr     = cquantize.fserrors[ci];                   // => entry before first column
                        errorptr_ind = 0;
                    }
                    byte[] colorindex_ci = cquantize.colorindex[ci];
                    byte[] colormap_ci   = cquantize.sv_colormap[ci];

                    // Preset error values: no error propagated to first pixel from left
                    int cur = 0;

                    // and no error propagated to row below yet
                    int belowerr = 0, bpreverr = 0;

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

                        // Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
                        // The maximum error is +- MAXJSAMPLE; this sets the required size
                        // of the range_limit array.
                        cur += input_ptr[iind];
                        cur  = (cur >= MAXJSAMPLE?MAXJSAMPLE:(cur < 0?0:cur));

                        // Select output value, accumulate into output code for this pixel
                        pixcode           = colorindex_ci[cur];
                        output_ptr[oind] += (byte)pixcode;

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

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

                        // At this point cur contains the 7/16 error value to be propagated
                        // to the next pixel on the current line, and all the errors for the
                        // next line have been shifted over. We are therefore ready to move on.
                        iind         += dirnc;                  // advance input ptr to next column
                        oind         += dir;                    // advance output ptr to next column
                        errorptr_ind += dir;                    // advance errorptr to current column
                    }
                    // Post-loop cleanup: we must unload the final error value into the
                    // final fserrors[] entry. Note we need not unload belowerr because
                    // it is for the dummy column before or after the actual array.
                    errorptr[errorptr_ind] = bpreverr;                   // unload prev err into array
                }
                cquantize.on_odd_row = (cquantize.on_odd_row?false:true);
            }
        }
Beispiel #12
0
		// Module initialization routine for 1-pass color quantization.
		public static void jinit_1pass_quantizer(jpeg_decompress cinfo)
		{
			my_cquantizer1 cquantize=null;

			try
			{
				cquantize=new my_cquantizer1();
			}
			catch
			{
				ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
			}
			cinfo.cquantize=cquantize;
			cquantize.start_pass=start_pass_1_quant;
			cquantize.finish_pass=finish_pass_1_quant;
			cquantize.new_color_map=new_color_map_1_quant;
			cquantize.fserrors[0]=null; // Flag FS workspace not allocated
			cquantize.odither[0]=null;	// Also flag odither arrays not allocated

			// Make sure my internal arrays won't overflow
			if(cinfo.out_color_components>MAX_Q_COMPS) ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_QUANT_COMPONENTS, MAX_Q_COMPS);

			// Make sure colormap indexes can be represented by bytes
			if(cinfo.desired_number_of_colors>(MAXJSAMPLE+1)) ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_QUANT_MANY_COLORS, MAXJSAMPLE+1);

			// Create the colormap and color index table.
			create_colormap(cinfo);
			create_colorindex(cinfo);

			// Allocate Floyd-Steinberg workspace now if requested.
			// We do this now since it is storage and may effect the memory
			// manager's space calculations. If the user changes to FS dither
			// mode in a later pass, we will allocate the space then, and will
			// possibly overrun the max_memory_to_use setting.
			if(cinfo.dither_mode==J_DITHER_MODE.JDITHER_FS) alloc_fs_workspace(cinfo);
		}