Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Utilities
4 : * Purpose: GDAL Raster creation utility
5 : * Author: Even Rouault <even dot rouault at spatialys.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2020, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "cpl_string.h"
30 : #include "gdal_version.h"
31 : #include "gdal_priv.h"
32 : #include "gdal.h"
33 : #include "commonutils.h"
34 : #include "ogr_spatialref.h"
35 :
36 : #include <cstdlib>
37 : #include <memory>
38 : #include <vector>
39 :
40 0 : static void Usage(bool bIsError)
41 :
42 : {
43 0 : fprintf(
44 : bIsError ? stderr : stdout,
45 : "Usage: gdal_create [--help] [--help-general]\n"
46 : " [-of <format>]\n"
47 : " [-outsize <xsize> <ysize>]\n"
48 : " [-bands <count>]\n"
49 : " [-burn <value>]...\n"
50 : " [-ot "
51 : "{Byte/Int8/Int16/UInt16/UInt32/Int32/UInt64/Int64/Float32/Float64/\n"
52 : " CInt16/CInt32/CFloat32/CFloat64}] [-strict]\n"
53 : " [-a_srs <srs_def>] [-a_ullr <ulx> <uly> <lrx> <lry>] "
54 : "[-a_nodata <value>]\n"
55 : " [-mo <META-TAG>=<VALUE>]... [-q]\n"
56 : " [-co <NAME>=<VALUE>]...\n"
57 : " [-if <input_dataset>]\n"
58 : " <out_dataset>\n");
59 :
60 0 : exit(bIsError ? 1 : 0);
61 : }
62 :
63 : /************************************************************************/
64 : /* ArgIsNumericCreate() */
65 : /************************************************************************/
66 :
67 3 : static bool ArgIsNumericCreate(const char *pszArg)
68 :
69 : {
70 3 : char *pszEnd = nullptr;
71 3 : CPLStrtod(pszArg, &pszEnd);
72 3 : return pszEnd != nullptr && pszEnd[0] == '\0';
73 : }
74 :
75 : /************************************************************************/
76 : /* main() */
77 : /************************************************************************/
78 :
79 9 : MAIN_START(argc, argv)
80 :
81 : {
82 : /* Check strict compilation and runtime library version as we use C++ API */
83 9 : if (!GDAL_CHECK_VERSION(argv[0]))
84 0 : exit(1);
85 :
86 9 : EarlySetConfigOptions(argc, argv);
87 :
88 : /* -------------------------------------------------------------------- */
89 : /* Register standard GDAL drivers, and process generic GDAL */
90 : /* command options. */
91 : /* -------------------------------------------------------------------- */
92 9 : GDALAllRegister();
93 9 : argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
94 9 : if (argc < 1)
95 0 : exit(-argc);
96 :
97 9 : const char *pszFormat = nullptr;
98 9 : const char *pszFilename = nullptr;
99 16 : CPLStringList aosCreateOptions;
100 9 : int nPixels = 0;
101 9 : int nLines = 0;
102 9 : int nBandCount = -1;
103 9 : GDALDataType eDT = GDT_Unknown;
104 9 : double dfULX = 0;
105 9 : double dfULY = 0;
106 9 : double dfLRX = 0;
107 9 : double dfLRY = 0;
108 9 : bool bGeoTransform = false;
109 9 : const char *pszOutputSRS = nullptr;
110 16 : CPLStringList aosMetadata;
111 16 : std::vector<double> adfBurnValues;
112 9 : bool bQuiet = false;
113 9 : int bSetNoData = false;
114 16 : std::string osNoData;
115 9 : const char *pszInputFile = nullptr;
116 38 : for (int i = 1; argv != nullptr && argv[i] != nullptr; i++)
117 : {
118 30 : if (EQUAL(argv[i], "--utility_version"))
119 : {
120 1 : printf("%s was compiled against GDAL %s and is running against "
121 : "GDAL %s\n",
122 : argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
123 1 : CSLDestroy(argv);
124 1 : return 0;
125 : }
126 29 : else if (EQUAL(argv[i], "--help"))
127 : {
128 0 : Usage(false);
129 : }
130 29 : else if (i < argc - 1 &&
131 29 : (EQUAL(argv[i], "-of") || EQUAL(argv[i], "-f")))
132 : {
133 2 : ++i;
134 2 : pszFormat = argv[i];
135 : }
136 27 : else if (i < argc - 1 && EQUAL(argv[i], "-co"))
137 : {
138 2 : ++i;
139 2 : aosCreateOptions.AddString(argv[i]);
140 : }
141 25 : else if (i < argc - 1 && EQUAL(argv[i], "-mo"))
142 : {
143 1 : ++i;
144 1 : aosMetadata.AddString(argv[i]);
145 : }
146 24 : else if (i < argc - 1 && EQUAL(argv[i], "-bands"))
147 : {
148 2 : ++i;
149 2 : nBandCount = atoi(argv[i]);
150 : }
151 22 : else if (i + 2 < argc && EQUAL(argv[i], "-outsize"))
152 : {
153 4 : ++i;
154 4 : nPixels = atoi(argv[i]);
155 4 : ++i;
156 4 : nLines = atoi(argv[i]);
157 : }
158 18 : else if (i < argc - 1 && EQUAL(argv[i], "-ot"))
159 : {
160 1 : ++i;
161 15 : for (int iType = 1; iType < GDT_TypeCount; iType++)
162 : {
163 14 : if (GDALGetDataTypeName(static_cast<GDALDataType>(iType)) !=
164 28 : nullptr &&
165 14 : EQUAL(GDALGetDataTypeName(static_cast<GDALDataType>(iType)),
166 : argv[i]))
167 : {
168 1 : eDT = static_cast<GDALDataType>(iType);
169 : }
170 : }
171 :
172 1 : if (eDT == GDT_Unknown)
173 : {
174 0 : CPLError(CE_Failure, CPLE_NotSupported,
175 0 : "Unknown output pixel type: %s.", argv[i]);
176 0 : CSLDestroy(argv);
177 0 : exit(1);
178 1 : }
179 : }
180 17 : else if (i + 4 < argc && EQUAL(argv[i], "-a_ullr"))
181 : {
182 1 : bGeoTransform = true;
183 : // coverity[tainted_data]
184 1 : dfULX = CPLAtofM(argv[++i]);
185 : // coverity[tainted_data]
186 1 : dfULY = CPLAtofM(argv[++i]);
187 : // coverity[tainted_data]
188 1 : dfLRX = CPLAtofM(argv[++i]);
189 : // coverity[tainted_data]
190 1 : dfLRY = CPLAtofM(argv[++i]);
191 : }
192 16 : else if (i < argc - 1 && EQUAL(argv[i], "-a_srs"))
193 : {
194 1 : ++i;
195 1 : pszOutputSRS = argv[i];
196 : }
197 15 : else if (i < argc - 1 && EQUAL(argv[i], "-a_nodata"))
198 : {
199 2 : bSetNoData = true;
200 2 : ++i;
201 : // coverity[tainted_data]
202 2 : osNoData = argv[i];
203 : }
204 :
205 13 : else if (i < argc - 1 && EQUAL(argv[i], "-burn"))
206 : {
207 1 : if (strchr(argv[i + 1], ' '))
208 : {
209 0 : ++i;
210 0 : CPLStringList aosTokens(CSLTokenizeString(argv[i]));
211 0 : for (int j = 0; j < aosTokens.size(); j++)
212 : {
213 0 : adfBurnValues.push_back(CPLAtof(aosTokens[j]));
214 : }
215 : }
216 : else
217 : {
218 : // coverity[tainted_data]
219 3 : while (i < argc - 1 && ArgIsNumericCreate(argv[i + 1]))
220 : {
221 2 : ++i;
222 : // coverity[tainted_data]
223 2 : adfBurnValues.push_back(CPLAtof(argv[i]));
224 : }
225 1 : }
226 : }
227 12 : else if (i < argc - 1 && EQUAL(argv[i], "-if"))
228 : {
229 4 : ++i;
230 4 : pszInputFile = argv[i];
231 : }
232 8 : else if (EQUAL(argv[i], "-q"))
233 : {
234 0 : bQuiet = true;
235 : }
236 8 : else if (argv[i][0] == '-')
237 : {
238 0 : CPLError(CE_Failure, CPLE_NotSupported, "Unknown option name '%s'",
239 0 : argv[i]);
240 0 : CSLDestroy(argv);
241 0 : Usage(true);
242 : }
243 8 : else if (pszFilename == nullptr)
244 : {
245 8 : pszFilename = argv[i];
246 : }
247 : else
248 : {
249 0 : CPLError(CE_Failure, CPLE_NotSupported,
250 0 : "Too many command options '%s'", argv[i]);
251 0 : CSLDestroy(argv);
252 0 : Usage(true);
253 : }
254 : }
255 8 : if (pszFilename == nullptr)
256 : {
257 0 : CSLDestroy(argv);
258 0 : Usage(true);
259 : }
260 :
261 8 : double adfGeoTransform[6] = {0, 1, 0, 0, 0, 1};
262 8 : if (bGeoTransform && nPixels > 0 && nLines > 0)
263 : {
264 1 : adfGeoTransform[0] = dfULX;
265 1 : adfGeoTransform[1] = (dfLRX - dfULX) / nPixels;
266 1 : adfGeoTransform[2] = 0;
267 1 : adfGeoTransform[3] = dfULY;
268 1 : adfGeoTransform[4] = 0;
269 1 : adfGeoTransform[5] = (dfLRY - dfULY) / nLines;
270 : }
271 :
272 0 : std::unique_ptr<GDALDataset> poInputDS;
273 8 : if (pszInputFile)
274 : {
275 4 : poInputDS.reset(GDALDataset::Open(
276 : pszInputFile, GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR));
277 4 : if (poInputDS == nullptr)
278 : {
279 1 : CSLDestroy(argv);
280 1 : GDALDestroyDriverManager();
281 1 : exit(1);
282 : }
283 3 : if (nPixels == 0)
284 : {
285 2 : nPixels = poInputDS->GetRasterXSize();
286 2 : nLines = poInputDS->GetRasterYSize();
287 : }
288 3 : if (nBandCount < 0)
289 : {
290 2 : nBandCount = poInputDS->GetRasterCount();
291 : }
292 3 : if (eDT == GDT_Unknown && poInputDS->GetRasterCount() > 0)
293 : {
294 3 : eDT = poInputDS->GetRasterBand(1)->GetRasterDataType();
295 : }
296 3 : if (pszOutputSRS == nullptr)
297 : {
298 3 : pszOutputSRS = poInputDS->GetProjectionRef();
299 : }
300 3 : if (!(bGeoTransform && nPixels > 0 && nLines > 0))
301 : {
302 3 : if (poInputDS->GetGeoTransform(adfGeoTransform) == CE_None)
303 : {
304 2 : bGeoTransform = true;
305 : }
306 : }
307 3 : if (!bSetNoData && poInputDS->GetRasterCount() > 0)
308 : {
309 2 : if (eDT == GDT_Int64)
310 : {
311 : const auto nNoDataValue =
312 0 : poInputDS->GetRasterBand(1)->GetNoDataValueAsInt64(
313 0 : &bSetNoData);
314 0 : if (bSetNoData)
315 : osNoData = CPLSPrintf(CPL_FRMT_GIB,
316 0 : static_cast<GIntBig>(nNoDataValue));
317 : }
318 2 : else if (eDT == GDT_UInt64)
319 : {
320 : const auto nNoDataValue =
321 0 : poInputDS->GetRasterBand(1)->GetNoDataValueAsUInt64(
322 0 : &bSetNoData);
323 0 : if (bSetNoData)
324 : osNoData = CPLSPrintf(CPL_FRMT_GUIB,
325 0 : static_cast<GUIntBig>(nNoDataValue));
326 : }
327 : else
328 : {
329 : const double dfNoDataValue =
330 2 : poInputDS->GetRasterBand(1)->GetNoDataValue(&bSetNoData);
331 2 : if (bSetNoData)
332 0 : osNoData = CPLSPrintf("%.18g", dfNoDataValue);
333 : }
334 : }
335 : }
336 :
337 12 : GDALDriverH hDriver = GDALGetDriverByName(
338 12 : pszFormat ? pszFormat : GetOutputDriverForRaster(pszFilename).c_str());
339 7 : if (hDriver == nullptr)
340 : {
341 0 : fprintf(stderr, "Output driver not found.\n");
342 0 : CSLDestroy(argv);
343 0 : GDALDestroyDriverManager();
344 0 : exit(1);
345 : }
346 : const bool bHasCreate =
347 7 : GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE, nullptr) != nullptr;
348 9 : if (!bHasCreate &&
349 2 : GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATECOPY, nullptr) == nullptr)
350 : {
351 1 : fprintf(stderr, "This driver has no creation capabilities.\n");
352 1 : CSLDestroy(argv);
353 1 : GDALDestroyDriverManager();
354 1 : exit(1);
355 : }
356 6 : GDALDriverH hTmpDriver = GDALGetDriverByName("MEM");
357 6 : if (!bHasCreate && hTmpDriver == nullptr)
358 : {
359 0 : fprintf(stderr, "MEM driver not available.\n");
360 0 : CSLDestroy(argv);
361 0 : GDALDestroyDriverManager();
362 0 : exit(1);
363 : }
364 :
365 6 : if (nPixels != 0 && eDT == GDT_Unknown)
366 : {
367 1 : eDT = GDT_Byte;
368 : }
369 6 : if (nBandCount < 0)
370 : {
371 2 : nBandCount = eDT == GDT_Unknown ? 0 : 1;
372 : }
373 11 : GDALDatasetH hDS = GDALCreate(
374 : bHasCreate ? hDriver : hTmpDriver, pszFilename, nPixels, nLines,
375 5 : nBandCount, eDT, bHasCreate ? aosCreateOptions.List() : nullptr);
376 :
377 6 : if (hDS == nullptr)
378 : {
379 0 : GDALDestroyDriverManager();
380 0 : CSLDestroy(argv);
381 0 : exit(1);
382 : }
383 :
384 6 : if (pszOutputSRS && pszOutputSRS[0] != '\0' && !EQUAL(pszOutputSRS, "NONE"))
385 : {
386 6 : OGRSpatialReference oSRS;
387 3 : oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
388 :
389 3 : if (oSRS.SetFromUserInput(pszOutputSRS) != OGRERR_NONE)
390 : {
391 0 : CPLError(CE_Failure, CPLE_AppDefined,
392 : "Failed to process SRS definition: %s", pszOutputSRS);
393 0 : CSLDestroy(argv);
394 0 : GDALDestroyDriverManager();
395 0 : exit(1);
396 : }
397 :
398 3 : char *pszSRS = nullptr;
399 3 : oSRS.exportToWkt(&pszSRS);
400 :
401 3 : if (GDALSetProjection(hDS, pszSRS) != CE_None)
402 : {
403 0 : CPLFree(pszSRS);
404 0 : GDALClose(hDS);
405 0 : CSLDestroy(argv);
406 0 : GDALDestroyDriverManager();
407 0 : exit(1);
408 : }
409 3 : CPLFree(pszSRS);
410 : }
411 6 : if (bGeoTransform)
412 : {
413 3 : if (nPixels == 0)
414 : {
415 0 : fprintf(stderr,
416 : "-outsize must be specified when -a_ullr is used.\n");
417 0 : GDALClose(hDS);
418 0 : GDALDestroyDriverManager();
419 0 : exit(1);
420 : }
421 3 : if (GDALSetGeoTransform(hDS, adfGeoTransform) != CE_None)
422 : {
423 0 : GDALClose(hDS);
424 0 : CSLDestroy(argv);
425 0 : GDALDestroyDriverManager();
426 0 : exit(1);
427 : }
428 : }
429 3 : else if (poInputDS && poInputDS->GetGCPCount() > 0)
430 : {
431 2 : GDALDataset::FromHandle(hDS)->SetGCPs(poInputDS->GetGCPCount(),
432 1 : poInputDS->GetGCPs(),
433 1 : poInputDS->GetGCPSpatialRef());
434 : }
435 :
436 6 : if (!aosMetadata.empty())
437 : {
438 1 : GDALSetMetadata(hDS, aosMetadata.List(), nullptr);
439 : }
440 6 : const int nBands = GDALGetRasterCount(hDS);
441 6 : if (bSetNoData)
442 : {
443 7 : for (int i = 0; i < nBands; i++)
444 : {
445 5 : auto hBand = GDALGetRasterBand(hDS, i + 1);
446 5 : if (eDT == GDT_Int64)
447 : {
448 0 : GDALSetRasterNoDataValueAsInt64(
449 : hBand, static_cast<int64_t>(
450 0 : std::strtoll(osNoData.c_str(), nullptr, 10)));
451 : }
452 5 : else if (eDT == GDT_UInt64)
453 : {
454 0 : GDALSetRasterNoDataValueAsUInt64(
455 : hBand, static_cast<uint64_t>(
456 0 : std::strtoull(osNoData.c_str(), nullptr, 10)));
457 : }
458 : else
459 : {
460 5 : GDALSetRasterNoDataValue(hBand, CPLAtofM(osNoData.c_str()));
461 : }
462 : }
463 : }
464 6 : if (!adfBurnValues.empty())
465 : {
466 4 : for (int i = 0; i < nBands; i++)
467 : {
468 3 : GDALFillRaster(GDALGetRasterBand(hDS, i + 1),
469 3 : i < static_cast<int>(adfBurnValues.size())
470 2 : ? adfBurnValues[i]
471 1 : : adfBurnValues.back(),
472 : 0);
473 : }
474 : }
475 :
476 6 : bool bHasGotErr = false;
477 6 : if (!bHasCreate)
478 : {
479 2 : GDALDatasetH hOutDS = GDALCreateCopy(
480 1 : hDriver, pszFilename, hDS, false, aosCreateOptions.List(),
481 : bQuiet ? GDALDummyProgress : GDALTermProgress, nullptr);
482 1 : if (hOutDS == nullptr)
483 : {
484 0 : GDALClose(hDS);
485 0 : CSLDestroy(argv);
486 0 : GDALDestroyDriverManager();
487 0 : exit(1);
488 : }
489 1 : if (GDALClose(hOutDS) != CE_None)
490 : {
491 0 : bHasGotErr = true;
492 : }
493 : }
494 :
495 6 : const bool bWasFailureBefore = (CPLGetLastErrorType() == CE_Failure);
496 6 : if (GDALClose(hDS) != CE_None)
497 0 : bHasGotErr = true;
498 6 : if (!bWasFailureBefore && CPLGetLastErrorType() == CE_Failure)
499 : {
500 0 : bHasGotErr = true;
501 : }
502 :
503 6 : CSLDestroy(argv);
504 6 : return bHasGotErr ? 1 : 0;
505 : }
506 :
507 0 : MAIN_END
|