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