jcdctmgr.c
/** Prevents visible ringing artifacts near hard edges on white backgrounds.

  1. JPEG can encode samples with higher values than it's possible to display (higher than 255 in RGB),
     and the decoder will always clamp values to 0-255. To encode 255 you can use any value >= 255,
     and distortions of the out-of-range values won't be visible as long as they decode to anything >= 255.

  2. From DCT perspective pixels in a block are a waveform. Hard edges form square waves (bad).
     Edges with white are similar to waveform clipping, and anti-clipping algorithms can turn square waves
     into softer ones that compress better.

 */
Prevents visible ringing artifacts near hard edges on white backgrounds.
1. JPEG can encode samples with higher values than it's possible to display (higher than 255 in RGB),
and the decoder will always clamp values to 0-255. To encode 255 you can use any value >= 255,
and distortions of the out-of-range values won't be visible as long as they decode to anything >= 255.

2. From DCT perspective pixels in a block are a waveform. Hard edges form square waves (bad).
Edges with white are similar to waveform clipping, and anti-clipping algorithms can turn square waves
into softer ones that compress better.
Prevents visible ringing artifacts near hard edges on white backgrounds . 1 . JPEG can encode samples with higher values than it ' s possible to display ( higher than 255 in RGB ) and the decoder will always clamp values to 0 - 255 . To encode 255 you can use any value > = 255 and distortions of the out - of - range values won ' t be visible as long as they decode to anything > = 255 . 2 . From DCT perspective pixels in a block are a waveform . Hard edges form square waves ( bad ) . Edges with white are similar to waveform clipping and anti - clipping algorithms can turn square waves into softer ones that compress better .
METHODDEF(void)
preprocess_deringing(DCTELEM *data, const JQUANT_TBL *quantization_table)
{
  const DCTELEM maxsample = 255 - CENTERJSAMPLE;
  const int size = DCTSIZE * DCTSIZE;
  int sum = 0;
  int maxsample_count = 0;
  int i;
  DCTELEM maxovershoot;
  int n;
  for(i=0; i < size; i++) {
    sum += data[i];
    if (data[i] >= maxsample) {
      maxsample_count++;
    }
  }
  if (!maxsample_count || maxsample_count == size) {
    return;
  }
  maxovershoot = maxsample + MIN(MIN(31, 2*quantization_table->quantval[0]), (maxsample * size - sum) / maxsample_count);
  n = 0;
  do {
    int start, end, length;
    DCTELEM f1, f2, l1, l2, fslope, lslope;
    float step, position;
    if (data[jpeg_natural_order[n]] < maxsample) {
      n++;
      continue;
    }
    start = n;
    while(++n < size && data[jpeg_natural_order[n]] >= maxsample) {}
    end = n;
    f1 = data[jpeg_natural_order[start >= 1 ? start-1 : 0]];
    f2 = data[jpeg_natural_order[start >= 2 ? start-2 : 0]];
    l1 = data[jpeg_natural_order[end < size-1 ? end : size-1]];
    l2 = data[jpeg_natural_order[end < size-2 ? end+1 : size-1]];
    fslope = MAX(f1-f2, maxsample-f1);
    lslope = MAX(l1-l2, maxsample-l1);
    if (start == 0) {
      fslope = lslope;
    }
    if (end == size) {
      lslope = fslope;
    }
    length = end - start;
    step = 1.f/(float)(length + 1);
    position = step;
    for(i = start; i < end; i++, position += step) {
      DCTELEM tmp = ceilf(catmull_rom(maxsample - fslope, maxsample, maxsample, maxsample - lslope, position, length));
      data[jpeg_natural_order[i]] = MIN(tmp, maxovershoot);
    }
    n++;
  }
  while(n < size);
}
METHODDEF ( void ) preprocess_deringing ( DCTELEM * data , const JQUANT_TBL * quantization_table ) { const DCTELEM maxsample = 255 - CENTERJSAMPLE ; const int size = DCTSIZE * DCTSIZE ; int sum = 0 ; int maxsample_count = 0 ; int i ; DCTELEM maxovershoot ; int n ; for ( i = 0 ; i < size ; i ++ ) { sum += data [ i ] ; if ( data [ i ] >= maxsample ) { maxsample_count ++ ; } } if ( ! maxsample_count || maxsample_count == size ) { return ; } maxovershoot = maxsample + MIN ( MIN ( 31 , 2 * quantization_table -> quantval [ 0 ] ) , ( maxsample * size - sum ) / maxsample_count ) ; n = 0 ; do { int start , end , length ; DCTELEM f1 , f2 , l1 , l2 , fslope , lslope ; float step , position ; if ( data [ jpeg_natural_order [ n ] ] < maxsample ) { n ++ ; continue ; } start = n ; while ( ++ n < size && data [ jpeg_natural_order [ n ] ] >= maxsample ) { } end = n ; f1 = data [ jpeg_natural_order [ start >= 1 ? start - 1 : 0 ] ] ; f2 = data [ jpeg_natural_order [ start >= 2 ? start - 2 : 0 ] ] ; l1 = data [ jpeg_natural_order [ end < size - 1 ? end : size - 1 ] ] ; l2 = data [ jpeg_natural_order [ end < size - 2 ? end + 1 : size - 1 ] ] ; fslope = MAX ( f1 - f2 , maxsample - f1 ) ; lslope = MAX ( l1 - l2 , maxsample - l1 ) ; if ( start == 0 ) { fslope = lslope ; } if ( end == size ) { lslope = fslope ; } length = end - start ; step = 1.f / ( float ) ( length + 1 ) ; position = step ; for ( i = start ; i < end ; i ++ , position += step ) { DCTELEM tmp = ceilf ( catmull_rom ( maxsample - fslope , maxsample , maxsample , maxsample - lslope , position , length ) ) ; data [ jpeg_natural_order [ i ] ] = MIN ( tmp , maxovershoot ) ; } n ++ ; } while ( n < size ) ; }
Prevents visible ringing artifacts near hard edges on white backgrounds.
Prevents visible ringing artifacts near hard edges on white backgrounds .
/* Decoders don't handle overflow of DC very well, so calculate
     maximum overflow that is safe to do without increasing DC out of range */ /* If nothing reaches max value there's nothing to overshoot
     and if the block is completely flat, it's already the best case. */ /* Too much overshoot is not good: increased amplitude will cost bits, and the cost is proportional to quantization (here using DC quant as a rough guide). */ /* Pixels are traversed in zig-zag order to process them as a line */ /* Find a run of maxsample pixels. Start is the first pixel inside the range, end the first pixel outside. */ /* the run will be replaced with a catmull-rom interpolation of values from the edges */ /* Find suitable upward slope from pixels around edges of the run.
       Just feeding nearby pixels as catmull rom points isn't good enough,
       as slope with one sample before the edge may have been flattened by clipping,
       and slope of two samples before the edge could be downward. */ /* if slope at the start/end is unknown, just make the curve symmetric */ /* The curve fits better if first and last pixel is omitted */