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