mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-06-01 14:22:41 -06:00
1125 lines
41 KiB
C++
1125 lines
41 KiB
C++
/******************************************************************************
|
|
* $Id: gdaldefaultoverviews.cpp 28907 2015-04-14 15:14:32Z rouault $
|
|
*
|
|
* Project: GDAL Core
|
|
* Purpose: Helper code to implement overview and mask support for many
|
|
* drivers with no inherent format support.
|
|
* Author: Frank Warmerdam, warmerdam@pobox.com
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 2000, 2007, Frank Warmerdam
|
|
* Copyright (c) 2007-2013, Even Rouault <even dot rouault at mines-paris dot org>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
****************************************************************************/
|
|
|
|
#include "gdal_priv.h"
|
|
#include "cpl_string.h"
|
|
|
|
CPL_CVSID("$Id: gdaldefaultoverviews.cpp 28907 2015-04-14 15:14:32Z rouault $");
|
|
|
|
/************************************************************************/
|
|
/* GDALDefaultOverviews() */
|
|
/************************************************************************/
|
|
|
|
GDALDefaultOverviews::GDALDefaultOverviews()
|
|
|
|
{
|
|
poDS = NULL;
|
|
poODS = NULL;
|
|
bOvrIsAux = FALSE;
|
|
|
|
bCheckedForMask = FALSE;
|
|
bCheckedForOverviews = FALSE;
|
|
|
|
poMaskDS = NULL;
|
|
|
|
bOwnMaskDS = FALSE;
|
|
poBaseDS = NULL;
|
|
|
|
papszInitSiblingFiles = NULL;
|
|
pszInitName = NULL;
|
|
bInitNameIsOVR = FALSE;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~GDALDefaultOverviews() */
|
|
/************************************************************************/
|
|
|
|
GDALDefaultOverviews::~GDALDefaultOverviews()
|
|
|
|
{
|
|
CPLFree( pszInitName );
|
|
CSLDestroy( papszInitSiblingFiles );
|
|
|
|
CloseDependentDatasets();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* CloseDependentDatasets() */
|
|
/************************************************************************/
|
|
|
|
int GDALDefaultOverviews::CloseDependentDatasets()
|
|
{
|
|
int bHasDroppedRef = FALSE;
|
|
if( poODS != NULL )
|
|
{
|
|
bHasDroppedRef = TRUE;
|
|
poODS->FlushCache();
|
|
GDALClose( poODS );
|
|
poODS = NULL;
|
|
}
|
|
|
|
if( poMaskDS != NULL )
|
|
{
|
|
if( bOwnMaskDS )
|
|
{
|
|
bHasDroppedRef = TRUE;
|
|
poMaskDS->FlushCache();
|
|
GDALClose( poMaskDS );
|
|
}
|
|
poMaskDS = NULL;
|
|
}
|
|
|
|
return bHasDroppedRef;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* IsInitialized() */
|
|
/* */
|
|
/* Returns TRUE if we are initialized. */
|
|
/************************************************************************/
|
|
|
|
int GDALDefaultOverviews::IsInitialized()
|
|
|
|
{
|
|
OverviewScan();
|
|
return poDS != NULL;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Initialize() */
|
|
/************************************************************************/
|
|
|
|
void GDALDefaultOverviews::Initialize( GDALDataset *poDSIn,
|
|
const char * pszBasename,
|
|
char **papszSiblingFiles,
|
|
int bNameIsOVR )
|
|
|
|
{
|
|
poDS = poDSIn;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* If we were already initialized, destroy the old overview */
|
|
/* file handle. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( poODS != NULL )
|
|
{
|
|
GDALClose( poODS );
|
|
poODS = NULL;
|
|
|
|
CPLDebug( "GDAL", "GDALDefaultOverviews::Initialize() called twice - this is odd and perhaps dangerous!" );
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Store the initialization information for later use in */
|
|
/* OverviewScan() */
|
|
/* -------------------------------------------------------------------- */
|
|
bCheckedForOverviews = FALSE;
|
|
|
|
CPLFree( pszInitName );
|
|
pszInitName = NULL;
|
|
if( pszBasename != NULL )
|
|
pszInitName = CPLStrdup(pszBasename);
|
|
bInitNameIsOVR = bNameIsOVR;
|
|
|
|
CSLDestroy( papszInitSiblingFiles );
|
|
papszInitSiblingFiles = NULL;
|
|
if( papszSiblingFiles != NULL )
|
|
papszInitSiblingFiles = CSLDuplicate(papszSiblingFiles);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* OverviewScan() */
|
|
/* */
|
|
/* This is called to scan for overview files when a first */
|
|
/* request is made with regard to overviews. It uses the */
|
|
/* pszInitName, bInitNameIsOVR and papszInitSiblingFiles */
|
|
/* information that was stored at Initialization() time. */
|
|
/************************************************************************/
|
|
|
|
void GDALDefaultOverviews::OverviewScan()
|
|
|
|
{
|
|
if( bCheckedForOverviews || poDS == NULL )
|
|
return;
|
|
|
|
bCheckedForOverviews = true;
|
|
|
|
CPLDebug( "GDAL", "GDALDefaultOverviews::OverviewScan()" );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Open overview dataset if it exists. */
|
|
/* -------------------------------------------------------------------- */
|
|
int bExists;
|
|
|
|
if( pszInitName == NULL )
|
|
pszInitName = CPLStrdup(poDS->GetDescription());
|
|
|
|
if( !EQUAL(pszInitName,":::VIRTUAL:::") )
|
|
{
|
|
if( bInitNameIsOVR )
|
|
osOvrFilename = pszInitName;
|
|
else
|
|
{
|
|
if( !GDALCanFileAcceptSidecarFile(pszInitName) )
|
|
return;
|
|
osOvrFilename.Printf( "%s.ovr", pszInitName );
|
|
}
|
|
|
|
bExists = CPLCheckForFile( (char *) osOvrFilename.c_str(),
|
|
papszInitSiblingFiles );
|
|
|
|
#if !defined(WIN32)
|
|
if( !bInitNameIsOVR && !bExists && !papszInitSiblingFiles )
|
|
{
|
|
osOvrFilename.Printf( "%s.OVR", pszInitName );
|
|
bExists = CPLCheckForFile( (char *) osOvrFilename.c_str(),
|
|
papszInitSiblingFiles );
|
|
if( !bExists )
|
|
osOvrFilename.Printf( "%s.ovr", pszInitName );
|
|
}
|
|
#endif
|
|
|
|
if( bExists )
|
|
{
|
|
poODS = (GDALDataset*) GDALOpenEx( osOvrFilename,
|
|
GDAL_OF_RASTER |
|
|
((poDS->GetAccess() == GA_Update) ? GDAL_OF_UPDATE : 0),
|
|
NULL, NULL, papszInitSiblingFiles );
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* We didn't find that, so try and find a corresponding aux */
|
|
/* file. Check that we are the dependent file of the aux */
|
|
/* file. */
|
|
/* */
|
|
/* We only use the .aux file for overviews if they already have */
|
|
/* overviews existing, or if USE_RRD is set true. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( !poODS && !EQUAL(pszInitName,":::VIRTUAL:::") )
|
|
{
|
|
int bTryFindAssociatedAuxFile = TRUE;
|
|
if( papszInitSiblingFiles )
|
|
{
|
|
CPLString osAuxFilename = CPLResetExtension( pszInitName, "aux");
|
|
int iSibling = CSLFindString( papszInitSiblingFiles,
|
|
CPLGetFilename(osAuxFilename) );
|
|
if( iSibling < 0 )
|
|
{
|
|
osAuxFilename = pszInitName;
|
|
osAuxFilename += ".aux";
|
|
iSibling = CSLFindString( papszInitSiblingFiles,
|
|
CPLGetFilename(osAuxFilename) );
|
|
if( iSibling < 0 )
|
|
bTryFindAssociatedAuxFile = FALSE;
|
|
}
|
|
}
|
|
|
|
if (bTryFindAssociatedAuxFile)
|
|
{
|
|
poODS = GDALFindAssociatedAuxFile( pszInitName, poDS->GetAccess(),
|
|
poDS );
|
|
}
|
|
|
|
if( poODS )
|
|
{
|
|
int bUseRRD = CSLTestBoolean(CPLGetConfigOption("USE_RRD","NO"));
|
|
|
|
bOvrIsAux = TRUE;
|
|
if( GetOverviewCount(1) == 0 && !bUseRRD )
|
|
{
|
|
bOvrIsAux = FALSE;
|
|
GDALClose( poODS );
|
|
poODS = NULL;
|
|
}
|
|
else
|
|
{
|
|
osOvrFilename = poODS->GetDescription();
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* If we still don't have an overview, check to see if we have */
|
|
/* overview metadata referencing a remote (ie. proxy) or local */
|
|
/* subdataset overview dataset. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( poODS == NULL )
|
|
{
|
|
const char *pszProxyOvrFilename =
|
|
poDS->GetMetadataItem( "OVERVIEW_FILE", "OVERVIEWS" );
|
|
|
|
if( pszProxyOvrFilename != NULL )
|
|
{
|
|
if( EQUALN(pszProxyOvrFilename,":::BASE:::",10) )
|
|
{
|
|
CPLString osPath = CPLGetPath(poDS->GetDescription());
|
|
|
|
osOvrFilename =
|
|
CPLFormFilename( osPath, pszProxyOvrFilename+10, NULL );
|
|
}
|
|
else
|
|
osOvrFilename = pszProxyOvrFilename;
|
|
|
|
CPLPushErrorHandler(CPLQuietErrorHandler);
|
|
poODS = (GDALDataset *) GDALOpen(osOvrFilename,poDS->GetAccess());
|
|
CPLPopErrorHandler();
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetOverviewCount() */
|
|
/************************************************************************/
|
|
|
|
int GDALDefaultOverviews::GetOverviewCount( int nBand )
|
|
|
|
{
|
|
GDALRasterBand * poBand;
|
|
|
|
if( poODS == NULL || nBand < 1 || nBand > poODS->GetRasterCount() )
|
|
return 0;
|
|
|
|
poBand = poODS->GetRasterBand( nBand );
|
|
if( poBand == NULL )
|
|
return 0;
|
|
else
|
|
{
|
|
if( bOvrIsAux )
|
|
return poBand->GetOverviewCount();
|
|
else
|
|
return poBand->GetOverviewCount() + 1;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetOverview() */
|
|
/************************************************************************/
|
|
|
|
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 );
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALOvLevelAdjust() */
|
|
/* */
|
|
/* Some overview levels cannot be achieved closely enough to be */
|
|
/* recognised as the desired overview level. This function */
|
|
/* will adjust an overview level to one that is achievable on */
|
|
/* the given raster size. */
|
|
/* */
|
|
/* For instance a 1200x1200 image on which a 256 level overview */
|
|
/* is request will end up generating a 5x5 overview. However, */
|
|
/* this will appear to the system be a level 240 overview. */
|
|
/* This function will adjust 256 to 240 based on knowledge of */
|
|
/* the image size. */
|
|
/************************************************************************/
|
|
|
|
int GDALOvLevelAdjust( int nOvLevel, int nXSize )
|
|
|
|
{
|
|
int nOXSize = (nXSize + nOvLevel - 1) / nOvLevel;
|
|
|
|
return (int) (0.5 + nXSize / (double) nOXSize);
|
|
}
|
|
|
|
|
|
int GDALOvLevelAdjust2( int nOvLevel, int nXSize, int nYSize )
|
|
|
|
{
|
|
/* Select the larger dimension to have increased accuracy, but */
|
|
/* with a slight preference to x even if (a bit) smaller than y */
|
|
/* in an attempt to behave closer as previous behaviour */
|
|
if( nXSize >= nYSize / 2 && !(nXSize < nYSize && nXSize < nOvLevel) )
|
|
{
|
|
int nOXSize = (nXSize + nOvLevel - 1) / nOvLevel;
|
|
|
|
return (int) (0.5 + nXSize / (double) nOXSize);
|
|
}
|
|
else
|
|
{
|
|
int nOYSize = (nYSize + nOvLevel - 1) / nOvLevel;
|
|
|
|
return (int) (0.5 + nYSize / (double) nOYSize);
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALComputeOvFactor() */
|
|
/************************************************************************/
|
|
|
|
int GDALComputeOvFactor( int nOvrXSize, int nRasterXSize,
|
|
int nOvrYSize, int nRasterYSize )
|
|
{
|
|
/* Select the larger dimension to have increased accuracy, but */
|
|
/* with a slight preference to x even if (a bit) smaller than y */
|
|
/* in an attempt to behave closer as previous behaviour */
|
|
if( nRasterXSize >= nRasterYSize / 2 )
|
|
{
|
|
return (int)
|
|
(0.5 + nRasterXSize / (double) nOvrXSize);
|
|
}
|
|
else
|
|
{
|
|
return (int)
|
|
(0.5 + nRasterYSize / (double) nOvrYSize);
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* CleanOverviews() */
|
|
/* */
|
|
/* Remove all existing overviews. */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALDefaultOverviews::CleanOverviews()
|
|
|
|
{
|
|
// Anything to do?
|
|
if( poODS == NULL )
|
|
return CE_None;
|
|
|
|
// Delete the overview file(s).
|
|
GDALDriver *poOvrDriver;
|
|
|
|
poOvrDriver = poODS->GetDriver();
|
|
GDALClose( poODS );
|
|
poODS = NULL;
|
|
|
|
CPLErr eErr;
|
|
if( poOvrDriver != NULL )
|
|
eErr = poOvrDriver->Delete( osOvrFilename );
|
|
else
|
|
eErr = CE_None;
|
|
|
|
// Reset the saved overview filename.
|
|
if( !EQUAL(poDS->GetDescription(),":::VIRTUAL:::") )
|
|
{
|
|
int bUseRRD = CSLTestBoolean(CPLGetConfigOption("USE_RRD","NO"));
|
|
|
|
if( bUseRRD )
|
|
osOvrFilename = CPLResetExtension( poDS->GetDescription(), "aux" );
|
|
else
|
|
osOvrFilename.Printf( "%s.ovr", poDS->GetDescription() );
|
|
}
|
|
else
|
|
osOvrFilename = "";
|
|
|
|
return eErr;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* BuildOverviewsSubDataset() */
|
|
/************************************************************************/
|
|
|
|
CPLErr
|
|
GDALDefaultOverviews::BuildOverviewsSubDataset(
|
|
const char * pszPhysicalFile,
|
|
const char * pszResampling,
|
|
int nOverviews, int * panOverviewList,
|
|
int nBands, int * panBandList,
|
|
GDALProgressFunc pfnProgress, void * pProgressData)
|
|
|
|
{
|
|
if( osOvrFilename.length() == 0 && nOverviews > 0 )
|
|
{
|
|
int iSequence = 0;
|
|
VSIStatBufL sStatBuf;
|
|
|
|
for( iSequence = 0; iSequence < 100; iSequence++ )
|
|
{
|
|
osOvrFilename.Printf( "%s_%d.ovr", pszPhysicalFile, iSequence );
|
|
if( VSIStatExL( osOvrFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
|
|
{
|
|
CPLString osAdjustedOvrFilename;
|
|
|
|
if( poDS->GetMOFlags() & GMO_PAM_CLASS )
|
|
{
|
|
osAdjustedOvrFilename.Printf( ":::BASE:::%s_%d.ovr",
|
|
CPLGetFilename(pszPhysicalFile),
|
|
iSequence );
|
|
}
|
|
else
|
|
osAdjustedOvrFilename = osOvrFilename;
|
|
|
|
poDS->SetMetadataItem( "OVERVIEW_FILE",
|
|
osAdjustedOvrFilename,
|
|
"OVERVIEWS" );
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( iSequence == 100 )
|
|
osOvrFilename = "";
|
|
}
|
|
|
|
return BuildOverviews( NULL, pszResampling, nOverviews, panOverviewList,
|
|
nBands, panBandList, pfnProgress, pProgressData );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* BuildOverviews() */
|
|
/************************************************************************/
|
|
|
|
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( 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 = (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 );
|
|
if (poOverview == NULL)
|
|
continue;
|
|
|
|
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;
|
|
}
|
|
|
|
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 )
|
|
{
|
|
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,
|
|
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 );
|
|
if (poOverview == NULL)
|
|
continue;
|
|
|
|
int bHasNoData;
|
|
double noDataValue = poBand->GetNoDataValue(&bHasNoData);
|
|
|
|
if (bHasNoData)
|
|
poOverview->SetNoDataValue(noDataValue);
|
|
|
|
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 )
|
|
{
|
|
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 )
|
|
{
|
|
/* Some config option are not compatible with mask overviews */
|
|
/* so unset them, and define more sensible values */
|
|
int bJPEG = EQUAL(CPLGetConfigOption("COMPRESS_OVERVIEW", ""), "JPEG");
|
|
int 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 *poBand = poDS->GetRasterBand(iBand);
|
|
if( poBand != NULL )
|
|
poBand->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 )
|
|
{
|
|
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;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* CreateMaskBand() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALDefaultOverviews::CreateMaskBand( int nFlags, int nBand )
|
|
|
|
{
|
|
if( nBand < 1 )
|
|
nFlags |= GMF_PER_DATASET;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* ensure existing file gets opened if there is one. */
|
|
/* -------------------------------------------------------------------- */
|
|
HaveMaskFile();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Try creating the mask file. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( poMaskDS == NULL )
|
|
{
|
|
CPLString osMskFilename;
|
|
GDALDriver *poDr = (GDALDriver *) GDALGetDriverByName( "GTiff" );
|
|
char **papszOpt = NULL;
|
|
int nBX, nBY;
|
|
int nBands;
|
|
|
|
if( poDr == NULL )
|
|
return CE_Failure;
|
|
|
|
GDALRasterBand *poTBand = poDS->GetRasterBand(1);
|
|
if( poTBand == NULL )
|
|
return CE_Failure;
|
|
|
|
if( nFlags & GMF_PER_DATASET )
|
|
nBands = 1;
|
|
else
|
|
nBands = poDS->GetRasterCount();
|
|
|
|
|
|
papszOpt = CSLSetNameValue( papszOpt, "COMPRESS", "DEFLATE" );
|
|
papszOpt = CSLSetNameValue( papszOpt, "INTERLEAVE", "BAND" );
|
|
|
|
poTBand->GetBlockSize( &nBX, &nBY );
|
|
|
|
// try to create matching tile size if legal in TIFF.
|
|
if( (nBX % 16) == 0 && (nBY % 16) == 0 )
|
|
{
|
|
papszOpt = CSLSetNameValue( papszOpt, "TILED", "YES" );
|
|
papszOpt = CSLSetNameValue( papszOpt, "BLOCKXSIZE",
|
|
CPLString().Printf("%d",nBX) );
|
|
papszOpt = CSLSetNameValue( papszOpt, "BLOCKYSIZE",
|
|
CPLString().Printf("%d",nBY) );
|
|
}
|
|
|
|
osMskFilename.Printf( "%s.msk", poDS->GetDescription() );
|
|
poMaskDS = poDr->Create( osMskFilename,
|
|
poDS->GetRasterXSize(),
|
|
poDS->GetRasterYSize(),
|
|
nBands, GDT_Byte, papszOpt );
|
|
CSLDestroy( papszOpt );
|
|
|
|
if( poMaskDS == NULL ) // presumably error already issued.
|
|
return CE_Failure;
|
|
|
|
bOwnMaskDS = TRUE;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Save the mask flags for this band. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( nBand > poMaskDS->GetRasterCount() )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Attempt to create a mask band for band %d of %s,\n"
|
|
"but the .msk file has a PER_DATASET mask.",
|
|
nBand, poDS->GetDescription() );
|
|
return CE_Failure;
|
|
}
|
|
|
|
int iBand;
|
|
|
|
for( iBand = 0; iBand < poDS->GetRasterCount(); iBand++ )
|
|
{
|
|
// we write only the info for this band, unless we are
|
|
// using PER_DATASET in which case we write for all.
|
|
if( nBand != iBand + 1 && !(nFlags | GMF_PER_DATASET) )
|
|
continue;
|
|
|
|
poMaskDS->SetMetadataItem(
|
|
CPLString().Printf("INTERNAL_MASK_FLAGS_%d", iBand+1 ),
|
|
CPLString().Printf("%d", nFlags ) );
|
|
}
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetMaskBand() */
|
|
/************************************************************************/
|
|
|
|
GDALRasterBand *GDALDefaultOverviews::GetMaskBand( int nBand )
|
|
|
|
{
|
|
int nFlags = GetMaskFlags( nBand );
|
|
|
|
if( nFlags == 0x8000 ) // secret code meaning we don't handle this band.
|
|
return NULL;
|
|
|
|
if( nFlags & GMF_PER_DATASET )
|
|
return poMaskDS->GetRasterBand(1);
|
|
|
|
if( nBand > 0 )
|
|
return poMaskDS->GetRasterBand( nBand );
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetMaskFlags() */
|
|
/************************************************************************/
|
|
|
|
int GDALDefaultOverviews::GetMaskFlags( int nBand )
|
|
|
|
{
|
|
/* -------------------------------------------------------------------- */
|
|
/* Fetch this band's metadata entry. They are of the form: */
|
|
/* INTERNAL_MASK_FLAGS_n: flags */
|
|
/* -------------------------------------------------------------------- */
|
|
if( !HaveMaskFile() )
|
|
return 0;
|
|
|
|
const char *pszValue =
|
|
poMaskDS->GetMetadataItem(
|
|
CPLString().Printf( "INTERNAL_MASK_FLAGS_%d", MAX(nBand,1)) );
|
|
|
|
if( pszValue == NULL )
|
|
return 0x8000;
|
|
else
|
|
return atoi(pszValue);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* HaveMaskFile() */
|
|
/* */
|
|
/* Check for a mask file if we haven't already done so. */
|
|
/* Returns TRUE if we have one, otherwise FALSE. */
|
|
/************************************************************************/
|
|
|
|
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;
|
|
|
|
if( !GDALCanFileAcceptSidecarFile(pszBasename) )
|
|
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. */
|
|
/* -------------------------------------------------------------------- */
|
|
poMaskDS = (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;
|
|
}
|