Beispiel #1
0
        // Process some data in subsequent passes of a multi-pass case.
        // We process the equivalent of one fully interleaved MCU row ("iMCU" row)
        // per call, ie, v_samp_factor block rows for each component in the scan.
        // The data is obtained from the arrays and fed to the entropy coder.
        // Returns true if the iMCU row is completed, false if suspended.
        //
        // NB: input_buf is ignored; it is likely to be a null pointer.
        static bool compress_output_coef(jpeg_compress cinfo, byte[][][] input_buf)
        {
            jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef;
            c_coef_controller  coef   = (c_coef_controller)lossyc.coef_private;

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

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

            // Loop to process one whole iMCU row
            for (int yoffset = coef.MCU_vert_offset; yoffset < coef.MCU_rows_per_iMCU_row; yoffset++)
            {
                for (uint MCU_col_num = coef.mcu_ctr; MCU_col_num < cinfo.MCUs_per_row; MCU_col_num++)
                {
                    // Construct list of pointers to DCT blocks belonging to this MCU
                    int blkn = 0;                   // index of current DCT block within MCU
                    for (int ci = 0; ci < cinfo.comps_in_scan; ci++)
                    {
                        jpeg_component_info compptr = cinfo.cur_comp_info[ci];
                        uint start_col = MCU_col_num * (uint)compptr.MCU_width;
                        for (int yindex = 0; yindex < compptr.MCU_height; yindex++)
                        {
                            short[][] buffer_ptr     = buffer[ci][buffer_ind[ci] + yindex + yoffset];
                            uint      buffer_ptr_ind = start_col;
                            for (int xindex = 0; xindex < compptr.MCU_width; xindex++)
                            {
                                coef.MCU_buffer[blkn++] = buffer_ptr[buffer_ptr_ind++];
                            }
                        }
                    }

                    // Try to write the MCU.
                    if (!lossyc.entropy_encode_mcu(cinfo, coef.MCU_buffer))
                    {
                        // Suspension forced; update state counters and exit
                        coef.MCU_vert_offset = yoffset;
                        coef.mcu_ctr         = MCU_col_num;
                        return(false);
                    }
                }

                // Completed an MCU row, but perhaps not an iMCU row
                coef.mcu_ctr = 0;
            }

            // Completed the iMCU row, advance counters for next one
            coef.iMCU_row_num++;
            start_iMCU_row_c_coef(cinfo);

            return(true);
        }
Beispiel #2
0
        // Reset within-iMCU-row counters for a new row
        static void start_iMCU_row_c_coef(jpeg_compress cinfo)
        {
            jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef;
            c_coef_controller  coef   = (c_coef_controller)lossyc.coef_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)
            {
                coef.MCU_rows_per_iMCU_row = 1;
            }
            else
            {
                if (coef.iMCU_row_num < (cinfo.total_iMCU_rows - 1))
                {
                    coef.MCU_rows_per_iMCU_row = cinfo.cur_comp_info[0].v_samp_factor;
                }
                else
                {
                    coef.MCU_rows_per_iMCU_row = cinfo.cur_comp_info[0].last_row_height;
                }
            }

            coef.mcu_ctr         = 0;
            coef.MCU_vert_offset = 0;
        }
Beispiel #3
0
        static void jinit_c_coef_controller(jpeg_compress cinfo, bool need_full_buffer)
        {
            jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef;
            c_coef_controller  coef   = null;

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

            lossyc.coef_private    = coef;
            lossyc.coef_start_pass = start_pass_coef;

            // Create the coefficient buffer.
            if (need_full_buffer)
            {
#if FULL_COEF_BUFFER_SUPPORTED
                // Allocate a full-image array for each component,
                // padded to a multiple of samp_factor DCT blocks in each direction.
                for (int ci = 0; ci < cinfo.num_components; ci++)
                {
                    jpeg_component_info compptr = cinfo.comp_info[ci];

                    coef.whole_image[ci] = alloc_barray(cinfo,
                                                        (uint)jround_up((int)compptr.width_in_blocks, compptr.h_samp_factor),
                                                        (uint)jround_up((int)compptr.height_in_blocks, compptr.v_samp_factor));
                }
#else
                ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_BUFFER_MODE);
#endif
            }
            else
            {
                // We only need a single-MCU buffer.
                try
                {
                    for (int i = 0; i < C_MAX_BLOCKS_IN_MCU; i++)
                    {
                        coef.MCU_buffer[i] = new short[DCTSIZE2];
                    }
                }
                catch
                {
                    ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
                }

                coef.whole_image[0] = null;               // flag for no arrays
            }
        }
Beispiel #4
0
        // Initialize for a processing pass.
        static void start_pass_coef(jpeg_compress cinfo, J_BUF_MODE pass_mode)
        {
            jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef;
            c_coef_controller  coef   = (c_coef_controller)lossyc.coef_private;

            coef.iMCU_row_num = 0;
            start_iMCU_row_c_coef(cinfo);

            switch (pass_mode)
            {
            case J_BUF_MODE.JBUF_PASS_THRU:
                if (coef.whole_image[0] != null)
                {
                    ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_BUFFER_MODE);
                }
                lossyc.compress_data = compress_data_coef;
                break;

#if FULL_COEF_BUFFER_SUPPORTED
            case J_BUF_MODE.JBUF_SAVE_AND_PASS:
                if (coef.whole_image[0] == null)
                {
                    ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_BUFFER_MODE);
                }
                lossyc.compress_data = compress_first_pass_coef;
                break;

            case J_BUF_MODE.JBUF_CRANK_DEST:
                if (coef.whole_image[0] == null)
                {
                    ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_BUFFER_MODE);
                }
                lossyc.compress_data = compress_output_coef;
                break;
#endif
            default:
                ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_BUFFER_MODE);
                break;
            }
        }
Beispiel #5
0
        // Process some data in the first pass of a multi-pass case.
        // We process the equivalent of one fully interleaved MCU row ("iMCU" row)
        // per call, ie, v_samp_factor block rows for each component in the image.
        // This amount of data is read from the source buffer, DCT'd and quantized,
        // and saved into the arrays. We also generate suitable dummy blocks
        // as needed at the right and lower edges. (The dummy blocks are constructed
        // in the arrays, which have been padded appropriately.) This makes
        // it possible for subsequent passes not to worry about real vs. dummy blocks.
        //
        // We must also emit the data to the entropy encoder. This is conveniently
        // done by calling compress_output_coef() after we've loaded the current strip
        // of the arrays.
        //
        // NB: input_buf contains a plane for each component in image. All
        // components are DCT'd and loaded into the arrays in this pass.
        // However, it may be that only a subset of the components are emitted to
        // the entropy encoder during this first pass; be careful about looking
        // at the scan-dependent variables (MCU dimensions, etc).
        static bool compress_first_pass_coef(jpeg_compress cinfo, byte[][][] input_buf)
        {
            jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef;
            c_coef_controller  coef   = (c_coef_controller)lossyc.coef_private;

            uint last_iMCU_row = cinfo.total_iMCU_rows - 1;

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

                // Align the buffer for this component.
                short[][][] buffer     = coef.whole_image[ci];
                int         buffer_ind = (int)coef.iMCU_row_num * compptr.v_samp_factor;

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

                uint blocks_across = compptr.width_in_blocks;
                int  h_samp_factor = compptr.h_samp_factor;

                // Count number of dummy blocks to be added at the right margin.
                int ndummy = (int)(blocks_across % h_samp_factor);
                if (ndummy > 0)
                {
                    ndummy = h_samp_factor - ndummy;
                }

                // Perform DCT for all non-dummy blocks in this iMCU row. Each call
                // on forward_DCT processes a complete horizontal row of DCT blocks.
                for (int block_row = 0; block_row < block_rows; block_row++)
                {
                    short[][] row = buffer[buffer_ind + block_row];
                    lossyc.fdct_forward_DCT(cinfo, compptr, input_buf[ci], row, 0, (uint)(block_row * DCTSIZE), 0, blocks_across);
                    if (ndummy > 0)
                    {
                        // Create dummy blocks at the right edge of the image.
                        short lastDC = row[blocks_across - 1][0];
                        for (int bi = 0; bi < ndummy; bi++)
                        {
                            short[] block = row[blocks_across + bi];
                            for (int i = 1; i < DCTSIZE2; i++)
                            {
                                block[i] = 0;
                            }
                            block[0] = lastDC;
                        }
                    }
                }
                // If at end of image, create dummy block rows as needed.
                // The tricky part here is that within each MCU, we want the DC values
                // of the dummy blocks to match the last real block's DC value.
                // This squeezes a few more bytes out of the resulting file...
                if (coef.iMCU_row_num == last_iMCU_row)
                {
                    blocks_across += (uint)ndummy;                   // include lower right corner
                    uint MCUs_across = blocks_across / (uint)h_samp_factor;
                    for (int block_row = block_rows; block_row < compptr.v_samp_factor; block_row++)
                    {
                        short[][] thisblockrow     = buffer[buffer_ind + block_row];
                        short[][] lastblockrow     = buffer[buffer_ind + block_row - 1];
                        int       thisblockrow_ind = 0;
                        int       lastblockrow_ind = h_samp_factor - 1;

                        for (int j = 0; j < blocks_across; j++)
                        {
                            short[] block = thisblockrow[j];
                            for (int i = 0; i < DCTSIZE2; i++)
                            {
                                block[i] = 0;
                            }
                        }

                        for (uint MCUindex = 0; MCUindex < MCUs_across; MCUindex++)
                        {
                            short lastDC = lastblockrow[lastblockrow_ind][0];
                            for (int bi = 0; bi < h_samp_factor; bi++)
                            {
                                thisblockrow[thisblockrow_ind + bi][0] = lastDC;
                            }

                            thisblockrow_ind += h_samp_factor;                           // advance to next MCU in row
                            lastblockrow_ind += h_samp_factor;
                        }
                    }
                }
            }

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

            // Emit data to the entropy encoder, sharing code with subsequent passes
            return(compress_output_coef(cinfo, input_buf));
        }
Beispiel #6
0
        // Process some data in the single-pass case.
        // We process the equivalent of one fully interleaved MCU row ("iMCU" row)
        // per call, ie, v_samp_factor block rows for each component in the image.
        // Returns true if the iMCU row is completed, false if suspended.
        //
        // NB: input_buf contains a plane for each component in image,
        // which we index according to the component's SOF position.
        static bool compress_data_coef(jpeg_compress cinfo, byte[][][] input_buf)
        {
            jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef;
            c_coef_controller  coef   = (c_coef_controller)lossyc.coef_private;
            uint last_MCU_col         = cinfo.MCUs_per_row - 1;
            uint last_iMCU_row        = cinfo.total_iMCU_rows - 1;

            // Loop to write as much as one whole iMCU row
            for (int yoffset = coef.MCU_vert_offset; yoffset < coef.MCU_rows_per_iMCU_row; yoffset++)
            {
                for (uint MCU_col_num = coef.mcu_ctr; MCU_col_num <= last_MCU_col; MCU_col_num++)            // index of current MCU within row
                {
                    // Determine where data comes from in input_buf and do the DCT thing.
                    // Each call on forward_DCT processes a horizontal row of DCT blocks
                    // as wide as an MCU; we rely on having allocated the MCU_buffer[] blocks
                    // sequentially. Dummy blocks at the right or bottom edge are filled in
                    // specially. The data in them does not matter for image reconstruction,
                    // so we fill them with values that will encode to the smallest amount of
                    // data, viz: all zeroes in the AC entries, DC entries equal to previous
                    // block's DC value. (Thanks to Thomas Kinsman for this idea.)
                    int blkn = 0;
                    for (int ci = 0; ci < cinfo.comps_in_scan; ci++)
                    {
                        jpeg_component_info compptr = cinfo.cur_comp_info[ci];
                        int blockcnt = (MCU_col_num < last_MCU_col)?compptr.MCU_width:compptr.last_col_width;

                        uint xpos = MCU_col_num * (uint)compptr.MCU_sample_width;
                        uint ypos = (uint)yoffset * DCTSIZE;                     // ypos == (yoffset+yindex) * DCTSIZE

                        for (int yindex = 0; yindex < compptr.MCU_height; yindex++)
                        {
                            if (coef.iMCU_row_num < last_iMCU_row || yoffset + yindex < compptr.last_row_height)
                            {
                                lossyc.fdct_forward_DCT(cinfo, compptr, input_buf[compptr.component_index], coef.MCU_buffer, blkn, ypos, xpos, (uint)blockcnt);
                                if (blockcnt < compptr.MCU_width)
                                {
                                    // Create some dummy blocks at the right edge of the image.
                                    for (int bi = blockcnt; bi < compptr.MCU_width; bi++)
                                    {
                                        short[] block = coef.MCU_buffer[blkn + bi];
                                        for (int i = 1; i < DCTSIZE2; i++)
                                        {
                                            block[i] = 0;                                                               // ACs
                                        }
                                        block[0] = coef.MCU_buffer[blkn + bi - 1][0];                                   // DCs
                                    }
                                }
                            }
                            else
                            {
                                // Create a row of dummy blocks at the bottom of the image.
                                for (int bi = 0; bi < compptr.MCU_width; bi++)
                                {
                                    short[] block = coef.MCU_buffer[blkn + bi];
                                    for (int i = 1; i < DCTSIZE2; i++)
                                    {
                                        block[i] = 0;                                                        // ACs
                                    }
                                    block[0] = coef.MCU_buffer[blkn - 1][0];                                 // DCs
                                }
                            }
                            blkn += compptr.MCU_width;
                            ypos += DCTSIZE;
                        }
                    }

                    // Try to write the MCU. In event of a suspension failure, we will
                    // re-DCT the MCU on restart (a bit inefficient, could be fixed...)
                    if (!lossyc.entropy_encode_mcu(cinfo, coef.MCU_buffer))
                    {
                        // Suspension forced; update state counters and exit
                        coef.MCU_vert_offset = yoffset;
                        coef.mcu_ctr         = MCU_col_num;
                        return(false);
                    }
                }

                // Completed an MCU row, but perhaps not an iMCU row
                coef.mcu_ctr = 0;
            }

            // Completed the iMCU row, advance counters for next one
            coef.iMCU_row_num++;
            start_iMCU_row_c_coef(cinfo);

            return(true);
        }
Beispiel #7
0
        public static uint jpeg_write_image(jpeg_compress cinfo, byte[] image, bool swapChannels, bool alpha)
        {
            if (cinfo.input_components != 3 || cinfo.lossless || cinfo.in_color_space != J_COLOR_SPACE.JCS_RGB ||
                cinfo.num_components != 3 || cinfo.jpeg_color_space != J_COLOR_SPACE.JCS_YCbCr ||
                cinfo.data_precision != 8 || cinfo.DCT_size != 8 || cinfo.block_in_MCU != 3 || cinfo.arith_code ||
                cinfo.max_h_samp_factor != 1 || cinfo.max_v_samp_factor != 1 || cinfo.next_scanline != 0 || cinfo.num_scans != 1)
            {
                throw new Exception();
            }

            if (cinfo.global_state != STATE.CSCANNING)
            {
                ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_BAD_STATE, cinfo.global_state);
            }

            // Give master control module another chance if this is first call to
            // jpeg_write_scanlines. This lets output of the frame/scan headers be
            // delayed so that application can write COM, etc, markers between
            // jpeg_start_compress and jpeg_write_scanlines.
            if (cinfo.master.call_pass_startup)
            {
                cinfo.master.pass_startup(cinfo);
            }

            jpeg_lossy_c_codec lossyc = (jpeg_lossy_c_codec)cinfo.coef;
            c_coef_controller  coef   = (c_coef_controller)lossyc.coef_private;
            fdct_controller    fdct   = (fdct_controller)lossyc.fdct_private;

            double[] workspaceY  = new double[DCTSIZE2];
            double[] workspaceCr = new double[DCTSIZE2];
            double[] workspaceCb = new double[DCTSIZE2];

            short[][] coefs = new short[][] { new short[DCTSIZE2], new short[DCTSIZE2], new short[DCTSIZE2] };

            short[] coefY  = coefs[0];
            short[] coefCb = coefs[1];
            short[] coefCr = coefs[2];

            double[] divisorY = fdct.float_divisors[0];
            double[] divisorC = fdct.float_divisors[1];

            int bpp = alpha?4:3;

            for (int y = 0; y < (cinfo.image_height + DCTSIZE - 1) / DCTSIZE; y++)
            {
                int yFormImage = Math.Min((int)cinfo.image_height - y * DCTSIZE, DCTSIZE);
                for (int x = 0; x < (cinfo.image_width + DCTSIZE - 1) / DCTSIZE; x++)
                {
                    int xFormImage   = Math.Min((int)cinfo.image_width - x * DCTSIZE, DCTSIZE);
                    int workspacepos = 0;
                    for (int j = 0; j < yFormImage; j++)
                    {
                        int imagepos = ((y * DCTSIZE + j) * (int)cinfo.image_width + x * DCTSIZE) * bpp;
                        for (int i = 0; i < xFormImage; i++, workspacepos++)
                        {
                            byte r = image[imagepos++];
                            byte g = image[imagepos++];
                            byte b = image[imagepos++];
                            if (alpha)
                            {
                                imagepos++;
                            }

                            if (!swapChannels)
                            {
                                workspaceY[workspacepos]  = 0.299 * r + 0.587 * g + 0.114 * b - CENTERJSAMPLE;
                                workspaceCb[workspacepos] = -0.168736 * r - 0.331264 * g + 0.5 * b;
                                workspaceCr[workspacepos] = 0.5 * r - 0.418688 * g - 0.081312 * b;
                            }
                            else
                            {
                                workspaceY[workspacepos]  = 0.299 * b + 0.587 * g + 0.114 * r - CENTERJSAMPLE;
                                workspaceCb[workspacepos] = -0.168736 * b - 0.331264 * g + 0.5 * r;
                                workspaceCr[workspacepos] = 0.5 * b - 0.418688 * g - 0.081312 * r;
                            }
                        }

                        int lastworkspacepos = workspacepos - 1;
                        for (int i = xFormImage; i < DCTSIZE; i++, workspacepos++)
                        {
                            workspaceY[workspacepos]  = workspaceY[lastworkspacepos];
                            workspaceCb[workspacepos] = workspaceCb[lastworkspacepos];
                            workspaceCr[workspacepos] = workspaceCr[lastworkspacepos];
                        }
                    }

                    int lastworkspacelinepos = (yFormImage - 1) * DCTSIZE;
                    for (int j = yFormImage; j < DCTSIZE; j++)
                    {
                        int lastworkspacepos = lastworkspacelinepos;
                        for (int i = 0; i < DCTSIZE; i++, workspacepos++, lastworkspacepos++)
                        {
                            workspaceY[workspacepos]  = workspaceY[lastworkspacepos];
                            workspaceCb[workspacepos] = workspaceCb[lastworkspacepos];
                            workspaceCr[workspacepos] = workspaceCr[lastworkspacepos];
                        }
                    }

                    // ein block (3 componenten)
                    jpeg_fdct_float(workspaceY);
                    jpeg_fdct_float(workspaceCb);
                    jpeg_fdct_float(workspaceCr);

                    for (int i = 0; i < DCTSIZE2; i++)
                    {
                        // Apply the quantization and scaling factor
                        double tempY  = workspaceY[i] * divisorY[i];
                        double tempCb = workspaceCb[i] * divisorC[i];
                        double tempCr = workspaceCr[i] * divisorC[i];

                        // Round to nearest integer.
                        // Since C does not specify the direction of rounding for negative
                        // quotients, we have to force the dividend positive for portability.
                        // The maximum coefficient size is +-16K (for 12-bit data), so this
                        // code should work for either 16-bit or 32-bit ints.
                        coefY[i]  = (short)((int)(tempY + 16384.5) - 16384);
                        coefCb[i] = (short)((int)(tempCb + 16384.5) - 16384);
                        coefCr[i] = (short)((int)(tempCr + 16384.5) - 16384);
                    }

                    lossyc.entropy_encode_mcu(cinfo, coefs);
                }
            }

            cinfo.next_scanline = cinfo.image_height;
            return(cinfo.image_height);
        }
Beispiel #8
0
		static void jinit_c_coef_controller(jpeg_compress cinfo, bool need_full_buffer)
		{
			jpeg_lossy_c_codec lossyc=(jpeg_lossy_c_codec)cinfo.coef;
			c_coef_controller coef=null;

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

			lossyc.coef_private=coef;
			lossyc.coef_start_pass=start_pass_coef;

			// Create the coefficient buffer.
			if(need_full_buffer)
			{
#if FULL_COEF_BUFFER_SUPPORTED
				// Allocate a full-image array for each component,
				// padded to a multiple of samp_factor DCT blocks in each direction.
				for(int ci=0; ci<cinfo.num_components; ci++)
				{
					jpeg_component_info compptr=cinfo.comp_info[ci];

					coef.whole_image[ci]=alloc_barray(cinfo,
						(uint)jround_up((int)compptr.width_in_blocks, compptr.h_samp_factor),
						(uint)jround_up((int)compptr.height_in_blocks, compptr.v_samp_factor));
				}
#else
				ERREXIT(cinfo, J_MESSAGE_CODE.JERR_BAD_BUFFER_MODE);
#endif
			}
			else
			{
				// We only need a single-MCU buffer.
				try
				{
					for(int i=0; i<C_MAX_BLOCKS_IN_MCU; i++) coef.MCU_buffer[i]=new short[DCTSIZE2];
				}
				catch
				{
					ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4);
				}

				coef.whole_image[0]=null; // flag for no arrays
			}
		}