Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: gdal "raster info" subcommand
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_info.h"
14 :
15 : #include "cpl_conv.h"
16 : #include "gdal_priv.h"
17 : #include "gdal_utils.h"
18 :
19 : //! @cond Doxygen_Suppress
20 :
21 : #ifndef _
22 : #define _(x) (x)
23 : #endif
24 :
25 : /************************************************************************/
26 : /* GDALRasterInfoAlgorithm::GDALRasterInfoAlgorithm() */
27 : /************************************************************************/
28 :
29 239 : GDALRasterInfoAlgorithm::GDALRasterInfoAlgorithm(bool standaloneStep,
30 239 : bool openForMixedRasterVector)
31 : : GDALRasterPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
32 0 : ConstructorOptions()
33 239 : .SetStandaloneStep(standaloneStep)
34 239 : .SetInputDatasetMaxCount(1)
35 239 : .SetAddDefaultArguments(false)
36 478 : .SetInputDatasetAlias("dataset"))
37 : {
38 239 : if (standaloneStep)
39 : {
40 163 : AddRasterInputArgs(openForMixedRasterVector,
41 : /* hiddenForCLI = */ false);
42 : }
43 : else
44 : {
45 76 : AddRasterHiddenInputDatasetArg();
46 : }
47 :
48 239 : AddOutputFormatArg(&m_format).SetChoices("json", "text");
49 478 : AddArg("min-max", 0, _("Compute minimum and maximum value"), &m_minMax)
50 239 : .AddAlias("mm");
51 : AddArg("stats", 0, _("Retrieve or compute statistics, using all pixels"),
52 478 : &m_stats)
53 239 : .SetMutualExclusionGroup("stats");
54 : AddArg("approx-stats", 0,
55 : _("Retrieve or compute statistics, using a subset of pixels"),
56 478 : &m_approxStats)
57 239 : .SetMutualExclusionGroup("stats");
58 239 : AddArg("hist", 0, _("Retrieve or compute histogram"), &m_hist);
59 :
60 : AddArg("no-gcp", 0, _("Suppress ground control points list printing"),
61 478 : &m_noGCP)
62 239 : .SetCategory(GAAC_ADVANCED);
63 478 : AddArg("no-md", 0, _("Suppress metadata printing"), &m_noMD)
64 239 : .SetCategory(GAAC_ADVANCED);
65 478 : AddArg("no-ct", 0, _("Suppress color table printing"), &m_noCT)
66 239 : .SetCategory(GAAC_ADVANCED);
67 478 : AddArg("no-fl", 0, _("Suppress file list printing"), &m_noFL)
68 239 : .SetCategory(GAAC_ADVANCED);
69 478 : AddArg("checksum", 0, _("Compute pixel checksum"), &m_checksum)
70 239 : .SetCategory(GAAC_ADVANCED);
71 : AddArg("list-mdd", 0,
72 478 : _("List all metadata domains available for the dataset"), &m_listMDD)
73 478 : .AddAlias("list-metadata-domains")
74 239 : .SetCategory(GAAC_ADVANCED);
75 : AddArg("metadata-domain", 0,
76 : _("Report metadata for the specified domain. 'all' can be used to "
77 : "report metadata in all domains"),
78 478 : &m_mdd)
79 478 : .AddAlias("mdd")
80 239 : .SetCategory(GAAC_ADVANCED);
81 :
82 478 : AddArg("no-nodata", 0, _("Suppress retrieving nodata value"), &m_noNodata)
83 239 : .SetCategory(GAAC_ESOTERIC);
84 478 : AddArg("no-mask", 0, _("Suppress mask band information"), &m_noMask)
85 239 : .SetCategory(GAAC_ESOTERIC);
86 : AddArg("subdataset", 0,
87 : _("Use subdataset of specified index (starting at 1), instead of "
88 : "the source dataset itself"),
89 478 : &m_subDS)
90 478 : .SetCategory(GAAC_ESOTERIC)
91 239 : .SetMinValueIncluded(1);
92 : AddArg("crs-format", 0, _("Which format to use to report CRS"),
93 478 : &m_crsFormat)
94 239 : .SetChoices("AUTO", "WKT2", "PROJJSON")
95 239 : .SetDefault(m_crsFormat)
96 239 : .SetCategory(GAAC_ESOTERIC);
97 :
98 239 : AddOutputStringArg(&m_output);
99 239 : AddStdoutArg(&m_stdout);
100 :
101 239 : AddValidationAction(
102 75 : [this]()
103 : {
104 75 : if (m_crsFormat != "AUTO" && m_format == "json")
105 : {
106 0 : ReportError(CE_Failure, CPLE_AppDefined,
107 : "'crs-format' cannot be set when 'format' is set "
108 : "to 'json'");
109 0 : return false;
110 : }
111 75 : return true;
112 : });
113 239 : }
114 :
115 : /************************************************************************/
116 : /* GDALRasterInfoAlgorithm::RunStep() */
117 : /************************************************************************/
118 :
119 34 : bool GDALRasterInfoAlgorithm::RunStep(GDALPipelineStepRunContext &)
120 : {
121 34 : CPLAssert(m_inputDataset.size() == 1);
122 34 : auto poSrcDS = m_inputDataset[0].GetDatasetRef();
123 34 : CPLAssert(poSrcDS);
124 :
125 34 : if (m_format.empty())
126 28 : m_format = IsCalledFromCommandLine() ? "text" : "json";
127 :
128 68 : CPLStringList aosOptions;
129 34 : aosOptions.AddString("--invoked-from=gdal-raster-info");
130 34 : aosOptions.AddString("--crs-format=" + m_crsFormat);
131 34 : if (m_format == "json")
132 24 : aosOptions.AddString("-json");
133 34 : if (m_minMax)
134 1 : aosOptions.AddString("-mm");
135 34 : if (m_stats)
136 2 : aosOptions.AddString("-stats");
137 34 : if (m_approxStats)
138 1 : aosOptions.AddString("-approx_stats");
139 34 : if (m_hist)
140 1 : aosOptions.AddString("-hist");
141 34 : if (m_noGCP)
142 1 : aosOptions.AddString("-nogcp");
143 34 : if (m_noMD)
144 1 : aosOptions.AddString("-nomd");
145 34 : if (m_noCT)
146 1 : aosOptions.AddString("-noct");
147 34 : if (m_noFL)
148 1 : aosOptions.AddString("-nofl");
149 34 : if (m_noMask)
150 1 : aosOptions.AddString("-nomask");
151 34 : if (m_noNodata)
152 1 : aosOptions.AddString("-nonodata");
153 34 : if (m_checksum)
154 2 : aosOptions.AddString("-checksum");
155 34 : if (m_listMDD)
156 1 : aosOptions.AddString("-listmdd");
157 34 : if (!m_mdd.empty())
158 : {
159 1 : aosOptions.AddString("-mdd");
160 1 : aosOptions.AddString(m_mdd.c_str());
161 : }
162 :
163 34 : GDALDatasetH hDS = GDALDataset::ToHandle(poSrcDS);
164 34 : std::unique_ptr<GDALDataset> poSubDataset;
165 :
166 34 : if (m_subDS > 0)
167 : {
168 : CSLConstList papszSubdatasets =
169 3 : GDALGetMetadata(hDS, GDAL_MDD_SUBDATASETS);
170 3 : const int nSubdatasets = CSLCount(papszSubdatasets) / 2;
171 3 : if (m_subDS > nSubdatasets)
172 : {
173 1 : CPLError(CE_Failure, CPLE_AppDefined,
174 : "Invalid value for 'subdataset' argument. Should be "
175 : "between 1 and %d",
176 : nSubdatasets);
177 2 : return false;
178 : }
179 :
180 : char szKeyName[64];
181 2 : snprintf(szKeyName, sizeof(szKeyName), "SUBDATASET_%d_NAME", m_subDS);
182 : const std::string osSubDSName =
183 2 : CSLFetchNameValueDef(papszSubdatasets, szKeyName, "");
184 :
185 2 : poSubDataset.reset(GDALDataset::Open(
186 : osSubDSName.c_str(), GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR,
187 : nullptr, nullptr, nullptr));
188 2 : if (!poSubDataset)
189 1 : return false;
190 1 : hDS = GDALDataset::ToHandle(poSubDataset.get());
191 : }
192 :
193 32 : if (m_stdout)
194 : {
195 7 : aosOptions.AddString("-stdout");
196 : }
197 :
198 32 : GDALInfoOptions *psOptions = GDALInfoOptionsNew(aosOptions.List(), nullptr);
199 32 : char *ret = GDALInfo(hDS, psOptions);
200 32 : GDALInfoOptionsFree(psOptions);
201 32 : const bool bOK = ret != nullptr;
202 32 : if (ret)
203 : {
204 32 : m_output = ret;
205 : }
206 32 : CPLFree(ret);
207 :
208 32 : return bOK;
209 : }
210 :
211 : GDALRasterInfoAlgorithmStandalone::~GDALRasterInfoAlgorithmStandalone() =
212 : default;
213 :
214 : //! @endcond
|