private void pass2_fs_dither(byte[][] input_buf, int in_row, byte[][] output_buf, int out_row, int num_rows)
{
byte[] limit = m_cinfo.m_sample_range_limit;
int limitOffset = m_cinfo.m_sampleRangeLimitOffset;
for (int row = 0; row < num_rows; row++)
{
int inputPixelIndex = 0;
int outputPixelIndex = 0;
int errorIndex = 0;
int dir; /* +1 or -1 depending on direction */
int dir3; /* 3*dir, for advancing inputIndex & errorIndex */
if (m_on_odd_row)
{
/* work right to left in this row */
inputPixelIndex += (m_cinfo.m_output_width - 1) * 3; /* so point to rightmost pixel */
outputPixelIndex += m_cinfo.m_output_width - 1;
dir = -1;
dir3 = -3;
errorIndex = (m_cinfo.m_output_width + 1) * 3; /* => entry after last column */
m_on_odd_row = false; /* flip for next time */
}
else
{
/* work left to right in this row */
dir = 1;
dir3 = 3;
errorIndex = 0; /* => entry before first real column */
m_on_odd_row = true; /* flip for next time */
}
/* Preset error values: no error propagated to first pixel from left */
/* current error or pixel value */
int cur0 = 0;
int cur1 = 0;
int cur2 = 0;
/* and no error propagated to row below yet */
/* error for pixel below cur */
int belowerr0 = 0;
int belowerr1 = 0;
int belowerr2 = 0;
/* error for below/prev col */
int bpreverr0 = 0;
int bpreverr1 = 0;
int bpreverr2 = 0;
for (int col = m_cinfo.m_output_width; col > 0; col--)
{
/* curN 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.
*/
cur0 = JpegUtils.RIGHT_SHIFT(cur0 + m_fserrors[errorIndex + dir3] + 8, 4);
cur1 = JpegUtils.RIGHT_SHIFT(cur1 + m_fserrors[errorIndex + dir3 + 1] + 8, 4);
cur2 = JpegUtils.RIGHT_SHIFT(cur2 + m_fserrors[errorIndex + dir3 + 2] + 8, 4);
/* Limit the error using transfer function set by init_error_limit.
* See comments with init_error_limit for rationale.
*/
cur0 = m_error_limiter[JpegConstants.MAXJSAMPLE + cur0];
cur1 = m_error_limiter[JpegConstants.MAXJSAMPLE + cur1];
cur2 = m_error_limiter[JpegConstants.MAXJSAMPLE + cur2];
/* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
* The maximum error is +- MAXJSAMPLE (or less with error limiting);
* this sets the required size of the range_limit array.
*/
cur0 += input_buf[in_row + row][inputPixelIndex];
cur1 += input_buf[in_row + row][inputPixelIndex + 1];
cur2 += input_buf[in_row + row][inputPixelIndex + 2];
cur0 = limit[limitOffset + cur0];
cur1 = limit[limitOffset + cur1];
cur2 = limit[limitOffset + cur2];
/* Index into the cache with adjusted pixel value */
int hRow = cur0 >> C0_SHIFT;
int hColumn = (cur1 >> C1_SHIFT) * HIST_C2_ELEMS + (cur2 >> C2_SHIFT);
/* If we have not seen this color before, find nearest colormap */
/* entry and update the cache */
if (m_histogram[hRow][hColumn] == 0)
fill_inverse_cmap(cur0 >> C0_SHIFT, cur1 >> C1_SHIFT, cur2 >> C2_SHIFT);
/* Now emit the colormap index for this cell */
int pixcode = m_histogram[hRow][hColumn] - 1;
output_buf[out_row + row][outputPixelIndex] = (byte) pixcode;
/* Compute representation error for this pixel */
cur0 -= m_cinfo.m_colormap[0][pixcode];
cur1 -= m_cinfo.m_colormap[1][pixcode];
cur2 -= m_cinfo.m_colormap[2][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 = cur0; /* Process component 0 */
int delta = cur0 * 2;
cur0 += delta; /* form error * 3 */
m_fserrors[errorIndex] = (short) (bpreverr0 + cur0);
cur0 += delta; /* form error * 5 */
bpreverr0 = belowerr0 + cur0;
belowerr0 = bnexterr;
cur0 += delta; /* form error * 7 */
bnexterr = cur1; /* Process component 1 */
delta = cur1 * 2;
cur1 += delta; /* form error * 3 */
m_fserrors[errorIndex + 1] = (short) (bpreverr1 + cur1);
cur1 += delta; /* form error * 5 */
bpreverr1 = belowerr1 + cur1;
belowerr1 = bnexterr;
cur1 += delta; /* form error * 7 */
bnexterr = cur2; /* Process component 2 */
delta = cur2 * 2;
cur2 += delta; /* form error * 3 */
m_fserrors[errorIndex + 2] = (short) (bpreverr2 + cur2);
cur2 += delta; /* form error * 5 */
bpreverr2 = belowerr2 + cur2;
belowerr2 = bnexterr;
cur2 += delta; /* form error * 7 */
/* At this point curN 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.
*/
inputPixelIndex += dir3; /* Advance pixel pointers to next column */
outputPixelIndex += dir;
errorIndex += dir3; /* advance errorIndex to current column */
}
/* Post-loop cleanup: we must unload the final error values into the
* final fserrors[] entry. Note we need not unload belowerrN because
* it is for the dummy column before or after the actual array.
*/
m_fserrors[errorIndex] = (short) bpreverr0; /* unload prev errs into array */
m_fserrors[errorIndex + 1] = (short) bpreverr1;
m_fserrors[errorIndex + 2] = (short) bpreverr2;
}
}