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