QgsRasterBlock* QgsSingleBandColorDataRenderer::block( int bandNo, QgsRectangle  const & extent, int width, int height, QgsRasterBlockFeedback* feedback )
{
  Q_UNUSED( bandNo );

  QgsRasterBlock *outputBlock = new QgsRasterBlock();
  if ( !mInput )
  {
    return outputBlock;
  }

  QgsRasterBlock *inputBlock = mInput->block( mBand, extent, width, height, feedback );
  if ( !inputBlock || inputBlock->isEmpty() )
  {
    QgsDebugMsg( "No raster data!" );
    delete inputBlock;
    return outputBlock;
  }

  bool hasTransparency = usesTransparency();
  if ( !hasTransparency )
  {
    // Nothing to do, just retype if necessary
    inputBlock->convert( Qgis::ARGB32_Premultiplied );
    delete outputBlock;
    return inputBlock;
  }

  if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) )
  {
    delete inputBlock;
    return outputBlock;
  }

  // make sure input is also premultiplied!
  inputBlock->convert( Qgis::ARGB32_Premultiplied );

  QRgb* inputBits = ( QRgb* )inputBlock->bits();
  QRgb* outputBits = ( QRgb* )outputBlock->bits();
  for ( qgssize i = 0; i < ( qgssize )width*height; i++ )
  {
    QRgb c = inputBits[i];
    outputBits[i] = qRgba( mOpacity * qRed( c ), mOpacity * qGreen( c ), mOpacity * qBlue( c ), mOpacity * qAlpha( c ) );
  }

  delete inputBlock;
  return outputBlock;
}
QgsRasterBlock* QgsSingleBandColorDataRenderer::block( int bandNo, QgsRectangle  const & extent, int width, int height )
{
  Q_UNUSED( bandNo );

  QgsRasterBlock *outputBlock = new QgsRasterBlock();
  if ( !mInput )
  {
    return outputBlock;
  }

  QgsRasterBlock *inputBlock = mInput->block( mBand, extent, width, height );
  if ( !inputBlock || inputBlock->isEmpty() )
  {
    QgsDebugMsg( "No raster data!" );
    delete inputBlock;
    return outputBlock;
  }

  bool hasTransparency = usesTransparency();
  if ( !hasTransparency )
  {
    // Nothing to do, just retype if necessary
    inputBlock->convert( QgsRasterBlock::ARGB32_Premultiplied );
    delete outputBlock;
    return inputBlock;
  }

  if ( !outputBlock->reset( QgsRasterBlock::ARGB32_Premultiplied, width, height ) )
  {
    delete inputBlock;
    return outputBlock;
  }

  for ( size_t i = 0; i < ( size_t )width*height; i++ )
  {
    QRgb pixelColor;
    double alpha = 255.0;
    QRgb c = inputBlock->color( i );
    alpha = qAlpha( c );
    pixelColor = qRgba( mOpacity * qRed( c ), mOpacity * qGreen( c ), mOpacity * qBlue( c ), mOpacity * alpha );
    outputBlock->setColor( i,  pixelColor );
  }

  delete inputBlock;
  return outputBlock;
}
Beispiel #3
0
QgsRasterBlock* QgsSingleBandPseudoColorRenderer::block( int bandNo, QgsRectangle  const & extent, int width, int height, QgsRasterBlockFeedback* feedback )
{
  Q_UNUSED( bandNo );

  QgsRasterBlock *outputBlock = new QgsRasterBlock();
  if ( !mInput || !mShader )
  {
    return outputBlock;
  }


  QgsRasterBlock *inputBlock = mInput->block( mBand, extent, width, height, feedback );
  if ( !inputBlock || inputBlock->isEmpty() )
  {
    QgsDebugMsg( "No raster data!" );
    delete inputBlock;
    return outputBlock;
  }

  //rendering is faster without considering user-defined transparency
  bool hasTransparency = usesTransparency();

  QgsRasterBlock *alphaBlock = nullptr;
  if ( mAlphaBand > 0 && mAlphaBand != mBand )
  {
    alphaBlock = mInput->block( mAlphaBand, extent, width, height, feedback );
    if ( !alphaBlock || alphaBlock->isEmpty() )
    {
      delete inputBlock;
      delete alphaBlock;
      return outputBlock;
    }
  }
  else if ( mAlphaBand == mBand )
  {
    alphaBlock = inputBlock;
  }

  if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) )
  {
    delete inputBlock;
    delete alphaBlock;
    return outputBlock;
  }

  QRgb myDefaultColor = NODATA_COLOR;

  for ( qgssize i = 0; i < ( qgssize )width*height; i++ )
  {
    if ( inputBlock->isNoData( i ) )
    {
      outputBlock->setColor( i, myDefaultColor );
      continue;
    }
    double val = inputBlock->value( i );
    int red, green, blue, alpha;
    if ( !mShader->shade( val, &red, &green, &blue, &alpha ) )
    {
      outputBlock->setColor( i, myDefaultColor );
      continue;
    }

    if ( alpha < 255 )
    {
      // Working with premultiplied colors, so multiply values by alpha
      red *= ( alpha / 255.0 );
      blue *= ( alpha / 255.0 );
      green *= ( alpha / 255.0 );
    }

    if ( !hasTransparency )
    {
      outputBlock->setColor( i, qRgba( red, green, blue, alpha ) );
    }
    else
    {
      //opacity
      double currentOpacity = mOpacity;
      if ( mRasterTransparency )
      {
        currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0;
      }
      if ( mAlphaBand > 0 )
      {
        currentOpacity *= alphaBlock->value( i ) / 255.0;
      }

      outputBlock->setColor( i, qRgba( currentOpacity * red, currentOpacity * green, currentOpacity * blue, currentOpacity * alpha ) );
    }
  }

  delete inputBlock;
  if ( mAlphaBand > 0 && mBand != mAlphaBand )
  {
    delete alphaBlock;
  }

  return outputBlock;
}
QgsRasterBlock * QgsPalettedRasterRenderer::block( int bandNo, QgsRectangle  const & extent, int width, int height )
{
    QgsRasterBlock *outputBlock = new QgsRasterBlock();
    if ( !mInput )
    {
        return outputBlock;
    }

    QgsRasterBlock *inputBlock = mInput->block( bandNo, extent, width, height );

    if ( !inputBlock || inputBlock->isEmpty() )
    {
        QgsDebugMsg( "No raster data!" );
        delete inputBlock;
        return outputBlock;
    }

    double currentOpacity = mOpacity;

    //rendering is faster without considering user-defined transparency
    bool hasTransparency = usesTransparency();
    QgsRasterBlock *alphaBlock = 0;

    if ( mAlphaBand > 0 && mAlphaBand != mBand )
    {
        alphaBlock = mInput->block( mAlphaBand, extent, width, height );
        if ( !alphaBlock || alphaBlock->isEmpty() )
        {
            delete inputBlock;
            delete alphaBlock;
            return outputBlock;
        }
    }
    else if ( mAlphaBand == mBand )
    {
        alphaBlock = inputBlock;
    }

    if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) )
    {
        delete inputBlock;
        delete alphaBlock;
        return outputBlock;
    }

    QRgb myDefaultColor = NODATA_COLOR;

    //use direct data access instead of QgsRasterBlock::setValue
    //because of performance
    unsigned int* outputData = ( unsigned int* )( outputBlock->bits() );

    qgssize rasterSize = ( qgssize )width * height;
    for ( qgssize i = 0; i < rasterSize; ++i )
    {
        if ( inputBlock->isNoData( i ) )
        {
            outputData[i] = myDefaultColor;
            continue;
        }
        int val = ( int ) inputBlock->value( i );
        if ( !hasTransparency )
        {
            outputData[i] = mColors[val];
        }
        else
        {
            currentOpacity = mOpacity;
            if ( mRasterTransparency )
            {
                currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0;
            }
            if ( mAlphaBand > 0 )
            {
                currentOpacity *=  alphaBlock->value( i ) / 255.0;
            }
            QColor currentColor = QColor( mColors[val] );
            outputData[i] = qRgba( currentOpacity * currentColor.red(), currentOpacity * currentColor.green(), currentOpacity * currentColor.blue(), currentOpacity * 255 );
        }
    }

    delete inputBlock;
    if ( mAlphaBand > 0 && mBand != mAlphaBand )
    {
        delete alphaBlock;
    }

    return outputBlock;
}
QgsRasterBlock *QgsPalettedRasterRenderer::block( int bandNo, QgsRectangle  const &extent, int width, int height, QgsRasterBlockFeedback *feedback )
{
  std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock() );
  if ( !mInput || mClassData.isEmpty() )
  {
    return outputBlock.release();
  }

  std::shared_ptr< QgsRasterBlock > inputBlock( mInput->block( bandNo, extent, width, height, feedback ) );

  if ( !inputBlock || inputBlock->isEmpty() )
  {
    QgsDebugMsg( QStringLiteral( "No raster data!" ) );
    return outputBlock.release();
  }

  double currentOpacity = mOpacity;

  //rendering is faster without considering user-defined transparency
  bool hasTransparency = usesTransparency();

  std::shared_ptr< QgsRasterBlock > alphaBlock;

  if ( mAlphaBand > 0 && mAlphaBand != mBand )
  {
    alphaBlock.reset( mInput->block( mAlphaBand, extent, width, height, feedback ) );
    if ( !alphaBlock || alphaBlock->isEmpty() )
    {
      return outputBlock.release();
    }
  }
  else if ( mAlphaBand == mBand )
  {
    alphaBlock = inputBlock;
  }

  if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) )
  {
    return outputBlock.release();
  }

  QRgb myDefaultColor = NODATA_COLOR;

  //use direct data access instead of QgsRasterBlock::setValue
  //because of performance
  unsigned int *outputData = ( unsigned int * )( outputBlock->bits() );

  qgssize rasterSize = ( qgssize )width * height;
  bool isNoData = false;
  for ( qgssize i = 0; i < rasterSize; ++i )
  {
    const double value = inputBlock->valueAndNoData( i, isNoData );
    if ( isNoData )
    {
      outputData[i] = myDefaultColor;
      continue;
    }
    int val = static_cast< int >( value );
    if ( !mColors.contains( val ) )
    {
      outputData[i] = myDefaultColor;
      continue;
    }

    if ( !hasTransparency )
    {
      outputData[i] = mColors.value( val );
    }
    else
    {
      currentOpacity = mOpacity;
      if ( mRasterTransparency )
      {
        currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0;
      }
      if ( mAlphaBand > 0 )
      {
        currentOpacity *= alphaBlock->value( i ) / 255.0;
      }

      QRgb c = mColors.value( val );
      outputData[i] = qRgba( currentOpacity * qRed( c ), currentOpacity * qGreen( c ), currentOpacity * qBlue( c ), currentOpacity * qAlpha( c ) );
    }
  }

  return outputBlock.release();
}
Beispiel #6
0
void * QgsMultiBandColorRenderer::readBlock( int bandNo, QgsRectangle  const & extent, int width, int height )
{
  Q_UNUSED( bandNo );
  if ( !mInput )
  {
    return 0;
  }

  //In some (common) cases, we can simplify the drawing loop considerably and save render time
  bool fastDraw = ( !usesTransparency()
                    && mRedBand > 0 && mGreenBand > 0 && mBlueBand > 0
                    && mAlphaBand < 1 && !mRedContrastEnhancement && !mGreenContrastEnhancement && !mBlueContrastEnhancement
                    && !mInvertColor );

  QgsRasterInterface::DataType redType = QgsRasterInterface::UnknownDataType;

  if ( mRedBand > 0 )
  {
    redType = ( QgsRasterInterface::DataType )mInput->dataType( mRedBand );
  }
  QgsRasterInterface::DataType greenType = QgsRasterInterface::UnknownDataType;
  if ( mGreenBand > 0 )
  {
    greenType = ( QgsRasterInterface::DataType )mInput->dataType( mGreenBand );
  }
  QgsRasterInterface::DataType blueType = QgsRasterInterface::UnknownDataType;
  if ( mBlueBand > 0 )
  {
    blueType = ( QgsRasterInterface::DataType )mInput->dataType( mBlueBand );
  }
  QgsRasterInterface::DataType transparencyType = QgsRasterInterface::UnknownDataType;
  if ( mAlphaBand > 0 )
  {
    transparencyType = ( QgsRasterInterface::DataType )mInput->dataType( mAlphaBand );
  }

  QSet<int> bands;
  if ( mRedBand > 0 )
  {
    bands << mRedBand;
  }
  if ( mGreenBand > 0 )
  {
    bands << mGreenBand;
  }
  if ( mBlueBand > 0 )
  {
    bands << mBlueBand;
  }
  if ( bands.size() < 1 )
  {
    return 0; //no need to draw anything if no band is set
  }

  if ( mAlphaBand > 0 )
  {
    bands << mAlphaBand;
  }

  QMap<int, void*> bandData;
  void* defaultPointer = 0;
  QSet<int>::const_iterator bandIt = bands.constBegin();
  for ( ; bandIt != bands.constEnd(); ++bandIt )
  {
    bandData.insert( *bandIt, defaultPointer );
  }

  void* redData = 0;
  void* greenData = 0;
  void* blueData = 0;
  void* alphaData = 0;

  bandIt = bands.constBegin();
  for ( ; bandIt != bands.constEnd(); ++bandIt )
  {
    bandData[*bandIt] =  mInput->block( *bandIt, extent, width, height );
    if ( !bandData[*bandIt] )
    {
      // We should free the alloced mem from block().
      QgsDebugMsg( "No input band" );
      bandIt--;
      for ( ; bandIt != bands.constBegin(); bandIt-- )
      {
        VSIFree( bandData[*bandIt] );
      }
      return 0;
    }
  }

  if ( mRedBand > 0 )
  {
    redData = bandData[mRedBand];
  }
  if ( mGreenBand > 0 )
  {
    greenData = bandData[mGreenBand];
  }
  if ( mBlueBand > 0 )
  {
    blueData = bandData[mBlueBand];
  }
  if ( mAlphaBand > 0 )
  {
    alphaData = bandData[mAlphaBand];
  }

  QImage img( width, height, QImage::Format_ARGB32_Premultiplied );
  if ( img.isNull() )
  {
    QgsDebugMsg( "Could not create QImage" );
    bandIt = bands.constBegin();
    for ( ; bandIt != bands.constEnd(); ++bandIt )
    {
      VSIFree( bandData[*bandIt] );
    }
    return 0;
  }

  QRgb* imageScanLine = 0;
  int currentRasterPos = 0;
  int redVal = 0;
  int greenVal = 0;
  int blueVal = 0;
  QRgb defaultColor = qRgba( 255, 255, 255, 0 );
  double currentOpacity = mOpacity; //opacity (between 0 and 1)

  for ( int i = 0; i < height; ++i )
  {
    imageScanLine = ( QRgb* )( img.scanLine( i ) );
    for ( int j = 0; j < width; ++j )
    {
      if ( fastDraw ) //fast rendering if no transparency, stretching, color inversion, etc.
      {
        redVal = readValue( redData, redType, currentRasterPos );
        greenVal = readValue( greenData, greenType, currentRasterPos );
        blueVal = readValue( blueData, blueType, currentRasterPos );
        if ( mInput->isNoDataValue( mRedBand, redVal ) ||
             mInput->isNoDataValue( mGreenBand, greenVal ) ||
             mInput->isNoDataValue( mBlueBand, blueVal ) )
        {
          imageScanLine[j] = defaultColor;
        }
        else
        {
          imageScanLine[j] = qRgba( redVal, greenVal, blueVal, 255 );
        }

        ++currentRasterPos;
        continue;
      }

      bool isNoData = false;
      if ( mRedBand > 0 )
      {
        redVal = readValue( redData, redType, currentRasterPos );
        if ( mInput->isNoDataValue( mRedBand, redVal ) ) isNoData = true;
      }
      if ( mGreenBand > 0 )
      {
        greenVal = readValue( greenData, greenType, currentRasterPos );
        if ( mInput->isNoDataValue( mGreenBand, greenVal ) ) isNoData = true;
      }
      if ( mBlueBand > 0 )
      {
        blueVal = readValue( blueData, blueType, currentRasterPos );
        if ( mInput->isNoDataValue( mBlueBand, blueVal ) ) isNoData = true;
      }
      if ( isNoData )
      {
        imageScanLine[j] = defaultColor;
        ++currentRasterPos;
        continue;
      }

      //apply default color if red, green or blue not in displayable range
      if (( mRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( redVal ) )
          || ( mGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( redVal ) )
          || ( mBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( redVal ) ) )
      {
        imageScanLine[j] = defaultColor;
        ++currentRasterPos;
        continue;
      }

      //stretch color values
      if ( mRedContrastEnhancement )
      {
        redVal = mRedContrastEnhancement->enhanceContrast( redVal );
      }
      if ( mGreenContrastEnhancement )
      {
        greenVal = mGreenContrastEnhancement->enhanceContrast( greenVal );
      }
      if ( mBlueContrastEnhancement )
      {
        blueVal = mBlueContrastEnhancement->enhanceContrast( blueVal );
      }

      if ( mInvertColor )
      {
        redVal = 255 - redVal;
        greenVal = 255 - greenVal;
        blueVal = 255 - blueVal;
      }

      //opacity
      currentOpacity = mOpacity;
      if ( mRasterTransparency )
      {
        currentOpacity = mRasterTransparency->alphaValue( redVal, greenVal, blueVal, mOpacity * 255 ) / 255.0;
      }
      if ( mAlphaBand > 0 )
      {
        currentOpacity *= ( readValue( alphaData, transparencyType, currentRasterPos ) / 255.0 );
      }

      if ( doubleNear( currentOpacity, 1.0 ) )
      {
        imageScanLine[j] = qRgba( redVal, greenVal, blueVal, 255 );
      }
      else
      {
        imageScanLine[j] = qRgba( currentOpacity * redVal, currentOpacity * greenVal, currentOpacity * blueVal, currentOpacity * 255 );
      }

      ++currentRasterPos;
    }
  }

  bandIt = bands.constBegin();
  for ( ; bandIt != bands.constEnd(); ++bandIt )
  {
    VSIFree( bandData[*bandIt] );
  }

  void * data = VSIMalloc( img.byteCount() );
  if ( ! data )
  {
    QgsDebugMsg( QString( "Couldn't allocate output data memory of % bytes" ).arg( img.byteCount() ) );
    return 0;
  }
  return memcpy( data, img.bits(), img.byteCount() );
}
QgsRasterBlock *QgsMultiBandColorRenderer::block( int bandNo, QgsRectangle  const &extent, int width, int height, QgsRasterBlockFeedback *feedback )
{
  Q_UNUSED( bandNo );
  std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock() );
  if ( !mInput )
  {
    return outputBlock.release();
  }

  //In some (common) cases, we can simplify the drawing loop considerably and save render time
  bool fastDraw = ( !usesTransparency()
                    && mRedBand > 0 && mGreenBand > 0 && mBlueBand > 0
                    && mAlphaBand < 1 );

  QSet<int> bands;
  if ( mRedBand > 0 )
  {
    bands << mRedBand;
  }
  if ( mGreenBand > 0 )
  {
    bands << mGreenBand;
  }
  if ( mBlueBand > 0 )
  {
    bands << mBlueBand;
  }
  if ( bands.empty() )
  {
    // no need to draw anything if no band is set
    // TODO:: we should probably return default color block
    return outputBlock.release();
  }

  if ( mAlphaBand > 0 )
  {
    bands << mAlphaBand;
  }

  QMap<int, QgsRasterBlock *> bandBlocks;
  QgsRasterBlock *defaultPointer = nullptr;
  QSet<int>::const_iterator bandIt = bands.constBegin();
  for ( ; bandIt != bands.constEnd(); ++bandIt )
  {
    bandBlocks.insert( *bandIt, defaultPointer );
  }

  QgsRasterBlock *redBlock = nullptr;
  QgsRasterBlock *greenBlock = nullptr;
  QgsRasterBlock *blueBlock = nullptr;
  QgsRasterBlock *alphaBlock = nullptr;

  bandIt = bands.constBegin();
  for ( ; bandIt != bands.constEnd(); ++bandIt )
  {
    bandBlocks[*bandIt] = mInput->block( *bandIt, extent, width, height, feedback );
    if ( !bandBlocks[*bandIt] )
    {
      // We should free the alloced mem from block().
      QgsDebugMsg( QStringLiteral( "No input band" ) );
      --bandIt;
      for ( ; bandIt != bands.constBegin(); --bandIt )
      {
        delete bandBlocks[*bandIt];
      }
      return outputBlock.release();
    }
  }

  if ( mRedBand > 0 )
  {
    redBlock = bandBlocks[mRedBand];
  }
  if ( mGreenBand > 0 )
  {
    greenBlock = bandBlocks[mGreenBand];
  }
  if ( mBlueBand > 0 )
  {
    blueBlock = bandBlocks[mBlueBand];
  }
  if ( mAlphaBand > 0 )
  {
    alphaBlock = bandBlocks[mAlphaBand];
  }

  if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) )
  {
    for ( int i = 0; i < bandBlocks.size(); i++ )
    {
      delete bandBlocks.value( i );
    }
    return outputBlock.release();
  }

  QRgb *outputBlockColorData = outputBlock->colorData();

  // faster data access to data for the common case that input data are coming from RGB image with 8-bit bands
  bool hasByteRgb = ( redBlock && greenBlock && blueBlock && redBlock->dataType() == Qgis::Byte && greenBlock->dataType() == Qgis::Byte && blueBlock->dataType() == Qgis::Byte );
  const quint8 *redData = nullptr, *greenData = nullptr, *blueData = nullptr;
  if ( hasByteRgb )
  {
    redData = redBlock->byteData();
    greenData = greenBlock->byteData();
    blueData = blueBlock->byteData();
  }

  QRgb myDefaultColor = NODATA_COLOR;

  if ( fastDraw )
  {
    // By default RGB raster layers have contrast enhancement assigned and normally that requires us to take the slow
    // route that applies the enhancement. However if the algorithm type is "no enhancement" and all input bands are byte-sized,
    // no transform would be applied to the input values and we can take the fast route.
    bool hasEnhancement;
    if ( hasByteRgb )
    {
      hasEnhancement =
        ( mRedContrastEnhancement && mRedContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement ) ||
        ( mGreenContrastEnhancement && mGreenContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement ) ||
        ( mBlueContrastEnhancement && mBlueContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement );
    }
    else
    {
      hasEnhancement = mRedContrastEnhancement || mGreenContrastEnhancement || mBlueContrastEnhancement;
    }
    if ( hasEnhancement )
      fastDraw = false;
  }

  qgssize count = ( qgssize )width * height;
  for ( qgssize i = 0; i < count; i++ )
  {
    if ( fastDraw ) //fast rendering if no transparency, stretching, color inversion, etc.
    {
      if ( redBlock->isNoData( i ) ||
           greenBlock->isNoData( i ) ||
           blueBlock->isNoData( i ) )
      {
        outputBlock->setColor( i, myDefaultColor );
      }
      else
      {
        if ( hasByteRgb )
        {
          outputBlockColorData[i] = qRgb( redData[i], greenData[i], blueData[i] );
        }
        else
        {
          int redVal = static_cast<int>( redBlock->value( i ) );
          int greenVal = static_cast<int>( greenBlock->value( i ) );
          int blueVal = static_cast<int>( blueBlock->value( i ) );
          outputBlockColorData[i] = qRgb( redVal, greenVal, blueVal );
        }
      }
      continue;
    }

    bool isNoData = false;
    double redVal = 0;
    double greenVal = 0;
    double blueVal = 0;
    if ( mRedBand > 0 )
    {
      redVal = redBlock->value( i );
      if ( redBlock->isNoData( i ) ) isNoData = true;
    }
    if ( !isNoData && mGreenBand > 0 )
    {
      greenVal = greenBlock->value( i );
      if ( greenBlock->isNoData( i ) ) isNoData = true;
    }
    if ( !isNoData && mBlueBand > 0 )
    {
      blueVal = blueBlock->value( i );
      if ( blueBlock->isNoData( i ) ) isNoData = true;
    }
    if ( isNoData )
    {
      outputBlock->setColor( i, myDefaultColor );
      continue;
    }

    //apply default color if red, green or blue not in displayable range
    if ( ( mRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( redVal ) )
         || ( mGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( redVal ) )
         || ( mBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( redVal ) ) )
    {
      outputBlock->setColor( i, myDefaultColor );
      continue;
    }

    //stretch color values
    if ( mRedContrastEnhancement )
    {
      redVal = mRedContrastEnhancement->enhanceContrast( redVal );
    }
    if ( mGreenContrastEnhancement )
    {
      greenVal = mGreenContrastEnhancement->enhanceContrast( greenVal );
    }
    if ( mBlueContrastEnhancement )
    {
      blueVal = mBlueContrastEnhancement->enhanceContrast( blueVal );
    }

    //opacity
    double currentOpacity = mOpacity;
    if ( mRasterTransparency )
    {
      currentOpacity = mRasterTransparency->alphaValue( redVal, greenVal, blueVal, mOpacity * 255 ) / 255.0;
    }
    if ( mAlphaBand > 0 )
    {
      currentOpacity *= alphaBlock->value( i ) / 255.0;
    }

    if ( qgsDoubleNear( currentOpacity, 1.0 ) )
    {
      outputBlock->setColor( i, qRgba( redVal, greenVal, blueVal, 255 ) );
    }
    else
    {
      outputBlock->setColor( i, qRgba( currentOpacity * redVal, currentOpacity * greenVal, currentOpacity * blueVal, currentOpacity * 255 ) );
    }
  }

  //delete input blocks
  QMap<int, QgsRasterBlock *>::const_iterator bandDelIt = bandBlocks.constBegin();
  for ( ; bandDelIt != bandBlocks.constEnd(); ++bandDelIt )
  {
    delete bandDelIt.value();
  }

  return outputBlock.release();
}
void QgsSingleBandPseudoColorRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel )
{
  if ( !p || !mProvider || !viewPort || !theQgsMapToPixel || !mShader )
  {
    return;
  }

  double oversamplingX, oversamplingY;
  QgsRasterDataProvider::DataType transparencyType = QgsRasterDataProvider::UnknownDataType;
  if ( mAlphaBand > 0 )
  {
    transparencyType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mAlphaBand );
  }
  startRasterRead( mBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY );
  //Read alpha band if necessary
  if ( mAlphaBand > 0 && mAlphaBand != mBand )
  {
    startRasterRead( mAlphaBand, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY );
  }

  //number of cols/rows in output pixels
  int nCols = 0;
  int nRows = 0;
  //number of raster cols/rows with oversampling
  int nRasterCols = 0;
  int nRasterRows = 0;
  //shift to top left point for the raster part
  int topLeftCol = 0;
  int topLeftRow = 0;
  void* rasterData;
  void* transparencyData = 0;
  double currentOpacity = mOpacity;
  QgsRasterDataProvider::DataType rasterType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mBand );
  int red, green, blue;
  QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );

  //rendering is faster without considering user-defined transparency
  bool hasTransparency = usesTransparency( viewPort->mSrcCRS, viewPort->mDestCRS );

  while ( readNextRasterPart( mBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows,
                              &rasterData, topLeftCol, topLeftRow ) )
  {
    if ( mAlphaBand > 0 && mAlphaBand != mBand )
    {
      readNextRasterPart( mAlphaBand, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows,
                          &transparencyData, topLeftCol, topLeftRow );
    }
    else if ( mAlphaBand == mBand )
    {
      transparencyData = rasterData;
    }

    //create image
    QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32_Premultiplied );
    QRgb* imageScanLine = 0;
    double val = 0;

    int currentRasterPos = 0;
    for ( int i = 0; i < nRasterRows; ++i )
    {
      imageScanLine = ( QRgb* )( img.scanLine( i ) );
      for ( int j = 0; j < nRasterCols; ++j )
      {
        val = readValue( rasterData, rasterType, currentRasterPos );
        if ( !mShader->shade( val, &red, &green, &blue ) )
        {
          imageScanLine[j] = myDefaultColor;
          ++currentRasterPos;
          continue;
        }

        if ( !hasTransparency )
        {
          imageScanLine[j] = qRgba( red, green, blue, 255 );
        }
        else
        {
          //opacity
          currentOpacity = mOpacity;
          if ( mRasterTransparency )
          {
            currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0;
          }
          if ( mAlphaBand > 0 )
          {
            currentOpacity *= ( readValue( transparencyData, transparencyType, currentRasterPos ) / 255.0 );
          }

          imageScanLine[j] = qRgba( currentOpacity * red, currentOpacity * green, currentOpacity * blue, currentOpacity * 255 );
        }
        ++currentRasterPos;
      }
    }

    drawImage( p, viewPort, img, topLeftCol, topLeftRow, nCols, nRows, oversamplingX, oversamplingY );
  }

  stopRasterRead( mBand );
  if ( mAlphaBand > 0 && mAlphaBand != mBand )
  {
    stopRasterRead( mAlphaBand );
  }
}
void * QgsSingleBandPseudoColorRenderer::readBlock( int bandNo, QgsRectangle  const & extent, int width, int height )
{
  Q_UNUSED( bandNo );
  if ( !mInput || !mShader )
  {
    return 0;
  }

  QgsRasterInterface::DataType transparencyType = QgsRasterInterface::UnknownDataType;
  if ( mAlphaBand > 0 )
  {
    transparencyType = ( QgsRasterInterface::DataType )mInput->dataType( mAlphaBand );
  }

  void* transparencyData = 0;
  double currentOpacity = mOpacity;
  QgsRasterInterface::DataType rasterType = ( QgsRasterInterface::DataType )mInput->dataType( mBand );

  void* rasterData = mInput->block( mBand, extent, width, height );

  int red, green, blue;
  QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );

  //rendering is faster without considering user-defined transparency
  bool hasTransparency = usesTransparency();

  if ( mAlphaBand > 0 && mAlphaBand != mBand )
  {
    transparencyData = mInput->block( mAlphaBand, extent, width, height );
  }
  else if ( mAlphaBand == mBand )
  {
    transparencyData = rasterData;
  }

  //create image
  QImage img( width, height, QImage::Format_ARGB32_Premultiplied );
  QRgb* imageScanLine = 0;
  double val = 0;

  int currentRasterPos = 0;
  for ( int i = 0; i < height; ++i )
  {
    imageScanLine = ( QRgb* )( img.scanLine( i ) );
    for ( int j = 0; j < width; ++j )
    {
      val = readValue( rasterData, rasterType, currentRasterPos );
      if ( !mShader->shade( val, &red, &green, &blue ) )
      {
        imageScanLine[j] = myDefaultColor;
        ++currentRasterPos;
        continue;
      }

      if ( !hasTransparency )
      {
        imageScanLine[j] = qRgba( red, green, blue, 255 );
      }
      else
      {
        //opacity
        currentOpacity = mOpacity;
        if ( mRasterTransparency )
        {
          currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0;
        }
        if ( mAlphaBand > 0 )
        {
          currentOpacity *= ( readValue( transparencyData, transparencyType, currentRasterPos ) / 255.0 );
        }

        imageScanLine[j] = qRgba( currentOpacity * red, currentOpacity * green, currentOpacity * blue, currentOpacity * 255 );
      }
      ++currentRasterPos;
    }
  }

  VSIFree( rasterData );

  void * data = VSIMalloc( img.byteCount() );
  return memcpy( data, img.bits(), img.byteCount() );
}
void QgsMultiBandColorRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel )
{
  if ( !p || !mProvider || !viewPort || !theQgsMapToPixel )
  {
    return;
  }

  //In some (common) cases, we can simplify the drawing loop considerably and save render time
  bool fastDraw = (
                    !usesTransparency( viewPort->mSrcCRS, viewPort->mDestCRS )
                    && mRedBand > 0 && mGreenBand > 0 && mBlueBand > 0
                    && mAlphaBand < 1 && !mRedContrastEnhancement && !mGreenContrastEnhancement && !mBlueContrastEnhancement
                    && !mInvertColor );

  QgsRasterDataProvider::DataType redType = QgsRasterDataProvider::UnknownDataType;
  if ( mRedBand > 0 )
  {
    redType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mRedBand );
  }
  QgsRasterDataProvider::DataType greenType = QgsRasterDataProvider::UnknownDataType;
  if ( mGreenBand > 0 )
  {
    greenType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mGreenBand );
  }
  QgsRasterDataProvider::DataType blueType = QgsRasterDataProvider::UnknownDataType;
  if ( mBlueBand > 0 )
  {
    blueType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mBlueBand );
  }
  QgsRasterDataProvider::DataType transparencyType = QgsRasterDataProvider::UnknownDataType;
  if ( mAlphaBand > 0 )
  {
    transparencyType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mAlphaBand );
  }

  double oversamplingX = 1.0, oversamplingY = 1.0;
  QSet<int> bands;
  if ( mRedBand > 0 )
  {
    bands << mRedBand;
  }
  if ( mGreenBand > 0 )
  {
    bands << mGreenBand;
  }
  if ( mBlueBand > 0 )
  {
    bands << mBlueBand;
  }
  if ( bands.size() < 1 )
  {
    return; //no need to draw anything if no band is set
  }

  if ( mAlphaBand > 0 )
  {
    bands << mAlphaBand;
  }

  QMap<int, void*> bandData;
  void* defaultPointer = 0;
  QSet<int>::const_iterator bandIt = bands.constBegin();
  for ( ; bandIt != bands.constEnd(); ++bandIt )
  {
    bandData.insert( *bandIt, defaultPointer );
    startRasterRead( *bandIt, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY );
  }

  void* redData = 0;
  void* greenData = 0;
  void* blueData = 0;
  void* alphaData = 0;
  //number of cols/rows in output pixels
  int nCols = 0;
  int nRows = 0;
  //number of raster cols/rows with oversampling
  int nRasterCols = 0;
  int nRasterRows = 0;
  //shift to top left point for the raster part
  int topLeftCol = 0;
  int topLeftRow = 0;

  bool readSuccess = true;
  while ( true )
  {
    QSet<int>::const_iterator bandIt = bands.constBegin();
    for ( ; bandIt != bands.constEnd(); ++bandIt )
    {
      readSuccess = readSuccess && readNextRasterPart( *bandIt, oversamplingX, oversamplingY, viewPort, nCols, nRows,
                    nRasterCols, nRasterRows, &bandData[*bandIt], topLeftCol, topLeftRow );
    }

    if ( !readSuccess )
    {
      break;
    }

    if ( mRedBand > 0 )
    {
      redData = bandData[mRedBand];
    }
    if ( mGreenBand > 0 )
    {
      greenData = bandData[mGreenBand];
    }
    if ( mBlueBand > 0 )
    {
      blueData = bandData[mBlueBand];
    }
    if ( mAlphaBand > 0 )
    {
      alphaData = bandData[mAlphaBand];
    }

    QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32_Premultiplied );
    QRgb* imageScanLine = 0;
    int currentRasterPos = 0;
    int redVal = 0;
    int greenVal = 0;
    int blueVal = 0;
    int redDataVal = 0;
    int greenDataVal = 0;
    int blueDataVal = 0;
    QRgb defaultColor = qRgba( 255, 255, 255, 0 );
    double currentOpacity = mOpacity; //opacity (between 0 and 1)

    for ( int i = 0; i < nRasterRows; ++i )
    {
      imageScanLine = ( QRgb* )( img.scanLine( i ) );
      for ( int j = 0; j < nRasterCols; ++j )
      {

        if ( fastDraw ) //fast rendering if no transparency, stretching, color inversion, etc.
        {
          redVal = readValue( redData, redType, currentRasterPos );
          greenVal = readValue( greenData, greenType, currentRasterPos );
          blueVal = readValue( blueData, blueType, currentRasterPos );
          imageScanLine[j] = qRgba( redVal, greenVal, blueVal, 255 );
          ++currentRasterPos;
          continue;
        }

        if ( mRedBand > 0 )
        {
          redVal = readValue( redData, redType, currentRasterPos );
          redDataVal = redVal;
        }
        if ( mGreenBand > 0 )
        {
          greenVal = readValue( greenData, greenType, currentRasterPos );
          greenDataVal = greenVal;
        }
        if ( mBlueBand > 0 )
        {
          blueVal = readValue( blueData, blueType, currentRasterPos );
          blueDataVal = blueVal;
        }

        //apply default color if red, green or blue not in displayable range
        if (( mRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( redVal ) )
            || ( mGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( redVal ) )
            || ( mBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( redVal ) ) )
        {
          imageScanLine[j] = defaultColor;
          ++currentRasterPos;
          continue;
        }

        //stretch color values
        if ( mRedContrastEnhancement )
        {
          redVal = mRedContrastEnhancement->enhanceContrast( redVal );
        }
        if ( mGreenContrastEnhancement )
        {
          greenVal = mGreenContrastEnhancement->enhanceContrast( greenVal );
        }
        if ( mBlueContrastEnhancement )
        {
          blueVal = mBlueContrastEnhancement->enhanceContrast( blueVal );
        }

        if ( mInvertColor )
        {
          redVal = 255 - redVal;
          greenVal = 255 - greenVal;
          blueVal = 255 - blueVal;
        }

        //opacity
        currentOpacity = mOpacity;
        if ( mRasterTransparency )
        {
          currentOpacity = mRasterTransparency->alphaValue( redDataVal, greenDataVal, blueDataVal, mOpacity * 255 ) / 255.0;
        }
        if ( mAlphaBand > 0 )
        {
          currentOpacity *= ( readValue( alphaData, transparencyType, currentRasterPos ) / 255.0 );
        }

        if ( doubleNear( currentOpacity, 1.0 ) )
        {
          imageScanLine[j] = qRgba( redVal, greenVal, blueVal, 255 );
        }
        else
        {
          imageScanLine[j] = qRgba( currentOpacity * redVal, currentOpacity * greenVal, currentOpacity * blueVal, currentOpacity * 255 );
        }
        ++currentRasterPos;
      }
    }

    drawImage( p, viewPort, img, topLeftCol, topLeftRow, nCols, nRows, oversamplingX, oversamplingY );
  }

  bandIt = bands.constBegin();
  for ( ; bandIt != bands.constEnd(); ++bandIt )
  {
    stopRasterRead( *bandIt );
  }
}
QgsRasterBlock *QgsMultiBandColorRenderer::block( int bandNo, QgsRectangle  const &extent, int width, int height, QgsRasterBlockFeedback *feedback )
{
  Q_UNUSED( bandNo );
  std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock() );
  if ( !mInput )
  {
    return outputBlock.release();
  }

  //In some (common) cases, we can simplify the drawing loop considerably and save render time
  bool fastDraw = ( !usesTransparency()
                    && mRedBand > 0 && mGreenBand > 0 && mBlueBand > 0
                    && mAlphaBand < 1 && !mRedContrastEnhancement && !mGreenContrastEnhancement && !mBlueContrastEnhancement );

  QSet<int> bands;
  if ( mRedBand > 0 )
  {
    bands << mRedBand;
  }
  if ( mGreenBand > 0 )
  {
    bands << mGreenBand;
  }
  if ( mBlueBand > 0 )
  {
    bands << mBlueBand;
  }
  if ( bands.size() < 1 )
  {
    // no need to draw anything if no band is set
    // TODO:: we should probably return default color block
    return outputBlock.release();
  }

  if ( mAlphaBand > 0 )
  {
    bands << mAlphaBand;
  }

  QMap<int, QgsRasterBlock *> bandBlocks;
  QgsRasterBlock *defaultPointer = nullptr;
  QSet<int>::const_iterator bandIt = bands.constBegin();
  for ( ; bandIt != bands.constEnd(); ++bandIt )
  {
    bandBlocks.insert( *bandIt, defaultPointer );
  }

  QgsRasterBlock *redBlock = nullptr;
  QgsRasterBlock *greenBlock = nullptr;
  QgsRasterBlock *blueBlock = nullptr;
  QgsRasterBlock *alphaBlock = nullptr;

  bandIt = bands.constBegin();
  for ( ; bandIt != bands.constEnd(); ++bandIt )
  {
    bandBlocks[*bandIt] =  mInput->block( *bandIt, extent, width, height, feedback );
    if ( !bandBlocks[*bandIt] )
    {
      // We should free the alloced mem from block().
      QgsDebugMsg( "No input band" );
      --bandIt;
      for ( ; bandIt != bands.constBegin(); --bandIt )
      {
        delete bandBlocks[*bandIt];
      }
      return outputBlock.release();
    }
  }

  if ( mRedBand > 0 )
  {
    redBlock = bandBlocks[mRedBand];
  }
  if ( mGreenBand > 0 )
  {
    greenBlock = bandBlocks[mGreenBand];
  }
  if ( mBlueBand > 0 )
  {
    blueBlock = bandBlocks[mBlueBand];
  }
  if ( mAlphaBand > 0 )
  {
    alphaBlock = bandBlocks[mAlphaBand];
  }

  if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) )
  {
    for ( int i = 0; i < bandBlocks.size(); i++ )
    {
      delete bandBlocks.value( i );
    }
    return outputBlock.release();
  }

  QRgb myDefaultColor = NODATA_COLOR;

  for ( qgssize i = 0; i < ( qgssize )width * height; i++ )
  {
    if ( fastDraw ) //fast rendering if no transparency, stretching, color inversion, etc.
    {
      if ( redBlock->isNoData( i ) ||
           greenBlock->isNoData( i ) ||
           blueBlock->isNoData( i ) )
      {
        outputBlock->setColor( i, myDefaultColor );
      }
      else
      {
        int redVal = ( int )redBlock->value( i );
        int greenVal = ( int )greenBlock->value( i );
        int blueVal = ( int )blueBlock->value( i );
        outputBlock->setColor( i, qRgba( redVal, greenVal, blueVal, 255 ) );
      }
      continue;
    }

    bool isNoData = false;
    double redVal = 0;
    double greenVal = 0;
    double blueVal = 0;
    if ( mRedBand > 0 )
    {
      redVal = redBlock->value( i );
      if ( redBlock->isNoData( i ) ) isNoData = true;
    }
    if ( !isNoData && mGreenBand > 0 )
    {
      greenVal = greenBlock->value( i );
      if ( greenBlock->isNoData( i ) ) isNoData = true;
    }
    if ( !isNoData && mBlueBand > 0 )
    {
      blueVal = blueBlock->value( i );
      if ( blueBlock->isNoData( i ) ) isNoData = true;
    }
    if ( isNoData )
    {
      outputBlock->setColor( i, myDefaultColor );
      continue;
    }

    //apply default color if red, green or blue not in displayable range
    if ( ( mRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( redVal ) )
         || ( mGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( redVal ) )
         || ( mBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( redVal ) ) )
    {
      outputBlock->setColor( i, myDefaultColor );
      continue;
    }

    //stretch color values
    if ( mRedContrastEnhancement )
    {
      redVal = mRedContrastEnhancement->enhanceContrast( redVal );
    }
    if ( mGreenContrastEnhancement )
    {
      greenVal = mGreenContrastEnhancement->enhanceContrast( greenVal );
    }
    if ( mBlueContrastEnhancement )
    {
      blueVal = mBlueContrastEnhancement->enhanceContrast( blueVal );
    }

    //opacity
    double currentOpacity = mOpacity;
    if ( mRasterTransparency )
    {
      currentOpacity = mRasterTransparency->alphaValue( redVal, greenVal, blueVal, mOpacity * 255 ) / 255.0;
    }
    if ( mAlphaBand > 0 )
    {
      currentOpacity *= alphaBlock->value( i ) / 255.0;
    }

    if ( qgsDoubleNear( currentOpacity, 1.0 ) )
    {
      outputBlock->setColor( i, qRgba( redVal, greenVal, blueVal, 255 ) );
    }
    else
    {
      outputBlock->setColor( i, qRgba( currentOpacity * redVal, currentOpacity * greenVal, currentOpacity * blueVal, currentOpacity * 255 ) );
    }
  }

  //delete input blocks
  QMap<int, QgsRasterBlock *>::const_iterator bandDelIt = bandBlocks.constBegin();
  for ( ; bandDelIt != bandBlocks.constEnd(); ++bandDelIt )
  {
    delete bandDelIt.value();
  }

  return outputBlock.release();
}