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_add.h"
14 :
15 : #include "cpl_string.h"
16 : #include "gdal_priv.h"
17 :
18 : //! @cond Doxygen_Suppress
19 :
20 : #ifndef _
21 : #define _(x) (x)
22 : #endif
23 :
24 : /************************************************************************/
25 : /* GDALRasterOverviewAlgorithmAdd() */
26 : /************************************************************************/
27 :
28 11 : GDALRasterOverviewAlgorithmAdd::GDALRasterOverviewAlgorithmAdd()
29 11 : : GDALAlgorithm(NAME, DESCRIPTION, HELP_URL)
30 : {
31 11 : AddProgressArg();
32 11 : AddOpenOptionsArg(&m_openOptions);
33 : AddArg("dataset", 0,
34 : _("Dataset (to be updated in-place, unless --external)"), &m_dataset,
35 22 : GDAL_OF_RASTER | GDAL_OF_UPDATE)
36 11 : .SetPositional()
37 11 : .SetRequired();
38 22 : AddArg("external", 0, _("Add external overviews"), &m_readOnly)
39 22 : .AddHiddenAlias("ro")
40 11 : .AddHiddenAlias(GDAL_ARG_NAME_READ_ONLY);
41 :
42 22 : AddArg("resampling", 'r', _("Resampling method"), &m_resampling)
43 : .SetChoices("nearest", "average", "cubic", "cubicspline", "lanczos",
44 11 : "bilinear", "gauss", "average_magphase", "rms", "mode")
45 11 : .SetHiddenChoices("near");
46 :
47 : auto &levelArg =
48 11 : AddArg("levels", 0, _("Levels / decimation factors"), &m_levels);
49 : levelArg.AddValidationAction(
50 5 : [this, &levelArg]()
51 : {
52 4 : const auto &values = levelArg.Get<std::vector<int>>();
53 7 : for (const auto &value : values)
54 : {
55 4 : if (value < 2)
56 : {
57 1 : ReportError(CE_Failure, CPLE_IllegalArg,
58 : "Values of 'levels' argument should be "
59 : "integers greater or equal to 2.");
60 1 : return false;
61 : }
62 : }
63 3 : return true;
64 11 : });
65 :
66 : auto &minSizeArg =
67 : AddArg("min-size", 0,
68 : _("Maximum width or height of the smallest overview level."),
69 11 : &m_minSize);
70 : minSizeArg.AddValidationAction(
71 5 : [this, &minSizeArg]()
72 : {
73 4 : const int val = minSizeArg.Get<int>();
74 4 : if (val <= 0)
75 : {
76 1 : ReportError(CE_Failure, CPLE_IllegalArg,
77 : "Value of 'min-size' should be an integer greater "
78 : "or equal to 1.");
79 1 : return false;
80 : }
81 3 : return true;
82 11 : });
83 11 : }
84 :
85 : /************************************************************************/
86 : /* GDALRasterOverviewAlgorithmAdd::RunImpl() */
87 : /************************************************************************/
88 :
89 7 : bool GDALRasterOverviewAlgorithmAdd::RunImpl(GDALProgressFunc pfnProgress,
90 : void *pProgressData)
91 : {
92 7 : auto poDS = m_dataset.GetDatasetRef();
93 7 : CPLAssert(poDS);
94 :
95 14 : std::string resampling = m_resampling;
96 7 : if (resampling.empty() && poDS->GetRasterCount() > 0)
97 : {
98 4 : auto poBand = poDS->GetRasterBand(1);
99 4 : if (poBand->GetOverviewCount() > 0)
100 : {
101 : const char *pszResampling =
102 1 : poBand->GetOverview(0)->GetMetadataItem("RESAMPLING");
103 1 : if (pszResampling)
104 : {
105 1 : resampling = pszResampling;
106 1 : CPLDebug("GDAL",
107 : "Reusing resampling method %s from existing "
108 : "overview",
109 : pszResampling);
110 : }
111 : }
112 : }
113 7 : if (resampling.empty())
114 3 : resampling = "nearest";
115 :
116 7 : std::vector<int> levels = m_levels;
117 :
118 : // If no levels are specified, reuse the potentially existing ones.
119 7 : if (levels.empty() && poDS->GetRasterCount() > 0)
120 : {
121 4 : auto poBand = poDS->GetRasterBand(1);
122 4 : const int nExistingCount = poBand->GetOverviewCount();
123 4 : if (nExistingCount > 0)
124 : {
125 2 : for (int iOvr = 0; iOvr < nExistingCount; ++iOvr)
126 : {
127 1 : auto poOverview = poBand->GetOverview(iOvr);
128 1 : if (poOverview)
129 : {
130 1 : const int nOvFactor = GDALComputeOvFactor(
131 : poOverview->GetXSize(), poBand->GetXSize(),
132 1 : poOverview->GetYSize(), poBand->GetYSize());
133 1 : levels.push_back(nOvFactor);
134 : }
135 : }
136 : }
137 : }
138 :
139 7 : if (levels.empty())
140 : {
141 3 : const int nXSize = poDS->GetRasterXSize();
142 3 : const int nYSize = poDS->GetRasterYSize();
143 3 : int nOvrFactor = 1;
144 6 : while (DIV_ROUND_UP(nXSize, nOvrFactor) > m_minSize ||
145 3 : DIV_ROUND_UP(nYSize, nOvrFactor) > m_minSize)
146 : {
147 3 : nOvrFactor *= 2;
148 3 : levels.push_back(nOvrFactor);
149 : }
150 : }
151 :
152 14 : return levels.empty() ||
153 7 : GDALBuildOverviews(GDALDataset::ToHandle(poDS), resampling.c_str(),
154 7 : static_cast<int>(levels.size()), levels.data(), 0,
155 14 : nullptr, pfnProgress, pProgressData) == CE_None;
156 : }
157 :
158 : //! @endcond
|