Skip to content

Commit c9a0dca

Browse files
authored
Merge pull request OSGeo#12133 from rouault/gdal_raster_create
Add 'gdal raster create' (port of gdal_create)
2 parents 89b8e9c + 2e4a728 commit c9a0dca

36 files changed

+1568
-255
lines changed

.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update,
132132
JPEGXL -raster- (rwv): JPEG-XL (*.jxl)
133133
GDALG -raster,vector- (rov): GDAL Streamed Algorithm driver (*.gdalg.json)
134134
GPKG -raster,vector- (rw+uvs): GeoPackage (*.gpkg, *.gpkg.zip)
135-
SQLite -raster,vector- (rw+uv): SQLite / Spatialite / RasterLite2 (*.sqlite, *.db)
135+
SQLite -raster,vector- (rw+uvs): SQLite / Spatialite / RasterLite2 (*.sqlite, *.db)
136136
OpenFileGDB -raster,vector- (rw+uv): ESRI FileGeodatabase (using OpenFileGDB) (*.gdb)
137137
CAD -raster,vector- (rovs): AutoCAD Driver (*.dwg)
138138
PLSCENES -raster,vector- (ro): Planet Labs Scenes API

.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update,
3232
Interlis 2 -vector- (rov): Interlis 2 (*.xtf, *.xml, *.ili)
3333
OGR_GMT -vector- (rw+v): GMT ASCII Vectors (.gmt) (*.gmt)
3434
GPKG -raster,vector- (rw+uvs): GeoPackage (*.gpkg, *.gpkg.zip)
35-
SQLite -raster,vector- (rw+uv): SQLite / Spatialite / RasterLite2 (*.sqlite, *.db)
35+
SQLite -raster,vector- (rw+uvs): SQLite / Spatialite / RasterLite2 (*.sqlite, *.db)
3636
ODBC -vector- (ro): Open Database Connectivity (ODBC) (*.mdb, *.accdb)
3737
WAsP -vector- (rw+v): WAsP .map format (*.map)
3838
PGeo -vector- (ro): ESRI Personal GeoDatabase (*.mdb)

apps/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ add_library(
2121
gdalalg_raster_clip.cpp
2222
gdalalg_raster_color_map.cpp
2323
gdalalg_raster_convert.cpp
24+
gdalalg_raster_create.cpp
2425
gdalalg_raster_edit.cpp
2526
gdalalg_raster_contour.cpp
2627
gdalalg_raster_hillshade.cpp

apps/gdal_translate_lib.cpp

Lines changed: 55 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -586,71 +586,6 @@ EditISIS3MetadataForBandChange(const char *pszJSON, int nSrcBandCount,
586586
return oRoot.Format(CPLJSONObject::PrettyFormat::Pretty);
587587
}
588588

589-
/************************************************************************/
590-
/* AdjustNoDataValue() */
591-
/************************************************************************/
592-
593-
static double AdjustNoDataValue(double dfInputNoDataValue,
594-
GDALRasterBand *poBand,
595-
const GDALTranslateOptions *psOptions)
596-
{
597-
bool bSignedByte = false;
598-
const char *pszPixelType =
599-
psOptions->aosCreateOptions.FetchNameValue("PIXELTYPE");
600-
if (pszPixelType == nullptr && poBand->GetRasterDataType() == GDT_Byte)
601-
{
602-
poBand->EnablePixelTypeSignedByteWarning(false);
603-
pszPixelType = poBand->GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
604-
poBand->EnablePixelTypeSignedByteWarning(true);
605-
}
606-
if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
607-
bSignedByte = true;
608-
int bClamped = FALSE;
609-
int bRounded = FALSE;
610-
double dfVal = 0.0;
611-
const GDALDataType eBandType = poBand->GetRasterDataType();
612-
if (bSignedByte)
613-
{
614-
if (dfInputNoDataValue < -128.0)
615-
{
616-
dfVal = -128.0;
617-
bClamped = TRUE;
618-
}
619-
else if (dfInputNoDataValue > 127.0)
620-
{
621-
dfVal = 127.0;
622-
bClamped = TRUE;
623-
}
624-
else
625-
{
626-
dfVal = static_cast<int>(floor(dfInputNoDataValue + 0.5));
627-
if (dfVal != dfInputNoDataValue)
628-
bRounded = TRUE;
629-
}
630-
}
631-
else
632-
{
633-
dfVal = GDALAdjustValueToDataType(eBandType, dfInputNoDataValue,
634-
&bClamped, &bRounded);
635-
}
636-
637-
if (bClamped)
638-
{
639-
CPLError(CE_Warning, CPLE_AppDefined,
640-
"for band %d, nodata value has been clamped "
641-
"to %.0f, the original value being out of range.",
642-
poBand->GetBand(), dfVal);
643-
}
644-
else if (bRounded)
645-
{
646-
CPLError(CE_Warning, CPLE_AppDefined,
647-
"for band %d, nodata value has been rounded "
648-
"to %.0f, %s being an integer datatype.",
649-
poBand->GetBand(), dfVal, GDALGetDataTypeName(eBandType));
650-
}
651-
return dfVal;
652-
}
653-
654589
/************************************************************************/
655590
/* GDALTranslate() */
656591
/************************************************************************/
@@ -1128,7 +1063,19 @@ GDALDatasetH GDALTranslate(const char *pszDest, GDALDatasetH hSrcDataset,
11281063
/* This is needed for */
11291064
/* gdal_translate foo.tif foo.tif.ovr -outsize 50% 50% */
11301065
/* -------------------------------------------------------------------- */
1131-
if (!psOptions->aosCreateOptions.FetchBool("APPEND_SUBDATASET", false))
1066+
if (psOptions->aosCreateOptions.FetchBool("APPEND_SUBDATASET", false))
1067+
{
1068+
if (GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE_SUBDATASETS,
1069+
nullptr) == nullptr)
1070+
{
1071+
CPLError(CE_Failure, CPLE_NotSupported,
1072+
"Subdataset creation not supported for driver %s",
1073+
GDALGetDescription(hDriver));
1074+
GDALTranslateOptionsFree(psOptions);
1075+
return nullptr;
1076+
}
1077+
}
1078+
else
11321079
{
11331080
if (!EQUAL(psOptions->osFormat.c_str(), "VRT"))
11341081
{
@@ -2496,87 +2443,46 @@ GDALDatasetH GDALTranslate(const char *pszDest, GDALDatasetH hSrcDataset,
24962443
*/
24972444
if (psOptions->bSetNoData)
24982445
{
2499-
if (poVRTBand->GetRasterDataType() == GDT_Int64)
2500-
{
2501-
if (psOptions->osNoData.find('.') != std::string::npos ||
2502-
CPLGetValueType(psOptions->osNoData.c_str()) ==
2503-
CPL_VALUE_STRING)
2504-
{
2505-
const double dfNoData =
2506-
CPLAtof(psOptions->osNoData.c_str());
2507-
if (GDALIsValueExactAs<int64_t>(dfNoData))
2508-
{
2509-
poVRTBand->SetNoDataValueAsInt64(
2510-
static_cast<int64_t>(dfNoData));
2511-
}
2512-
else
2513-
{
2514-
CPLError(CE_Warning, CPLE_AppDefined,
2515-
"Cannot set nodata value %s on a Int64 band",
2516-
psOptions->osNoData.c_str());
2517-
}
2518-
}
2519-
else
2520-
{
2521-
errno = 0;
2522-
const auto val =
2523-
std::strtoll(psOptions->osNoData.c_str(), nullptr, 10);
2524-
if (errno == 0)
2525-
{
2526-
poVRTBand->SetNoDataValueAsInt64(
2527-
static_cast<int64_t>(val));
2528-
}
2529-
else
2530-
{
2531-
CPLError(CE_Warning, CPLE_AppDefined,
2532-
"Cannot set nodata value %s on a Int64 band",
2533-
psOptions->osNoData.c_str());
2534-
}
2535-
}
2446+
const char *pszPixelType =
2447+
psOptions->aosCreateOptions.FetchNameValue("PIXELTYPE");
2448+
if (pszPixelType == nullptr &&
2449+
poVRTBand->GetRasterDataType() == GDT_Byte)
2450+
{
2451+
poVRTBand->EnablePixelTypeSignedByteWarning(false);
2452+
pszPixelType =
2453+
poVRTBand->GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2454+
poVRTBand->EnablePixelTypeSignedByteWarning(true);
25362455
}
2537-
else if (poVRTBand->GetRasterDataType() == GDT_UInt64)
2456+
2457+
bool bCannotBeExactlyRepresented = false;
2458+
2459+
if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
25382460
{
2539-
if (psOptions->osNoData.find('.') != std::string::npos ||
2540-
CPLGetValueType(psOptions->osNoData.c_str()) ==
2541-
CPL_VALUE_STRING)
2461+
char *endptr = nullptr;
2462+
const double dfVal =
2463+
CPLStrtod(psOptions->osNoData.c_str(), &endptr);
2464+
if (endptr == psOptions->osNoData.c_str() +
2465+
psOptions->osNoData.size() &&
2466+
dfVal >= -128.0 && dfVal <= 127.0 &&
2467+
static_cast<int8_t>(dfVal) == dfVal)
25422468
{
2543-
const double dfNoData =
2544-
CPLAtof(psOptions->osNoData.c_str());
2545-
if (GDALIsValueExactAs<uint64_t>(dfNoData))
2546-
{
2547-
poVRTBand->SetNoDataValueAsUInt64(
2548-
static_cast<uint64_t>(dfNoData));
2549-
}
2550-
else
2551-
{
2552-
CPLError(CE_Warning, CPLE_AppDefined,
2553-
"Cannot set nodata value %s on a UInt64 band",
2554-
psOptions->osNoData.c_str());
2555-
}
2469+
poVRTBand->SetNoDataValue(dfVal);
25562470
}
25572471
else
25582472
{
2559-
errno = 0;
2560-
const auto val =
2561-
std::strtoull(psOptions->osNoData.c_str(), nullptr, 10);
2562-
if (errno == 0)
2563-
{
2564-
poVRTBand->SetNoDataValueAsUInt64(
2565-
static_cast<uint64_t>(val));
2566-
}
2567-
else
2568-
{
2569-
CPLError(CE_Warning, CPLE_AppDefined,
2570-
"Cannot set nodata value %s on a UInt64 band",
2571-
psOptions->osNoData.c_str());
2572-
}
2473+
bCannotBeExactlyRepresented = true;
25732474
}
25742475
}
25752476
else
25762477
{
2577-
const double dfVal = AdjustNoDataValue(
2578-
CPLAtof(psOptions->osNoData.c_str()), poVRTBand, psOptions);
2579-
poVRTBand->SetNoDataValue(dfVal);
2478+
poVRTBand->SetNoDataValueAsString(psOptions->osNoData.c_str(),
2479+
&bCannotBeExactlyRepresented);
2480+
}
2481+
if (bCannotBeExactlyRepresented)
2482+
{
2483+
CPLError(CE_Warning, CPLE_AppDefined,
2484+
"Nodata value was not set to output band, "
2485+
"as it cannot be represented on its data type.");
25802486
}
25812487
}
25822488

@@ -2758,7 +2664,7 @@ static void AttachDomainMetadata(GDALDatasetH hDS,
27582664
static void CopyBandInfo(GDALRasterBand *poSrcBand, GDALRasterBand *poDstBand,
27592665
int bCanCopyStatsMetadata, int bCopyScale,
27602666
int bCopyNoData, bool bCopyRAT,
2761-
const GDALTranslateOptions *psOptions)
2667+
const GDALTranslateOptions * /*psOptions*/)
27622668

27632669
{
27642670

@@ -2809,24 +2715,20 @@ static void CopyBandInfo(GDALRasterBand *poSrcBand, GDALRasterBand *poDstBand,
28092715

28102716
if (bCopyNoData)
28112717
{
2812-
if (poSrcBand->GetRasterDataType() != GDT_Int64 &&
2813-
poSrcBand->GetRasterDataType() != GDT_UInt64 &&
2814-
poDstBand->GetRasterDataType() != GDT_Int64 &&
2815-
poDstBand->GetRasterDataType() != GDT_UInt64)
2718+
int bSuccess = FALSE;
2719+
CPL_IGNORE_RET_VAL(poSrcBand->GetNoDataValue(&bSuccess));
2720+
if (bSuccess)
28162721
{
2817-
int bSuccess = FALSE;
2818-
double dfNoData = poSrcBand->GetNoDataValue(&bSuccess);
2819-
if (bSuccess)
2722+
bool bCannotBeExactlyRepresented = false;
2723+
if (!GDALCopyNoDataValue(poDstBand, poSrcBand,
2724+
&bCannotBeExactlyRepresented) &&
2725+
bCannotBeExactlyRepresented)
28202726
{
2821-
const double dfVal =
2822-
AdjustNoDataValue(dfNoData, poDstBand, psOptions);
2823-
poDstBand->SetNoDataValue(dfVal);
2727+
CPLError(CE_Warning, CPLE_AppDefined,
2728+
"Source nodata value was not copied to output band, "
2729+
"as it cannot be represented on its data type.");
28242730
}
28252731
}
2826-
else
2827-
{
2828-
GDALCopyNoDataValue(poDstBand, poSrcBand);
2829-
}
28302732
}
28312733

28322734
if (bCopyScale)
@@ -3516,7 +3418,7 @@ GDALTranslateOptionsNew(char **papszArgv,
35163418
{
35173419
++i;
35183420
const std::string s = papszArgv[i];
3519-
if (EQUAL(s.c_str(), "none"))
3421+
if (EQUAL(s.c_str(), "none") || EQUAL(s.c_str(), "null"))
35203422
{
35213423
psOptions->bUnsetNoData = true;
35223424
}

apps/gdalalg_raster.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "gdalalg_raster_clip.h"
2020
#include "gdalalg_raster_color_map.h"
2121
#include "gdalalg_raster_convert.h"
22+
#include "gdalalg_raster_create.h"
2223
#include "gdalalg_raster_edit.h"
2324
#include "gdalalg_raster_contour.h"
2425
#include "gdalalg_raster_hillshade.h"
@@ -57,6 +58,7 @@ class GDALRasterAlgorithm final : public GDALAlgorithm
5758
RegisterSubAlgorithm<GDALRasterColorMapAlgorithmStandalone>();
5859
RegisterSubAlgorithm<GDALRasterConvertAlgorithm>();
5960
RegisterSubAlgorithm<GDALRasterClipAlgorithmStandalone>();
61+
RegisterSubAlgorithm<GDALRasterCreateAlgorithm>();
6062
RegisterSubAlgorithm<GDALRasterEditAlgorithmStandalone>();
6163
RegisterSubAlgorithm<GDALRasterHillshadeAlgorithmStandalone>();
6264
RegisterSubAlgorithm<GDALRasterIndexAlgorithm>();

0 commit comments

Comments
 (0)