Example #1
0
GDALRasterBand *
GDALDefaultOverviews::GetOverview( int nBand, int iOverview )

{
    GDALRasterBand * poBand;

    if( poODS == NULL || nBand < 1 || nBand > poODS->GetRasterCount() )
        return NULL;

    poBand = poODS->GetRasterBand( nBand );
    if( poBand == NULL )
        return NULL;

    if( bOvrIsAux )
        return poBand->GetOverview( iOverview );

    else // TIFF case, base is overview 0.
    {
        if( iOverview == 0 )
            return poBand;
        else if( iOverview-1 >= poBand->GetOverviewCount() )
            return NULL;
        else
            return poBand->GetOverview( iOverview-1 );
    }
}
Example #2
0
CPLErr GDALMRFRasterBand::FillBlock(int xblk, int yblk, void *buffer) {
    vector<GDALRasterBlock *> blocks;

    for (int i = 0; i < poDS->nBands; i++) {
        GDALRasterBand *b = poDS->GetRasterBand(i + 1);
        if (b->GetOverviewCount() && 0 != m_l)
            b = b->GetOverview(m_l - 1);

        // Get the other band blocks, keep them around until later
        if (b == this) {
            FillBlock(buffer);
        }
        else {
            GDALRasterBlock *poBlock = b->GetLockedBlockRef(xblk, yblk, 1);
            if (poBlock == nullptr) // Didn't get this block
                break;
            FillBlock(poBlock->GetDataRef());
            blocks.push_back(poBlock);
        }
    }

    // Drop the locks for blocks we acquired
    for (int i = 0; i < int(blocks.size()); i++)
        blocks[i]->DropLock();

    return CE_None;
}
Example #3
0
CPLErr GDALMRFRasterBand::RB(int xblk, int yblk, buf_mgr /*src*/, void *buffer) {
    vector<GDALRasterBlock *> blocks;

    for (int i = 0; i < poDS->nBands; i++) {
	GDALRasterBand *b = poDS->GetRasterBand(i+1);
	if (b->GetOverviewCount() && m_l)
	    b = b->GetOverview(m_l-1);

	void *ob = buffer;
	// Get the other band blocks, keep them around until later
	if (b != this)
	{
	    GDALRasterBlock *poBlock = b->GetLockedBlockRef(xblk, yblk, 1);
            if( poBlock == NULL )
                break;
	    ob = poBlock->GetDataRef();
	    blocks.push_back(poBlock);
	} 

// Just the right mix of templates and macros make deinterleaving tidy
#define CpySI(T) cpy_stride_in<T> (ob, (T *)poDS->GetPBuffer() + i,\
    blockSizeBytes()/sizeof(T), img.pagesize.c)

	// Page is already in poDS->pbuffer, not empty
	// There are only four cases, since only the real data type matters
	switch (GDALGetDataTypeSize(eDataType)/8)
	{
	case 1: CpySI(GByte); break;
	case 2: CpySI(GInt16); break;
	case 4: CpySI(GInt32); break;
	case 8: CpySI(GIntBig); break;
	}
    }

#undef CpySI

    // Drop the locks we acquired
    for (int i=0; i < int(blocks.size()); i++)
	blocks[i]->DropLock();

    return CE_None;
}
Example #4
0
GDALRasterBand *GDALProxyPoolRasterBand::GetOverview(int nOverviewBand)
{
    if (nOverviewBand >= 0 && nOverviewBand < nSizeProxyOverviewRasterBand)
    {
        if (papoProxyOverviewRasterBand[nOverviewBand])
            return papoProxyOverviewRasterBand[nOverviewBand];
    }

    GDALRasterBand* poUnderlyingRasterBand = RefUnderlyingRasterBand();
    if (poUnderlyingRasterBand == NULL)
        return NULL;

    GDALRasterBand* poOverviewRasterBand = poUnderlyingRasterBand->GetOverview(nOverviewBand);
    if (poOverviewRasterBand == NULL)
    {
        UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
        return NULL;
    }

    if (nOverviewBand >= nSizeProxyOverviewRasterBand)
    {
        int i;
        papoProxyOverviewRasterBand = (GDALProxyPoolOverviewRasterBand**)
                CPLRealloc(papoProxyOverviewRasterBand,
                        sizeof(GDALProxyPoolOverviewRasterBand*) * (nOverviewBand + 1));
        for(i=nSizeProxyOverviewRasterBand; i<nOverviewBand + 1;i++)
            papoProxyOverviewRasterBand[i] = NULL;
        nSizeProxyOverviewRasterBand = nOverviewBand + 1;
    }

    papoProxyOverviewRasterBand[nOverviewBand] =
            new GDALProxyPoolOverviewRasterBand((GDALProxyPoolDataset*)poDS,
                                                poOverviewRasterBand,
                                                this, nOverviewBand);

    UnrefUnderlyingRasterBand(poUnderlyingRasterBand);

    return papoProxyOverviewRasterBand[nOverviewBand];
}
Example #5
0
CPLErr 
GTIFFBuildOverviews( const char * pszFilename,
                     int nBands, GDALRasterBand **papoBandList, 
                     int nOverviews, int * panOverviewList,
                     const char * pszResampling, 
                     GDALProgressFunc pfnProgress, void * pProgressData )

{
    TIFF    *hOTIFF;
    int     nBitsPerPixel=0, nCompression=COMPRESSION_NONE, nPhotometric=0;
    int     nSampleFormat=0, nPlanarConfig, iOverview, iBand;
    int     nXSize=0, nYSize=0;

    if( nBands == 0 || nOverviews == 0 )
        return CE_None;

    if (!GTiffOneTimeInit())
        return CE_Failure;

/* -------------------------------------------------------------------- */
/*      Verify that the list of bands is suitable for emitting in       */
/*      TIFF file.                                                      */
/* -------------------------------------------------------------------- */
    for( iBand = 0; iBand < nBands; iBand++ )
    {
        int     nBandBits, nBandFormat;
        GDALRasterBand *hBand = papoBandList[iBand];

        switch( hBand->GetRasterDataType() )
        {
          case GDT_Byte:
            nBandBits = 8;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_UInt16:
            nBandBits = 16;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_Int16:
            nBandBits = 16;
            nBandFormat = SAMPLEFORMAT_INT;
            break;

          case GDT_UInt32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_Int32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_INT;
            break;

          case GDT_Float32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_IEEEFP;
            break;

          case GDT_Float64:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_IEEEFP;
            break;

          case GDT_CInt16:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_COMPLEXINT;
            break;

          case GDT_CInt32:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_COMPLEXINT;
            break;

          case GDT_CFloat32:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
            break;

          case GDT_CFloat64:
            nBandBits = 128;
            nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
            break;

          default:
            CPLAssert( FALSE );
            return CE_Failure;
        }

        if( hBand->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" ) )
        {
            nBandBits = 
                atoi(hBand->GetMetadataItem("NBITS","IMAGE_STRUCTURE"));

            if( nBandBits == 1 
                && EQUALN(pszResampling,"AVERAGE_BIT2",12) )
                nBandBits = 8;
        }

        if( iBand == 0 )
        {
            nBitsPerPixel = nBandBits;
            nSampleFormat = nBandFormat;
            nXSize = hBand->GetXSize();
            nYSize = hBand->GetYSize();
        }
        else if( nBitsPerPixel != nBandBits || nSampleFormat != nBandFormat )
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                      "GTIFFBuildOverviews() doesn't support a mixture of band"
                      " data types." );
            return CE_Failure;
        }
        else if( hBand->GetColorTable() != NULL )
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                      "GTIFFBuildOverviews() doesn't support building"
                      " overviews of multiple colormapped bands." );
            return CE_Failure;
        }
        else if( hBand->GetXSize() != nXSize 
                 || hBand->GetYSize() != nYSize )
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                      "GTIFFBuildOverviews() doesn't support building"
                      " overviews of different sized bands." );
            return CE_Failure;
        }
    }

/* -------------------------------------------------------------------- */
/*      Use specified compression method.                               */
/* -------------------------------------------------------------------- */
    const char *pszCompress = CPLGetConfigOption( "COMPRESS_OVERVIEW", NULL );

    if( pszCompress != NULL && pszCompress[0] != '\0' )
    {
        nCompression = GTIFFGetCompressionMethod(pszCompress, "COMPRESS_OVERVIEW");
        if (nCompression < 0)
            return CE_Failure;
    }
    
    if( nCompression == COMPRESSION_JPEG && nBitsPerPixel > 8 )
    {  
        if( nBitsPerPixel > 16 )
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                      "GTIFFBuildOverviews() doesn't support building"
                      " JPEG compressed overviews of nBitsPerPixel > 16." );
            return CE_Failure;
        }

        nBitsPerPixel = 12;
    }

/* -------------------------------------------------------------------- */
/*      Figure out the planar configuration to use.                     */
/* -------------------------------------------------------------------- */
    if( nBands == 1 )
        nPlanarConfig = PLANARCONFIG_CONTIG;
    else
        nPlanarConfig = PLANARCONFIG_SEPARATE;

    const char* pszInterleave = CPLGetConfigOption( "INTERLEAVE_OVERVIEW", NULL );
    if (pszInterleave != NULL && pszInterleave[0] != '\0')
    {
        if( EQUAL( pszInterleave, "PIXEL" ) )
            nPlanarConfig = PLANARCONFIG_CONTIG;
        else if( EQUAL( pszInterleave, "BAND" ) )
            nPlanarConfig = PLANARCONFIG_SEPARATE;
        else
        {
            CPLError( CE_Failure, CPLE_AppDefined, 
                      "INTERLEAVE_OVERVIEW=%s unsupported, value must be PIXEL or BAND. ignoring",
                      pszInterleave );
        }
    }

/* -------------------------------------------------------------------- */
/*      Figure out the photometric interpretation to use.               */
/* -------------------------------------------------------------------- */
    if( nBands == 3 )
        nPhotometric = PHOTOMETRIC_RGB;
    else if( papoBandList[0]->GetColorTable() != NULL 
             && !EQUALN(pszResampling,"AVERAGE_BIT2",12) )
    {
        nPhotometric = PHOTOMETRIC_PALETTE;
        /* should set the colormap up at this point too! */
    }
    else
        nPhotometric = PHOTOMETRIC_MINISBLACK;

    const char* pszPhotometric = CPLGetConfigOption( "PHOTOMETRIC_OVERVIEW", NULL );
    if (pszPhotometric != NULL && pszPhotometric[0] != '\0')
    {
        if( EQUAL( pszPhotometric, "MINISBLACK" ) )
            nPhotometric = PHOTOMETRIC_MINISBLACK;
        else if( EQUAL( pszPhotometric, "MINISWHITE" ) )
            nPhotometric = PHOTOMETRIC_MINISWHITE;
        else if( EQUAL( pszPhotometric, "RGB" ))
        {
            nPhotometric = PHOTOMETRIC_RGB;
        }
        else if( EQUAL( pszPhotometric, "CMYK" ))
        {
            nPhotometric = PHOTOMETRIC_SEPARATED;
        }
        else if( EQUAL( pszPhotometric, "YCBCR" ))
        {
            nPhotometric = PHOTOMETRIC_YCBCR;

            /* Because of subsampling, setting YCBCR without JPEG compression leads */
            /* to a crash currently. Would need to make GTiffRasterBand::IWriteBlock() */
            /* aware of subsampling so that it doesn't overrun buffer size returned */
            /* by libtiff */
            if ( nCompression != COMPRESSION_JPEG )
            {
                CPLError(CE_Failure, CPLE_NotSupported,
                         "Currently, PHOTOMETRIC_OVERVIEW=YCBCR requires COMPRESS_OVERVIEW=JPEG");
                return CE_Failure;
            }

            if (pszInterleave != NULL && pszInterleave[0] != '\0' && nPlanarConfig == PLANARCONFIG_SEPARATE)
            {
                CPLError(CE_Failure, CPLE_NotSupported,
                         "PHOTOMETRIC_OVERVIEW=YCBCR requires INTERLEAVE_OVERVIEW=PIXEL");
                return CE_Failure;
            }
            else
            {
                nPlanarConfig = PLANARCONFIG_CONTIG;
            }

            /* YCBCR strictly requires 3 bands. Not less, not more */
            /* Issue an explicit error message as libtiff one is a bit cryptic : */
            /* JPEGLib:Bogus input colorspace */
            if ( nBands != 3 )
            {
                CPLError(CE_Failure, CPLE_NotSupported,
                         "PHOTOMETRIC_OVERVIEW=YCBCR requires a source raster with only 3 bands (RGB)");
                return CE_Failure;
            }
        }
        else if( EQUAL( pszPhotometric, "CIELAB" ))
        {
            nPhotometric = PHOTOMETRIC_CIELAB;
        }
        else if( EQUAL( pszPhotometric, "ICCLAB" ))
        {
            nPhotometric = PHOTOMETRIC_ICCLAB;
        }
        else if( EQUAL( pszPhotometric, "ITULAB" ))
        {
            nPhotometric = PHOTOMETRIC_ITULAB;
        }
        else
        {
            CPLError( CE_Warning, CPLE_IllegalArg, 
                      "PHOTOMETRIC_OVERVIEW=%s value not recognised, ignoring.\n",
                      pszPhotometric );
        }
    }

/* -------------------------------------------------------------------- */
/*      Figure out the predictor value to use.                          */
/* -------------------------------------------------------------------- */
    int nPredictor = PREDICTOR_NONE;
    if ( nCompression == COMPRESSION_LZW ||
         nCompression == COMPRESSION_ADOBE_DEFLATE )
    {
        const char* pszPredictor = CPLGetConfigOption( "PREDICTOR_OVERVIEW", NULL );
        if( pszPredictor  != NULL )
        {
            nPredictor =  atoi( pszPredictor );
        }
    }

/* -------------------------------------------------------------------- */
/*      Create the file, if it does not already exist.                  */
/* -------------------------------------------------------------------- */
    VSIStatBufL  sStatBuf;
    VSILFILE* fpL = NULL;

    if( VSIStatExL( pszFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
    {
    /* -------------------------------------------------------------------- */
    /*      Compute the uncompressed size.                                  */
    /* -------------------------------------------------------------------- */
        double  dfUncompressedOverviewSize = 0;
        int nDataTypeSize = GDALGetDataTypeSize(papoBandList[0]->GetRasterDataType())/8;

        for( iOverview = 0; iOverview < nOverviews; iOverview++ )
        {
            int    nOXSize, nOYSize;

            nOXSize = (nXSize + panOverviewList[iOverview] - 1) 
                / panOverviewList[iOverview];
            nOYSize = (nYSize + panOverviewList[iOverview] - 1) 
                / panOverviewList[iOverview];

            dfUncompressedOverviewSize += 
                nOXSize * ((double)nOYSize) * nBands * nDataTypeSize;
        }

        if( nCompression == COMPRESSION_NONE 
            && dfUncompressedOverviewSize > 4200000000.0 )
        {
    #ifndef BIGTIFF_SUPPORT
            CPLError( CE_Failure, CPLE_NotSupported, 
                    "The overview file would be larger than 4GB\n"
                    "but this is the largest size a TIFF can be, and BigTIFF is unavailable.\n"
                    "Creation failed." );
            return CE_Failure;
    #endif
        }
    /* -------------------------------------------------------------------- */
    /*      Should the file be created as a bigtiff file?                   */
    /* -------------------------------------------------------------------- */
        const char *pszBIGTIFF = CPLGetConfigOption( "BIGTIFF_OVERVIEW", NULL );

        if( pszBIGTIFF == NULL )
            pszBIGTIFF = "IF_NEEDED";

        int bCreateBigTIFF = FALSE;
        if( EQUAL(pszBIGTIFF,"IF_NEEDED") )
        {
            if( nCompression == COMPRESSION_NONE 
                && dfUncompressedOverviewSize > 4200000000.0 )
                bCreateBigTIFF = TRUE;
        }
        else if( EQUAL(pszBIGTIFF,"IF_SAFER") )
        {
            /* Look at the size of the base image and suppose that */
            /* the added overview levels won't be more than 1/2 of */
            /* the size of the base image. The theory says 1/3 of the */
            /* base image size if the overview levels are 2, 4, 8, 16... */
            /* Thus take 1/2 as the security margin for 1/3 */
            double dfUncompressedImageSize =
                        nXSize * ((double)nYSize) * nBands * nDataTypeSize;
            if( dfUncompressedImageSize * .5 > 4200000000.0 )
                bCreateBigTIFF = TRUE;
        }
        else
        {
            bCreateBigTIFF = CSLTestBoolean( pszBIGTIFF );
            if (!bCreateBigTIFF && nCompression == COMPRESSION_NONE 
                && dfUncompressedOverviewSize > 4200000000.0 )
            {
                CPLError( CE_Failure, CPLE_NotSupported, 
                    "The overview file will be larger than 4GB, so BigTIFF is necessary.\n"
                    "Creation failed.");
                return CE_Failure;
            }
        }

    #ifndef BIGTIFF_SUPPORT
        if( bCreateBigTIFF )
        {
            CPLError( CE_Warning, CPLE_NotSupported,
                    "BigTIFF requested, but GDAL built without BigTIFF\n"
                    "enabled libtiff, request ignored." );
            bCreateBigTIFF = FALSE;
        }
    #endif

        if( bCreateBigTIFF )
            CPLDebug( "GTiff", "File being created as a BigTIFF." );

        fpL = VSIFOpenL( pszFilename, "w+" );
        if( fpL == NULL )
            hOTIFF = NULL;
        else
            hOTIFF = VSI_TIFFOpen( pszFilename, (bCreateBigTIFF) ? "w+8" : "w+", fpL );
        if( hOTIFF == NULL )
        {
            if( CPLGetLastErrorNo() == 0 )
                CPLError( CE_Failure, CPLE_OpenFailed,
                          "Attempt to create new tiff file `%s'\n"
                          "failed in VSI_TIFFOpen().\n",
                          pszFilename );
            if( fpL != NULL )
                VSIFCloseL(fpL);
            return CE_Failure;
        }
    }
/* -------------------------------------------------------------------- */
/*      Otherwise just open it for update access.                       */
/* -------------------------------------------------------------------- */
    else 
    {
        fpL = VSIFOpenL( pszFilename, "r+" );
        if( fpL == NULL )
            hOTIFF = NULL;
        else
            hOTIFF = VSI_TIFFOpen( pszFilename, "r+", fpL );
        if( hOTIFF == NULL )
        {
            if( CPLGetLastErrorNo() == 0 )
                CPLError( CE_Failure, CPLE_OpenFailed,
                          "Attempt to create new tiff file `%s'\n"
                          "failed in VSI_TIFFOpen().\n",
                          pszFilename );
            if( fpL != NULL )
                VSIFCloseL(fpL);
            return CE_Failure;
        }
    }

/* -------------------------------------------------------------------- */
/*      Do we have a palette?  If so, create a TIFF compatible version. */
/* -------------------------------------------------------------------- */
    unsigned short      *panRed=NULL, *panGreen=NULL, *panBlue=NULL;

    if( nPhotometric == PHOTOMETRIC_PALETTE )
    {
        GDALColorTable *poCT = papoBandList[0]->GetColorTable();
        int nColorCount;

        if( nBitsPerPixel <= 8 )
            nColorCount = 256;
        else
            nColorCount = 65536;

        panRed   = (unsigned short *) 
            CPLCalloc(nColorCount,sizeof(unsigned short));
        panGreen = (unsigned short *) 
            CPLCalloc(nColorCount,sizeof(unsigned short));
        panBlue  = (unsigned short *) 
            CPLCalloc(nColorCount,sizeof(unsigned short));

        for( int iColor = 0; iColor < nColorCount; iColor++ )
        {
            GDALColorEntry  sRGB;

            if( poCT->GetColorEntryAsRGB( iColor, &sRGB ) )
            {
                panRed[iColor] = (unsigned short) (257 * sRGB.c1);
                panGreen[iColor] = (unsigned short) (257 * sRGB.c2);
                panBlue[iColor] = (unsigned short) (257 * sRGB.c3);
            }
        }
    }

/* -------------------------------------------------------------------- */
/*      Do we need some metadata for the overviews?                     */
/* -------------------------------------------------------------------- */
    CPLString osMetadata;
    GDALDataset *poBaseDS = papoBandList[0]->GetDataset();

    GTIFFBuildOverviewMetadata( pszResampling, poBaseDS, osMetadata );

/* -------------------------------------------------------------------- */
/*      Loop, creating overviews.                                       */
/* -------------------------------------------------------------------- */
    int nOvrBlockXSize, nOvrBlockYSize;
    GTIFFGetOverviewBlockSize(&nOvrBlockXSize, &nOvrBlockYSize);
    for( iOverview = 0; iOverview < nOverviews; iOverview++ )
    {
        int    nOXSize, nOYSize;

        nOXSize = (nXSize + panOverviewList[iOverview] - 1) 
            / panOverviewList[iOverview];
        nOYSize = (nYSize + panOverviewList[iOverview] - 1) 
            / panOverviewList[iOverview];

        GTIFFWriteDirectory(hOTIFF, FILETYPE_REDUCEDIMAGE,
                            nOXSize, nOYSize, nBitsPerPixel, 
                            nPlanarConfig, nBands,
                            nOvrBlockXSize, nOvrBlockYSize, TRUE, nCompression,
                            nPhotometric, nSampleFormat, nPredictor,
                            panRed, panGreen, panBlue,
                            0, NULL, /* FIXME? how can we fetch extrasamples */
                            osMetadata );
    }

    if (panRed)
    {
        CPLFree(panRed);
        CPLFree(panGreen);
        CPLFree(panBlue);
        panRed = panGreen = panBlue = NULL;
    }

    XTIFFClose( hOTIFF );
    VSIFCloseL(fpL);
    fpL = NULL;

/* -------------------------------------------------------------------- */
/*      Open the overview dataset so that we can get at the overview    */
/*      bands.                                                          */
/* -------------------------------------------------------------------- */
    GDALDataset *hODS;
    CPLErr eErr = CE_None;

    hODS = (GDALDataset *) GDALOpen( pszFilename, GA_Update );
    if( hODS == NULL )
        return CE_Failure;
    
/* -------------------------------------------------------------------- */
/*      Do we need to set the jpeg quality?                             */
/* -------------------------------------------------------------------- */
    TIFF *hTIFF = (TIFF*) hODS->GetInternalHandle(NULL);

    if( nCompression == COMPRESSION_JPEG 
        && CPLGetConfigOption( "JPEG_QUALITY_OVERVIEW", NULL ) != NULL )
    {
        int nJpegQuality = atoi(CPLGetConfigOption("JPEG_QUALITY_OVERVIEW","75"));
        TIFFSetField( hTIFF, TIFFTAG_JPEGQUALITY, 
                      nJpegQuality );
        GTIFFSetJpegQuality((GDALDatasetH)hODS, nJpegQuality);
    }

/* -------------------------------------------------------------------- */
/*      Loop writing overview data.                                     */
/* -------------------------------------------------------------------- */

    if (nCompression != COMPRESSION_NONE &&
        nPlanarConfig == PLANARCONFIG_CONTIG &&
        GDALDataTypeIsComplex(papoBandList[0]->GetRasterDataType()) == FALSE &&
        papoBandList[0]->GetColorTable() == NULL &&
        (EQUALN(pszResampling, "NEAR", 4) || EQUAL(pszResampling, "AVERAGE") ||
         EQUAL(pszResampling, "GAUSS") || EQUAL(pszResampling, "CUBIC") ||
         EQUAL(pszResampling, "CUBICSPLINE") || EQUAL(pszResampling, "LANCZOS") ||
         EQUAL(pszResampling, "BILINEAR")))
    {
        /* In the case of pixel interleaved compressed overviews, we want to generate */
        /* the overviews for all the bands block by block, and not band after band, */
        /* in order to write the block once and not loose space in the TIFF file */
        GDALRasterBand ***papapoOverviewBands;

        papapoOverviewBands = (GDALRasterBand ***) CPLCalloc(sizeof(void*),nBands);
        for( iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
        {
            GDALRasterBand    *hSrcBand = papoBandList[iBand];
            GDALRasterBand    *hDstBand = hODS->GetRasterBand( iBand+1 );
            papapoOverviewBands[iBand] = (GDALRasterBand **) CPLCalloc(sizeof(void*),nOverviews);
            papapoOverviewBands[iBand][0] = hDstBand;

            int bHasNoData;
            double noDataValue = hSrcBand->GetNoDataValue(&bHasNoData);
            if (bHasNoData)
                hDstBand->SetNoDataValue(noDataValue);

            for( int i = 0; i < nOverviews-1 && eErr == CE_None; i++ )
            {
                papapoOverviewBands[iBand][i+1] = hDstBand->GetOverview(i);
                if (papapoOverviewBands[iBand][i+1] == NULL)
                    eErr = CE_Failure;
                else
                {
                    if (bHasNoData)
                        papapoOverviewBands[iBand][i+1]->SetNoDataValue(noDataValue);
                }
            }
        }

        if (eErr == CE_None)
            eErr = GDALRegenerateOverviewsMultiBand(nBands, papoBandList,
                                            nOverviews, papapoOverviewBands,
                                            pszResampling, pfnProgress, pProgressData );

        for( iBand = 0; iBand < nBands; iBand++ )
        {
            CPLFree(papapoOverviewBands[iBand]);
        }
        CPLFree(papapoOverviewBands);
    }
    else
    {
        GDALRasterBand   **papoOverviews;

        papoOverviews = (GDALRasterBand **) CPLCalloc(sizeof(void*),128);

        for( iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
        {
            GDALRasterBand    *hSrcBand = papoBandList[iBand];
            GDALRasterBand    *hDstBand;
            int               nDstOverviews;

            hDstBand = hODS->GetRasterBand( iBand+1 );

            int bHasNoData;
            double noDataValue = hSrcBand->GetNoDataValue(&bHasNoData);
            if (bHasNoData)
                hDstBand->SetNoDataValue(noDataValue);

            papoOverviews[0] = hDstBand;
            nDstOverviews = hDstBand->GetOverviewCount() + 1;
            CPLAssert( nDstOverviews < 128 );
            nDstOverviews = MIN(128,nDstOverviews);

            for( int i = 0; i < nDstOverviews-1 && eErr == CE_None; i++ )
            {
                papoOverviews[i+1] = hDstBand->GetOverview(i);
                if (papoOverviews[i+1] == NULL)
                    eErr = CE_Failure;
                else
                {
                    if (bHasNoData)
                        papoOverviews[i+1]->SetNoDataValue(noDataValue);
                }
            }

            void         *pScaledProgressData;

            pScaledProgressData = 
                GDALCreateScaledProgress( iBand / (double) nBands, 
                                        (iBand+1) / (double) nBands,
                                        pfnProgress, pProgressData );

            if (eErr == CE_None)
                eErr = 
                    GDALRegenerateOverviews( (GDALRasterBandH) hSrcBand, 
                                        nDstOverviews, 
                                        (GDALRasterBandH *) papoOverviews, 
                                        pszResampling,
                                        GDALScaledProgress, 
                                        pScaledProgressData);

            GDALDestroyScaledProgress( pScaledProgressData );
        }

        CPLFree( papoOverviews );
    }

/* -------------------------------------------------------------------- */
/*      Cleanup                                                         */
/* -------------------------------------------------------------------- */
    if (eErr == CE_None)
        hODS->FlushCache();
    delete hODS;

    pfnProgress( 1.0, NULL, pProgressData );

    return eErr;
}
Example #6
0
CPLErr GDALMRFRasterBand::IWriteBlock(int xblk, int yblk, void *buffer)

{
    GInt32 cstride = img.pagesize.c;
    ILSize req(xblk, yblk, 0, m_band/cstride, m_l);
    GUIntBig infooffset = IdxOffset(req, img);

    CPLDebug("MRF_IB", "IWriteBlock %d,%d,0,%d, level  %d, stride %d\n", xblk, yblk, 
	m_band, m_l, cstride);

    if (1 == cstride) {     // Separate bands, we can write it as is
	// Empty page skip

	int success;
	double val = GetNoDataValue(&success);
	if (!success) val = 0.0;
	if (isAllVal(eDataType, buffer, img.pageSizeBytes, val))
	    return poDS->WriteTile(NULL, infooffset, 0);

	// Use the pbuffer to hold the compressed page before writing it
	poDS->tile = ILSize(); // Mark it corrupt

	buf_mgr src;
        src.buffer = (char *)buffer;
        src.size = static_cast<size_t>(img.pageSizeBytes);
	buf_mgr dst = {(char *)poDS->GetPBuffer(), poDS->GetPBufferSize()};

	// Swab the source before encoding if we need to 
	if (is_Endianess_Dependent(img.dt, img.comp) && (img.nbo != NET_ORDER)) 
	    swab_buff(src, img);

	// Compress functions need to return the compressed size in
	// the bytes in buffer field
	Compress(dst, src);
	void *usebuff = dst.buffer;
	if (deflatep) {
	    usebuff = DeflateBlock(dst, poDS->pbsize - dst.size, deflate_flags);
	    if (!usebuff) {
		CPLError(CE_Failure,CPLE_AppDefined, "MRF: Deflate error");
		return CE_Failure;
	    }
	}
	return poDS->WriteTile(usebuff, infooffset , dst.size);
    }

    // Multiple bands per page, use a temporary to assemble the page
    // Temporary is large because we use it to hold both the uncompressed and the compressed
    poDS->tile=req; poDS->bdirty=0;

    // Keep track of what bands are empty
    GUIntBig empties=0;

    void *tbuffer = VSIMalloc(img.pageSizeBytes + poDS->pbsize);

    if (!tbuffer) {
	CPLError(CE_Failure,CPLE_AppDefined, "MRF: Can't allocate write buffer");
	return CE_Failure;
    }
	
    // Get the other bands from the block cache
    for (int iBand=0; iBand < poDS->nBands; iBand++ )
    {
	const char *pabyThisImage=NULL;
	GDALRasterBlock *poBlock=NULL;

	if (iBand == m_band)
	{
	    pabyThisImage = (char *) buffer;
	    poDS->bdirty |= bandbit();
	} else {
	    GDALRasterBand *band = poDS->GetRasterBand(iBand +1);
	    // Pick the right overview
	    if (m_l) band = band->GetOverview(m_l -1);
	    poBlock = ((GDALMRFRasterBand *)band)
		->TryGetLockedBlockRef(xblk, yblk);
	    if (NULL==poBlock) continue;
	    // This is where the image data is for this band

	    pabyThisImage = (char*) poBlock->GetDataRef();
	    poDS->bdirty |= bandbit(iBand);
	}

	// Keep track of empty bands, but encode them anyhow, in case some are not empty
	int success;
	double val = GetNoDataValue(&success);
	if (!success) val = 0.0;
        if (isAllVal(eDataType, (char *)pabyThisImage, blockSizeBytes(), val))
	    empties |= bandbit(iBand);

	// Copy the data into the dataset buffer here
	// Just the right mix of templates and macros make this real tidy
#define CpySO(T) cpy_stride_out<T> (((T *)tbuffer)+iBand, pabyThisImage,\
		blockSizeBytes()/sizeof(T), cstride)


	// Build the page in tbuffer
	switch (GDALGetDataTypeSize(eDataType)/8)
	{
	    case 1: CpySO(GByte); break;
	    case 2: CpySO(GInt16); break;
	    case 4: CpySO(GInt32); break;
	    case 8: CpySO(GIntBig); break;
	    default:
            {
		CPLError(CE_Failure,CPLE_AppDefined, "MRF: Write datatype of %d bytes "
			"not implemented", GDALGetDataTypeSize(eDataType)/8);
                if (poBlock != NULL)
                {
                    poBlock->MarkClean();
                    poBlock->DropLock();
                }
                CPLFree(tbuffer);
		return CE_Failure;
            }
	}

	if (poBlock != NULL)
	{
	    poBlock->MarkClean();
	    poBlock->DropLock();
	}
    }

    // Should keep track of the individual band buffers and only mix them if this is not
    // an empty page ( move the Copy with Stride Out from above below this test
    // This way works fine, but it does work extra for empty pages

    if (GIntBig(empties) == AllBandMask()) {
	CPLFree(tbuffer);
	return poDS->WriteTile(NULL, infooffset, 0);
    }

    if (poDS->bdirty != AllBandMask())
	CPLError(CE_Warning, CPLE_AppDefined,
	"MRF: IWrite, band dirty mask is " CPL_FRMT_GIB " instead of " CPL_FRMT_GIB,
	poDS->bdirty, AllBandMask());

    buf_mgr src;
    src.buffer = (char *)tbuffer;
    src.size = static_cast<size_t>(img.pageSizeBytes);

    // Use the space after pagesizebytes for compressed output, it is of pbsize
    char *outbuff = (char *)tbuffer + img.pageSizeBytes;

    buf_mgr dst = {outbuff, poDS->pbsize};
    CPLErr ret;

    ret = Compress(dst, src);
    if (ret != CE_None) {
        // Compress failed, write it as an empty tile
        CPLFree(tbuffer);
        poDS->WriteTile(NULL, infooffset, 0);
        return CE_None; // Should report the error, but it triggers partial band attempts
    }

    // Where the output is, in case we deflate
    void *usebuff = outbuff;
    if (deflatep) {
	// Move the packed part at the start of tbuffer, to make more space available
	memcpy(tbuffer, outbuff, dst.size);
	dst.buffer = (char *)tbuffer;
	usebuff = DeflateBlock(dst, img.pageSizeBytes + poDS->pbsize - dst.size, deflate_flags);
	if (!usebuff) {
	    CPLError(CE_Failure,CPLE_AppDefined, "MRF: Deflate error");
	    CPLFree(tbuffer);
            poDS->WriteTile(NULL, infooffset, 0);
            poDS->bdirty = 0;
	    return CE_Failure;
	}
    }

    ret = poDS->WriteTile(usebuff, infooffset, dst.size);
    CPLFree(tbuffer);

    poDS->bdirty = 0;
    return ret;
}
Example #7
0
CPLErr 
GTIFFBuildOverviews( const char * pszFilename,
                     int nBands, GDALRasterBand **papoBandList, 
                     int nOverviews, int * panOverviewList,
                     const char * pszResampling, 
                     GDALProgressFunc pfnProgress, void * pProgressData )

{
    TIFF    *hOTIFF;
    int     nBitsPerPixel=0, nCompression=COMPRESSION_NONE, nPhotometric=0;
    int     nSampleFormat=0, nPlanarConfig, iOverview, iBand;
    int     nXSize=0, nYSize=0;

    if( nBands == 0 || nOverviews == 0 )
        return CE_None;

    GTiffOneTimeInit();

/* -------------------------------------------------------------------- */
/*      Verify that the list of bands is suitable for emitting in       */
/*      TIFF file.                                                      */
/* -------------------------------------------------------------------- */
    for( iBand = 0; iBand < nBands; iBand++ )
    {
        int     nBandBits, nBandFormat;
        GDALRasterBand *hBand = papoBandList[iBand];

        switch( hBand->GetRasterDataType() )
        {
          case GDT_Byte:
            nBandBits = 8;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_UInt16:
            nBandBits = 16;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_Int16:
            nBandBits = 16;
            nBandFormat = SAMPLEFORMAT_INT;
            break;

          case GDT_UInt32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_Int32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_INT;
            break;

          case GDT_Float32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_IEEEFP;
            break;

          case GDT_Float64:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_IEEEFP;
            break;

          case GDT_CInt16:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_COMPLEXINT;
            break;

          case GDT_CFloat32:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
            break;

          case GDT_CFloat64:
            nBandBits = 128;
            nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
            break;

          default:
            CPLAssert( FALSE );
            return CE_Failure;
        }

        if( iBand == 0 )
        {
            nBitsPerPixel = nBandBits;
            nSampleFormat = nBandFormat;
            nXSize = hBand->GetXSize();
            nYSize = hBand->GetYSize();
        }
        else if( nBitsPerPixel != nBandBits || nSampleFormat != nBandFormat )
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                      "GTIFFBuildOverviews() doesn't support a mixture of band"
                      " data types." );
            return CE_Failure;
        }
        else if( hBand->GetColorTable() != NULL )
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                      "GTIFFBuildOverviews() doesn't support building"
                      " overviews of multiple colormapped bands." );
            return CE_Failure;
        }
        else if( hBand->GetXSize() != nXSize 
                 || hBand->GetYSize() != nYSize )
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                      "GTIFFBuildOverviews() doesn't support building"
                      " overviews of different sized bands." );
            return CE_Failure;
        }
    }

/* -------------------------------------------------------------------- */
/*      Use specified compression method.                               */
/* -------------------------------------------------------------------- */
    const char *pszCompress = CPLGetConfigOption( "COMPRESS_OVERVIEW", NULL );

    if( pszCompress != NULL && pszCompress[0] != '\0' )
    {
        if( EQUAL( pszCompress, "JPEG" ) )
            nCompression = COMPRESSION_JPEG;
        else if( EQUAL( pszCompress, "LZW" ) )
            nCompression = COMPRESSION_LZW;
        else if( EQUAL( pszCompress, "PACKBITS" ))
            nCompression = COMPRESSION_PACKBITS;
        else if( EQUAL( pszCompress, "DEFLATE" ) || EQUAL( pszCompress, "ZIP" ))
            nCompression = COMPRESSION_ADOBE_DEFLATE;
        else
            CPLError( CE_Warning, CPLE_IllegalArg, 
                      "COMPRESS_OVERVIEW=%s value not recognised, ignoring.",
                      pszCompress );
    }

/* -------------------------------------------------------------------- */
/*      Figure out the planar configuration to use.                     */
/* -------------------------------------------------------------------- */
    if( nBands == 1 )
        nPlanarConfig = PLANARCONFIG_CONTIG;
    else
        nPlanarConfig = PLANARCONFIG_SEPARATE;

    const char* pszInterleave = CPLGetConfigOption( "INTERLEAVE_OVERVIEW", NULL );
    if (pszInterleave != NULL && pszInterleave[0] != '\0')
    {
        if( EQUAL( pszInterleave, "PIXEL" ) )
            nPlanarConfig = PLANARCONFIG_CONTIG;
        else if( EQUAL( pszInterleave, "BAND" ) )
            nPlanarConfig = PLANARCONFIG_SEPARATE;
        else
        {
            CPLError( CE_Failure, CPLE_AppDefined, 
                      "INTERLEAVE_OVERVIEW=%s unsupported, value must be PIXEL or BAND. ignoring",
                      pszInterleave );
        }
    }

/* -------------------------------------------------------------------- */
/*      Figure out the photometric interpretation to use.               */
/* -------------------------------------------------------------------- */
    if( nBands == 3 )
        nPhotometric = PHOTOMETRIC_RGB;
    else if( papoBandList[0]->GetColorTable() != NULL 
             && !EQUALN(pszResampling,"AVERAGE_BIT2",12) )
    {
        nPhotometric = PHOTOMETRIC_PALETTE;
        /* should set the colormap up at this point too! */
    }
    else
        nPhotometric = PHOTOMETRIC_MINISBLACK;

    const char* pszPhotometric = CPLGetConfigOption( "PHOTOMETRIC_OVERVIEW", NULL );
    if (pszPhotometric != NULL && pszPhotometric[0] != '\0')
    {
        if( EQUAL( pszPhotometric, "MINISBLACK" ) )
            nPhotometric = PHOTOMETRIC_MINISBLACK;
        else if( EQUAL( pszPhotometric, "MINISWHITE" ) )
            nPhotometric = PHOTOMETRIC_MINISWHITE;
        else if( EQUAL( pszPhotometric, "RGB" ))
        {
            nPhotometric = PHOTOMETRIC_RGB;
        }
        else if( EQUAL( pszPhotometric, "CMYK" ))
        {
            nPhotometric = PHOTOMETRIC_SEPARATED;
        }
        else if( EQUAL( pszPhotometric, "YCBCR" ))
        {
            nPhotometric = PHOTOMETRIC_YCBCR;
        }
        else if( EQUAL( pszPhotometric, "CIELAB" ))
        {
            nPhotometric = PHOTOMETRIC_CIELAB;
        }
        else if( EQUAL( pszPhotometric, "ICCLAB" ))
        {
            nPhotometric = PHOTOMETRIC_ICCLAB;
        }
        else if( EQUAL( pszPhotometric, "ITULAB" ))
        {
            nPhotometric = PHOTOMETRIC_ITULAB;
        }
        else
        {
            CPLError( CE_Warning, CPLE_IllegalArg, 
                      "PHOTOMETRIC_OVERVIEW=%s value not recognised, ignoring.\n",
                      pszPhotometric );
        }
    }

/* -------------------------------------------------------------------- */
/*      Create the file, if it does not already exist.                  */
/* -------------------------------------------------------------------- */
    VSIStatBuf  sStatBuf;

    if( VSIStat( pszFilename, &sStatBuf ) != 0 )
    {
        hOTIFF = XTIFFOpen( pszFilename, "w+" );
        if( hOTIFF == NULL )
        {
            if( CPLGetLastErrorNo() == 0 )
                CPLError( CE_Failure, CPLE_OpenFailed,
                          "Attempt to create new tiff file `%s'\n"
                          "failed in XTIFFOpen().\n",
                          pszFilename );

            return CE_Failure;
        }
    }
/* -------------------------------------------------------------------- */
/*      Otherwise just open it for update access.                       */
/* -------------------------------------------------------------------- */
    else 
    {
        hOTIFF = XTIFFOpen( pszFilename, "r+" );
        if( hOTIFF == NULL )
        {
            if( CPLGetLastErrorNo() == 0 )
                CPLError( CE_Failure, CPLE_OpenFailed,
                          "Attempt to create new tiff file `%s'\n"
                          "failed in XTIFFOpen().\n",
                          pszFilename );

            return CE_Failure;
        }
    }

/* -------------------------------------------------------------------- */
/*      Do we have a palette?  If so, create a TIFF compatible version. */
/* -------------------------------------------------------------------- */
    unsigned short      *panRed=NULL, *panGreen=NULL, *panBlue=NULL;

    if( nPhotometric == PHOTOMETRIC_PALETTE )
    {
        GDALColorTable *poCT = papoBandList[0]->GetColorTable();
        int nColorCount;

        if( nBitsPerPixel <= 8 )
            nColorCount = 256;
        else
            nColorCount = 65536;

        panRed   = (unsigned short *) 
            CPLCalloc(nColorCount,sizeof(unsigned short));
        panGreen = (unsigned short *) 
            CPLCalloc(nColorCount,sizeof(unsigned short));
        panBlue  = (unsigned short *) 
            CPLCalloc(nColorCount,sizeof(unsigned short));

        for( int iColor = 0; iColor < nColorCount; iColor++ )
        {
            GDALColorEntry  sRGB;

            if( poCT->GetColorEntryAsRGB( iColor, &sRGB ) )
            {
                panRed[iColor] = (unsigned short) (257 * sRGB.c1);
                panGreen[iColor] = (unsigned short) (257 * sRGB.c2);
                panBlue[iColor] = (unsigned short) (257 * sRGB.c3);
            }
        }
    }

/* -------------------------------------------------------------------- */
/*      Do we need some metadata for the overviews?                     */
/* -------------------------------------------------------------------- */
    CPLString osMetadata;
    GDALDataset *poBaseDS = papoBandList[0]->GetDataset();

    GTIFFBuildOverviewMetadata( pszResampling, poBaseDS, osMetadata );

/* -------------------------------------------------------------------- */
/*      Loop, creating overviews.                                       */
/* -------------------------------------------------------------------- */
    for( iOverview = 0; iOverview < nOverviews; iOverview++ )
    {
        int    nOXSize, nOYSize;
        uint32 nDirOffset;

        nOXSize = (nXSize + panOverviewList[iOverview] - 1) 
            / panOverviewList[iOverview];
        nOYSize = (nYSize + panOverviewList[iOverview] - 1) 
            / panOverviewList[iOverview];

        nDirOffset = 
            GTIFFWriteDirectory(hOTIFF, FILETYPE_REDUCEDIMAGE,
                                nOXSize, nOYSize, nBitsPerPixel, 
                                nPlanarConfig, nBands,
                                128, 128, TRUE, nCompression,
                                nPhotometric, nSampleFormat, 
                                panRed, panGreen, panBlue,
                                0, NULL, /* FIXME ? how can we fetch extrasamples from here */
                                osMetadata );
    }

    if (panRed)
    {
        CPLFree(panRed);
        CPLFree(panGreen);
        CPLFree(panBlue);
        panRed = panGreen = panBlue = NULL;
    }

    XTIFFClose( hOTIFF );

/* -------------------------------------------------------------------- */
/*      Open the overview dataset so that we can get at the overview    */
/*      bands.                                                          */
/* -------------------------------------------------------------------- */
    GDALDataset *hODS;

    hODS = (GDALDataset *) GDALOpen( pszFilename, GA_Update );
    if( hODS == NULL )
        return CE_Failure;
    
/* -------------------------------------------------------------------- */
/*      Loop writing overview data.                                     */
/* -------------------------------------------------------------------- */

    if (nCompression != COMPRESSION_NONE &&
        nPlanarConfig == PLANARCONFIG_CONTIG &&
        GDALDataTypeIsComplex(papoBandList[0]->GetRasterDataType()) == FALSE &&
        papoBandList[0]->GetColorTable() == NULL &&
        (EQUALN(pszResampling, "NEAR", 4) || EQUAL(pszResampling, "AVERAGE") || EQUAL(pszResampling, "GAUSS")))
    {
        /* In the case of pixel interleaved compressed overviews, we want to generate */
        /* the overviews for all the bands block by block, and not band after band, */
        /* in order to write the block once and not loose space in the TIFF file */

        GDALRasterBand ***papapoOverviewBands;

        papapoOverviewBands = (GDALRasterBand ***) CPLCalloc(sizeof(void*),nBands);
        for( iBand = 0; iBand < nBands; iBand++ )
        {
            GDALRasterBand    *hDstBand = hODS->GetRasterBand( iBand+1 );
            papapoOverviewBands[iBand] = (GDALRasterBand **) CPLCalloc(sizeof(void*),nOverviews);
            papapoOverviewBands[iBand][0] = hDstBand;
            for( int i = 0; i < nOverviews-1; i++ )
            {
                papapoOverviewBands[iBand][i+1] = hDstBand->GetOverview(i);
            }
        }

        GDALRegenerateOverviewsMultiBand(nBands, papoBandList,
                                         nOverviews, papapoOverviewBands,
                                         pszResampling, pfnProgress, pProgressData );

        for( iBand = 0; iBand < nBands; iBand++ )
        {
            CPLFree(papapoOverviewBands[iBand]);
        }
        CPLFree(papapoOverviewBands);
    }
    else
    {
        GDALRasterBand   **papoOverviews;

        papoOverviews = (GDALRasterBand **) CPLCalloc(sizeof(void*),128);

        for( iBand = 0; iBand < nBands; iBand++ )
        {
            GDALRasterBand    *hSrcBand = papoBandList[iBand];
            GDALRasterBand    *hDstBand;
            int               nDstOverviews;
            CPLErr            eErr;

            hDstBand = hODS->GetRasterBand( iBand+1 );

            papoOverviews[0] = hDstBand;
            nDstOverviews = hDstBand->GetOverviewCount() + 1;
            CPLAssert( nDstOverviews < 128 );
            nDstOverviews = MIN(128,nDstOverviews);

            for( int i = 0; i < nDstOverviews-1; i++ )
            {
                papoOverviews[i+1] = hDstBand->GetOverview(i);
            }

            void         *pScaledProgressData;

            pScaledProgressData = 
                GDALCreateScaledProgress( iBand / (double) nBands, 
                                        (iBand+1) / (double) nBands,
                                        pfnProgress, pProgressData );

            eErr = 
                GDALRegenerateOverviews( (GDALRasterBandH) hSrcBand, 
                                        nDstOverviews, 
                                        (GDALRasterBandH *) papoOverviews, 
                                        pszResampling,
                                        GDALScaledProgress, 
                                        pScaledProgressData);

            GDALDestroyScaledProgress( pScaledProgressData );

            if( eErr != CE_None )
            {
                delete hODS;
                return eErr;
            }
        }

        CPLFree( papoOverviews );
    }

/* -------------------------------------------------------------------- */
/*      Cleanup                                                         */
/* -------------------------------------------------------------------- */
    hODS->FlushCache();
    delete hODS;

    pfnProgress( 1.0, NULL, pProgressData );

    return CE_None;
}
CPLErr
GDALDefaultOverviews::BuildOverviews(
    const char * pszBasename,
    const char * pszResampling,
    int nOverviews, int * panOverviewList,
    int nBands, int * panBandList,
    GDALProgressFunc pfnProgress, void * pProgressData)

{
    if( pfnProgress == NULL )
        pfnProgress = GDALDummyProgress;

    if( nOverviews == 0 )
        return CleanOverviews();

/* -------------------------------------------------------------------- */
/*      If we don't already have an overview file, we need to decide    */
/*      what format to use.                                             */
/* -------------------------------------------------------------------- */
    if( poODS == NULL )
    {
        bOvrIsAux = CPLTestBool(CPLGetConfigOption( "USE_RRD", "NO" ));
        if( bOvrIsAux )
        {
            osOvrFilename = CPLResetExtension(poDS->GetDescription(),"aux");

            VSIStatBufL sStatBuf;
            if( VSIStatExL( osOvrFilename, &sStatBuf,
                            VSI_STAT_EXISTS_FLAG ) == 0 )
                osOvrFilename.Printf( "%s.aux", poDS->GetDescription() );
        }
    }
/* -------------------------------------------------------------------- */
/*      If we already have the overviews open, but they are             */
/*      read-only, then try and reopen them read-write.                 */
/* -------------------------------------------------------------------- */
    else if( poODS->GetAccess() == GA_ReadOnly )
    {
        GDALClose( poODS );
        poODS = static_cast<GDALDataset *>(
            GDALOpen( osOvrFilename, GA_Update ));
        if( poODS == NULL )
            return CE_Failure;
    }

/* -------------------------------------------------------------------- */
/*      Our TIFF overview support currently only works safely if all    */
/*      bands are handled at the same time.                             */
/* -------------------------------------------------------------------- */
    if( !bOvrIsAux && nBands != poDS->GetRasterCount() )
    {
        CPLError( CE_Failure, CPLE_NotSupported,
                  "Generation of overviews in external TIFF currently only "
                  "supported when operating on all bands.  "
                  "Operation failed." );
        return CE_Failure;
    }

/* -------------------------------------------------------------------- */
/*      If a basename is provided, use it to override the internal      */
/*      overview filename.                                              */
/* -------------------------------------------------------------------- */
    if( pszBasename == NULL && osOvrFilename.length() == 0  )
        pszBasename = poDS->GetDescription();

    if( pszBasename != NULL )
    {
        if( bOvrIsAux )
            osOvrFilename.Printf( "%s.aux", pszBasename );
        else
            osOvrFilename.Printf( "%s.ovr", pszBasename );
    }

/* -------------------------------------------------------------------- */
/*      Establish which of the overview levels we already have, and     */
/*      which are new.  We assume that band 1 of the file is            */
/*      representative.                                                 */
/* -------------------------------------------------------------------- */
    GDALRasterBand *poBand = poDS->GetRasterBand( 1 );

    int nNewOverviews = 0;
    int *panNewOverviewList = static_cast<int *>(
        CPLCalloc(sizeof(int), nOverviews) );
    double dfAreaNewOverviews = 0;
    double dfAreaRefreshedOverviews = 0;
    for( int i = 0; i < nOverviews && poBand != NULL; i++ )
    {
        for( int j = 0; j < poBand->GetOverviewCount(); j++ )
        {
            GDALRasterBand * poOverview = poBand->GetOverview( j );
            if( poOverview == NULL )
                continue;

            int nOvFactor =
                GDALComputeOvFactor(poOverview->GetXSize(),
                                    poBand->GetXSize(),
                                    poOverview->GetYSize(),
                                    poBand->GetYSize());

            if( nOvFactor == panOverviewList[i]
                || nOvFactor == GDALOvLevelAdjust2( panOverviewList[i],
                                                   poBand->GetXSize(),
                                                   poBand->GetYSize() ) )
            {
                panOverviewList[i] *= -1;
            }
        }

        const double dfArea = 1.0 / (panOverviewList[i] * panOverviewList[i]);
        dfAreaRefreshedOverviews += dfArea;
        if( panOverviewList[i] > 0 )
        {
            dfAreaNewOverviews += dfArea;
            panNewOverviewList[nNewOverviews++] = panOverviewList[i];
        }
    }

/* -------------------------------------------------------------------- */
/*      Build band list.                                                */
/* -------------------------------------------------------------------- */
    GDALRasterBand **pahBands = static_cast<GDALRasterBand **>(
        CPLCalloc(sizeof(GDALRasterBand *), nBands) );
    for( int i = 0; i < nBands; i++ )
        pahBands[i] = poDS->GetRasterBand( panBandList[i] );

/* -------------------------------------------------------------------- */
/*      Build new overviews - Imagine.  Keep existing file open if      */
/*      we have it.  But mark all overviews as in need of               */
/*      regeneration, since HFAAuxBuildOverviews() doesn't actually     */
/*      produce the imagery.                                            */
/* -------------------------------------------------------------------- */

    CPLErr eErr = CE_None;

    void* pScaledProgress = GDALCreateScaledProgress(
            0, dfAreaNewOverviews / dfAreaRefreshedOverviews,
            pfnProgress, pProgressData );
    if( bOvrIsAux )
    {
        if( nNewOverviews == 0 )
        {
            /* if we call HFAAuxBuildOverviews() with nNewOverviews == 0 */
            /* because that there's no new, this will wipe existing */
            /* overviews (#4831) */
            // eErr = CE_None;
        }
        else
        {
            eErr = HFAAuxBuildOverviews( osOvrFilename, poDS, &poODS,
                                     nBands, panBandList,
                                     nNewOverviews, panNewOverviewList,
                                     pszResampling,
                                     GDALScaledProgress, pScaledProgress );
        }
        for( int j = 0; j < nOverviews; j++ )
        {
            if( panOverviewList[j] > 0 )
                panOverviewList[j] *= -1;
        }
    }

/* -------------------------------------------------------------------- */
/*      Build new overviews - TIFF.  Close TIFF files while we          */
/*      operate on it.                                                  */
/* -------------------------------------------------------------------- */
    else
    {
        if( poODS != NULL )
        {
            delete poODS;
            poODS = NULL;
        }

        eErr = GTIFFBuildOverviews( osOvrFilename, nBands, pahBands,
                                    nNewOverviews, panNewOverviewList,
                                    pszResampling,
                                    GDALScaledProgress, pScaledProgress );

        // Probe for proxy overview filename.
        if( eErr == CE_Failure )
        {
            const char *pszProxyOvrFilename =
                poDS->GetMetadataItem("FILENAME","ProxyOverviewRequest");

            if( pszProxyOvrFilename != NULL )
            {
                osOvrFilename = pszProxyOvrFilename;
                eErr = GTIFFBuildOverviews( osOvrFilename, nBands, pahBands,
                                            nNewOverviews, panNewOverviewList,
                                            pszResampling,
                                            GDALScaledProgress, pScaledProgress );
            }
        }

        if( eErr == CE_None )
        {
            poODS = static_cast<GDALDataset *>(
                GDALOpen( osOvrFilename, GA_Update ) );
            if( poODS == NULL )
                eErr = CE_Failure;
        }
    }

    GDALDestroyScaledProgress( pScaledProgress );

/* -------------------------------------------------------------------- */
/*      Refresh old overviews that were listed.                         */
/* -------------------------------------------------------------------- */
    GDALRasterBand **papoOverviewBands = static_cast<GDALRasterBand **>(
        CPLCalloc(sizeof(void*), nOverviews) );

    for( int iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
    {
        poBand = poDS->GetRasterBand( panBandList[iBand] );

        nNewOverviews = 0;
        for( int i = 0; i < nOverviews && poBand != NULL; i++ )
        {
            for( int j = 0; j < poBand->GetOverviewCount(); j++ )
            {
                GDALRasterBand * poOverview = poBand->GetOverview( j );
                if( poOverview == NULL )
                    continue;

                int bHasNoData = FALSE;
                double noDataValue = poBand->GetNoDataValue(&bHasNoData);

                if( bHasNoData )
                  poOverview->SetNoDataValue(noDataValue);

                const int nOvFactor =
                    GDALComputeOvFactor(poOverview->GetXSize(),
                                        poBand->GetXSize(),
                                        poOverview->GetYSize(),
                                        poBand->GetYSize());

                if( nOvFactor == - panOverviewList[i]
                    || (panOverviewList[i] < 0 &&
                        nOvFactor == GDALOvLevelAdjust2( -panOverviewList[i],
                                                       poBand->GetXSize(),
                                                       poBand->GetYSize() )) )
                {
                    papoOverviewBands[nNewOverviews++] = poOverview;
                    break;
                }
            }
        }

        if( nNewOverviews > 0 )
        {
            const double dfOffset = dfAreaNewOverviews / dfAreaRefreshedOverviews;
            const double dfScale = 1.0 - dfOffset;
            pScaledProgress = GDALCreateScaledProgress(
                    dfOffset + dfScale * iBand / nBands,
                    dfOffset + dfScale * (iBand+1) / nBands,
                    pfnProgress, pProgressData );
            eErr = GDALRegenerateOverviews( (GDALRasterBandH) poBand,
                                            nNewOverviews,
                                            (GDALRasterBandH*)papoOverviewBands,
                                            pszResampling,
                                            GDALScaledProgress, pScaledProgress );
            GDALDestroyScaledProgress( pScaledProgress );
        }
    }

/* -------------------------------------------------------------------- */
/*      Cleanup                                                         */
/* -------------------------------------------------------------------- */
    CPLFree( papoOverviewBands );
    CPLFree( panNewOverviewList );
    CPLFree( pahBands );

/* -------------------------------------------------------------------- */
/*      If we have a mask file, we need to build its overviews too.     */
/* -------------------------------------------------------------------- */
    if( HaveMaskFile() && poMaskDS )
    {
        // Some config option are not compatible with mask overviews
        // so unset them, and define more sensible values.
        const bool bJPEG =
            EQUAL(CPLGetConfigOption("COMPRESS_OVERVIEW", ""), "JPEG");
        const bool bPHOTOMETRIC_YCBCR =
            EQUAL(CPLGetConfigOption("PHOTOMETRIC_OVERVIEW", ""), "YCBCR");
        if( bJPEG )
            CPLSetThreadLocalConfigOption("COMPRESS_OVERVIEW", "DEFLATE");
        if( bPHOTOMETRIC_YCBCR )
            CPLSetThreadLocalConfigOption("PHOTOMETRIC_OVERVIEW", "");

        poMaskDS->BuildOverviews( pszResampling, nOverviews, panOverviewList,
                                  0, NULL, pfnProgress, pProgressData );

        // Restore config option.
        if( bJPEG )
            CPLSetThreadLocalConfigOption("COMPRESS_OVERVIEW", "JPEG");
        if( bPHOTOMETRIC_YCBCR )
            CPLSetThreadLocalConfigOption("PHOTOMETRIC_OVERVIEW", "YCBCR");

        if( bOwnMaskDS )
        {
            // Reset the poMask member of main dataset bands, since it
            // will become invalid after poMaskDS closing.
            for( int iBand = 1; iBand <= poDS->GetRasterCount(); iBand ++ )
            {
                GDALRasterBand *poOtherBand = poDS->GetRasterBand(iBand);
                if( poOtherBand != NULL )
                    poOtherBand->InvalidateMaskBand();
            }

            GDALClose( poMaskDS );
        }

        // force next request to reread mask file.
        poMaskDS = NULL;
        bOwnMaskDS = false;
        bCheckedForMask = false;
    }

/* -------------------------------------------------------------------- */
/*      If we have an overview dataset, then mark all the overviews     */
/*      with the base dataset  Used later for finding overviews         */
/*      masks.  Uggg.                                                   */
/* -------------------------------------------------------------------- */
    if( poODS )
    {
        const int nOverviewCount = GetOverviewCount(1);

        for( int iOver = 0; iOver < nOverviewCount; iOver++ )
        {
            GDALRasterBand *poOtherBand = GetOverview( 1, iOver );
            GDALDataset *poOverDS = poOtherBand != NULL ?
                poOtherBand->GetDataset() : NULL;

            if( poOverDS != NULL )
            {
                poOverDS->oOvManager.poBaseDS = poDS;
                poOverDS->oOvManager.poDS = poOverDS;
            }
        }
    }

    return eErr;
}
int GDALDefaultOverviews::HaveMaskFile( char ** papszSiblingFiles,
                                        const char *pszBasename )

{
/* -------------------------------------------------------------------- */
/*      Have we already checked for masks?                              */
/* -------------------------------------------------------------------- */
    if( bCheckedForMask )
        return poMaskDS != NULL;

    if( papszSiblingFiles == NULL )
        papszSiblingFiles = papszInitSiblingFiles;

/* -------------------------------------------------------------------- */
/*      Are we an overview?  If so we need to find the corresponding    */
/*      overview in the base files mask file (if there is one).         */
/* -------------------------------------------------------------------- */
    if( poBaseDS != NULL && poBaseDS->oOvManager.HaveMaskFile() )
    {
        GDALRasterBand * const poBaseBand = poBaseDS->GetRasterBand(1);
        GDALRasterBand * poBaseMask = poBaseBand != NULL ?
            poBaseBand->GetMaskBand() : NULL;

        const int nOverviewCount = poBaseMask != NULL ?
            poBaseMask->GetOverviewCount() : 0;

        for( int iOver = 0; iOver < nOverviewCount; iOver++ )
        {
            GDALRasterBand * const poOverBand =
                poBaseMask->GetOverview( iOver );
            if( poOverBand == NULL )
                continue;

            if( poOverBand->GetXSize() == poDS->GetRasterXSize()
                && poOverBand->GetYSize() == poDS->GetRasterYSize() )
            {
                poMaskDS = poOverBand->GetDataset();
                break;
            }
        }

        bCheckedForMask = true;
        bOwnMaskDS = false;

        CPLAssert( poMaskDS != poDS );

        return poMaskDS != NULL;
    }

/* -------------------------------------------------------------------- */
/*      Are we even initialized?  If not, we apparently don't want      */
/*      to support overviews and masks.                                 */
/* -------------------------------------------------------------------- */
    if( poDS == NULL )
        return FALSE;

/* -------------------------------------------------------------------- */
/*      Check for .msk file.                                            */
/* -------------------------------------------------------------------- */
    bCheckedForMask = true;

    if( pszBasename == NULL )
        pszBasename = poDS->GetDescription();

    // Don't bother checking for masks of masks.
    if( EQUAL(CPLGetExtension(pszBasename),"msk") )
        return FALSE;

    if( !GDALCanFileAcceptSidecarFile(pszBasename) )
        return FALSE;
    CPLString osMskFilename;
    osMskFilename.Printf( "%s.msk", pszBasename );

    std::vector<char> achMskFilename;
    achMskFilename.resize(osMskFilename.size() + 1);
    memcpy(&(achMskFilename[0]),
           osMskFilename.c_str(),
           osMskFilename.size() + 1);
    bool bExists = CPL_TO_BOOL(
        CPLCheckForFile( &achMskFilename[0],
                         papszSiblingFiles ) );
    osMskFilename = &achMskFilename[0];

#if !defined(WIN32)
    if( !bExists && !papszSiblingFiles )
    {
        osMskFilename.Printf( "%s.MSK", pszBasename );
        memcpy(&(achMskFilename[0]),
               osMskFilename.c_str(),
               osMskFilename.size() + 1);
        bExists = CPL_TO_BOOL(
            CPLCheckForFile( &achMskFilename[0],
                             papszSiblingFiles ) );
        osMskFilename = &achMskFilename[0];
    }
#endif

    if( !bExists )
        return FALSE;

/* -------------------------------------------------------------------- */
/*      Open the file.                                                  */
/* -------------------------------------------------------------------- */
    poMaskDS = static_cast<GDALDataset *>(
        GDALOpenEx( osMskFilename,
                    GDAL_OF_RASTER |
                    (poDS->GetAccess() == GA_Update ? GDAL_OF_UPDATE : 0),
                    NULL, NULL, papszInitSiblingFiles ));
    CPLAssert( poMaskDS != poDS );

    if( poMaskDS == NULL )
        return FALSE;

    bOwnMaskDS = true;

    return TRUE;
}
Example #10
0
CPLErr
GTIFFBuildOverviews( const char * pszFilename,
                     int nBands, GDALRasterBand **papoBandList,
                     int nOverviews, int * panOverviewList,
                     const char * pszResampling,
                     GDALProgressFunc pfnProgress, void * pProgressData )

{
    if( nBands == 0 || nOverviews == 0 )
        return CE_None;

    if( !GTiffOneTimeInit() )
        return CE_Failure;

    TIFF *hOTIFF = nullptr;
    int nBitsPerPixel = 0;
    int nCompression = COMPRESSION_NONE;
    int nPhotometric = 0;
    int nSampleFormat = 0;
    int nPlanarConfig = 0;
    int iOverview = 0;
    int nXSize = 0;
    int nYSize = 0;

/* -------------------------------------------------------------------- */
/*      Verify that the list of bands is suitable for emitting in       */
/*      TIFF file.                                                      */
/* -------------------------------------------------------------------- */
    for( int iBand = 0; iBand < nBands; iBand++ )
    {
        int nBandBits = 0;
        int nBandFormat = 0;
        GDALRasterBand *hBand = papoBandList[iBand];

        switch( hBand->GetRasterDataType() )
        {
          case GDT_Byte:
            nBandBits = 8;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_UInt16:
            nBandBits = 16;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_Int16:
            nBandBits = 16;
            nBandFormat = SAMPLEFORMAT_INT;
            break;

          case GDT_UInt32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_Int32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_INT;
            break;

          case GDT_Float32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_IEEEFP;
            break;

          case GDT_Float64:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_IEEEFP;
            break;

          case GDT_CInt16:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_COMPLEXINT;
            break;

          case GDT_CInt32:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_COMPLEXINT;
            break;

          case GDT_CFloat32:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
            break;

          case GDT_CFloat64:
            nBandBits = 128;
            nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
            break;

          default:
            CPLAssert( false );
            return CE_Failure;
        }

        if( hBand->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" ) )
        {
            nBandBits =
                atoi(hBand->GetMetadataItem("NBITS", "IMAGE_STRUCTURE"));

            if( nBandBits == 1
                && STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2") )
                nBandBits = 8;
        }

        if( iBand == 0 )
        {
            nBitsPerPixel = nBandBits;
            nSampleFormat = nBandFormat;
            nXSize = hBand->GetXSize();
            nYSize = hBand->GetYSize();
        }
        else if( nBitsPerPixel != nBandBits || nSampleFormat != nBandFormat )
        {
            CPLError( CE_Failure, CPLE_NotSupported,
                      "GTIFFBuildOverviews() doesn't support a mixture of band"
                      " data types." );
            return CE_Failure;
        }
        else if( hBand->GetColorTable() != nullptr )
        {
            CPLError( CE_Failure, CPLE_NotSupported,
                      "GTIFFBuildOverviews() doesn't support building"
                      " overviews of multiple colormapped bands." );
            return CE_Failure;
        }
        else if( hBand->GetXSize() != nXSize
                 || hBand->GetYSize() != nYSize )
        {
            CPLError( CE_Failure, CPLE_NotSupported,
                      "GTIFFBuildOverviews() doesn't support building"
                      " overviews of different sized bands." );
            return CE_Failure;
        }
    }

/* -------------------------------------------------------------------- */
/*      Use specified compression method.                               */
/* -------------------------------------------------------------------- */
    const char *pszCompress = CPLGetConfigOption( "COMPRESS_OVERVIEW", nullptr );

    if( pszCompress != nullptr && pszCompress[0] != '\0' )
    {
        nCompression =
            GTIFFGetCompressionMethod(pszCompress, "COMPRESS_OVERVIEW");
        if( nCompression < 0 )
            return CE_Failure;
    }

    if( nCompression == COMPRESSION_JPEG && nBitsPerPixel > 8 )
    {
        if( nBitsPerPixel > 16 )
        {
            CPLError( CE_Failure, CPLE_NotSupported,
                      "GTIFFBuildOverviews() doesn't support building"
                      " JPEG compressed overviews of nBitsPerPixel > 16." );
            return CE_Failure;
        }

        nBitsPerPixel = 12;
    }

/* -------------------------------------------------------------------- */
/*      Figure out the planar configuration to use.                     */
/* -------------------------------------------------------------------- */
    if( nBands == 1 )
        nPlanarConfig = PLANARCONFIG_CONTIG;
    else
        nPlanarConfig = PLANARCONFIG_SEPARATE;

    bool bSourceIsPixelInterleaved = false;
    bool bSourceIsJPEG2000 = false;
    if( nBands > 1 )
    {
        GDALDataset* poSrcDS = papoBandList[0]->GetDataset();
        if( poSrcDS )
        {
            const char* pszSrcInterleave = poSrcDS->GetMetadataItem("INTERLEAVE",
                                                                "IMAGE_STRUCTURE");
            if( pszSrcInterleave && EQUAL(pszSrcInterleave, "PIXEL") )
            {
                bSourceIsPixelInterleaved = true;
            }
        }

        const char* pszSrcCompression = papoBandList[0]->GetMetadataItem("COMPRESSION",
                                                                "IMAGE_STRUCTURE");
        if( pszSrcCompression )
        {
            bSourceIsJPEG2000 = EQUAL(pszSrcCompression, "JPEG2000");
        }
        if( bSourceIsPixelInterleaved && bSourceIsJPEG2000 )
        {
            nPlanarConfig = PLANARCONFIG_CONTIG;
        }
    }

    const char* pszInterleave =
        CPLGetConfigOption( "INTERLEAVE_OVERVIEW", nullptr );
    if( pszInterleave != nullptr && pszInterleave[0] != '\0' )
    {
        if( EQUAL( pszInterleave, "PIXEL" ) )
            nPlanarConfig = PLANARCONFIG_CONTIG;
        else if( EQUAL( pszInterleave, "BAND" ) )
            nPlanarConfig = PLANARCONFIG_SEPARATE;
        else
        {
            CPLError(
                CE_Failure, CPLE_AppDefined,
                "INTERLEAVE_OVERVIEW=%s unsupported, "
                "value must be PIXEL or BAND. ignoring",
                pszInterleave );
        }
    }

/* -------------------------------------------------------------------- */
/*      Figure out the photometric interpretation to use.               */
/* -------------------------------------------------------------------- */
    if( nBands == 3 )
        nPhotometric = PHOTOMETRIC_RGB;
    else if( papoBandList[0]->GetColorTable() != nullptr
             && !STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2") )
    {
        nPhotometric = PHOTOMETRIC_PALETTE;
        // Should set the colormap up at this point too!
    }
    else if( nBands >= 3 &&
             papoBandList[0]->GetColorInterpretation() == GCI_RedBand &&
             papoBandList[1]->GetColorInterpretation() == GCI_GreenBand &&
             papoBandList[2]->GetColorInterpretation() == GCI_BlueBand )
    {
        nPhotometric = PHOTOMETRIC_RGB;
    }
    else
        nPhotometric = PHOTOMETRIC_MINISBLACK;

    const char* pszPhotometric =
        CPLGetConfigOption( "PHOTOMETRIC_OVERVIEW", nullptr );
    if( pszPhotometric != nullptr && pszPhotometric[0] != '\0' )
    {
        if( EQUAL( pszPhotometric, "MINISBLACK" ) )
            nPhotometric = PHOTOMETRIC_MINISBLACK;
        else if( EQUAL( pszPhotometric, "MINISWHITE" ) )
            nPhotometric = PHOTOMETRIC_MINISWHITE;
        else if( EQUAL( pszPhotometric, "RGB" ))
        {
            nPhotometric = PHOTOMETRIC_RGB;
        }
        else if( EQUAL( pszPhotometric, "CMYK" ))
        {
            nPhotometric = PHOTOMETRIC_SEPARATED;
        }
        else if( EQUAL( pszPhotometric, "YCBCR" ))
        {
            nPhotometric = PHOTOMETRIC_YCBCR;

            // Because of subsampling, setting YCBCR without JPEG compression
            // leads to a crash currently. Would need to make
            // GTiffRasterBand::IWriteBlock() aware of subsampling so that it
            // doesn't overrun buffer size returned by libtiff.
            if( nCompression != COMPRESSION_JPEG )
            {
                CPLError(
                    CE_Failure, CPLE_NotSupported,
                    "Currently, PHOTOMETRIC_OVERVIEW=YCBCR requires "
                    "COMPRESS_OVERVIEW=JPEG" );
                return CE_Failure;
            }

            if( pszInterleave != nullptr &&
                pszInterleave[0] != '\0' &&
                nPlanarConfig == PLANARCONFIG_SEPARATE )
            {
                CPLError(
                    CE_Failure, CPLE_NotSupported,
                    "PHOTOMETRIC_OVERVIEW=YCBCR requires "
                    "INTERLEAVE_OVERVIEW=PIXEL" );
                return CE_Failure;
            }
            else
            {
                nPlanarConfig = PLANARCONFIG_CONTIG;
            }

            // YCBCR strictly requires 3 bands. Not less, not more
            // Issue an explicit error message as libtiff one is a bit cryptic:
            // JPEGLib:Bogus input colorspace.
            if( nBands != 3 )
            {
                CPLError(
                    CE_Failure, CPLE_NotSupported,
                    "PHOTOMETRIC_OVERVIEW=YCBCR requires a source raster "
                    "with only 3 bands (RGB)" );
                return CE_Failure;
            }
        }
        else if( EQUAL( pszPhotometric, "CIELAB" ))
        {
            nPhotometric = PHOTOMETRIC_CIELAB;
        }
        else if( EQUAL( pszPhotometric, "ICCLAB" ))
        {
            nPhotometric = PHOTOMETRIC_ICCLAB;
        }
        else if( EQUAL( pszPhotometric, "ITULAB" ))
        {
            nPhotometric = PHOTOMETRIC_ITULAB;
        }
        else
        {
            CPLError(
                CE_Warning, CPLE_IllegalArg,
                "PHOTOMETRIC_OVERVIEW=%s value not recognised, ignoring.",
                pszPhotometric );
        }
    }

/* -------------------------------------------------------------------- */
/*      Figure out the predictor value to use.                          */
/* -------------------------------------------------------------------- */
    int nPredictor = PREDICTOR_NONE;
    if( nCompression == COMPRESSION_LZW ||
        nCompression == COMPRESSION_ADOBE_DEFLATE )
    {
        const char* pszPredictor =
            CPLGetConfigOption( "PREDICTOR_OVERVIEW", nullptr );
        if( pszPredictor != nullptr )
        {
            nPredictor = atoi( pszPredictor );
        }
    }

/* -------------------------------------------------------------------- */
/*      Create the file, if it does not already exist.                  */
/* -------------------------------------------------------------------- */
    VSIStatBufL sStatBuf;
    VSILFILE* fpL = nullptr;

    if( VSIStatExL( pszFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
    {
    /* -------------------------------------------------------------------- */
    /*      Compute the uncompressed size.                                  */
    /* -------------------------------------------------------------------- */
        double dfUncompressedOverviewSize = 0;
        int nDataTypeSize =
            GDALGetDataTypeSizeBytes(papoBandList[0]->GetRasterDataType());

        for( iOverview = 0; iOverview < nOverviews; iOverview++ )
        {
            const int nOXSize = (nXSize + panOverviewList[iOverview] - 1)
                / panOverviewList[iOverview];
            const int nOYSize = (nYSize + panOverviewList[iOverview] - 1)
                / panOverviewList[iOverview];

            dfUncompressedOverviewSize +=
                nOXSize * static_cast<double>(nOYSize) * nBands * nDataTypeSize;
        }

        if( nCompression == COMPRESSION_NONE
            && dfUncompressedOverviewSize > 4200000000.0 )
        {
    #ifndef BIGTIFF_SUPPORT
            CPLError(
                CE_Failure, CPLE_NotSupported,
                "The overview file would be larger than 4GB, "
                "but this is the largest size a TIFF can be, "
                "and BigTIFF is unavailable.  "
                "Creation failed." );
            return CE_Failure;
    #endif
        }
    /* -------------------------------------------------------------------- */
    /*      Should the file be created as a bigtiff file?                   */
    /* -------------------------------------------------------------------- */
        const char *pszBIGTIFF = CPLGetConfigOption( "BIGTIFF_OVERVIEW", nullptr );

        if( pszBIGTIFF == nullptr )
            pszBIGTIFF = "IF_SAFER";

        bool bCreateBigTIFF = false;
        if( EQUAL(pszBIGTIFF,"IF_NEEDED") )
        {
            if( nCompression == COMPRESSION_NONE
                && dfUncompressedOverviewSize > 4200000000.0 )
                bCreateBigTIFF = true;
        }
        else if( EQUAL(pszBIGTIFF,"IF_SAFER") )
        {
            // Look at the size of the base image and suppose that
            // the added overview levels won't be more than 1/2 of
            // the size of the base image. The theory says 1/3 of the
            // base image size if the overview levels are 2, 4, 8, 16.
            // Thus take 1/2 as the security margin for 1/3.
            const double dfUncompressedImageSize =
                nXSize * static_cast<double>(nYSize) * nBands * nDataTypeSize;
            if( dfUncompressedImageSize * 0.5 > 4200000000.0 )
                bCreateBigTIFF = true;
        }
        else
        {
            bCreateBigTIFF = CPLTestBool( pszBIGTIFF );
            if( !bCreateBigTIFF && nCompression == COMPRESSION_NONE
                && dfUncompressedOverviewSize > 4200000000.0 )
            {
                CPLError(
                    CE_Failure, CPLE_NotSupported,
                    "The overview file will be larger than 4GB, "
                    "so BigTIFF is necessary.  "
                    "Creation failed.");
                return CE_Failure;
            }
        }

    #ifndef BIGTIFF_SUPPORT
        if( bCreateBigTIFF )
        {
            CPLError(
                CE_Warning, CPLE_NotSupported,
                "BigTIFF requested, but GDAL built without BigTIFF "
                "enabled libtiff, request ignored." );
            bCreateBigTIFF = false;
        }
    #endif

        if( bCreateBigTIFF )
            CPLDebug( "GTiff", "File being created as a BigTIFF." );

        fpL = VSIFOpenL( pszFilename, "w+" );
        if( fpL == nullptr )
            hOTIFF = nullptr;
        else
            hOTIFF =
               VSI_TIFFOpen( pszFilename, bCreateBigTIFF ? "w+8" : "w+", fpL );
        if( hOTIFF == nullptr )
        {
            if( CPLGetLastErrorNo() == 0 )
                CPLError( CE_Failure, CPLE_OpenFailed,
                          "Attempt to create new tiff file `%s' "
                          "failed in VSI_TIFFOpen().",
                          pszFilename );
            if( fpL != nullptr )
                CPL_IGNORE_RET_VAL(VSIFCloseL(fpL));
            return CE_Failure;
        }
    }
/* -------------------------------------------------------------------- */
/*      Otherwise just open it for update access.                       */
/* -------------------------------------------------------------------- */
    else
    {
        fpL = VSIFOpenL( pszFilename, "r+" );
        if( fpL == nullptr )
            hOTIFF = nullptr;
        else
            hOTIFF = VSI_TIFFOpen( pszFilename, "r+", fpL );
        if( hOTIFF == nullptr )
        {
            if( CPLGetLastErrorNo() == 0 )
                CPLError( CE_Failure, CPLE_OpenFailed,
                          "Attempt to create new tiff file `%s' "
                          "failed in VSI_TIFFOpen().",
                          pszFilename );
            if( fpL != nullptr )
                CPL_IGNORE_RET_VAL(VSIFCloseL(fpL));
            return CE_Failure;
        }
    }

/* -------------------------------------------------------------------- */
/*      Do we have a palette?  If so, create a TIFF compatible version. */
/* -------------------------------------------------------------------- */
    unsigned short *panRed = nullptr;
    unsigned short *panGreen = nullptr;
    unsigned short *panBlue = nullptr;

    if( nPhotometric == PHOTOMETRIC_PALETTE )
    {
        GDALColorTable *poCT = papoBandList[0]->GetColorTable();
        int nColorCount = 65536;

        if( nBitsPerPixel <= 8 )
            nColorCount = 256;

        panRed = static_cast<unsigned short *>(
            CPLCalloc(nColorCount, sizeof(unsigned short)) );
        panGreen = static_cast<unsigned short *>(
            CPLCalloc(nColorCount, sizeof(unsigned short)) );
        panBlue = static_cast<unsigned short *>(
            CPLCalloc(nColorCount, sizeof(unsigned short)) );

        for( int iColor = 0; iColor < nColorCount; iColor++ )
        {
          GDALColorEntry sRGB = { 0, 0, 0, 0 };

            if( poCT->GetColorEntryAsRGB( iColor, &sRGB ) )
            {
                // TODO(schwehr): Check for underflow.
                // Going from signed short to unsigned short.
                panRed[iColor] = static_cast<unsigned short>(257 * sRGB.c1);
                panGreen[iColor] = static_cast<unsigned short>(257 * sRGB.c2);
                panBlue[iColor] = static_cast<unsigned short>(257 * sRGB.c3);
            }
        }
    }

/* -------------------------------------------------------------------- */
/*      Do we need some metadata for the overviews?                     */
/* -------------------------------------------------------------------- */
    CPLString osMetadata;
    GDALDataset *poBaseDS = papoBandList[0]->GetDataset();

    GTIFFBuildOverviewMetadata( pszResampling, poBaseDS, osMetadata );

/* -------------------------------------------------------------------- */
/*      Loop, creating overviews.                                       */
/* -------------------------------------------------------------------- */
    int nOvrBlockXSize = 0;
    int nOvrBlockYSize = 0;
    GTIFFGetOverviewBlockSize(&nOvrBlockXSize, &nOvrBlockYSize);

    CPLString osNoData; // don't move this in inner scope
    const char* pszNoData = nullptr;
    int bNoDataSet = FALSE;
    const double dfNoDataValue = papoBandList[0]->GetNoDataValue(&bNoDataSet);
    if( bNoDataSet )
    {
        osNoData = GTiffFormatGDALNoDataTagValue(dfNoDataValue);
        pszNoData = osNoData.c_str();
    }

    std::vector<uint16> anExtraSamples;
    for( int i = GTIFFGetMaxColorChannels(nPhotometric)+1; i <= nBands; i++ )
    {
        if( papoBandList[i-1]->GetColorInterpretation() == GCI_AlphaBand )
        {
            anExtraSamples.push_back(
                GTiffGetAlphaValue(CPLGetConfigOption("GTIFF_ALPHA", nullptr),
                                   DEFAULT_ALPHA_TYPE));
        }
        else
        {
            anExtraSamples.push_back(EXTRASAMPLE_UNSPECIFIED);
        }
    }

    for( iOverview = 0; iOverview < nOverviews; iOverview++ )
    {
        const int nOXSize = (nXSize + panOverviewList[iOverview] - 1)
            / panOverviewList[iOverview];
        const int nOYSize = (nYSize + panOverviewList[iOverview] - 1)
            / panOverviewList[iOverview];

        GTIFFWriteDirectory( hOTIFF, FILETYPE_REDUCEDIMAGE,
                             nOXSize, nOYSize, nBitsPerPixel,
                             nPlanarConfig, nBands,
                             nOvrBlockXSize, nOvrBlockYSize, TRUE, nCompression,
                             nPhotometric, nSampleFormat, nPredictor,
                             panRed, panGreen, panBlue,
                             static_cast<int>(anExtraSamples.size()),
                             anExtraSamples.empty() ? nullptr : anExtraSamples.data(),
                             osMetadata,
                             CPLGetConfigOption( "JPEG_QUALITY_OVERVIEW", nullptr ),
                             CPLGetConfigOption( "JPEG_TABLESMODE_OVERVIEW", nullptr ),
                             pszNoData,
                             nullptr
                           );
    }

    if( panRed )
    {
        CPLFree(panRed);
        CPLFree(panGreen);
        CPLFree(panBlue);
        panRed = nullptr;
        panGreen = nullptr;
        panBlue = nullptr;
    }

    XTIFFClose( hOTIFF );
    if( VSIFCloseL(fpL) != 0 )
        return CE_Failure;
    fpL = nullptr;

/* -------------------------------------------------------------------- */
/*      Open the overview dataset so that we can get at the overview    */
/*      bands.                                                          */
/* -------------------------------------------------------------------- */
    GDALDataset *hODS = GDALDataset::Open( pszFilename,
                                           GDAL_OF_RASTER | GDAL_OF_UPDATE );
    if( hODS == nullptr )
        return CE_Failure;

/* -------------------------------------------------------------------- */
/*      Do we need to set the jpeg quality?                             */
/* -------------------------------------------------------------------- */
    TIFF *hTIFF = static_cast<TIFF *>( hODS->GetInternalHandle(nullptr) );

    if( nCompression == COMPRESSION_JPEG
        && CPLGetConfigOption( "JPEG_QUALITY_OVERVIEW", nullptr ) != nullptr )
    {
        const int nJpegQuality =
            atoi(CPLGetConfigOption("JPEG_QUALITY_OVERVIEW","75"));
        TIFFSetField( hTIFF, TIFFTAG_JPEGQUALITY,
                      nJpegQuality );
        GTIFFSetJpegQuality(GDALDataset::ToHandle(hODS), nJpegQuality);
    }

    if( nCompression == COMPRESSION_JPEG
        && CPLGetConfigOption( "JPEG_TABLESMODE_OVERVIEW", nullptr ) != nullptr )
    {
        const int nJpegTablesMode =
            atoi(CPLGetConfigOption("JPEG_TABLESMODE_OVERVIEW",
                            CPLSPrintf("%d", knGTIFFJpegTablesModeDefault)));
        TIFFSetField( hTIFF, TIFFTAG_JPEGTABLESMODE,
                      nJpegTablesMode );
        GTIFFSetJpegTablesMode(GDALDataset::ToHandle(hODS), nJpegTablesMode);
    }

/* -------------------------------------------------------------------- */
/*      Loop writing overview data.                                     */
/* -------------------------------------------------------------------- */

    int *panOverviewListSorted =
        static_cast<int*>(CPLMalloc(sizeof(int) * nOverviews));
    memcpy( panOverviewListSorted, panOverviewList, sizeof(int) * nOverviews);
    std::sort(panOverviewListSorted, panOverviewListSorted + nOverviews);

    GTIFFSetInExternalOvr(true);

    CPLErr eErr = CE_None;

    if(  ((bSourceIsPixelInterleaved && bSourceIsJPEG2000) ||
          (nCompression != COMPRESSION_NONE)) &&
         nPlanarConfig == PLANARCONFIG_CONTIG &&
         !GDALDataTypeIsComplex(papoBandList[0]->GetRasterDataType()) &&
         papoBandList[0]->GetColorTable() == nullptr &&
         (STARTS_WITH_CI(pszResampling, "NEAR") ||
          EQUAL(pszResampling, "AVERAGE") ||
          EQUAL(pszResampling, "GAUSS") ||
          EQUAL(pszResampling, "CUBIC") ||
          EQUAL(pszResampling, "CUBICSPLINE") ||
          EQUAL(pszResampling, "LANCZOS") ||
          EQUAL(pszResampling, "BILINEAR")) )
    {
        // In the case of pixel interleaved compressed overviews, we want to
        // generate the overviews for all the bands block by block, and not
        // band after band, in order to write the block once and not loose
        // space in the TIFF file.
        GDALRasterBand ***papapoOverviewBands =
            static_cast<GDALRasterBand ***>(
                CPLCalloc(sizeof(void *), nBands) );
        for( int iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
        {
            GDALRasterBand *poSrcBand = papoBandList[iBand];
            GDALRasterBand *poDstBand = hODS->GetRasterBand( iBand + 1 );
            papapoOverviewBands[iBand] =
                static_cast<GDALRasterBand **>(
                    CPLCalloc(sizeof(void *), nOverviews) );

            int bHasNoData = FALSE;
            const double noDataValue = poSrcBand->GetNoDataValue(&bHasNoData);
            if( bHasNoData )
                poDstBand->SetNoDataValue(noDataValue);

            for( int i = 0; i < nOverviews && eErr == CE_None; i++ )
            {
                for( int j = -1; j < poDstBand->GetOverviewCount() &&
                                 eErr == CE_None; j++ )
                {
                    GDALRasterBand * poOverview =
                            (j < 0 ) ? poDstBand : poDstBand->GetOverview( j );
                    if( poOverview == nullptr )
                    {
                        eErr = CE_Failure;
                        continue;
                    }

                    const int nOvFactor =
                        GDALComputeOvFactor(poOverview->GetXSize(),
                                            poSrcBand->GetXSize(),
                                            poOverview->GetYSize(),
                                            poSrcBand->GetYSize());

                    if( nOvFactor == panOverviewListSorted[i]
                        || nOvFactor == GDALOvLevelAdjust2(
                                            panOverviewListSorted[i],
                                            poSrcBand->GetXSize(),
                                            poSrcBand->GetYSize() ) )
                    {
                        papapoOverviewBands[iBand][i] = poOverview;
                        if( bHasNoData )
                            poOverview->SetNoDataValue(noDataValue);
                        break;
                    }
                }
                CPLAssert( papapoOverviewBands[iBand][i] != nullptr );
            }
        }

        if( eErr == CE_None )
            eErr =
                GDALRegenerateOverviewsMultiBand(
                    nBands, papoBandList,
                    nOverviews, papapoOverviewBands,
                    pszResampling, pfnProgress, pProgressData );

        for( int iBand = 0; iBand < nBands; iBand++ )
        {
            CPLFree(papapoOverviewBands[iBand]);
        }
        CPLFree(papapoOverviewBands);
    }
    else
    {
        GDALRasterBand **papoOverviews =
            static_cast<GDALRasterBand **>(
                CPLCalloc( sizeof(void*), knMaxOverviews ) );

        for( int iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
        {
            GDALRasterBand *hSrcBand = papoBandList[iBand];
            GDALRasterBand *hDstBand = hODS->GetRasterBand( iBand + 1 );

            int bHasNoData = FALSE;
            const double noDataValue = hSrcBand->GetNoDataValue(&bHasNoData);
            if( bHasNoData )
                hDstBand->SetNoDataValue(noDataValue);

            // FIXME: this logic regenerates all overview bands, not only the
            // ones requested.

            papoOverviews[0] = hDstBand;
            int nDstOverviews = hDstBand->GetOverviewCount() + 1;
            CPLAssert( nDstOverviews < knMaxOverviews );
            nDstOverviews = std::min(knMaxOverviews, nDstOverviews);

            // TODO(schwehr): Convert to starting with i = 1 and remove +1.
            for( int i = 0; i < nDstOverviews - 1 && eErr == CE_None; i++ )
            {
                papoOverviews[i+1] = hDstBand->GetOverview(i);
                if( papoOverviews[i+1] == nullptr )
                {
                    eErr = CE_Failure;
                }
                else
                {
                    if( bHasNoData )
                        papoOverviews[i+1]->SetNoDataValue(noDataValue);
                }
            }

            void *pScaledProgressData =
                GDALCreateScaledProgress(
                    iBand / static_cast<double>( nBands ),
                    (iBand + 1) / static_cast<double>( nBands ),
                    pfnProgress, pProgressData );

            if( eErr == CE_None )
                eErr =
                    GDALRegenerateOverviews(
                        hSrcBand,
                        nDstOverviews,
                        reinterpret_cast<GDALRasterBandH *>( papoOverviews ),
                        pszResampling,
                        GDALScaledProgress,
                        pScaledProgressData );

            GDALDestroyScaledProgress( pScaledProgressData );
        }

        CPLFree( papoOverviews );
    }

/* -------------------------------------------------------------------- */
/*      Cleanup                                                         */
/* -------------------------------------------------------------------- */
    if( eErr == CE_None )
        hODS->FlushCache();
    delete hODS;

    GTIFFSetInExternalOvr(false);

    CPLFree(panOverviewListSorted);

    pfnProgress( 1.0, nullptr, pProgressData );

    return eErr;
}
Example #11
0
int GDALDefaultOverviews::HaveMaskFile( char ** papszSiblingFiles,
                                        const char *pszBasename )

{
/* -------------------------------------------------------------------- */
/*      Have we already checked for masks?                              */
/* -------------------------------------------------------------------- */
    if( bCheckedForMask )
        return poMaskDS != NULL;

    if( papszSiblingFiles == NULL )
        papszSiblingFiles = papszInitSiblingFiles;

/* -------------------------------------------------------------------- */
/*      Are we an overview?  If so we need to find the corresponding    */
/*      overview in the base files mask file (if there is one).         */
/* -------------------------------------------------------------------- */
    if( poBaseDS != NULL && poBaseDS->oOvManager.HaveMaskFile() )
    {
        int iOver, nOverviewCount = 0;
        GDALRasterBand *poBaseBand = poBaseDS->GetRasterBand(1);
        GDALRasterBand *poBaseMask = NULL;

        if( poBaseBand != NULL )
            poBaseMask = poBaseBand->GetMaskBand();
        if( poBaseMask )
            nOverviewCount = poBaseMask->GetOverviewCount();

        for( iOver = 0; iOver < nOverviewCount; iOver++ )
        {
            GDALRasterBand *poOverBand = poBaseMask->GetOverview( iOver );
            if (poOverBand == NULL)
                continue;
            
            if( poOverBand->GetXSize() == poDS->GetRasterXSize() 
                && poOverBand->GetYSize() == poDS->GetRasterYSize() )
            {
                poMaskDS = poOverBand->GetDataset();
                break;
            }
        }

        bCheckedForMask = TRUE;
        bOwnMaskDS = FALSE;
        
        CPLAssert( poMaskDS != poDS );

        return poMaskDS != NULL;
    }

/* -------------------------------------------------------------------- */
/*      Are we even initialized?  If not, we apparently don't want      */
/*      to support overviews and masks.                                 */
/* -------------------------------------------------------------------- */
    if( poDS == NULL )
        return FALSE;

/* -------------------------------------------------------------------- */
/*      Check for .msk file.                                            */
/* -------------------------------------------------------------------- */
    CPLString osMskFilename;
    bCheckedForMask = TRUE;

    if( pszBasename == NULL )
        pszBasename = poDS->GetDescription();

    // Don't bother checking for masks of masks. 
    if( EQUAL(CPLGetExtension(pszBasename),"msk") )
        return FALSE;

    osMskFilename.Printf( "%s.msk", pszBasename );

    int bExists = CPLCheckForFile( (char *) osMskFilename.c_str(), 
                                   papszSiblingFiles );

#if !defined(WIN32)
    if( !bExists && !papszSiblingFiles )
    {
        osMskFilename.Printf( "%s.MSK", pszBasename );
        bExists = CPLCheckForFile( (char *) osMskFilename.c_str(), 
                                   papszSiblingFiles );
    }
#endif

    if( !bExists )
        return FALSE;

/* -------------------------------------------------------------------- */
/*      Open the file.                                                  */
/* -------------------------------------------------------------------- */
    GDALOpenInfo oOpenInfo(osMskFilename, poDS->GetAccess(),
                           papszInitSiblingFiles);
    poMaskDS = (GDALDataset *) GDALOpenInternal( oOpenInfo, NULL );
    CPLAssert( poMaskDS != poDS );

    if( poMaskDS == NULL )
        return FALSE;

    bOwnMaskDS = TRUE;
    
    return TRUE;
}
Example #12
0
const char *GDALWMSRasterBand::GetMetadataItem( const char * pszName,
                                                const char * pszDomain )
{
/* ==================================================================== */
/*      LocationInfo handling.                                          */
/* ==================================================================== */
    if( pszDomain != NULL
        && EQUAL(pszDomain,"LocationInfo")
        && (STARTS_WITH_CI(pszName, "Pixel_") || STARTS_WITH_CI(pszName, "GeoPixel_")) )
    {
        int iPixel, iLine;

/* -------------------------------------------------------------------- */
/*      What pixel are we aiming at?                                    */
/* -------------------------------------------------------------------- */
        if( STARTS_WITH_CI(pszName, "Pixel_") )
        {
            if( sscanf( pszName+6, "%d_%d", &iPixel, &iLine ) != 2 )
                return NULL;
        }
        else if( STARTS_WITH_CI(pszName, "GeoPixel_") )
        {
            double adfGeoTransform[6];
            double adfInvGeoTransform[6];
            double dfGeoX, dfGeoY;

            {
                dfGeoX = CPLAtof(pszName + 9);
                const char* pszUnderscore = strchr(pszName + 9, '_');
                if( !pszUnderscore )
                    return NULL;
                dfGeoY = CPLAtof(pszUnderscore+1);
            }

            if( m_parent_dataset->GetGeoTransform( adfGeoTransform ) != CE_None )
                return NULL;

            if( !GDALInvGeoTransform( adfGeoTransform, adfInvGeoTransform ) )
                return NULL;

            iPixel = (int) floor(
                adfInvGeoTransform[0]
                + adfInvGeoTransform[1] * dfGeoX
                + adfInvGeoTransform[2] * dfGeoY );
            iLine = (int) floor(
                adfInvGeoTransform[3]
                + adfInvGeoTransform[4] * dfGeoX
                + adfInvGeoTransform[5] * dfGeoY );

            /* The GetDataset() for the WMS driver is always the main overview level, so rescale */
            /* the values if we are an overview */
            if (m_overview >= 0)
            {
                iPixel = (int) (1.0 * iPixel * GetXSize() / m_parent_dataset->GetRasterBand(1)->GetXSize());
                iLine = (int) (1.0 * iLine * GetYSize() / m_parent_dataset->GetRasterBand(1)->GetYSize());
            }
        }
        else
            return NULL;

        if( iPixel < 0 || iLine < 0
            || iPixel >= GetXSize()
            || iLine >= GetYSize() )
            return NULL;

        if (nBand != 1)
        {
            GDALRasterBand* poFirstBand = m_parent_dataset->GetRasterBand(1);
            if (m_overview >= 0)
                poFirstBand = poFirstBand->GetOverview(m_overview);
            if (poFirstBand)
                return poFirstBand->GetMetadataItem(pszName, pszDomain);
        }

        GDALWMSImageRequestInfo iri;
        GDALWMSTiledImageRequestInfo tiri;
        int nBlockXOff = iPixel / nBlockXSize;
        int nBlockYOff = iLine / nBlockYSize;

        ComputeRequestInfo(iri, tiri, nBlockXOff, nBlockYOff);

        CPLString url;
        m_parent_dataset->m_mini_driver->GetTiledImageInfo(&url,
                                                           iri, tiri,
                                                           iPixel % nBlockXSize,
                                                           iLine % nBlockXSize);


        char* pszRes = NULL;

        if (url.size() != 0)
        {
            if (url == osMetadataItemURL)
            {
                return osMetadataItem.size() != 0 ? osMetadataItem.c_str() : NULL;
            }
            osMetadataItemURL = url;

            char **http_request_opts = BuildHTTPRequestOpts();
            CPLHTTPResult* psResult = CPLHTTPFetch( url.c_str(), http_request_opts);
            if( psResult && psResult->pabyData )
                pszRes = CPLStrdup((const char*) psResult->pabyData);
            CPLHTTPDestroyResult(psResult);
            CSLDestroy(http_request_opts);
        }

        if (pszRes)
        {
            osMetadataItem = "<LocationInfo>";
            CPLPushErrorHandler(CPLQuietErrorHandler);
            CPLXMLNode* psXML = CPLParseXMLString(pszRes);
            CPLPopErrorHandler();
            if (psXML != NULL && psXML->eType == CXT_Element)
            {
                if (strcmp(psXML->pszValue, "?xml") == 0)
                {
                    if (psXML->psNext)
                    {
                        char* pszXML = CPLSerializeXMLTree(psXML->psNext);
                        osMetadataItem += pszXML;
                        CPLFree(pszXML);
                    }
                }
                else
                {
                    osMetadataItem += pszRes;
                }
            }
            else
            {
                char* pszEscapedXML = CPLEscapeString(pszRes, -1, CPLES_XML_BUT_QUOTES);
                osMetadataItem += pszEscapedXML;
                CPLFree(pszEscapedXML);
            }
            if (psXML != NULL)
                CPLDestroyXMLNode(psXML);

            osMetadataItem += "</LocationInfo>";
            CPLFree(pszRes);
            return osMetadataItem.c_str();
        }
        else
        {
            osMetadataItem = "";
            return NULL;
        }
    }

    return GDALPamRasterBand::GetMetadataItem(pszName, pszDomain);
}
CPLErr
GDALDefaultOverviews::BuildOverviews( 
    const char * pszBasename,
    const char * pszResampling, 
    int nOverviews, int * panOverviewList,
    int nBands, int * panBandList,
    GDALProgressFunc pfnProgress, void * pProgressData)

{
    GDALRasterBand **pahBands;
    CPLErr       eErr;
    int          i;

    if( pfnProgress == NULL )
        pfnProgress = GDALDummyProgress;

    if( nOverviews == 0 )
        return CleanOverviews();

/* -------------------------------------------------------------------- */
/*      If we don't already have an overview file, we need to decide    */
/*      what format to use.                                             */
/* -------------------------------------------------------------------- */
    if( poODS == NULL )
    {
        bOvrIsAux = CSLTestBoolean(CPLGetConfigOption( "USE_RRD", "NO" ));
        if( bOvrIsAux )
        {
            VSIStatBufL sStatBuf;

            osOvrFilename = CPLResetExtension(poDS->GetDescription(),"aux");

            if( VSIStatL( osOvrFilename, &sStatBuf ) == 0 )
                osOvrFilename.Printf( "%s.aux", poDS->GetDescription() );
        }
    }
/* -------------------------------------------------------------------- */
/*      If we already have the overviews open, but they are             */
/*      read-only, then try and reopen them read-write.                 */
/* -------------------------------------------------------------------- */
    else if( poODS->GetAccess() == GA_ReadOnly )
    {
        GDALClose( poODS );
        poODS = (GDALDataset *) GDALOpen( osOvrFilename, GA_Update );
        if( poODS == NULL )
            return CE_Failure;
    }

/* -------------------------------------------------------------------- */
/*      Our TIFF overview support currently only works safely if all    */
/*      bands are handled at the same time.                             */
/* -------------------------------------------------------------------- */
    if( !bOvrIsAux && nBands != poDS->GetRasterCount() )
    {
        CPLError( CE_Failure, CPLE_NotSupported,
                  "Generation of overviews in external TIFF currently only"
                  " supported when operating on all bands.\n" 
                  "Operation failed.\n" );
        return CE_Failure;
    }

/* -------------------------------------------------------------------- */
/*      If a basename is provided, use it to override the internal      */
/*      overview filename.                                              */
/* -------------------------------------------------------------------- */
    if( pszBasename == NULL && osOvrFilename.length() == 0  )
        pszBasename = poDS->GetDescription();

    if( pszBasename != NULL )
    {
        if( bOvrIsAux )
            osOvrFilename.Printf( "%s.aux", pszBasename );
        else
            osOvrFilename.Printf( "%s.ovr", pszBasename );
    }

/* -------------------------------------------------------------------- */
/*      Establish which of the overview levels we already have, and     */
/*      which are new.  We assume that band 1 of the file is            */
/*      representative.                                                 */
/* -------------------------------------------------------------------- */
    int   nNewOverviews, *panNewOverviewList = NULL;
    GDALRasterBand *poBand = poDS->GetRasterBand( 1 );

    nNewOverviews = 0;
    panNewOverviewList = (int *) CPLCalloc(sizeof(int),nOverviews);
    for( i = 0; i < nOverviews && poBand != NULL; i++ )
    {
        int   j;

        for( j = 0; j < poBand->GetOverviewCount(); j++ )
        {
            int    nOvFactor;
            GDALRasterBand * poOverview = poBand->GetOverview( j );
 
            nOvFactor = (int) 
                (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());

            if( nOvFactor == panOverviewList[i] 
                || nOvFactor == GDALOvLevelAdjust( panOverviewList[i], 
                                                   poBand->GetXSize() ) )
                panOverviewList[i] *= -1;
        }

        if( panOverviewList[i] > 0 )
            panNewOverviewList[nNewOverviews++] = panOverviewList[i];
    }

/* -------------------------------------------------------------------- */
/*      Build band list.                                                */
/* -------------------------------------------------------------------- */
    pahBands = (GDALRasterBand **) CPLCalloc(sizeof(GDALRasterBand *),nBands);
    for( i = 0; i < nBands; i++ )
        pahBands[i] = poDS->GetRasterBand( panBandList[i] );

/* -------------------------------------------------------------------- */
/*      Build new overviews - Imagine.  Keep existing file open if      */
/*      we have it.  But mark all overviews as in need of               */
/*      regeneration, since HFAAuxBuildOverviews() doesn't actually     */
/*      produce the imagery.                                            */
/* -------------------------------------------------------------------- */

#ifndef WIN32CE

    if( bOvrIsAux )
    {
        eErr = HFAAuxBuildOverviews( osOvrFilename, poDS, &poODS,
                                     nBands, panBandList,
                                     nNewOverviews, panNewOverviewList, 
                                     pszResampling, 
                                     pfnProgress, pProgressData );

        int j;
        
        for( j = 0; j < nOverviews; j++ )
        {
            if( panOverviewList[j] > 0 )
                panOverviewList[j] *= -1;
        }
    }

/* -------------------------------------------------------------------- */
/*      Build new overviews - TIFF.  Close TIFF files while we          */
/*      operate on it.                                                  */
/* -------------------------------------------------------------------- */
    else
#endif /* WIN32CE */
    {
        if( poODS != NULL )
        {
            delete poODS;
            poODS = NULL;
        }

        eErr = GTIFFBuildOverviews( osOvrFilename, nBands, pahBands, 
                                    nNewOverviews, panNewOverviewList, 
                                    pszResampling, pfnProgress, pProgressData );
        
        // Probe for proxy overview filename. 
        if( eErr == CE_Failure )
        {
            const char *pszProxyOvrFilename = 
                poDS->GetMetadataItem("FILENAME","ProxyOverviewRequest");

            if( pszProxyOvrFilename != NULL )
            {
                osOvrFilename = pszProxyOvrFilename;
                eErr = GTIFFBuildOverviews( osOvrFilename, nBands, pahBands, 
                                            nNewOverviews, panNewOverviewList, 
                                            pszResampling, 
                                            pfnProgress, pProgressData );
            }
        }

        if( eErr == CE_None )
        {
            poODS = (GDALDataset *) GDALOpen( osOvrFilename, GA_Update );
            if( poODS == NULL )
                eErr = CE_Failure;
        }
    }

/* -------------------------------------------------------------------- */
/*      Refresh old overviews that were listed.                         */
/* -------------------------------------------------------------------- */
    GDALRasterBand **papoOverviewBands;

    papoOverviewBands = (GDALRasterBand **) 
        CPLCalloc(sizeof(void*),nOverviews);

    for( int iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
    {
        poBand = poDS->GetRasterBand( panBandList[iBand] );

        nNewOverviews = 0;
        for( i = 0; i < nOverviews && poBand != NULL; i++ )
        {
            int   j;
            
            for( j = 0; j < poBand->GetOverviewCount(); j++ )
            {
                int    nOvFactor;
                GDALRasterBand * poOverview = poBand->GetOverview( j );

                int bHasNoData;
                double noDataValue = poBand->GetNoDataValue(&bHasNoData);

                if (bHasNoData)
                  poOverview->SetNoDataValue(noDataValue);

                nOvFactor = (int) 
                    (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());

                if( nOvFactor == - panOverviewList[i] 
                    || nOvFactor == GDALOvLevelAdjust( -panOverviewList[i], 
                                                       poBand->GetXSize() ) )
                {
                    papoOverviewBands[nNewOverviews++] = poOverview;
                    break;
                }
            }
        }

        if( nNewOverviews > 0 )
        {
            eErr = GDALRegenerateOverviews( (GDALRasterBandH) poBand, 
                                            nNewOverviews, 
                                            (GDALRasterBandH*)papoOverviewBands,
                                            pszResampling, 
                                            pfnProgress, pProgressData );
        }
    }

/* -------------------------------------------------------------------- */
/*      Cleanup                                                         */
/* -------------------------------------------------------------------- */
    CPLFree( papoOverviewBands );
    CPLFree( panNewOverviewList );
    CPLFree( pahBands );

/* -------------------------------------------------------------------- */
/*      If we have a mask file, we need to build it's overviews         */
/*      too.                                                            */
/* -------------------------------------------------------------------- */
    if( HaveMaskFile() && poMaskDS )
    {
        poMaskDS->BuildOverviews( pszResampling, nOverviews, panOverviewList,
                                  0, NULL, pfnProgress, pProgressData );
        if( bOwnMaskDS )
            GDALClose( poMaskDS );

        // force next request to reread mask file.
        poMaskDS = NULL;
        bOwnMaskDS = FALSE;
        bCheckedForMask = FALSE;
    }

/* -------------------------------------------------------------------- */
/*      If we have an overview dataset, then mark all the overviews     */
/*      with the base dataset  Used later for finding overviews         */
/*      masks.  Uggg.                                                   */
/* -------------------------------------------------------------------- */
    if( poODS )
    {
        int nOverviewCount = GetOverviewCount(1);
        int iOver;

        for( iOver = 0; iOver < nOverviewCount; iOver++ )
        {
            GDALRasterBand *poBand = GetOverview( 1, iOver );
            GDALDataset    *poOverDS = NULL;

            if( poBand != NULL )
                poOverDS = poBand->GetDataset();

            if (poOverDS != NULL)
            {
                poOverDS->oOvManager.poBaseDS = poDS;
                poOverDS->oOvManager.poDS = poOverDS;
            }
        }
    }

    return eErr;
}