287 lines
9.9 KiB
C++
287 lines
9.9 KiB
C++
/******************************************************************************
|
|
*
|
|
* Project: GDAL Utilities
|
|
* Purpose: GDAL Image Translator Program
|
|
* Author: Frank Warmerdam, warmerdam@pobox.com
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 1998, 2002, Frank Warmerdam
|
|
* Copyright (c) 2007-2014, Even Rouault <even dot rouault at spatialys.com>
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
****************************************************************************/
|
|
|
|
#include "cpl_string.h"
|
|
#include "gdal_version.h"
|
|
#include "gdal_priv.h"
|
|
#include "ogr_spatialref.h"
|
|
#include "commonutils.h"
|
|
#include "gdal_utils_priv.h"
|
|
|
|
/* ******************************************************************* */
|
|
/* Usage() */
|
|
/* ******************************************************************** */
|
|
|
|
static void Usage()
|
|
{
|
|
fprintf(stderr, "%s\n", GDALTranslateGetParserUsage().c_str());
|
|
|
|
exit(1);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* main() */
|
|
/************************************************************************/
|
|
|
|
MAIN_START(argc, argv)
|
|
|
|
{
|
|
/* Check strict compilation and runtime library version as we use C++ API */
|
|
if (!GDAL_CHECK_VERSION(argv[0]))
|
|
exit(1);
|
|
|
|
EarlySetConfigOptions(argc, argv);
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Register standard GDAL drivers, and process generic GDAL */
|
|
/* command options. */
|
|
/* -------------------------------------------------------------------- */
|
|
GDALAllRegister();
|
|
argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
|
|
if (argc < 1)
|
|
exit(-argc);
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Set optimal setting for best performance with huge input VRT. */
|
|
/* The rationale for 450 is that typical Linux process allow */
|
|
/* only 1024 file descriptors per process and we need to keep some */
|
|
/* spare for shared libraries, etc. so let's go down to 900. */
|
|
/* And some datasets may need 2 file descriptors, so divide by 2 */
|
|
/* for security. */
|
|
/* -------------------------------------------------------------------- */
|
|
if (CPLGetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", nullptr) == nullptr)
|
|
{
|
|
#if defined(__MACH__) && defined(__APPLE__)
|
|
// On Mach, the default limit is 256 files per process
|
|
// TODO We should eventually dynamically query the limit for all OS
|
|
CPLSetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "100");
|
|
#else
|
|
CPLSetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "450");
|
|
#endif
|
|
}
|
|
|
|
GDALTranslateOptionsForBinary sOptionsForBinary;
|
|
GDALTranslateOptions *psOptions =
|
|
GDALTranslateOptionsNew(argv + 1, &sOptionsForBinary);
|
|
CSLDestroy(argv);
|
|
|
|
if (psOptions == nullptr)
|
|
{
|
|
Usage();
|
|
}
|
|
|
|
if (sOptionsForBinary.osDest == "/vsistdout/")
|
|
{
|
|
sOptionsForBinary.bQuiet = true;
|
|
}
|
|
|
|
if (!(sOptionsForBinary.bQuiet))
|
|
{
|
|
GDALTranslateOptionsSetProgress(psOptions, GDALTermProgress, nullptr);
|
|
}
|
|
|
|
if (!sOptionsForBinary.osFormat.empty())
|
|
{
|
|
GDALDriverH hDriver =
|
|
GDALGetDriverByName(sOptionsForBinary.osFormat.c_str());
|
|
if (hDriver == nullptr)
|
|
{
|
|
fprintf(stderr, "Output driver `%s' not recognised.\n",
|
|
sOptionsForBinary.osFormat.c_str());
|
|
fprintf(stderr, "The following format drivers are configured and "
|
|
"support output:\n");
|
|
for (int iDr = 0; iDr < GDALGetDriverCount(); iDr++)
|
|
{
|
|
hDriver = GDALGetDriver(iDr);
|
|
|
|
if (GDALGetMetadataItem(hDriver, GDAL_DCAP_RASTER, nullptr) !=
|
|
nullptr &&
|
|
(GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE, nullptr) !=
|
|
nullptr ||
|
|
GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATECOPY,
|
|
nullptr) != nullptr))
|
|
{
|
|
fprintf(stderr, " %s: %s\n",
|
|
GDALGetDriverShortName(hDriver),
|
|
GDALGetDriverLongName(hDriver));
|
|
}
|
|
}
|
|
|
|
GDALTranslateOptionsFree(psOptions);
|
|
|
|
GDALDestroyDriverManager();
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Attempt to open source file. */
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
GDALDatasetH hDataset =
|
|
GDALOpenEx(sOptionsForBinary.osSource.c_str(),
|
|
GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR,
|
|
sOptionsForBinary.aosAllowedInputDrivers.List(),
|
|
sOptionsForBinary.aosOpenOptions.List(), nullptr);
|
|
|
|
if (hDataset == nullptr)
|
|
{
|
|
GDALDestroyDriverManager();
|
|
exit(1);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Handle subdatasets. */
|
|
/* -------------------------------------------------------------------- */
|
|
if (!sOptionsForBinary.bCopySubDatasets &&
|
|
GDALGetRasterCount(hDataset) == 0 &&
|
|
CSLCount(GDALGetMetadata(hDataset, "SUBDATASETS")) > 0)
|
|
{
|
|
fprintf(stderr, "Input file contains subdatasets. Please, select one "
|
|
"of them for reading.\n");
|
|
GDALClose(hDataset);
|
|
GDALDestroyDriverManager();
|
|
exit(1);
|
|
}
|
|
|
|
int bUsageError = FALSE;
|
|
GDALDatasetH hOutDS = nullptr;
|
|
GDALDriverH hOutDriver = nullptr;
|
|
|
|
if (sOptionsForBinary.osFormat.empty())
|
|
{
|
|
hOutDriver = GDALGetDriverByName(
|
|
GetOutputDriverForRaster(sOptionsForBinary.osDest.c_str()));
|
|
}
|
|
else
|
|
{
|
|
hOutDriver = GDALGetDriverByName(sOptionsForBinary.osFormat.c_str());
|
|
}
|
|
|
|
if (hOutDriver == nullptr)
|
|
{
|
|
fprintf(stderr, "Output driver not found.\n");
|
|
GDALClose(hDataset);
|
|
GDALDestroyDriverManager();
|
|
exit(1);
|
|
}
|
|
|
|
bool bCopyCreateSubDatasets =
|
|
(GDALGetMetadataItem(hOutDriver, GDAL_DCAP_SUBCREATECOPY, nullptr) !=
|
|
nullptr);
|
|
|
|
if (sOptionsForBinary.bCopySubDatasets &&
|
|
CSLCount(GDALGetMetadata(hDataset, "SUBDATASETS")) > 0)
|
|
{
|
|
if (bCopyCreateSubDatasets)
|
|
{
|
|
// GDAL sets the size of the dataset with subdatasets to 512x512
|
|
// this removes the srcwin function from this operation
|
|
hOutDS = GDALTranslate(sOptionsForBinary.osDest.c_str(), hDataset,
|
|
psOptions, &bUsageError);
|
|
GDALClose(hOutDS);
|
|
}
|
|
else
|
|
{
|
|
char **papszSubdatasets = GDALGetMetadata(hDataset, "SUBDATASETS");
|
|
const int nSubdatasets = CSLCount(papszSubdatasets) / 2;
|
|
char *pszSubDest = static_cast<char *>(
|
|
CPLMalloc(strlen(sOptionsForBinary.osDest.c_str()) + 32));
|
|
|
|
CPLString osPath = CPLGetPath(sOptionsForBinary.osDest.c_str());
|
|
CPLString osBasename =
|
|
CPLGetBasename(sOptionsForBinary.osDest.c_str());
|
|
CPLString osExtension =
|
|
CPLGetExtension(sOptionsForBinary.osDest.c_str());
|
|
CPLString osTemp;
|
|
|
|
const char *pszFormat = nullptr;
|
|
if (nSubdatasets < 10)
|
|
{
|
|
pszFormat = "%s_%d";
|
|
}
|
|
else if (nSubdatasets < 100)
|
|
{
|
|
pszFormat = "%s_%002d";
|
|
}
|
|
else
|
|
{
|
|
pszFormat = "%s_%003d";
|
|
}
|
|
|
|
const char *pszDest = pszSubDest;
|
|
|
|
for (int i = 0; papszSubdatasets[i] != nullptr; i += 2)
|
|
{
|
|
char *pszSource =
|
|
CPLStrdup(strstr(papszSubdatasets[i], "=") + 1);
|
|
osTemp = CPLSPrintf(pszFormat, osBasename.c_str(), i / 2 + 1);
|
|
osTemp = CPLFormFilename(osPath, osTemp, osExtension);
|
|
strcpy(pszSubDest, osTemp.c_str());
|
|
hDataset = GDALOpenEx(pszSource, GDAL_OF_RASTER, nullptr,
|
|
sOptionsForBinary.aosOpenOptions.List(),
|
|
nullptr);
|
|
CPLFree(pszSource);
|
|
if (!sOptionsForBinary.bQuiet)
|
|
printf("Input file size is %d, %d\n",
|
|
GDALGetRasterXSize(hDataset),
|
|
GDALGetRasterYSize(hDataset));
|
|
hOutDS =
|
|
GDALTranslate(pszDest, hDataset, psOptions, &bUsageError);
|
|
if (hOutDS == nullptr)
|
|
break;
|
|
GDALClose(hOutDS);
|
|
}
|
|
|
|
CPLFree(pszSubDest);
|
|
}
|
|
|
|
if (bUsageError == TRUE)
|
|
Usage();
|
|
GDALClose(hDataset);
|
|
GDALTranslateOptionsFree(psOptions);
|
|
|
|
GDALDestroy();
|
|
return 0;
|
|
}
|
|
|
|
if (!sOptionsForBinary.bQuiet)
|
|
printf("Input file size is %d, %d\n", GDALGetRasterXSize(hDataset),
|
|
GDALGetRasterYSize(hDataset));
|
|
|
|
hOutDS = GDALTranslate(sOptionsForBinary.osDest.c_str(), hDataset,
|
|
psOptions, &bUsageError);
|
|
if (bUsageError == TRUE)
|
|
Usage();
|
|
int nRetCode = hOutDS ? 0 : 1;
|
|
|
|
/* Close hOutDS before hDataset for the -f VRT case */
|
|
if (GDALClose(hOutDS) != CE_None)
|
|
{
|
|
nRetCode = 1;
|
|
if (CPLGetLastErrorType() == CE_None)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"Unknown error occurred in GDALClose()");
|
|
}
|
|
}
|
|
GDALClose(hDataset);
|
|
GDALTranslateOptionsFree(psOptions);
|
|
|
|
GDALDestroy();
|
|
|
|
return nRetCode;
|
|
}
|
|
|
|
MAIN_END
|