Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: "edit" step of "raster pipeline"
5 : * Author: Even Rouault <even dot rouault at spatialys.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "gdalalg_raster_edit.h"
14 :
15 : #include "gdal_priv.h"
16 : #include "gdal_utils.h"
17 :
18 : //! @cond Doxygen_Suppress
19 :
20 : #ifndef _
21 : #define _(x) (x)
22 : #endif
23 :
24 : /************************************************************************/
25 : /* GDALRasterEditAlgorithm::GDALRasterEditAlgorithm() */
26 : /************************************************************************/
27 :
28 26 : GDALRasterEditAlgorithm::GDALRasterEditAlgorithm(bool standaloneStep)
29 : : GDALRasterPipelineStepAlgorithm(
30 : NAME, DESCRIPTION, HELP_URL,
31 : // Avoid automatic addition of input/output arguments
32 26 : /*standaloneStep = */ false)
33 : {
34 26 : if (standaloneStep)
35 : {
36 : AddArg("dataset", 0, _("Dataset (in-place updated)"), &m_dataset,
37 30 : GDAL_OF_RASTER | GDAL_OF_UPDATE)
38 15 : .SetPositional()
39 15 : .SetRequired();
40 15 : m_standaloneStep = true;
41 : }
42 :
43 52 : AddArg("crs", 0, _("Override CRS (without reprojection)"), &m_overrideCrs)
44 52 : .AddHiddenAlias("a_srs")
45 26 : .SetIsCRSArg(/*noneAllowed=*/true);
46 :
47 26 : AddBBOXArg(&m_bbox);
48 :
49 : {
50 : auto &arg = AddArg("metadata", 0, _("Add/update dataset metadata item"),
51 52 : &m_metadata)
52 26 : .SetMetaVar("<KEY>=<VALUE>");
53 3 : arg.AddValidationAction([this, &arg]()
54 29 : { return ValidateKeyValue(arg); });
55 26 : arg.AddHiddenAlias("mo");
56 : }
57 :
58 : AddArg("unset-metadata", 0, _("Remove dataset metadata item"),
59 52 : &m_unsetMetadata)
60 26 : .SetMetaVar("<KEY>");
61 26 : }
62 :
63 : /************************************************************************/
64 : /* GDALRasterEditAlgorithm::RunImpl() */
65 : /************************************************************************/
66 :
67 17 : bool GDALRasterEditAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
68 : void *pProgressData)
69 : {
70 17 : if (m_standaloneStep)
71 : {
72 12 : auto poDS = m_dataset.GetDatasetRef();
73 12 : CPLAssert(poDS);
74 12 : if (poDS->GetAccess() != GA_Update)
75 : {
76 1 : ReportError(CE_Failure, CPLE_AppDefined,
77 : "Dataset should be opened in update mode");
78 1 : return false;
79 : }
80 :
81 11 : if (m_overrideCrs == "null" || m_overrideCrs == "none")
82 : {
83 2 : if (poDS->SetSpatialRef(nullptr) != CE_None)
84 : {
85 1 : ReportError(CE_Failure, CPLE_AppDefined,
86 : "SetSpatialRef(%s) failed", m_overrideCrs.c_str());
87 1 : return false;
88 : }
89 : }
90 9 : else if (!m_overrideCrs.empty())
91 : {
92 2 : OGRSpatialReference oSRS;
93 2 : oSRS.SetFromUserInput(m_overrideCrs.c_str());
94 2 : oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
95 2 : if (poDS->SetSpatialRef(&oSRS) != CE_None)
96 : {
97 1 : ReportError(CE_Failure, CPLE_AppDefined,
98 : "SetSpatialRef(%s) failed", m_overrideCrs.c_str());
99 1 : return false;
100 : }
101 : }
102 :
103 9 : if (!m_bbox.empty())
104 : {
105 3 : if (poDS->GetRasterXSize() == 0 || poDS->GetRasterYSize() == 0)
106 : {
107 1 : ReportError(
108 : CE_Failure, CPLE_AppDefined,
109 : "Cannot set extent because dataset has 0x0 dimension");
110 2 : return false;
111 : }
112 : double adfGT[6];
113 2 : adfGT[0] = m_bbox[0];
114 2 : adfGT[1] = (m_bbox[2] - m_bbox[0]) / poDS->GetRasterXSize();
115 2 : adfGT[2] = 0;
116 2 : adfGT[3] = m_bbox[3];
117 2 : adfGT[4] = 0;
118 2 : adfGT[5] = -(m_bbox[3] - m_bbox[1]) / poDS->GetRasterYSize();
119 2 : if (poDS->SetGeoTransform(adfGT) != CE_None)
120 : {
121 1 : ReportError(CE_Failure, CPLE_AppDefined,
122 : "Setting extent failed");
123 1 : return false;
124 : }
125 : }
126 :
127 14 : const CPLStringList aosMD(m_metadata);
128 9 : for (const auto &[key, value] : cpl::IterateNameValue(aosMD))
129 : {
130 3 : if (poDS->SetMetadataItem(key, value) != CE_None)
131 : {
132 1 : ReportError(CE_Failure, CPLE_AppDefined,
133 : "SetMetadataItem('%s', '%s') failed", key, value);
134 1 : return false;
135 : }
136 : }
137 :
138 7 : for (const std::string &key : m_unsetMetadata)
139 : {
140 2 : if (poDS->SetMetadataItem(key.c_str(), nullptr) != CE_None)
141 : {
142 1 : ReportError(CE_Failure, CPLE_AppDefined,
143 : "SetMetadataItem('%s', NULL) failed", key.c_str());
144 1 : return false;
145 : }
146 : }
147 :
148 5 : return true;
149 : }
150 : else
151 : {
152 5 : return RunStep(pfnProgress, pProgressData);
153 : }
154 : }
155 :
156 : /************************************************************************/
157 : /* GDALRasterEditAlgorithm::RunStep() */
158 : /************************************************************************/
159 :
160 5 : bool GDALRasterEditAlgorithm::RunStep(GDALProgressFunc, void *)
161 : {
162 5 : CPLAssert(m_inputDataset.GetDatasetRef());
163 5 : CPLAssert(m_outputDataset.GetName().empty());
164 5 : CPLAssert(!m_outputDataset.GetDatasetRef());
165 :
166 5 : CPLStringList aosOptions;
167 5 : aosOptions.AddString("-of");
168 5 : aosOptions.AddString("VRT");
169 5 : if (!m_overrideCrs.empty())
170 : {
171 2 : aosOptions.AddString("-a_srs");
172 2 : aosOptions.AddString(m_overrideCrs.c_str());
173 : }
174 5 : if (!m_bbox.empty())
175 : {
176 1 : aosOptions.AddString("-a_ullr");
177 1 : aosOptions.AddString(CPLSPrintf("%.17g", m_bbox[0])); // upper-left X
178 1 : aosOptions.AddString(CPLSPrintf("%.17g", m_bbox[3])); // upper-left Y
179 1 : aosOptions.AddString(CPLSPrintf("%.17g", m_bbox[2])); // lower-right X
180 1 : aosOptions.AddString(CPLSPrintf("%.17g", m_bbox[1])); // lower-right Y
181 : }
182 :
183 7 : for (const auto &val : m_metadata)
184 : {
185 2 : aosOptions.AddString("-mo");
186 2 : aosOptions.AddString(val.c_str());
187 : }
188 :
189 6 : for (const std::string &key : m_unsetMetadata)
190 : {
191 1 : aosOptions.AddString("-mo");
192 1 : aosOptions.AddString((key + "=").c_str());
193 : }
194 :
195 : GDALTranslateOptions *psOptions =
196 5 : GDALTranslateOptionsNew(aosOptions.List(), nullptr);
197 :
198 5 : GDALDatasetH hSrcDS = GDALDataset::ToHandle(m_inputDataset.GetDatasetRef());
199 : auto poRetDS =
200 5 : GDALDataset::FromHandle(GDALTranslate("", hSrcDS, psOptions, nullptr));
201 5 : GDALTranslateOptionsFree(psOptions);
202 5 : const bool ok = poRetDS != nullptr;
203 5 : if (ok)
204 5 : m_outputDataset.Set(std::unique_ptr<GDALDataset>(poRetDS));
205 :
206 10 : return ok;
207 : }
208 :
209 : //! @endcond
|