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