QgsRasterBlock * QgsRasterResampleFilter::block( int bandNo, QgsRectangle  const & extent, int width, int height )
{
  Q_UNUSED( bandNo );
  QgsDebugMsg( "Entered" );
  QgsRasterBlock *outputBlock = new QgsRasterBlock();
  if ( !mInput ) return outputBlock;

  double oversampling = 1.0; // approximate global oversampling factor

  if ( mZoomedInResampler || mZoomedOutResampler )
  {
    QgsRasterDataProvider *provider = dynamic_cast<QgsRasterDataProvider*>( mInput->srcInput() );
    // Do not oversample if data source does not have fixed resolution (WMS)
    if ( provider && ( provider->capabilities() & QgsRasterDataProvider::ExactResolution ) )
    {
      double xRes = extent.width() / width;
      double providerXRes = provider->extent().width() / provider->xSize();
      double pixelRatio = xRes / providerXRes;
      oversampling = ( pixelRatio > mMaxOversampling ) ? mMaxOversampling : pixelRatio;
      QgsDebugMsg( QString( "xRes = %1 providerXRes = %2 pixelRatio = %3 oversampling = %4" ).arg( xRes ).arg( providerXRes ).arg( pixelRatio ).arg( oversampling ) );
    }
  }

  //set oversampling back to 1.0 if no resampler for zoomed in / zoomed out (nearest neighbour)
  if (( oversampling < 1.0 && !mZoomedInResampler ) || ( oversampling > 1.0 && !mZoomedOutResampler ) )
  {
    oversampling = 1.0;
  }

  QgsDebugMsg( QString( "oversampling %1" ).arg( oversampling ) );

  //effective oversampling factors are different to global one because of rounding
  double oversamplingX = (( double )width * oversampling ) / width;
  double oversamplingY = (( double )height * oversampling ) / height;

  // TODO: we must also increase the extent to get correct result on borders of parts

  int resWidth = width * oversamplingX;
  int resHeight = height * oversamplingY;

  // At moment we know that we read rendered image
  int bandNumber = 1;
  //void *rasterData = mInput->block( bandNumber, extent, resWidth, resHeight );
  QgsRasterBlock *inputBlock = mInput->block( bandNumber, extent, resWidth, resHeight );
  if ( !inputBlock || inputBlock->isEmpty() )
  {
    QgsDebugMsg( "No raster data!" );
    delete inputBlock;
    return outputBlock;
  }

  if ( doubleNear( oversamplingX, 1.0 ) || doubleNear( oversamplingY, 1.0 ) )
  {
    QgsDebugMsg( "No oversampling." );
    delete outputBlock;
    return inputBlock;
  }

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

  //resample image
  QImage img = inputBlock->image();

  QImage dstImg = QImage( width, height, QImage::Format_ARGB32_Premultiplied );

  if ( mZoomedInResampler && oversamplingX < 1.0 )
  {
    QgsDebugMsg( "zoomed in resampling" );
    mZoomedInResampler->resample( img, dstImg );
  }
  else if ( mZoomedOutResampler && oversamplingX > 1.0 )
  {
    QgsDebugMsg( "zoomed out resampling" );
    mZoomedOutResampler->resample( img, dstImg );
  }
  else
  {
    // Should not happen
    QgsDebugMsg( "Unexpected resampling" );
    dstImg = img.scaled( width, height );
  }

  outputBlock->setImage( &dstImg );

  delete inputBlock;
  return outputBlock; // No resampling
}
QgsRasterBlock* QgsRasterResampleFilter::block2( int bandNo, QgsRectangle  const & extent, int width, int height, QgsRasterBlockFeedback *feedback )
{
  Q_UNUSED( bandNo );
  QgsDebugMsg( QString( "width = %1 height = %2 extent = %3" ).arg( width ).arg( height ).arg( extent.toString() ) );
  QgsRasterBlock *outputBlock = new QgsRasterBlock();
  if ( !mInput ) return outputBlock;

  double oversampling = 1.0; // approximate global oversampling factor

  if ( mZoomedInResampler || mZoomedOutResampler )
  {
    QgsRasterDataProvider *provider = dynamic_cast<QgsRasterDataProvider*>( mInput->srcInput() );
    if ( provider && ( provider->capabilities() & QgsRasterDataProvider::Size ) )
    {
      double xRes = extent.width() / width;
      double providerXRes = provider->extent().width() / provider->xSize();
      double pixelRatio = xRes / providerXRes;
      oversampling = ( pixelRatio > mMaxOversampling ) ? mMaxOversampling : pixelRatio;
      QgsDebugMsg( QString( "xRes = %1 providerXRes = %2 pixelRatio = %3 oversampling = %4" ).arg( xRes ).arg( providerXRes ).arg( pixelRatio ).arg( oversampling ) );
    }
    else
    {
      // We don't know exact data source resolution (WMS) so we expect that
      // server data have higher resolution (which is not always true) and use
      // mMaxOversampling
      oversampling = mMaxOversampling;
    }
  }

  QgsDebugMsg( QString( "oversampling %1" ).arg( oversampling ) );

  int bandNumber = 1;

  // Do no oversampling if no resampler for zoomed in / zoomed out (nearest neighbour)
  // We do mZoomedInResampler if oversampling == 1 (otherwise for example reprojected
  // zoom in rasters are never resampled because projector limits resolution.
  if ((( oversampling < 1.0 || qgsDoubleNear( oversampling, 1.0 ) ) && !mZoomedInResampler ) || ( oversampling > 1.0 && !mZoomedOutResampler ) )
  {
    QgsDebugMsg( "No oversampling." );
    delete outputBlock;
    return mInput->block2( bandNumber, extent, width, height, feedback );
  }

  //effective oversampling factors are different to global one because of rounding
  double oversamplingX = (( double )width * oversampling ) / width;
  double oversamplingY = (( double )height * oversampling ) / height;

  // TODO: we must also increase the extent to get correct result on borders of parts

  int resWidth = width * oversamplingX;
  int resHeight = height * oversamplingY;

  QgsRasterBlock *inputBlock = mInput->block2( bandNumber, extent, resWidth, resHeight, feedback );
  if ( !inputBlock || inputBlock->isEmpty() )
  {
    QgsDebugMsg( "No raster data!" );
    delete inputBlock;
    return outputBlock;
  }

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

  //resample image
  QImage img = inputBlock->image();

  QImage dstImg = QImage( width, height, QImage::Format_ARGB32_Premultiplied );

  if ( mZoomedInResampler && ( oversamplingX < 1.0 || qgsDoubleNear( oversampling, 1.0 ) ) )
  {
    QgsDebugMsg( "zoomed in resampling" );
    mZoomedInResampler->resample( img, dstImg );
  }
  else if ( mZoomedOutResampler && oversamplingX > 1.0 )
  {
    QgsDebugMsg( "zoomed out resampling" );
    mZoomedOutResampler->resample( img, dstImg );
  }
  else
  {
    // Should not happen
    QgsDebugMsg( "Unexpected resampling" );
    dstImg = img.scaled( width, height );
  }

  outputBlock->setImage( &dstImg );

  delete inputBlock;
  return outputBlock; // No resampling
}
Example #3
0
void QgsRasterDrawer::draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel )
{
  QgsDebugMsg( "Entered" );
  if ( !p || !mIterator || !viewPort || !theQgsMapToPixel )
  {
    return;
  }

  // last pipe filter has only 1 band
  int bandNumber = 1;
  mIterator->startRasterRead( bandNumber, viewPort->mWidth, viewPort->mHeight, viewPort->mDrawnExtent );

  //number of cols/rows in output pixels
  int nCols = 0;
  int nRows = 0;
  //shift to top left point for the raster part
  int topLeftCol = 0;
  int topLeftRow = 0;

  // We know that the output data type of last pipe filter is QImage data

  QgsRasterBlock *block;

  // readNextRasterPart calcs and resets  nCols, nRows, topLeftCol, topLeftRow
  while ( mIterator->readNextRasterPart( bandNumber, nCols, nRows,
                                         &block, topLeftCol, topLeftRow ) )
  {
    if ( !block )
    {
      QgsDebugMsg( "Cannot get block" );
      continue;
    }

    QImage img = block->image();

    // Because of bug in Acrobat Reader we must use "white" transparent color instead
    // of "black" for PDF. See #9101.
    QPrinter *printer = dynamic_cast<QPrinter *>( p->device() );
    if ( printer && printer->outputFormat() == QPrinter::PdfFormat )
    {
      QgsDebugMsg( "PdfFormat" );

      img = img.convertToFormat( QImage::Format_ARGB32 );
      QRgb transparentBlack = qRgba( 0, 0, 0, 0 );
      QRgb transparentWhite = qRgba( 255, 255, 255, 0 );
      for ( int x = 0; x < img.width(); x++ )
      {
        for ( int y = 0; y < img.height(); y++ )
        {
          if ( img.pixel( x, y ) == transparentBlack )
          {
            img.setPixel( x, y, transparentWhite );
          }
        }
      }
    }

    drawImage( p, viewPort, img, topLeftCol, topLeftRow );

    delete block;
  }
}