private void quantize_fs_dither(byte[][] input_buf, int in_row, byte[][] output_buf, int out_row, int num_rows)
{
int nc = m_cinfo.m_out_color_components;
int width = m_cinfo.m_output_width;
byte[] limit = m_cinfo.m_sample_range_limit;
int limitOffset = m_cinfo.m_sampleRangeLimitOffset;
for (int row = 0; row < num_rows; row++)
{
/* Initialize output values to 0 so can process components separately */
Array.Clear(output_buf[out_row + row], 0, width);
for (int ci = 0; ci < nc; ci++)
{
int inRow = in_row + row;
int inIndex = ci;
int outIndex = 0;
int outRow = out_row + row;
int errorIndex = 0;
int dir; /* 1 for left-to-right, -1 for right-to-left */
if (m_on_odd_row)
{
/* work right to left in this row */
inIndex += (width - 1) * nc; /* so point to rightmost pixel */
outIndex += width - 1;
dir = -1;
errorIndex = width + 1; /* => entry after last column */
}
else
{
/* work left to right in this row */
dir = 1;
errorIndex = 0; /* => entry before first column */
}
int dirnc = dir * nc;
/* 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;
int bpreverr = 0;
for (int 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: errorIndex is for *previous* column's array entry.
*/
cur = JpegUtils.RIGHT_SHIFT(cur + m_fserrors[ci][errorIndex + 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_buf[inRow][inIndex];
cur = limit[limitOffset + cur];
/* Select output value, accumulate into output code for this pixel */
int pixcode = m_colorindex[ci][m_colorindexOffset[ci] + cur];
output_buf[outRow][outIndex] += (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 -= m_sv_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 */
m_fserrors[ci][errorIndex + 0] = (short) (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.
*/
inIndex += dirnc; /* advance input to next column */
outIndex += dir; /* advance output to next column */
errorIndex += dir; /* advance errorIndex 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.
*/
m_fserrors[ci][errorIndex + 0] = (short) bpreverr; /* unload prev err into array */
}
m_on_odd_row = !m_on_odd_row;
}
}