552 lines
19 KiB
C++
552 lines
19 KiB
C++
/******************************************************************************
|
|
*
|
|
* Project: GDAL Utilities
|
|
* Purpose: GDAL Async Image Reader, primarily for testing async api.
|
|
* Author: Frank Warmerdam, warmerdam@pobox.com
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 2010, Frank Warmerdam
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
****************************************************************************/
|
|
|
|
#include "cpl_vsi.h"
|
|
#include "cpl_conv.h"
|
|
#include "cpl_string.h"
|
|
#include "gdal_version.h"
|
|
#include "gdal_priv.h"
|
|
#include "ogr_spatialref.h"
|
|
|
|
/* ******************************************************************** */
|
|
/* Usage() */
|
|
/* ******************************************************************** */
|
|
|
|
static void Usage()
|
|
|
|
{
|
|
printf("Usage: gdalasyncread [--help] [--help-general]\n"
|
|
" [-ot {Byte/Int16/UInt16/UInt32/Int32/Float32/Float64/\n"
|
|
" CInt16/CInt32/CFloat32/CFloat64}]\n"
|
|
" [-of <format>] [-b <band>]\n"
|
|
" [-outsize <xsize>[%%] <ysize>[%%]]\n"
|
|
" [-srcwin <xoff> <yoff> <xsize> <ysize>]\n"
|
|
" [-co <NAME>=<VALUE>]... [-ao <NAME>=<VALUE>]...\n"
|
|
" [-to <timeout>] [-multi]\n"
|
|
" <src_dataset> <dst_dataset>\n\n");
|
|
|
|
printf("%s\n\n", GDALVersionInfo("--version"));
|
|
printf("The following format drivers are configured and support output:\n");
|
|
for (int iDr = 0; iDr < GDALGetDriverCount(); iDr++)
|
|
{
|
|
GDALDriverH hDriver = GDALGetDriver(iDr);
|
|
|
|
if (GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE, nullptr) !=
|
|
nullptr ||
|
|
GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATECOPY, nullptr) !=
|
|
nullptr)
|
|
{
|
|
printf(" %s: %s\n", GDALGetDriverShortName(hDriver),
|
|
GDALGetDriverLongName(hDriver));
|
|
}
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* main() */
|
|
/************************************************************************/
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
GDALDatasetH hSrcDS, hDstDS;
|
|
GDALDataset *poSrcDS, *poDstDS = nullptr;
|
|
int i;
|
|
int nRasterXSize, nRasterYSize;
|
|
const char *pszSource = nullptr, *pszDest = nullptr, *pszFormat = "GTiff";
|
|
GDALDriverH hDriver;
|
|
int *panBandList = nullptr, nBandCount = 0, bDefBands = TRUE;
|
|
GDALDataType eOutputType = GDT_Unknown;
|
|
int nOXSize = 0, nOYSize = 0;
|
|
char **papszCreateOptions = nullptr;
|
|
char **papszAsyncOptions = nullptr;
|
|
int anSrcWin[4];
|
|
int bQuiet = FALSE;
|
|
GDALProgressFunc pfnProgress = GDALTermProgress;
|
|
int iSrcFileArg = -1, iDstFileArg = -1;
|
|
int bMulti = FALSE;
|
|
double dfTimeout = -1.0;
|
|
const char *pszOXSize = nullptr, *pszOYSize = nullptr;
|
|
|
|
anSrcWin[0] = 0;
|
|
anSrcWin[1] = 0;
|
|
anSrcWin[2] = 0;
|
|
anSrcWin[3] = 0;
|
|
|
|
/* Check strict compilation and runtime library version as we use C++ API */
|
|
if (!GDAL_CHECK_VERSION(argv[0]))
|
|
exit(1);
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Register standard GDAL drivers, and process generic GDAL */
|
|
/* command options. */
|
|
/* -------------------------------------------------------------------- */
|
|
GDALAllRegister();
|
|
argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
|
|
if (argc < 1)
|
|
exit(-argc);
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Handle command line arguments. */
|
|
/* -------------------------------------------------------------------- */
|
|
for (i = 1; i < argc; i++)
|
|
{
|
|
if (EQUAL(argv[i], "--utility_version"))
|
|
{
|
|
printf("%s was compiled against GDAL %s and is running against "
|
|
"GDAL %s\n",
|
|
argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
|
|
return 0;
|
|
}
|
|
else if (EQUAL(argv[i], "--help"))
|
|
{
|
|
Usage();
|
|
}
|
|
else if ((EQUAL(argv[i], "-of") || EQUAL(argv[i], "-f")) &&
|
|
i < argc - 1)
|
|
pszFormat = argv[++i];
|
|
|
|
else if (EQUAL(argv[i], "-quiet"))
|
|
{
|
|
bQuiet = TRUE;
|
|
pfnProgress = GDALDummyProgress;
|
|
}
|
|
|
|
else if (EQUAL(argv[i], "-ot") && i < argc - 1)
|
|
{
|
|
for (int iType = 1; iType < GDT_TypeCount; iType++)
|
|
{
|
|
if (GDALGetDataTypeName((GDALDataType)iType) != nullptr &&
|
|
EQUAL(GDALGetDataTypeName((GDALDataType)iType),
|
|
argv[i + 1]))
|
|
{
|
|
eOutputType = (GDALDataType)iType;
|
|
}
|
|
}
|
|
|
|
if (eOutputType == GDT_Unknown)
|
|
{
|
|
printf("Unknown output pixel type: %s\n", argv[i + 1]);
|
|
Usage();
|
|
GDALDestroyDriverManager();
|
|
exit(2);
|
|
}
|
|
i++;
|
|
}
|
|
|
|
else if (EQUAL(argv[i], "-b") && i < argc - 1)
|
|
{
|
|
if (atoi(argv[i + 1]) < 1)
|
|
{
|
|
printf("Unrecognizable band number (%s).\n", argv[i + 1]);
|
|
Usage();
|
|
GDALDestroyDriverManager();
|
|
exit(2);
|
|
}
|
|
|
|
nBandCount++;
|
|
panBandList = static_cast<int *>(
|
|
CPLRealloc(panBandList, sizeof(int) * nBandCount));
|
|
panBandList[nBandCount - 1] = atoi(argv[++i]);
|
|
|
|
if (panBandList[nBandCount - 1] != nBandCount)
|
|
bDefBands = FALSE;
|
|
}
|
|
else if (EQUAL(argv[i], "-co") && i < argc - 1)
|
|
{
|
|
papszCreateOptions = CSLAddString(papszCreateOptions, argv[++i]);
|
|
}
|
|
|
|
else if (EQUAL(argv[i], "-ao") && i < argc - 1)
|
|
{
|
|
papszAsyncOptions = CSLAddString(papszAsyncOptions, argv[++i]);
|
|
}
|
|
|
|
else if (EQUAL(argv[i], "-to") && i < argc - 1)
|
|
{
|
|
dfTimeout = CPLAtof(argv[++i]);
|
|
}
|
|
|
|
else if (EQUAL(argv[i], "-outsize") && i < argc - 2)
|
|
{
|
|
pszOXSize = argv[++i];
|
|
pszOYSize = argv[++i];
|
|
}
|
|
|
|
else if (EQUAL(argv[i], "-srcwin") && i < argc - 4)
|
|
{
|
|
anSrcWin[0] = atoi(argv[++i]);
|
|
anSrcWin[1] = atoi(argv[++i]);
|
|
anSrcWin[2] = atoi(argv[++i]);
|
|
anSrcWin[3] = atoi(argv[++i]);
|
|
}
|
|
|
|
else if (EQUAL(argv[i], "-multi"))
|
|
{
|
|
bMulti = TRUE;
|
|
}
|
|
else if (argv[i][0] == '-')
|
|
{
|
|
printf("Option %s incomplete, or not recognised.\n\n", argv[i]);
|
|
Usage();
|
|
GDALDestroyDriverManager();
|
|
exit(2);
|
|
}
|
|
else if (pszSource == nullptr)
|
|
{
|
|
iSrcFileArg = i;
|
|
pszSource = argv[i];
|
|
}
|
|
else if (pszDest == nullptr)
|
|
{
|
|
pszDest = argv[i];
|
|
iDstFileArg = i;
|
|
}
|
|
|
|
else
|
|
{
|
|
printf("Too many command options.\n\n");
|
|
Usage();
|
|
GDALDestroyDriverManager();
|
|
exit(2);
|
|
}
|
|
}
|
|
|
|
if (pszDest == nullptr)
|
|
{
|
|
Usage();
|
|
GDALDestroyDriverManager();
|
|
exit(10);
|
|
}
|
|
|
|
if (strcmp(pszSource, pszDest) == 0)
|
|
{
|
|
fprintf(stderr, "Source and destination datasets must be different.\n");
|
|
GDALDestroyDriverManager();
|
|
exit(1);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Attempt to open source file. */
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
hSrcDS = GDALOpenShared(pszSource, GA_ReadOnly);
|
|
poSrcDS = (GDALDataset *)hSrcDS;
|
|
|
|
if (hSrcDS == nullptr)
|
|
{
|
|
fprintf(stderr, "GDALOpen failed - %d\n%s\n", CPLGetLastErrorNo(),
|
|
CPLGetLastErrorMsg());
|
|
GDALDestroyDriverManager();
|
|
exit(1);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Collect some information from the source file. */
|
|
/* -------------------------------------------------------------------- */
|
|
nRasterXSize = GDALGetRasterXSize(hSrcDS);
|
|
nRasterYSize = GDALGetRasterYSize(hSrcDS);
|
|
|
|
if (!bQuiet)
|
|
printf("Input file size is %d, %d\n", nRasterXSize, nRasterYSize);
|
|
|
|
if (anSrcWin[2] == 0 && anSrcWin[3] == 0)
|
|
{
|
|
anSrcWin[2] = nRasterXSize;
|
|
anSrcWin[3] = nRasterYSize;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Establish output size. */
|
|
/* -------------------------------------------------------------------- */
|
|
if (pszOXSize == nullptr)
|
|
{
|
|
nOXSize = anSrcWin[2];
|
|
nOYSize = anSrcWin[3];
|
|
}
|
|
else
|
|
{
|
|
nOXSize = static_cast<int>((pszOXSize[strlen(pszOXSize) - 1] == '%'
|
|
? CPLAtof(pszOXSize) / 100 * anSrcWin[2]
|
|
: atoi(pszOXSize)));
|
|
nOYSize = static_cast<int>((pszOYSize[strlen(pszOYSize) - 1] == '%'
|
|
? CPLAtof(pszOYSize) / 100 * anSrcWin[3]
|
|
: atoi(pszOYSize)));
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Build band list to translate */
|
|
/* -------------------------------------------------------------------- */
|
|
if (nBandCount == 0)
|
|
{
|
|
nBandCount = GDALGetRasterCount(hSrcDS);
|
|
if (nBandCount == 0)
|
|
{
|
|
fprintf(stderr,
|
|
"Input file has no bands, and so cannot be translated.\n");
|
|
GDALDestroyDriverManager();
|
|
exit(1);
|
|
}
|
|
|
|
panBandList = static_cast<int *>(CPLMalloc(sizeof(int) * nBandCount));
|
|
for (i = 0; i < nBandCount; i++)
|
|
panBandList[i] = i + 1;
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < nBandCount; i++)
|
|
{
|
|
if (panBandList[i] < 1 ||
|
|
panBandList[i] > GDALGetRasterCount(hSrcDS))
|
|
{
|
|
fprintf(
|
|
stderr,
|
|
"Band %d requested, but only bands 1 to %d available.\n",
|
|
panBandList[i], GDALGetRasterCount(hSrcDS));
|
|
GDALDestroyDriverManager();
|
|
exit(2);
|
|
}
|
|
}
|
|
|
|
if (nBandCount != GDALGetRasterCount(hSrcDS))
|
|
bDefBands = FALSE;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Verify source window. */
|
|
/* -------------------------------------------------------------------- */
|
|
if (anSrcWin[0] < 0 || anSrcWin[1] < 0 || anSrcWin[2] <= 0 ||
|
|
anSrcWin[3] <= 0 ||
|
|
anSrcWin[0] + anSrcWin[2] > GDALGetRasterXSize(hSrcDS) ||
|
|
anSrcWin[1] + anSrcWin[3] > GDALGetRasterYSize(hSrcDS))
|
|
{
|
|
fprintf(stderr,
|
|
"-srcwin %d %d %d %d falls outside raster size of %dx%d\n"
|
|
"or is otherwise illegal.\n",
|
|
anSrcWin[0], anSrcWin[1], anSrcWin[2], anSrcWin[3],
|
|
GDALGetRasterXSize(hSrcDS), GDALGetRasterYSize(hSrcDS));
|
|
exit(1);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Find the output driver. */
|
|
/* -------------------------------------------------------------------- */
|
|
hDriver = GDALGetDriverByName(pszFormat);
|
|
|
|
if (hDriver == nullptr)
|
|
{
|
|
printf("Output driver `%s' not recognised.\n", pszFormat);
|
|
}
|
|
else if (GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE, nullptr) == nullptr)
|
|
{
|
|
printf("Output driver '%s' does not support direct creation.\n",
|
|
pszFormat);
|
|
hDriver = nullptr;
|
|
}
|
|
|
|
if (hDriver == nullptr)
|
|
{
|
|
printf("The following format drivers are configured and support "
|
|
"output:\n");
|
|
for (int iDr = 0; iDr < GDALGetDriverCount(); iDr++)
|
|
{
|
|
GDALDriverH hDriver = GDALGetDriver(iDr);
|
|
|
|
if (GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE, nullptr) !=
|
|
nullptr)
|
|
{
|
|
printf(" %s: %s\n", GDALGetDriverShortName(hDriver),
|
|
GDALGetDriverLongName(hDriver));
|
|
}
|
|
}
|
|
printf("\n");
|
|
Usage();
|
|
|
|
GDALClose(hSrcDS);
|
|
CPLFree(panBandList);
|
|
GDALDestroyDriverManager();
|
|
CSLDestroy(argv);
|
|
CSLDestroy(papszCreateOptions);
|
|
exit(1);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Establish the pixel data type to use. */
|
|
/* -------------------------------------------------------------------- */
|
|
if (eOutputType == GDT_Unknown)
|
|
eOutputType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Allocate one big buffer for the whole imagery area to */
|
|
/* transfer. */
|
|
/* -------------------------------------------------------------------- */
|
|
const int nBytesPerPixel =
|
|
nBandCount * GDALGetDataTypeSizeBytes(eOutputType);
|
|
void *pImage = VSIMalloc3(nOXSize, nOYSize, nBytesPerPixel);
|
|
|
|
if (pImage == nullptr)
|
|
{
|
|
printf("Unable to allocate %dx%dx%d byte window buffer.\n", nOXSize,
|
|
nOYSize, nBytesPerPixel);
|
|
exit(1);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Establish view window */
|
|
/* -------------------------------------------------------------------- */
|
|
int nPixelSpace = nBytesPerPixel;
|
|
int nLineSpace = nBytesPerPixel * nOXSize;
|
|
int nBandSpace = nBytesPerPixel / nBandCount;
|
|
|
|
GDALAsyncReader *poAsyncReq = poSrcDS->BeginAsyncReader(
|
|
anSrcWin[0], anSrcWin[1], anSrcWin[2], anSrcWin[3], pImage, nOXSize,
|
|
nOYSize, eOutputType, nBandCount, panBandList, nPixelSpace, nLineSpace,
|
|
nBandSpace, papszAsyncOptions);
|
|
|
|
if (poAsyncReq == nullptr)
|
|
exit(1);
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Process until done or an error. */
|
|
/* -------------------------------------------------------------------- */
|
|
GDALAsyncStatusType eAStatus;
|
|
CPLErr eErr = CE_None;
|
|
int iMultiCounter = 0;
|
|
|
|
hDstDS = nullptr;
|
|
|
|
do
|
|
{
|
|
/* ====================================================================
|
|
*/
|
|
/* Create the output file, and initialize if needed. */
|
|
/* ====================================================================
|
|
*/
|
|
if (hDstDS == nullptr)
|
|
{
|
|
CPLString osOutFilename = pszDest;
|
|
|
|
if (bMulti)
|
|
osOutFilename.Printf("%s_%d", pszDest, iMultiCounter++);
|
|
|
|
hDstDS = GDALCreate(hDriver, osOutFilename, nOXSize, nOYSize,
|
|
nBandCount, eOutputType, papszCreateOptions);
|
|
if (hDstDS == nullptr)
|
|
{
|
|
exit(1);
|
|
}
|
|
|
|
poDstDS = (GDALDataset *)hDstDS;
|
|
|
|
/* --------------------------------------------------------------------
|
|
*/
|
|
/* Copy georeferencing. */
|
|
/* --------------------------------------------------------------------
|
|
*/
|
|
double adfGeoTransform[6];
|
|
|
|
if (poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None)
|
|
{
|
|
adfGeoTransform[0] += anSrcWin[0] * adfGeoTransform[1] +
|
|
anSrcWin[1] * adfGeoTransform[2];
|
|
adfGeoTransform[3] += anSrcWin[0] * adfGeoTransform[4] +
|
|
anSrcWin[1] * adfGeoTransform[5];
|
|
|
|
adfGeoTransform[1] *= anSrcWin[2] / (double)nOXSize;
|
|
adfGeoTransform[2] *= anSrcWin[3] / (double)nOYSize;
|
|
adfGeoTransform[4] *= anSrcWin[2] / (double)nOXSize;
|
|
adfGeoTransform[5] *= anSrcWin[3] / (double)nOYSize;
|
|
|
|
poDstDS->SetGeoTransform(adfGeoTransform);
|
|
}
|
|
|
|
poDstDS->SetProjection(poSrcDS->GetProjectionRef());
|
|
|
|
/* --------------------------------------------------------------------
|
|
*/
|
|
/* Transfer generally applicable metadata. */
|
|
/* --------------------------------------------------------------------
|
|
*/
|
|
poDstDS->SetMetadata(poSrcDS->GetMetadata());
|
|
}
|
|
|
|
/* ====================================================================
|
|
*/
|
|
/* Fetch an update and write it to the output file. */
|
|
/* ====================================================================
|
|
*/
|
|
|
|
int nUpXOff;
|
|
int nUpYOff;
|
|
int nUpXSize;
|
|
int nUpYSize;
|
|
|
|
eAStatus = poAsyncReq->GetNextUpdatedRegion(
|
|
dfTimeout, &nUpXOff, &nUpYOff, &nUpXSize, &nUpYSize);
|
|
|
|
if (eAStatus != GARIO_UPDATE && eAStatus != GARIO_COMPLETE)
|
|
continue;
|
|
|
|
if (!bQuiet)
|
|
{
|
|
printf("Got %dx%d @ (%d,%d)\n", nUpXSize, nUpYSize, nUpXOff,
|
|
nUpYOff);
|
|
}
|
|
|
|
poAsyncReq->LockBuffer();
|
|
eErr = poDstDS->RasterIO(
|
|
GF_Write, nUpXOff, nUpYOff, nUpXSize, nUpYSize,
|
|
((GByte *)pImage) + nUpXOff * nPixelSpace + nUpYOff * nLineSpace,
|
|
nUpXSize, nUpYSize, eOutputType, nBandCount, nullptr, nPixelSpace,
|
|
nLineSpace, nBandSpace, nullptr);
|
|
poAsyncReq->UnlockBuffer();
|
|
|
|
/* --------------------------------------------------------------------
|
|
*/
|
|
/* In multi mode we will close this file and reopen another for */
|
|
/* the next request. */
|
|
/* --------------------------------------------------------------------
|
|
*/
|
|
if (bMulti)
|
|
{
|
|
GDALClose(hDstDS);
|
|
hDstDS = nullptr;
|
|
}
|
|
else
|
|
{
|
|
GDALFlushCache(hDstDS);
|
|
}
|
|
} while (eAStatus != GARIO_ERROR && eAStatus != GARIO_COMPLETE &&
|
|
eErr == CE_None);
|
|
|
|
poSrcDS->EndAsyncReader(poAsyncReq);
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Cleanup. */
|
|
/* -------------------------------------------------------------------- */
|
|
VSIFree(pImage);
|
|
|
|
if (hDstDS)
|
|
GDALClose(hDstDS);
|
|
|
|
GDALClose(hSrcDS);
|
|
|
|
CPLFree(panBandList);
|
|
|
|
CSLDestroy(argv);
|
|
CSLDestroy(papszCreateOptions);
|
|
CSLDestroy(papszAsyncOptions);
|
|
|
|
GDALDumpOpenDatasets(stderr);
|
|
GDALDestroyDriverManager();
|
|
}
|