private void h2v2_smooth_downsample(int componentIndex, byte[][] input_data, int startInputRow, byte[][] output_data, int startOutRow)
{
/* Expand input data enough to let all the output samples be generated
* by the standard loop. Special-casing padded output would be more
* efficient.
*/
jpeg_component_info compptr = m_cinfo.Component_info[componentIndex];
int output_cols = compptr.Width_in_blocks * compptr.DCT_h_scaled_size;
expand_right_edge(input_data, startInputRow - 1, m_cinfo.m_max_v_samp_factor + 2, m_cinfo.m_image_width, output_cols * 2);
/* We don't bother to form the individual "smoothed" input pixel values;
* we can directly compute the output which is the average of the four
* smoothed values. Each of the four member pixels contributes a fraction
* (1-8*SF) to its own smoothed image and a fraction SF to each of the three
* other smoothed pixels, therefore a total fraction (1-5*SF)/4 to the final
* output. The four corner-adjacent neighbor pixels contribute a fraction
* SF to just one smoothed pixel, or SF/4 to the final output; while the
* eight edge-adjacent neighbors contribute SF to each of two smoothed
* pixels, or SF/2 overall. In order to use integer arithmetic, these
* factors are scaled by 2^16 = 65536.
* Also recall that SF = smoothing_factor / 1024.
*/
int memberscale = 16384 - m_cinfo.m_smoothing_factor * 80; /* scaled (1-5*SF)/4 */
int neighscale = m_cinfo.m_smoothing_factor * 16; /* scaled SF/4 */
int inrow = 0;
int outrow = 0;
while (inrow < m_cinfo.m_max_v_samp_factor)
{
int outIndex = 0;
int inIndex0 = 0;
int inIndex1 = 0;
int aboveIndex = 0;
int belowIndex = 0;
/* Special case for first column: pretend column -1 is same as column 0 */
int membersum = input_data[startInputRow + inrow][inIndex0] +
input_data[startInputRow + inrow][inIndex0 + 1] +
input_data[startInputRow + inrow + 1][inIndex1] +
input_data[startInputRow + inrow + 1][inIndex1 + 1];
int neighsum = input_data[startInputRow + inrow - 1][aboveIndex] +
input_data[startInputRow + inrow - 1][aboveIndex + 1] +
input_data[startInputRow + inrow + 2][belowIndex] +
input_data[startInputRow + inrow + 2][belowIndex + 1] +
input_data[startInputRow + inrow][inIndex0] +
input_data[startInputRow + inrow][inIndex0 + 2] +
input_data[startInputRow + inrow + 1][inIndex1] +
input_data[startInputRow + inrow + 1][inIndex1 + 2];
neighsum += neighsum;
neighsum += input_data[startInputRow + inrow - 1][aboveIndex] +
input_data[startInputRow + inrow - 1][aboveIndex + 2] +
input_data[startInputRow + inrow + 2][belowIndex] +
input_data[startInputRow + inrow + 2][belowIndex + 2];
membersum = membersum * memberscale + neighsum * neighscale;
output_data[startOutRow + outrow][outIndex] = (byte)((membersum + 32768) >> 16);
outIndex++;
inIndex0 += 2;
inIndex1 += 2;
aboveIndex += 2;
belowIndex += 2;
for (int colctr = output_cols - 2; colctr > 0; colctr--)
{
/* sum of pixels directly mapped to this output element */
membersum = input_data[startInputRow + inrow][inIndex0] +
input_data[startInputRow + inrow][inIndex0 + 1] +
input_data[startInputRow + inrow + 1][inIndex1] +
input_data[startInputRow + inrow + 1][inIndex1 + 1];
/* sum of edge-neighbor pixels */
neighsum = input_data[startInputRow + inrow - 1][aboveIndex] +
input_data[startInputRow + inrow - 1][aboveIndex + 1] +
input_data[startInputRow + inrow + 2][belowIndex] +
input_data[startInputRow + inrow + 2][belowIndex + 1] +
input_data[startInputRow + inrow][inIndex0 - 1] +
input_data[startInputRow + inrow][inIndex0 + 2] +
input_data[startInputRow + inrow + 1][inIndex1 - 1] +
input_data[startInputRow + inrow + 1][inIndex1 + 2];
/* The edge-neighbors count twice as much as corner-neighbors */
neighsum += neighsum;
/* Add in the corner-neighbors */
neighsum += input_data[startInputRow + inrow - 1][aboveIndex - 1] +
input_data[startInputRow + inrow - 1][aboveIndex + 2] +
input_data[startInputRow + inrow + 2][belowIndex - 1] +
input_data[startInputRow + inrow + 2][belowIndex + 2];
/* form final output scaled up by 2^16 */
membersum = membersum * memberscale + neighsum * neighscale;
/* round, descale and output it */
output_data[startOutRow + outrow][outIndex] = (byte)((membersum + 32768) >> 16);
outIndex++;
inIndex0 += 2;
inIndex1 += 2;
aboveIndex += 2;
belowIndex += 2;
}
/* Special case for last column */
membersum = input_data[startInputRow + inrow][inIndex0] +
input_data[startInputRow + inrow][inIndex0 + 1] +
input_data[startInputRow + inrow + 1][inIndex1] +
input_data[startInputRow + inrow + 1][inIndex1 + 1];
neighsum = input_data[startInputRow + inrow - 1][aboveIndex] +
input_data[startInputRow + inrow - 1][aboveIndex + 1] +
input_data[startInputRow + inrow + 2][belowIndex] +
input_data[startInputRow + inrow + 2][belowIndex + 1] +
input_data[startInputRow + inrow][inIndex0 - 1] +
input_data[startInputRow + inrow][inIndex0 + 1] +
input_data[startInputRow + inrow + 1][inIndex1 - 1] +
input_data[startInputRow + inrow + 1][inIndex1 + 1];
neighsum += neighsum;
neighsum += input_data[startInputRow + inrow - 1][aboveIndex - 1] +
input_data[startInputRow + inrow - 1][aboveIndex + 1] +
input_data[startInputRow + inrow + 2][belowIndex - 1] +
input_data[startInputRow + inrow + 2][belowIndex + 1];
membersum = membersum * memberscale + neighsum * neighscale;
output_data[startOutRow + outrow][outIndex] = (byte)((membersum + 32768) >> 16);
inrow += 2;
outrow++;
}
}