From df71b418157c69a3f20356d9956bd6a21ffae72d Mon Sep 17 00:00:00 2001 From: Momtchil Momtchev Date: Sat, 21 Mar 2026 18:13:24 +0100 Subject: [PATCH] update GDAL to 3.12.3 --- CHANGELOG.md | 5 + deps/libgdal.sh | 2 +- deps/libgdal/gdal/CITATION.cff | 4 +- deps/libgdal/gdal/VERSION | 2 +- deps/libgdal/gdal/alg/gdal_homography.cpp | 4 +- deps/libgdal/gdal/alg/gdalwarper.cpp | 26 ++- deps/libgdal/gdal/alg/gdalwarpkernel.cpp | 9 + deps/libgdal/gdal/alg/viewshed/viewshed.cpp | 11 +- deps/libgdal/gdal/apps/gdal_grid_lib.cpp | 2 +- deps/libgdal/gdal/apps/gdal_translate_lib.cpp | 2 +- .../gdal/apps/gdalalg_abstract_pipeline.h | 3 + deps/libgdal/gdal/apps/gdalalg_pipeline.cpp | 20 +- .../libgdal/gdal/apps/gdalalg_raster_calc.cpp | 8 +- .../gdal/apps/gdalalg_raster_contour.cpp | 5 + .../libgdal/gdal/apps/gdalalg_raster_edit.cpp | 1 + .../gdal/apps/gdalalg_raster_polygonize.cpp | 5 + .../gdal/apps/gdalalg_raster_viewshed.cpp | 4 +- .../gdal/apps/gdalalg_vector_select.cpp | 18 +- deps/libgdal/gdal/apps/gdalbuildvrt_lib.cpp | 2 +- deps/libgdal/gdal/apps/gdalinfo_lib.cpp | 5 +- deps/libgdal/gdal/apps/gdaltindex_lib.cpp | 60 +++++- deps/libgdal/gdal/apps/ogr2ogr_lib.cpp | 2 +- .../gdal/frmts/georaster/cpl_vsil_ocilob.cpp | 8 +- .../frmts/georaster/georaster_wrapper.cpp | 6 +- deps/libgdal/gdal/frmts/gif/giflib/dgif_lib.c | 6 +- .../gdal/frmts/gti/gdaltileindexdataset.cpp | 141 ++++++++++++-- .../gdal/frmts/gtiff/gtiffdataset_read.cpp | 22 ++- .../gdal/frmts/gtiff/gtiffdataset_write.cpp | 32 ++- .../gdal/frmts/gtiff/gtiffrasterband_read.cpp | 9 +- deps/libgdal/gdal/frmts/hdf5/CMakeLists.txt | 8 + .../gdal/frmts/libertiff/libertiffdataset.cpp | 15 +- .../gdal/frmts/netcdf/netcdfdataset.cpp | 56 +++++- .../gdal/frmts/netcdf/netcdfdrivercore.cpp | 17 ++ .../libgdal/gdal/frmts/nitf/rpftocdataset.cpp | 112 ++++++----- deps/libgdal/gdal/frmts/pdf/pdfdataset.cpp | 58 ++++-- deps/libgdal/gdal/frmts/pdf/pdfio.cpp | 9 + deps/libgdal/gdal/frmts/pdf/pdfio.h | 5 + deps/libgdal/gdal/frmts/pds/pds4dataset.cpp | 10 +- deps/libgdal/gdal/frmts/vrt/vrtdataset.h | 4 + .../gdal/frmts/vrt/vrtderivedrasterband.cpp | 182 +++++++++++------- .../gdal/frmts/vrt/vrtsourcedrasterband.cpp | 123 ++++++------ deps/libgdal/gdal/frmts/vrt/vrtwarped.cpp | 4 +- .../libgdal/gdal/frmts/zarr/zarr_v2_array.cpp | 36 ++-- deps/libgdal/gdal/gcore/gdal_misc.cpp | 4 +- deps/libgdal/gdal/gcore/gdal_version.h | 6 +- .../gcore/gdal_version_full/gdal_version.h | 6 +- deps/libgdal/gdal/gcore/gdalalgorithm.cpp | 54 ++++-- deps/libgdal/gdal/gcore/gdaldriver.cpp | 95 ++++++--- deps/libgdal/gdal/gcore/gdalmultidim.cpp | 6 +- .../gdal/gcore/mdreader/reader_eros.cpp | 5 + deps/libgdal/gdal/gcore/overview.cpp | 2 +- deps/libgdal/gdal/ogr/ogr_srs_api.h | 2 +- .../gdal/ogr/ogrsf_frmts/adbc/ogr_adbc.h | 4 +- .../ogrsf_frmts/adbc/ogradbcbigquerylayer.cpp | 2 +- .../ogr/ogrsf_frmts/adbc/ogradbcdataset.cpp | 2 + .../ogr/ogrsf_frmts/adbc/ogradbclayer.cpp | 134 ++++++++++--- .../ogr/ogrsf_frmts/generic/ogr_gensql.cpp | 47 +++-- .../gdal/ogr/ogrsf_frmts/generic/ogr_gensql.h | 1 + .../gdal/ogr/ogrsf_frmts/gml/gmlhandler.cpp | 69 ++++--- .../gpkg/ogrgeopackagetablelayer.cpp | 8 + deps/libgdal/gdal/port/cpl_conv.cpp | 8 +- deps/libgdal/gdal/port/cpl_conv.h | 8 +- .../gdal/port/cpl_known_config_options.h | 1 + deps/libgdal/gdal/port/cpl_path.cpp | 132 ++++++++++++- deps/libgdal/gdal/port/cpl_vsil_s3.cpp | 178 ++++++++++------- 65 files changed, 1342 insertions(+), 495 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9680a74b..8974a43cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.12.3] 2026-03-21 + +### Added + - GDAL 3.12.3 + ## [3.12.2] 2026-02-11 ### Added diff --git a/deps/libgdal.sh b/deps/libgdal.sh index ceefe2a2c..261fc7170 100755 --- a/deps/libgdal.sh +++ b/deps/libgdal.sh @@ -5,7 +5,7 @@ set -eu DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd "$DIR/libgdal" -GDAL_VERSION=3.12.2 +GDAL_VERSION=3.12.3 GDAL_VERSION_SUFFIX= dir_gdal=./gdal dir_formats_gyp=./gyp-formats diff --git a/deps/libgdal/gdal/CITATION.cff b/deps/libgdal/gdal/CITATION.cff index c0263237c..928f8702f 100644 --- a/deps/libgdal/gdal/CITATION.cff +++ b/deps/libgdal/gdal/CITATION.cff @@ -2,8 +2,8 @@ cff-version: 1.2.0 message: Please cite this software using these metadata or in the CITATION file. type: software title: GDAL -version: 3.12.2 -date-released: 2026-02-03 +version: 3.12.3 +date-released: 2026-03-17 doi: 10.5281/zenodo.5884351 abstract: GDAL is a translator library for raster and vector geospatial data formats that is released under an MIT style Open Source License by the Open diff --git a/deps/libgdal/gdal/VERSION b/deps/libgdal/gdal/VERSION index 8531a3b7e..871f80a34 100644 --- a/deps/libgdal/gdal/VERSION +++ b/deps/libgdal/gdal/VERSION @@ -1 +1 @@ -3.12.2 +3.12.3 diff --git a/deps/libgdal/gdal/alg/gdal_homography.cpp b/deps/libgdal/gdal/alg/gdal_homography.cpp index 332326352..f8f35b814 100644 --- a/deps/libgdal/gdal/alg/gdal_homography.cpp +++ b/deps/libgdal/gdal/alg/gdal_homography.cpp @@ -62,8 +62,8 @@ static void *GDALCreateSimilarHomographyTransformer(void *hTransformArg, double homography[9]; for (int i = 0; i < 3; i++) { - homography[3 * i + 1] = psInfo->padfForward[3 * i + 1] / dfRatioX; - homography[3 * i + 2] = psInfo->padfForward[3 * i + 2] / dfRatioY; + homography[3 * i + 1] = psInfo->padfForward[3 * i + 1] * dfRatioX; + homography[3 * i + 2] = psInfo->padfForward[3 * i + 2] * dfRatioY; homography[3 * i] = psInfo->padfForward[3 * i]; } psInfo = static_cast( diff --git a/deps/libgdal/gdal/alg/gdalwarper.cpp b/deps/libgdal/gdal/alg/gdalwarper.cpp index 32b0cb573..dec1307e5 100644 --- a/deps/libgdal/gdal/alg/gdalwarper.cpp +++ b/deps/libgdal/gdal/alg/gdalwarper.cpp @@ -265,13 +265,15 @@ CPLErr CPL_STDCALL GDALCreateAndReprojectImage( int nPixels = 0; int nLines = 0; - if (GDALSuggestedWarpOutput(hSrcDS, GDALGenImgProjTransform, hTransformArg, - adfDstGeoTransform, &nPixels, - &nLines) != CE_None) - return CE_Failure; + CPLErr eErr = + GDALSuggestedWarpOutput(hSrcDS, GDALGenImgProjTransform, hTransformArg, + adfDstGeoTransform, &nPixels, &nLines); GDALDestroyGenImgProjTransformer(hTransformArg); + if (eErr != CE_None) + return eErr; + /* -------------------------------------------------------------------- */ /* Create the output file. */ /* -------------------------------------------------------------------- */ @@ -292,9 +294,9 @@ CPLErr CPL_STDCALL GDALCreateAndReprojectImage( /* -------------------------------------------------------------------- */ /* Perform the reprojection. */ /* -------------------------------------------------------------------- */ - CPLErr eErr = GDALReprojectImage( - hSrcDS, pszSrcWKT, hDstDS, pszDstWKT, eResampleAlg, dfWarpMemoryLimit, - dfMaxError, pfnProgress, pProgressArg, psOptions); + eErr = GDALReprojectImage(hSrcDS, pszSrcWKT, hDstDS, pszDstWKT, + eResampleAlg, dfWarpMemoryLimit, dfMaxError, + pfnProgress, pProgressArg, psOptions); GDALClose(hDstDS); @@ -371,6 +373,11 @@ CPLErr GDALWarpNoDataMasker(void *pMaskFuncArg, int nBandCount, *ppImageData, // Already a GByte *. panValidityMask, pbOutAllValid); + case GDT_Int8: + return GDALWarpNoDataMaskerT( + padfNoData, nPixels, reinterpret_cast(*ppImageData), + panValidityMask, pbOutAllValid); + case GDT_Int16: return GDALWarpNoDataMaskerT( padfNoData, nPixels, reinterpret_cast(*ppImageData), @@ -1756,8 +1763,6 @@ void CPL_STDCALL GDALWarpResolveWorkingDataType(GDALWarpOptions *psOptions) return; } - psOptions->eWorkingDataType = GDT_Byte; - // If none of the provided input nodata values can be represented in the // data type of the corresponding source band, ignore them. if (psOptions->hSrcDS && psOptions->padfSrcNoDataReal) @@ -1843,6 +1848,9 @@ void CPL_STDCALL GDALWarpResolveWorkingDataType(GDALWarpOptions *psOptions) } } + if (psOptions->eWorkingDataType == GDT_Unknown) + psOptions->eWorkingDataType = GDT_Byte; + const bool bApplyVerticalShift = CPLFetchBool( psOptions->papszWarpOptions, "APPLY_VERTICAL_SHIFT", false); if (bApplyVerticalShift && diff --git a/deps/libgdal/gdal/alg/gdalwarpkernel.cpp b/deps/libgdal/gdal/alg/gdalwarpkernel.cpp index 78e8aece9..6b4b7c62e 100644 --- a/deps/libgdal/gdal/alg/gdalwarpkernel.cpp +++ b/deps/libgdal/gdal/alg/gdalwarpkernel.cpp @@ -186,6 +186,7 @@ static CPLErr GWKBilinearNoMasksOrDstDensityOnlyDouble(GDALWarpKernel *poWK); #endif static CPLErr GWKCubicNoMasksOrDstDensityOnlyShort(GDALWarpKernel *poWK); static CPLErr GWKCubicSplineNoMasksOrDstDensityOnlyShort(GDALWarpKernel *poWK); +static CPLErr GWKNearestInt8(GDALWarpKernel *poWK); static CPLErr GWKNearestShort(GDALWarpKernel *poWK); static CPLErr GWKNearestUnsignedShort(GDALWarpKernel *poWK); static CPLErr GWKNearestNoMasksOrDstDensityOnlyFloat(GDALWarpKernel *poWK); @@ -1253,6 +1254,9 @@ CPLErr GDALWarpKernel::PerformWarp() bNoMasksOrDstDensityOnly) return GWKBilinearNoMasksOrDstDensityOnlyUShort(this); + if (eWorkingDataType == GDT_Int8 && eResample == GRA_NearestNeighbour) + return GWKNearestInt8(this); + if (eWorkingDataType == GDT_Int16 && eResample == GRA_NearestNeighbour) return GWKNearestShort(this); @@ -6660,6 +6664,11 @@ static CPLErr GWKCubicSplineNoMasksOrDstDensityOnlyUShort(GDALWarpKernel *poWK) GWKResampleNoMasksOrDstDensityOnlyThread); } +static CPLErr GWKNearestInt8(GDALWarpKernel *poWK) +{ + return GWKRun(poWK, "GWKNearestInt8", GWKNearestThread); +} + static CPLErr GWKNearestShort(GDALWarpKernel *poWK) { return GWKRun(poWK, "GWKNearestShort", GWKNearestThread); diff --git a/deps/libgdal/gdal/alg/viewshed/viewshed.cpp b/deps/libgdal/gdal/alg/viewshed/viewshed.cpp index 6cfe6bd42..ad039439d 100644 --- a/deps/libgdal/gdal/alg/viewshed/viewshed.cpp +++ b/deps/libgdal/gdal/alg/viewshed/viewshed.cpp @@ -178,11 +178,14 @@ GDALDatasetH GDALViewshedGenerate( "dfInvisibleVal out of range. Must be [0, 255]."); return nullptr; } - if (!GDALIsValueInRange(dfOutOfRangeVal)) + if (oOpts.outputMode == viewshed::OutputMode::Normal) { - CPLError(CE_Failure, CPLE_AppDefined, - "dfOutOfRangeVal out of range. Must be [0, 255]."); - return nullptr; + if (!GDALIsValueInRange(dfOutOfRangeVal)) + { + CPLError(CE_Failure, CPLE_AppDefined, + "dfOutOfRangeVal out of range. Must be [0, 255]."); + return nullptr; + } } oOpts.visibleVal = dfVisibleVal; oOpts.invisibleVal = dfInvisibleVal; diff --git a/deps/libgdal/gdal/apps/gdal_grid_lib.cpp b/deps/libgdal/gdal/apps/gdal_grid_lib.cpp index 93104b03a..d0260035c 100644 --- a/deps/libgdal/gdal/apps/gdal_grid_lib.cpp +++ b/deps/libgdal/gdal/apps/gdal_grid_lib.cpp @@ -973,7 +973,7 @@ GDALGridOptionsGetParser(GDALGridOptions *psOptions, .help(_("Set the size of the output file.")); argParser->add_argument("-tr") - .metavar(" ") + .metavar(" ") .nargs(2) .scan<'g', double>() .help(_("Set target resolution.")); diff --git a/deps/libgdal/gdal/apps/gdal_translate_lib.cpp b/deps/libgdal/gdal/apps/gdal_translate_lib.cpp index 4f3516355..685af7b55 100644 --- a/deps/libgdal/gdal/apps/gdal_translate_lib.cpp +++ b/deps/libgdal/gdal/apps/gdal_translate_lib.cpp @@ -2944,7 +2944,7 @@ GDALTranslateOptionsGetParser(GDALTranslateOptions *psOptions, .help(_("Set the size of the output file.")); argParser->add_argument("-tr") - .metavar(" ") + .metavar(" ") .nargs(2) .scan<'g', double>() .help(_("Set target resolution.")); diff --git a/deps/libgdal/gdal/apps/gdalalg_abstract_pipeline.h b/deps/libgdal/gdal/apps/gdalalg_abstract_pipeline.h index 7a7542849..e2ed89a86 100644 --- a/deps/libgdal/gdal/apps/gdalalg_abstract_pipeline.h +++ b/deps/libgdal/gdal/apps/gdalalg_abstract_pipeline.h @@ -351,6 +351,9 @@ class GDALPipelineStepAlgorithm /* non final */ : public GDALAlgorithm void AddVectorInputArgs(bool hiddenForCLI); void AddVectorOutputArgs(bool hiddenForCLI, bool shortNameOutputLayerAllowed); + using GDALAlgorithm::AddOutputLayerNameArg; + void AddOutputLayerNameArg(bool hiddenForCLI, + bool shortNameOutputLayerAllowed); private: bool RunImpl(GDALProgressFunc pfnProgress, void *pProgressData) override; diff --git a/deps/libgdal/gdal/apps/gdalalg_pipeline.cpp b/deps/libgdal/gdal/apps/gdalalg_pipeline.cpp index 1bc52229a..19e508f49 100644 --- a/deps/libgdal/gdal/apps/gdalalg_pipeline.cpp +++ b/deps/libgdal/gdal/apps/gdalalg_pipeline.cpp @@ -221,11 +221,7 @@ void GDALPipelineStepAlgorithm::AddVectorOutputArgs( } if (m_constructorOptions.addOutputLayerNameArgument) { - AddArg(GDAL_ARG_NAME_OUTPUT_LAYER, - shortNameOutputLayerAllowed ? 'l' : 0, _("Output layer name"), - &m_outputLayerName) - .AddHiddenAlias("nln") // For ogr2ogr nostalgic people - .SetHiddenForCLI(hiddenForCLI); + AddOutputLayerNameArg(hiddenForCLI, shortNameOutputLayerAllowed); } if (m_constructorOptions.addSkipErrorsArgument) { @@ -235,6 +231,20 @@ void GDALPipelineStepAlgorithm::AddVectorOutputArgs( } } +/************************************************************************/ +/* GDALPipelineStepAlgorithm::AddOutputLayerNameArg() */ +/************************************************************************/ + +void GDALPipelineStepAlgorithm::AddOutputLayerNameArg( + bool hiddenForCLI, bool shortNameOutputLayerAllowed) +{ + AddArg(GDAL_ARG_NAME_OUTPUT_LAYER, shortNameOutputLayerAllowed ? 'l' : 0, + _("Output layer name"), + &m_outputLayerName) + .AddHiddenAlias("nln") // For ogr2ogr nostalgic people + .SetHiddenForCLI(hiddenForCLI); +} + /************************************************************************/ /* GDALPipelineStepAlgorithm::RunImpl() */ /************************************************************************/ diff --git a/deps/libgdal/gdal/apps/gdalalg_raster_calc.cpp b/deps/libgdal/gdal/apps/gdalalg_raster_calc.cpp index 49c8887cb..cf1726ad8 100644 --- a/deps/libgdal/gdal/apps/gdalalg_raster_calc.cpp +++ b/deps/libgdal/gdal/apps/gdalalg_raster_calc.cpp @@ -183,6 +183,7 @@ struct SourceProperties int nBands{0}; int nX{0}; int nY{0}; + bool hasGT{false}; GDALGeoTransform gt{}; std::unique_ptr srs{ nullptr}; @@ -777,7 +778,7 @@ static std::unique_ptr GDALCalcCreateVRTDerived( out.nBands = 1; out.srs.reset(ds->GetSpatialRef() ? ds->GetSpatialRef()->Clone() : nullptr); - ds->GetGeoTransform(out.gt); + out.hasGT = ds->GetGeoTransform(out.gt) == CE_None; } CPLXMLTreeCloser root(CPLCreateXMLNode(nullptr, CXT_Element, "VRTDataset")); @@ -847,7 +848,10 @@ static std::unique_ptr GDALCalcCreateVRTDerived( { return nullptr; }; - ds->SetGeoTransform(out.gt); + if (out.hasGT) + { + ds->SetGeoTransform(out.gt); + } if (out.srs) { ds->SetSpatialRef(out.srs.get()); diff --git a/deps/libgdal/gdal/apps/gdalalg_raster_contour.cpp b/deps/libgdal/gdal/apps/gdalalg_raster_contour.cpp index e089755ac..e63154803 100644 --- a/deps/libgdal/gdal/apps/gdalalg_raster_contour.cpp +++ b/deps/libgdal/gdal/apps/gdalalg_raster_contour.cpp @@ -50,6 +50,11 @@ GDALRasterContourAlgorithm::GDALRasterContourAlgorithm(bool standaloneStep) AddRasterInputArgs(false, false); AddVectorOutputArgs(false, false); } + else + { + AddOutputLayerNameArg(/* hiddenForCLI = */ false, + /* shortNameOutputLayerAllowed = */ false); + } // gdal_contour specific options AddBandArg(&m_band).SetDefault(1); diff --git a/deps/libgdal/gdal/apps/gdalalg_raster_edit.cpp b/deps/libgdal/gdal/apps/gdalalg_raster_edit.cpp index 93afd14a1..4b2714607 100644 --- a/deps/libgdal/gdal/apps/gdalalg_raster_edit.cpp +++ b/deps/libgdal/gdal/apps/gdalalg_raster_edit.cpp @@ -53,6 +53,7 @@ GDALRasterEditAlgorithm::GDALRasterEditAlgorithm(bool standaloneStep) &m_dataset, GDAL_OF_RASTER | GDAL_OF_UPDATE) .SetPositional() .SetRequired(); + AddOpenOptionsArg(&m_openOptions); AddArg("auxiliary", 0, _("Ask for an auxiliary .aux.xml file to be edited"), &m_readOnly) diff --git a/deps/libgdal/gdal/apps/gdalalg_raster_polygonize.cpp b/deps/libgdal/gdal/apps/gdalalg_raster_polygonize.cpp index cb178fadb..95984f044 100644 --- a/deps/libgdal/gdal/apps/gdalalg_raster_polygonize.cpp +++ b/deps/libgdal/gdal/apps/gdalalg_raster_polygonize.cpp @@ -46,6 +46,11 @@ GDALRasterPolygonizeAlgorithm::GDALRasterPolygonizeAlgorithm( AddRasterInputArgs(false, false); AddVectorOutputArgs(false, false); } + else + { + AddOutputLayerNameArg(/* hiddenForCLI = */ false, + /* shortNameOutputLayerAllowed = */ false); + } // gdal_polygonize specific options AddBandArg(&m_band).SetDefault(m_band); diff --git a/deps/libgdal/gdal/apps/gdalalg_raster_viewshed.cpp b/deps/libgdal/gdal/apps/gdalalg_raster_viewshed.cpp index f3a1a3270..d26641a14 100644 --- a/deps/libgdal/gdal/apps/gdalalg_raster_viewshed.cpp +++ b/deps/libgdal/gdal/apps/gdalalg_raster_viewshed.cpp @@ -121,9 +121,7 @@ GDALRasterViewshedAlgorithm::GDALRasterViewshedAlgorithm(bool standaloneStep) _("Pixel value to set for the cells that fall outside of the range " "specified by the observer location and the maximum distance"), &m_opts.outOfRangeVal) - .SetDefault(m_opts.outOfRangeVal) - .SetMinValueIncluded(0) - .SetMaxValueIncluded(255); + .SetDefault(m_opts.outOfRangeVal); AddArg("dst-nodata", 0, _("The value to be set for the cells in the output raster that have " "no data."), diff --git a/deps/libgdal/gdal/apps/gdalalg_vector_select.cpp b/deps/libgdal/gdal/apps/gdalalg_vector_select.cpp index 605f7f26b..5f9853d31 100644 --- a/deps/libgdal/gdal/apps/gdalalg_vector_select.cpp +++ b/deps/libgdal/gdal/apps/gdalalg_vector_select.cpp @@ -32,6 +32,11 @@ GDALVectorSelectAlgorithm::GDALVectorSelectAlgorithm(bool standaloneStep) : GDALVectorPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL, standaloneStep) { + if (!standaloneStep) + { + AddOutputLayerNameArg(/* hiddenForCLI = */ false, + /* shortNameOutputLayerAllowed = */ false); + } AddActiveLayerArg(&m_activeLayer); AddArg("fields", 0, _("Fields to select (or exclude if --exclude)"), &m_fields) @@ -90,11 +95,14 @@ class GDALVectorSelectAlgorithmLayer final } public: - explicit GDALVectorSelectAlgorithmLayer(OGRLayer &oSrcLayer) + explicit GDALVectorSelectAlgorithmLayer( + OGRLayer &oSrcLayer, const std::string &osOutputLayerName) : GDALVectorPipelineOutputLayer(oSrcLayer), - m_poFeatureDefn(new OGRFeatureDefn(oSrcLayer.GetName())) + m_poFeatureDefn(new OGRFeatureDefn(osOutputLayerName.empty() + ? oSrcLayer.GetName() + : osOutputLayerName.c_str())) { - SetDescription(oSrcLayer.GetDescription()); + SetDescription(m_poFeatureDefn->GetName()); SetMetadata(oSrcLayer.GetMetadata()); m_poFeatureDefn->SetGeomType(wkbNone); m_poFeatureDefn->Reference(); @@ -301,8 +309,8 @@ bool GDALVectorSelectAlgorithm::RunStep(GDALPipelineStepRunContext &) if (m_activeLayer.empty() || m_activeLayer == poSrcLayer->GetDescription()) { - auto poLayer = - std::make_unique(*poSrcLayer); + auto poLayer = std::make_unique( + *poSrcLayer, m_outputLayerName); if (m_exclude) { poLayer->ExcludeFields(m_fields); diff --git a/deps/libgdal/gdal/apps/gdalbuildvrt_lib.cpp b/deps/libgdal/gdal/apps/gdalbuildvrt_lib.cpp index de8eed036..9a05db230 100644 --- a/deps/libgdal/gdal/apps/gdalbuildvrt_lib.cpp +++ b/deps/libgdal/gdal/apps/gdalbuildvrt_lib.cpp @@ -2202,7 +2202,7 @@ GDALBuildVRTOptionsGetParser(GDALBuildVRTOptions *psOptions, .help(_("Control the way the output resolution is computed.")); argParser->add_argument("-tr") - .metavar(" ") + .metavar(" ") .nargs(2) .scan<'g', double>() .help(_("Set target resolution.")); diff --git a/deps/libgdal/gdal/apps/gdalinfo_lib.cpp b/deps/libgdal/gdal/apps/gdalinfo_lib.cpp index 174ace799..bca8a6805 100644 --- a/deps/libgdal/gdal/apps/gdalinfo_lib.cpp +++ b/deps/libgdal/gdal/apps/gdalinfo_lib.cpp @@ -298,8 +298,9 @@ GDALInfoAppOptionsGetParser(GDALInfoOptions *psOptions, "system.")); argParser->add_argument("-wkt_format") - .metavar("") - .choices("WKT1", "WKT2", "WKT2_2015", "WKT2_2018", "WKT2_2019") + .metavar("") + .choices("WKT1", "WKT1_ESRI", "WKT2", "WKT2_2015", "WKT2_2018", + "WKT2_2019") .store_into(psOptions->osWKTFormat) .help(_("WKT format used for SRS.")); diff --git a/deps/libgdal/gdal/apps/gdaltindex_lib.cpp b/deps/libgdal/gdal/apps/gdaltindex_lib.cpp index 932d2d317..f843fcaa1 100644 --- a/deps/libgdal/gdal/apps/gdaltindex_lib.cpp +++ b/deps/libgdal/gdal/apps/gdaltindex_lib.cpp @@ -1126,19 +1126,44 @@ GDALDatasetH GDALTileIndexInternal(const char *pszDest, adfX[4] = gt[0] + 0 * gt[1] + 0 * gt[2]; adfY[4] = gt[3] + 0 * gt[4] + 0 * gt[5]; - // If set target srs, do the forward transformation of all points. + // If set target srs, compute the reprojected extent. + // Use GDALWarp() with VRT output so the stored bounding box matches + // what the GTI reader computes in its Pass 1 (GetSourceDesc). + // A plain 4-corner transform or standalone GDALSuggestedWarpOutput2() + // can underestimate the extent because GDALWarp() may adjust the + // resolution after calling GDALSuggestedWarpOutput2(), producing a + // different pixel count and thus a different extent. if (!oTargetSRS.IsEmpty() && poSrcSRS) { if (!poSrcSRS->IsSame(&oTargetSRS)) { - auto poCT = std::unique_ptr( - OGRCreateCoordinateTransformation(poSrcSRS, &oTargetSRS)); - if (!poCT || !poCT->Transform(5, adfX, adfY, nullptr)) + char *pszDstWKT = nullptr; + oTargetSRS.exportToWkt(&pszDstWKT); + + CPLStringList aosWarpArgs; + aosWarpArgs.AddString("-of"); + aosWarpArgs.AddString("VRT"); + aosWarpArgs.AddString("-t_srs"); + aosWarpArgs.AddString(pszDstWKT); + CPLFree(pszDstWKT); + + GDALWarpAppOptions *psWarpOptions = + GDALWarpAppOptionsNew(aosWarpArgs.List(), nullptr); + GDALDatasetH hSrcDS = GDALDataset::ToHandle(poSrcDS.get()); + GDALDatasetH ahSrcDS[] = {hSrcDS}; + int bUsageError = false; + auto poWarpDS = std::unique_ptr( + GDALDataset::FromHandle(GDALWarp( + "", nullptr, 1, ahSrcDS, psWarpOptions, &bUsageError))); + GDALWarpAppOptionsFree(psWarpOptions); + + if (!poWarpDS) { CPLError(bFailOnErrors ? CE_Failure : CE_Warning, CPLE_AppDefined, - "unable to transform points from source " - "SRS `%s' to target SRS `%s' for file `%s'%s", + "unable to compute reprojected extent from " + "source SRS `%s' to target SRS `%s' for " + "file `%s'%s", poSrcDS->GetProjectionRef(), psOptions->osTargetSRS.c_str(), osFileNameToWrite.c_str(), @@ -1147,6 +1172,29 @@ GDALDatasetH GDALTileIndexInternal(const char *pszDest, return nullptr; continue; } + + GDALGeoTransform warpGT; + poWarpDS->GetGeoTransform(warpGT); + const int nDstPixels = poWarpDS->GetRasterXSize(); + const int nDstLines = poWarpDS->GetRasterYSize(); + + const double dfDstMinX = warpGT.xorig; + const double dfDstMaxY = warpGT.yorig; + const double dfDstMaxX = + warpGT.xorig + nDstPixels * warpGT.xscale; + const double dfDstMinY = + warpGT.yorig + nDstLines * warpGT.yscale; + + adfX[0] = dfDstMinX; + adfY[0] = dfDstMaxY; + adfX[1] = dfDstMaxX; + adfY[1] = dfDstMaxY; + adfX[2] = dfDstMaxX; + adfY[2] = dfDstMinY; + adfX[3] = dfDstMinX; + adfY[3] = dfDstMinY; + adfX[4] = dfDstMinX; + adfY[4] = dfDstMaxY; } } else if (bIsGTIContext && !oAlreadyExistingSRS.IsEmpty() && diff --git a/deps/libgdal/gdal/apps/ogr2ogr_lib.cpp b/deps/libgdal/gdal/apps/ogr2ogr_lib.cpp index f0332867c..9c37be71c 100644 --- a/deps/libgdal/gdal/apps/ogr2ogr_lib.cpp +++ b/deps/libgdal/gdal/apps/ogr2ogr_lib.cpp @@ -2970,7 +2970,7 @@ GDALDatasetH GDALVectorTranslate(const char *pszDest, GDALDatasetH hDstDS, // method. GDALDatasetUniquePtr poODSUniquePtr(hDstDS == nullptr ? poODS : nullptr); - // Some syntaxic sugar to make "ogr2ogr [-f PostgreSQL] PG:dbname=.... + // Some syntactic sugar to make "ogr2ogr [-f PostgreSQL] PG:dbname=.... // source [srclayer] -lco OVERWRITE=YES" work like "ogr2ogr -overwrite // PG:dbname=.... source [srclayer]" The former syntax used to work at // GDAL 1.1.8 time when it was documented in the PG driver, but was broken diff --git a/deps/libgdal/gdal/frmts/georaster/cpl_vsil_ocilob.cpp b/deps/libgdal/gdal/frmts/georaster/cpl_vsil_ocilob.cpp index 720254277..bb9848b20 100644 --- a/deps/libgdal/gdal/frmts/georaster/cpl_vsil_ocilob.cpp +++ b/deps/libgdal/gdal/frmts/georaster/cpl_vsil_ocilob.cpp @@ -94,10 +94,10 @@ char **WSIOCILobFSHandle::ParseIdentificator(const char *pszFilename) return nullptr; } - char **papszParam = - CSLTokenizeString2(&pszFilename[strlen("/vsiocilob/")], ",", - CSLT_HONOURSTRINGS | CSLT_ALLOWEMPTYTOKENS | - CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES); + char **papszParam = CSLTokenizeString2( + &pszFilename[strlen("/vsiocilob/")], ",", + CSLT_HONOURSTRINGS | CSLT_ALLOWEMPTYTOKENS | CSLT_STRIPLEADSPACES | + CSLT_STRIPENDSPACES | CSLT_PRESERVEQUOTES); if (CSLCount(papszParam) < 6) { diff --git a/deps/libgdal/gdal/frmts/georaster/georaster_wrapper.cpp b/deps/libgdal/gdal/frmts/georaster/georaster_wrapper.cpp index be3130f8a..35986123f 100644 --- a/deps/libgdal/gdal/frmts/georaster/georaster_wrapper.cpp +++ b/deps/libgdal/gdal/frmts/georaster/georaster_wrapper.cpp @@ -214,7 +214,8 @@ char **GeoRasterWrapper::ParseIdentificator(const char *pszStringID) if (CSLCount(papszParam) > 0) { char **papszFirst2 = CSLTokenizeString2( - papszParam[0], "/", CSLT_HONOURSTRINGS | CSLT_ALLOWEMPTYTOKENS); + papszParam[0], "/", + CSLT_HONOURSTRINGS | CSLT_ALLOWEMPTYTOKENS | CSLT_PRESERVEQUOTES); if (CSLCount(papszFirst2) == 2) { papszParam = CSLInsertStrings(papszParam, 0, papszFirst2); @@ -328,7 +329,8 @@ GeoRasterWrapper *GeoRasterWrapper::Open(const char *pszStringId, bool bUpdate, else { char **papszSchema = CSLTokenizeString2( - papszParam[3], ".", CSLT_HONOURSTRINGS | CSLT_ALLOWEMPTYTOKENS); + papszParam[3], ".", + CSLT_HONOURSTRINGS | CSLT_ALLOWEMPTYTOKENS | CSLT_PRESERVEQUOTES); if (CSLCount(papszSchema) == 2) { diff --git a/deps/libgdal/gdal/frmts/gif/giflib/dgif_lib.c b/deps/libgdal/gdal/frmts/gif/giflib/dgif_lib.c index 8713df20e..e634d4bc5 100644 --- a/deps/libgdal/gdal/frmts/gif/giflib/dgif_lib.c +++ b/deps/libgdal/gdal/frmts/gif/giflib/dgif_lib.c @@ -427,9 +427,7 @@ DGifGetImageDesc(GifFileType * GifFile) { Private->PixelCount = (long)GifFile->Image.Width * (long)GifFile->Image.Height; - DGifSetupDecompress(GifFile); /* Reset decompress algorithm parameters. */ - - return GIF_OK; + return DGifSetupDecompress(GifFile); /* Reset decompress algorithm parameters. */ } /****************************************************************************** @@ -727,6 +725,8 @@ DGifSetupDecompress(GifFileType * GifFile) { return GIF_ERROR; /* Failed to read Code size. */ } BitsPerPixel = CodeSize; + if (BitsPerPixel > 8) + return GIF_ERROR; Private->Buf[0] = 0; /* Input Buffer empty. */ Private->BitsPerPixel = BitsPerPixel; diff --git a/deps/libgdal/gdal/frmts/gti/gdaltileindexdataset.cpp b/deps/libgdal/gdal/frmts/gti/gdaltileindexdataset.cpp index 2ad467321..550ba73e3 100644 --- a/deps/libgdal/gdal/frmts/gti/gdaltileindexdataset.cpp +++ b/deps/libgdal/gdal/frmts/gti/gdaltileindexdataset.cpp @@ -238,12 +238,21 @@ class GDALTileIndexDataset final : public GDALPamDataset //! SRS of the tile index. OGRSpatialReference m_oSRS{}; + struct SharedDataset + { + //! Source dataset (possibly warped). + std::shared_ptr poDS{}; + + //! Source dataset, raw/unwarped + GDALDataset *poUnreprojectedDS = nullptr; + }; + //! Cache from dataset name to dataset handle. //! Note that the dataset objects are ultimately GDALProxyPoolDataset, //! and that the GDALProxyPoolDataset limits the number of simultaneously //! opened real datasets (controlled by GDAL_MAX_DATASET_POOL_SIZE). Hence 500 is not too big. - lru11::Cache> m_oMapSharedSources{ - 500}; + lru11::Cache> + m_oMapSharedSources{500}; //! Mask band (e.g. for JPEG compressed + mask band) std::unique_ptr m_poMaskBand{}; @@ -310,9 +319,12 @@ class GDALTileIndexDataset final : public GDALPamDataset //! Source dataset name. std::string osName{}; - //! Source dataset handle. + //! Source dataset (possibly warped). std::shared_ptr poDS{}; + //! Source dataset, raw/unwarped + GDALDataset *poUnreprojectedDS = nullptr; + //! VRTSimpleSource or VRTComplexSource for the source. std::unique_ptr poSource{}; @@ -350,6 +362,8 @@ class GDALTileIndexDataset final : public GDALPamDataset //! Whether the GTI file is a STAC collection bool m_bSTACCollection = false; + std::string m_osWarpMemory{}; + //! From a source dataset name, return its SourceDesc description structure. bool GetSourceDesc(const std::string &osTileName, SourceDesc &oSourceDesc, std::mutex *pMutex); @@ -2414,6 +2428,9 @@ bool GDALTileIndexDataset::Open(GDALOpenInfo *poOpenInfo) /* -------------------------------------------------------------------- */ oOvManager.Initialize(this, poOpenInfo->pszFilename); + m_osWarpMemory = CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, + "WARPING_MEMORY_SIZE", ""); + return true; } @@ -3494,15 +3511,23 @@ bool GDALTileIndexDataset::GetSourceDesc(const std::string &osTileName, SourceDesc &oSourceDesc, std::mutex *pMutex) { - std::shared_ptr poTileDS; if (pMutex) pMutex->lock(); - const bool bTileKnown = m_oMapSharedSources.tryGet(osTileName, poTileDS); + std::shared_ptr sharedDS; + m_oMapSharedSources.tryGet(osTileName, sharedDS); if (pMutex) pMutex->unlock(); - if (!bTileKnown) + std::shared_ptr poTileDS; + GDALDataset *poUnreprojectedDS = nullptr; + + if (sharedDS) + { + poTileDS = sharedDS->poDS; + poUnreprojectedDS = sharedDS->poUnreprojectedDS; + } + else { poTileDS = std::shared_ptr( GDALProxyPoolDataset::Create( @@ -3515,6 +3540,7 @@ bool GDALTileIndexDataset::GetSourceDesc(const std::string &osTileName, osTileName.c_str()); return false; } + poUnreprojectedDS = poTileDS.get(); if (poTileDS->GetRasterCount() == 0) { CPLError(CE_Failure, CPLE_AppDefined, @@ -3540,7 +3566,13 @@ bool GDALTileIndexDataset::GetSourceDesc(const std::string &osTileName, osTileName.c_str()); bWarpVRT = true; bExportSRS = true; - bAddAlphaToVRT = true; + if (poTileDS->GetRasterBand(poTileDS->GetRasterCount()) + ->GetColorInterpretation() != GCI_AlphaBand && + GetRasterBand(nBands)->GetColorInterpretation() == + GCI_AlphaBand) + { + bAddAlphaToVRT = true; + } } else if (poTileDS->GetGeoTransform(tileGT) == CE_None && tileGT[GT_NS_RES] > 0 && @@ -3654,6 +3686,12 @@ bool GDALTileIndexDataset::GetSourceDesc(const std::string &osTileName, if (bAddAlphaToVRT) aosOptions.AddString("-dstalpha"); + if (!m_osWarpMemory.empty()) + { + aosOptions.AddString("-wm"); + aosOptions.AddString(m_osWarpMemory.c_str()); + } + psWarpOptions = GDALWarpAppOptionsNew(aosOptions.List(), nullptr); poWarpDS.reset(GDALDataset::FromHandle(GDALWarp( "", nullptr, 1, ahSrcDS, psWarpOptions, &bUsageError))); @@ -3666,9 +3704,13 @@ bool GDALTileIndexDataset::GetSourceDesc(const std::string &osTileName, poTileDS.reset(poWarpDS.release()); } + sharedDS = std::make_shared(); + sharedDS->poDS = poTileDS; + sharedDS->poUnreprojectedDS = poUnreprojectedDS; + if (pMutex) pMutex->lock(); - m_oMapSharedSources.insert(osTileName, poTileDS); + m_oMapSharedSources.insert(osTileName, sharedDS); if (pMutex) pMutex->unlock(); } @@ -3733,6 +3775,7 @@ bool GDALTileIndexDataset::GetSourceDesc(const std::string &osTileName, oSourceDesc.osName = osTileName; oSourceDesc.poDS = std::move(poTileDS); + oSourceDesc.poUnreprojectedDS = poUnreprojectedDS; oSourceDesc.poSource = std::move(poSource); oSourceDesc.bHasNoData = bHasNoData; oSourceDesc.bSameNoData = bSameNoData; @@ -3978,8 +4021,9 @@ bool GDALTileIndexDataset::CollectSources(double dfXOff, double dfYOff, CPLError(CE_Warning, CPLE_AppDefined, "Tile index is out of sync with actual " "extent of %s. Bounding box from tile index " - "is (%g, %g, %g, %g) does not intersect at " - "all bounding box from tile (%g, %g, %g, %g)", + "is (%.15g, %.15g, %.15g, %.15g) does not " + "intersect at all bounding box from tile " + "(%.15g, %.15g, %.15g, %.15g)", osTileName.c_str(), sGeomTileExtent.MinX, sGeomTileExtent.MinY, sGeomTileExtent.MaxX, sGeomTileExtent.MaxY, sActualTileExtent.MinX, @@ -3987,11 +4031,77 @@ bool GDALTileIndexDataset::CollectSources(double dfXOff, double dfYOff, sActualTileExtent.MaxY); continue; } + + // The above test assumes, in the case of reprojection, that + // the reprojected geometry in the index is computed the + // same way as we do here, that is using GDALWarp() + // Which wasn't the case for example before GDAL 3.12.3 when + // using "gdal raster index", which uses a simple 4-corner + // reprojection logic. So also test using that method, + // before emitting any warning. + if (oSourceDesc.poUnreprojectedDS != oSourceDesc.poDS.get()) + { + const int nXSize = + oSourceDesc.poUnreprojectedDS->GetRasterXSize(); + const int nYSize = + oSourceDesc.poUnreprojectedDS->GetRasterYSize(); + GDALGeoTransform gt; + const auto poSrcSRS = + oSourceDesc.poUnreprojectedDS->GetSpatialRef(); + if (poSrcSRS && !m_oSRS.IsEmpty() && + oSourceDesc.poUnreprojectedDS->GetGeoTransform( + gt) == CE_None) + { + double adfX[4] = {0.0, 0.0, 0.0, 0.0}; + double adfY[4] = {0.0, 0.0, 0.0, 0.0}; + adfX[0] = gt.xorig + 0 * gt.xscale + 0 * gt.xrot; + adfY[0] = gt.yorig + 0 * gt.yrot + 0 * gt.yscale; + + adfX[1] = + gt.xorig + nXSize * gt.xscale + 0 * gt.xrot; + adfY[1] = + gt.yorig + nXSize * gt.yrot + 0 * gt.yscale; + + adfX[2] = gt.xorig + nXSize * gt.xscale + + nYSize * gt.xrot; + adfY[2] = gt.yorig + nXSize * gt.yrot + + nYSize * gt.yscale; + + adfX[3] = + gt.xorig + 0 * gt.xscale + nYSize * gt.xrot; + adfY[3] = + gt.yorig + 0 * gt.yrot + nYSize * gt.yscale; + + auto poCT = + std::unique_ptr( + OGRCreateCoordinateTransformation(poSrcSRS, + &m_oSRS)); + if (poCT && poCT->Transform(4, adfX, adfY, nullptr)) + { + OGREnvelope sActualTileExtent2; + sActualTileExtent2.MinX = std::min( + {adfX[0], adfX[1], adfX[2], adfX[3]}); + sActualTileExtent2.MinY = std::min( + {adfY[0], adfY[1], adfY[2], adfY[3]}); + sActualTileExtent2.MaxX = std::max( + {adfX[0], adfX[1], adfX[2], adfX[3]}); + sActualTileExtent2.MaxY = std::max( + {adfY[0], adfY[1], adfY[2], adfY[3]}); + if (sGeomTileExtent.Contains( + sActualTileExtent2)) + { + continue; + } + } + } + } + CPLError(CE_Warning, CPLE_AppDefined, "Tile index is out of sync with actual extent " - "of %s. Bounding box from tile index is (%g, %g, " - "%g, %g) does not fully contain bounding box from " - "tile (%g, %g, %g, %g)", + "of %s. Bounding box from tile index is " + "(%.15g, %.15g, %.15g, %.15g) does not fully " + "contain bounding box from tile " + "(%.15g, %.15g, %.15g, %.15g)", osTileName.c_str(), sGeomTileExtent.MinX, sGeomTileExtent.MinY, sGeomTileExtent.MaxX, sGeomTileExtent.MaxY, sActualTileExtent.MinX, @@ -5249,9 +5359,12 @@ void GDALRegister_GTI() "