LCOV - code coverage report
Current view: top level - apps - gdal_create.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 180 255 70.6 %
Date: 2024-05-03 15:49:35 Functions: 2 3 66.7 %

          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

Generated by: LCOV version 1.14