tightvnc/viewer-core/TightDecoder.cpp
/*
 *-- The "gradient" filter pre-processes pixel data with a simple algorithm
 * which converts each color component to a difference between a "predicted"
 * intensity and the actual intensity. Such a technique does not affect
 * uncompressed data size, but helps to compress photo-like images better. 
 * Pseudo-code for converting intensities to differences is the following:
 *
 *   P[i,j] := V[i-1,j] + V[i,j-1] - V[i-1,j-1];
 *   if (P[i,j] < 0) then P[i,j] := 0;
 *   if (P[i,j] > MAX) then P[i,j] := MAX;
 *   D[i,j] := V[i,j] - P[i,j];
 *
 * Here V[i,j] is the intensity of a color component for a pixel at
 * coordinates (i,j). MAX is the maximum value of intensity for a color
 * component.
 */
The "gradient" filter pre-processes pixel data with a simple algorithm
which converts each color component to a difference between a "predicted"
intensity and the actual intensity. Such a technique does not affect
uncompressed data size, but helps to compress photo-like images better.
Pseudo-code for converting intensities to differences is the following.



Here V[i,j] is the intensity of a color component for a pixel at
coordinates (i,j). MAX is the maximum value of intensity for a color
component.
The " gradient " filter pre - processes pixel data with a simple algorithm which converts each color component to a difference between a " predicted " intensity and the actual intensity . Such a technique does not affect uncompressed data size but helps to compress photo - like images better . Pseudo - code for converting intensities to differences is the following . Here V [ i j ] is the intensity of a color component for a pixel at coordinates ( i j ) . MAX is the maximum value of intensity for a color component .
void TightDecoder::drawGradient(FrameBuffer *fb,
                                const vector<UINT8> &pixels,
                                const Rect *dstRect)
{
  typedef vector<UINT16> RowType;
  size_t opRowLength = dstRect->getWidth() * 3 + 3;
  vector<RowType> opRows(2);
  opRows[0].resize(opRowLength);
  opRows[1].resize(opRowLength);
  memset(&opRows[0].front(), 0, opRowLength * sizeof(UINT16));
  memset(&opRows[1].front(), 0, opRowLength * sizeof(UINT16));
  PixelFormat pxFormat = fb->getPixelFormat();
  int fbBytesPerPixel = fb->getBytesPerPixel();
  int bytesPerCPixel = fbBytesPerPixel;
  if (m_isCPixel) {
    bytesPerCPixel = 3;
  }
  int opRowIndex = 0;
  UINT16 max[3] = {pxFormat.redMax, pxFormat.greenMax, pxFormat.blueMax};
  UINT16 shift[3] = {pxFormat.redShift, pxFormat.greenShift, pxFormat.blueShift};
  size_t pixelOffset = 0;
  for (int i = 0; i < dstRect->getHeight(); ++i) {
    RowType &thisRow = opRows[opRowIndex];
    RowType &prevRow = opRows[opRowIndex = (opRowIndex + 1) % 2];
    for (size_t j = 3; j < opRowLength; j += 3, pixelOffset += bytesPerCPixel) {
      UINT8 rawColor[3];
      fillRawComponents(&pxFormat, rawColor, pixels, pixelOffset);
      UINT32 color = 0;
      for (int index = 0; index < 3; index++) {
        INT32 d = prevRow[j + index] +      
                  thisRow[j + index - 3] -  
                  prevRow[j + index - 3];   
        UINT16 converted = d < 0 ? 0 : d > max[index] ? max[index] : d;
        thisRow[j + index] = (converted + rawColor[index]) & max[index];
        color |= (thisRow[j + index] & max[index]) << shift[index];
      }
      void *pixelPtr = fb->getBufferPtr(static_cast<int>(dstRect->left + j/3 - 1),
                                        dstRect->top + i);
      memcpy(pixelPtr, &color, fbBytesPerPixel);
    }
  }
}
void TightDecoder :: drawGradient ( FrameBuffer * fb , const vector < UINT8 > & pixels , const Rect * dstRect ) { typedef vector < UINT16 > RowType ; size_t opRowLength = dstRect -> getWidth ( ) * 3 + 3 ; vector < RowType > opRows ( 2 ) ; opRows [ 0 ] . resize ( opRowLength ) ; opRows [ 1 ] . resize ( opRowLength ) ; memset ( & opRows [ 0 ] . front ( ) , 0 , opRowLength * sizeof ( UINT16 ) ) ; memset ( & opRows [ 1 ] . front ( ) , 0 , opRowLength * sizeof ( UINT16 ) ) ; PixelFormat pxFormat = fb -> getPixelFormat ( ) ; int fbBytesPerPixel = fb -> getBytesPerPixel ( ) ; int bytesPerCPixel = fbBytesPerPixel ; if ( m_isCPixel ) { bytesPerCPixel = 3 ; } int opRowIndex = 0 ; UINT16 max [ 3 ] = { pxFormat . redMax , pxFormat . greenMax , pxFormat . blueMax } ; UINT16 shift [ 3 ] = { pxFormat . redShift , pxFormat . greenShift , pxFormat . blueShift } ; size_t pixelOffset = 0 ; for ( int i = 0 ; i < dstRect -> getHeight ( ) ; ++ i ) { RowType & thisRow = opRows [ opRowIndex ] ; RowType & prevRow = opRows [ opRowIndex = ( opRowIndex + 1 ) % 2 ] ; for ( size_t j = 3 ; j < opRowLength ; j += 3 , pixelOffset += bytesPerCPixel ) { UINT8 rawColor [ 3 ] ; fillRawComponents ( & pxFormat , rawColor , pixels , pixelOffset ) ; UINT32 color = 0 ; for ( int index = 0 ; index < 3 ; index ++ ) { INT32 d = prevRow [ j + index ] + thisRow [ j + index - 3 ] - prevRow [ j + index - 3 ] ; UINT16 converted = d < 0 ? 0 : d > max [ index ] ? max [ index ] : d ; thisRow [ j + index ] = ( converted + rawColor [ index ] ) & max [ index ] ; color |= ( thisRow [ j + index ] & max [ index ] ) << shift [ index ] ; } void * pixelPtr = fb -> getBufferPtr ( static_cast < int > ( dstRect -> left + j / 3 - 1 ) , dstRect -> top + i ) ; memcpy ( pixelPtr , & color , fbBytesPerPixel ) ; } } }
The "gradient" filter pre-processes pixel data with a simple algorithm
 which converts each color component to a difference between a "predicted"
 intensity and the actual intensity.
The " gradient " filter pre - processes pixel data with a simple algorithm which converts each color component to a difference between a " predicted " intensity and the actual intensity .
// exchange thisRow and prevRow: // "upper" pixel (from prev row) // prev pixel // "diagonal" prev pixel