Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: gdal "raster overview add" subcommand
5 : * Author: Even Rouault <even dot rouault at spatialys.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2025, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "gdalalg_raster_overview.h"
14 : #include "gdalalg_raster_overview_add.h"
15 :
16 : #include "cpl_string.h"
17 : #include "gdal_priv.h"
18 :
19 : //! @cond Doxygen_Suppress
20 :
21 : #ifndef _
22 : #define _(x) (x)
23 : #endif
24 :
25 0 : bool GDALRasterOverviewAlgorithm::RunStep(GDALPipelineStepRunContext &)
26 : {
27 0 : CPLError(CE_Failure, CPLE_AppDefined,
28 : "The Run() method should not be called directly on the \"gdal "
29 : "raster overview\" program.");
30 0 : return false;
31 : }
32 :
33 : GDALRasterOverviewAlgorithmStandalone::
34 : ~GDALRasterOverviewAlgorithmStandalone() = default;
35 :
36 : /************************************************************************/
37 : /* GDALRasterOverviewAlgorithmAdd() */
38 : /************************************************************************/
39 :
40 85 : GDALRasterOverviewAlgorithmAdd::GDALRasterOverviewAlgorithmAdd(
41 85 : bool standaloneStep)
42 : : GDALRasterPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
43 0 : ConstructorOptions()
44 85 : .SetStandaloneStep(standaloneStep)
45 170 : .SetAddDefaultArguments(false))
46 : {
47 85 : if (standaloneStep)
48 75 : AddProgressArg();
49 :
50 85 : AddOpenOptionsArg(&m_openOptions);
51 : auto &datasetArg =
52 : AddInputDatasetArg(
53 : &m_inputDataset, GDAL_OF_RASTER | GDAL_OF_UPDATE,
54 : /* positionalAndRequired = */ standaloneStep,
55 85 : _("Dataset (to be updated in-place, unless --external)"))
56 170 : .AddAlias("dataset")
57 85 : .SetMaxCount(1);
58 85 : if (!standaloneStep)
59 : {
60 10 : datasetArg.SetPositional();
61 10 : datasetArg.SetHidden();
62 : }
63 :
64 85 : constexpr const char *OVERVIEW_SRC_LEVELS_MUTEX = "overview-src-levels";
65 :
66 : auto &overviewSrcArg =
67 : AddArg("overview-src", 0, _("Source overview dataset"),
68 170 : &m_overviewSources, GDAL_OF_RASTER)
69 85 : .SetMutualExclusionGroup(OVERVIEW_SRC_LEVELS_MUTEX);
70 85 : SetAutoCompleteFunctionForFilename(overviewSrcArg, GDAL_OF_RASTER);
71 :
72 85 : if (standaloneStep)
73 : {
74 150 : AddArg("external", 0, _("Add external overviews"), &m_readOnly)
75 150 : .AddHiddenAlias("ro")
76 75 : .AddHiddenAlias(GDAL_ARG_NAME_READ_ONLY);
77 : }
78 :
79 170 : AddArg("resampling", 'r', _("Resampling method"), &m_resampling)
80 : .SetChoices("nearest", "average", "cubic", "cubicspline", "lanczos",
81 85 : "bilinear", "gauss", "average_magphase", "rms", "mode")
82 85 : .SetHiddenChoices("near", "none");
83 :
84 170 : AddArg("levels", 0, _("Levels / decimation factors"), &m_levels)
85 85 : .SetMinValueIncluded(2)
86 85 : .SetMutualExclusionGroup(OVERVIEW_SRC_LEVELS_MUTEX);
87 : AddArg("min-size", 0,
88 : _("Maximum width or height of the smallest overview level."),
89 170 : &m_minSize)
90 85 : .SetMinValueIncluded(1);
91 :
92 85 : if (standaloneStep)
93 : {
94 : auto &ovrCreationOptionArg =
95 : AddArg(GDAL_ARG_NAME_CREATION_OPTION, 0,
96 150 : _("Overview creation option"), &m_creationOptions)
97 150 : .AddAlias("co")
98 150 : .SetMetaVar("<KEY>=<VALUE>")
99 75 : .SetPackedValuesAllowed(false);
100 : ovrCreationOptionArg.AddValidationAction(
101 5 : [this, &ovrCreationOptionArg]()
102 80 : { return ParseAndValidateKeyValue(ovrCreationOptionArg); });
103 :
104 : ovrCreationOptionArg.SetAutoCompleteFunction(
105 6 : [this](const std::string ¤tValue)
106 : {
107 2 : std::vector<std::string> oRet;
108 :
109 2 : const std::string osDSName = m_inputDataset.size() == 1
110 2 : ? m_inputDataset[0].GetName()
111 6 : : std::string();
112 4 : const std::string osExt = CPLGetExtensionSafe(osDSName.c_str());
113 2 : if (!osExt.empty())
114 : {
115 2 : std::set<std::string> oVisitedExtensions;
116 2 : auto poDM = GetGDALDriverManager();
117 233 : for (int i = 0; i < poDM->GetDriverCount(); ++i)
118 : {
119 232 : auto poDriver = poDM->GetDriver(i);
120 232 : if (poDriver->GetMetadataItem(GDAL_DCAP_RASTER))
121 : {
122 : const char *pszExtensions =
123 160 : poDriver->GetMetadataItem(GDAL_DMD_EXTENSIONS);
124 160 : if (pszExtensions)
125 : {
126 : const CPLStringList aosExts(
127 105 : CSLTokenizeString2(pszExtensions, " ", 0));
128 232 : for (const char *pszExt : cpl::Iterate(aosExts))
129 : {
130 133 : if (EQUAL(pszExt, osExt.c_str()) &&
131 4 : !cpl::contains(oVisitedExtensions,
132 : pszExt))
133 : {
134 2 : oVisitedExtensions.insert(pszExt);
135 2 : if (AddOptionsSuggestions(
136 : poDriver->GetMetadataItem(
137 2 : GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST),
138 : GDAL_OF_RASTER, currentValue,
139 : oRet))
140 : {
141 1 : return oRet;
142 : }
143 1 : break;
144 : }
145 : }
146 : }
147 : }
148 : }
149 : }
150 :
151 1 : return oRet;
152 75 : });
153 : }
154 85 : }
155 :
156 : /************************************************************************/
157 : /* GDALRasterOverviewAlgorithmAdd::RunStep() */
158 : /************************************************************************/
159 :
160 27 : bool GDALRasterOverviewAlgorithmAdd::RunStep(GDALPipelineStepRunContext &ctxt)
161 : {
162 27 : GDALProgressFunc pfnProgress = ctxt.m_pfnProgress;
163 27 : void *pProgressData = ctxt.m_pProgressData;
164 27 : auto poDS = m_inputDataset[0].GetDatasetRef();
165 27 : CPLAssert(poDS);
166 :
167 54 : CPLStringList aosOptions(m_creationOptions);
168 27 : if (m_readOnly)
169 : {
170 7 : auto poDriver = poDS->GetDriver();
171 7 : if (poDriver)
172 : {
173 : const char *pszOptionList =
174 7 : poDriver->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST);
175 7 : if (pszOptionList)
176 : {
177 7 : if (strstr(pszOptionList, "<Value>EXTERNAL</Value>") == nullptr)
178 : {
179 1 : ReportError(CE_Failure, CPLE_NotSupported,
180 : "Driver %s does not support external overviews",
181 1 : poDriver->GetDescription());
182 1 : return false;
183 : }
184 6 : else if (aosOptions.FetchNameValue("LOCATION") == nullptr)
185 : {
186 6 : aosOptions.SetNameValue("LOCATION", "EXTERNAL");
187 : }
188 : }
189 : }
190 : }
191 :
192 52 : std::string resampling = m_resampling;
193 26 : if (resampling.empty() && poDS->GetRasterCount() > 0)
194 : {
195 22 : auto poBand = poDS->GetRasterBand(1);
196 22 : if (poBand->GetOverviewCount() > 0)
197 : {
198 : const char *pszResampling =
199 5 : poBand->GetOverview(0)->GetMetadataItem("RESAMPLING");
200 5 : if (pszResampling)
201 : {
202 1 : resampling = pszResampling;
203 1 : CPLDebug("GDAL",
204 : "Reusing resampling method %s from existing "
205 : "overview",
206 : pszResampling);
207 : }
208 : }
209 : }
210 26 : if (resampling.empty())
211 21 : resampling = "nearest";
212 :
213 26 : if (!m_overviewSources.empty())
214 : {
215 14 : std::vector<GDALDataset *> apoDS;
216 28 : for (auto &val : m_overviewSources)
217 : {
218 14 : CPLAssert(val.GetDatasetRef());
219 14 : apoDS.push_back(val.GetDatasetRef());
220 : }
221 14 : return poDS->AddOverviews(apoDS, pfnProgress, pProgressData, nullptr) ==
222 14 : CE_None;
223 : }
224 :
225 24 : std::vector<int> levels = m_levels;
226 :
227 : // If no levels are specified, reuse the potentially existing ones.
228 12 : if (levels.empty() && poDS->GetRasterCount() > 0)
229 : {
230 5 : auto poBand = poDS->GetRasterBand(1);
231 5 : const int nExistingCount = poBand->GetOverviewCount();
232 5 : if (nExistingCount > 0)
233 : {
234 2 : for (int iOvr = 0; iOvr < nExistingCount; ++iOvr)
235 : {
236 1 : auto poOverview = poBand->GetOverview(iOvr);
237 1 : if (poOverview)
238 : {
239 1 : const int nOvFactor = GDALComputeOvFactor(
240 : poOverview->GetXSize(), poBand->GetXSize(),
241 1 : poOverview->GetYSize(), poBand->GetYSize());
242 1 : levels.push_back(nOvFactor);
243 : }
244 : }
245 : }
246 : }
247 :
248 12 : if (levels.empty())
249 : {
250 4 : const int nXSize = poDS->GetRasterXSize();
251 4 : const int nYSize = poDS->GetRasterYSize();
252 4 : int nOvrFactor = 1;
253 9 : while (DIV_ROUND_UP(nXSize, nOvrFactor) > m_minSize ||
254 4 : DIV_ROUND_UP(nYSize, nOvrFactor) > m_minSize)
255 : {
256 5 : nOvrFactor *= 2;
257 5 : levels.push_back(nOvrFactor);
258 : }
259 : }
260 :
261 12 : if (!m_standaloneStep && !levels.empty())
262 : {
263 1 : auto poVRTDriver = GetGDALDriverManager()->GetDriverByName("VRT");
264 1 : if (!poVRTDriver)
265 : {
266 0 : ReportError(CE_Failure, CPLE_AppDefined,
267 : "VRT driver not available");
268 0 : return false;
269 : }
270 : auto poVRTDS = std::unique_ptr<GDALDataset>(poVRTDriver->CreateCopy(
271 1 : "", poDS, false, nullptr, nullptr, nullptr));
272 1 : bool bRet = poVRTDS != nullptr;
273 1 : if (bRet)
274 : {
275 1 : aosOptions.SetNameValue("VIRTUAL", "YES");
276 1 : bRet = GDALBuildOverviewsEx(
277 : GDALDataset::ToHandle(poVRTDS.get()), resampling.c_str(),
278 1 : static_cast<int>(levels.size()), levels.data(), 0,
279 1 : nullptr, nullptr, nullptr, aosOptions.List()) == CE_None;
280 1 : if (bRet)
281 1 : m_outputDataset.Set(std::move(poVRTDS));
282 : }
283 1 : return bRet;
284 : }
285 : else
286 : {
287 : const auto ret =
288 22 : levels.empty() ||
289 11 : GDALBuildOverviewsEx(
290 : GDALDataset::ToHandle(poDS), resampling.c_str(),
291 11 : static_cast<int>(levels.size()), levels.data(), 0, nullptr,
292 11 : pfnProgress, pProgressData, aosOptions.List()) == CE_None;
293 11 : if (ret)
294 11 : m_outputDataset.Set(poDS);
295 11 : return ret;
296 : }
297 : }
298 :
299 : /************************************************************************/
300 : /* GDALRasterOverviewAlgorithmAdd::RunImpl() */
301 : /************************************************************************/
302 :
303 26 : bool GDALRasterOverviewAlgorithmAdd::RunImpl(GDALProgressFunc pfnProgress,
304 : void *pProgressData)
305 : {
306 26 : GDALPipelineStepRunContext stepCtxt;
307 26 : stepCtxt.m_pfnProgress = pfnProgress;
308 26 : stepCtxt.m_pProgressData = pProgressData;
309 52 : return RunStep(stepCtxt);
310 : }
311 :
312 : GDALRasterOverviewAlgorithmAddStandalone::
313 : ~GDALRasterOverviewAlgorithmAddStandalone() = default;
314 :
315 : //! @endcond
|