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