Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: GDAL 4 : * Purpose: "color-map" step of "raster pipeline" 5 : * Author: Even Rouault <even dot rouault at spatialys.com> 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2025, Even Rouault <even dot rouault at spatialys.com> 9 : * 10 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #include "gdalalg_raster_color_map.h" 14 : #include "gdalalg_raster_write.h" 15 : 16 : #include "gdal_priv.h" 17 : #include "gdal_utils.h" 18 : 19 : #include <cmath> 20 : 21 : //! @cond Doxygen_Suppress 22 : 23 : #ifndef _ 24 : #define _(x) (x) 25 : #endif 26 : 27 : /************************************************************************/ 28 : /* GDALRasterColorMapAlgorithm::GDALRasterColorMapAlgorithm() */ 29 : /************************************************************************/ 30 : 31 107 : GDALRasterColorMapAlgorithm::GDALRasterColorMapAlgorithm(bool standaloneStep) 32 : : GDALRasterPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL, 33 107 : standaloneStep) 34 : { 35 107 : AddBandArg(&m_band).SetDefault(m_band); 36 214 : AddArg("color-map", 0, _("Color map filename"), &m_colorMap) 37 107 : .AddHiddenAlias("color-table"); 38 : AddArg("add-alpha", 0, _("Adds an alpha mask band to the destination."), 39 107 : &m_addAlpha); 40 : AddArg("color-selection", 0, 41 : _("How to compute output colors from input values"), 42 214 : &m_colorSelection) 43 107 : .SetChoices("interpolate", "exact", "nearest") 44 107 : .SetDefault(m_colorSelection); 45 107 : } 46 : 47 : /************************************************************************/ 48 : /* GDALRasterColorMapAlgorithm::CanHandleNextStep() */ 49 : /************************************************************************/ 50 : 51 40 : bool GDALRasterColorMapAlgorithm::CanHandleNextStep( 52 : GDALPipelineStepAlgorithm *poNextStep) const 53 : { 54 76 : return poNextStep->GetName() == GDALRasterWriteAlgorithm::NAME && 55 76 : poNextStep->GetOutputFormat() != "stream"; 56 : } 57 : 58 : /************************************************************************/ 59 : /* GDALRasterColorMapAlgorithm::RunStep() */ 60 : /************************************************************************/ 61 : 62 22 : bool GDALRasterColorMapAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt) 63 : { 64 22 : auto poSrcDS = m_inputDataset[0].GetDatasetRef(); 65 22 : CPLAssert(poSrcDS); 66 22 : CPLAssert(m_outputDataset.GetName().empty()); 67 22 : CPLAssert(!m_outputDataset.GetDatasetRef()); 68 : 69 44 : CPLStringList aosOptions; 70 44 : std::string outputFilename; 71 22 : if (ctxt.m_poNextUsableStep) 72 : { 73 18 : CPLAssert(CanHandleNextStep(ctxt.m_poNextUsableStep)); 74 18 : outputFilename = ctxt.m_poNextUsableStep->GetOutputDataset().GetName(); 75 18 : const auto &format = ctxt.m_poNextUsableStep->GetOutputFormat(); 76 18 : if (!format.empty()) 77 : { 78 18 : aosOptions.AddString("-of"); 79 18 : aosOptions.AddString(format.c_str()); 80 : } 81 : 82 0 : for (const std::string &co : 83 18 : ctxt.m_poNextUsableStep->GetCreationOptions()) 84 : { 85 0 : aosOptions.AddString("-co"); 86 0 : aosOptions.AddString(co.c_str()); 87 : } 88 : } 89 : else 90 : { 91 4 : aosOptions.AddString("-of"); 92 4 : aosOptions.AddString("VRT"); 93 : } 94 : 95 22 : aosOptions.AddString("-b"); 96 22 : aosOptions.AddString(CPLSPrintf("%d", m_band)); 97 : 98 22 : if (m_colorMap.empty()) 99 : { 100 7 : if (poSrcDS->GetRasterBand(m_band)->GetColorTable() == nullptr) 101 : { 102 1 : ReportError(CE_Failure, CPLE_AppDefined, 103 : "Input dataset has no color table and 'color-map' " 104 : "option was not specified."); 105 1 : return false; 106 : } 107 : 108 8 : if (GetArg("color-selection")->IsExplicitlySet() && 109 2 : m_colorSelection != "exact") 110 : { 111 2 : ReportError( 112 : CE_Warning, CPLE_NotSupported, 113 : "When using band color table, 'color-selection' is ignored"); 114 : } 115 : 116 6 : aosOptions.AddString("-expand"); 117 6 : aosOptions.AddString(m_addAlpha ? "rgba" : "rgb"); 118 : 119 : GDALTranslateOptions *psOptions = 120 6 : GDALTranslateOptionsNew(aosOptions.List(), nullptr); 121 6 : if (ctxt.m_poNextUsableStep) 122 : { 123 6 : GDALTranslateOptionsSetProgress(psOptions, ctxt.m_pfnProgress, 124 : ctxt.m_pProgressData); 125 : } 126 : 127 : // Backup error state since GDALTranslate() resets it multiple times 128 6 : const auto nLastErrorNum = CPLGetLastErrorNo(); 129 6 : const auto nLastErrorType = CPLGetLastErrorType(); 130 12 : const std::string osLastErrorMsg = CPLGetLastErrorMsg(); 131 6 : const auto nLastErrorCounter = CPLGetErrorCounter(); 132 : 133 : auto poOutDS = std::unique_ptr<GDALDataset>(GDALDataset::FromHandle( 134 : GDALTranslate(outputFilename.c_str(), 135 6 : GDALDataset::ToHandle(poSrcDS), psOptions, nullptr))); 136 : 137 6 : if (nLastErrorCounter > 0 && CPLGetErrorCounter() == 0) 138 : { 139 2 : CPLErrorSetState(nLastErrorType, nLastErrorNum, 140 : osLastErrorMsg.c_str(), &nLastErrorCounter); 141 : } 142 : 143 6 : GDALTranslateOptionsFree(psOptions); 144 6 : const bool bRet = poOutDS != nullptr; 145 6 : if (poOutDS) 146 : { 147 6 : m_outputDataset.Set(std::move(poOutDS)); 148 : } 149 : 150 6 : return bRet; 151 : } 152 : else 153 : { 154 15 : if (m_addAlpha) 155 2 : aosOptions.AddString("-alpha"); 156 15 : if (m_colorSelection == "exact") 157 2 : aosOptions.AddString("-exact_color_entry"); 158 13 : else if (m_colorSelection == "nearest") 159 2 : aosOptions.AddString("-nearest_color_entry"); 160 : 161 : GDALDEMProcessingOptions *psOptions = 162 15 : GDALDEMProcessingOptionsNew(aosOptions.List(), nullptr); 163 15 : bool bOK = false; 164 15 : if (psOptions) 165 : { 166 15 : if (ctxt.m_poNextUsableStep) 167 : { 168 11 : GDALDEMProcessingOptionsSetProgress( 169 : psOptions, ctxt.m_pfnProgress, ctxt.m_pProgressData); 170 : } 171 : auto poOutDS = std::unique_ptr<GDALDataset>( 172 : GDALDataset::FromHandle(GDALDEMProcessing( 173 : outputFilename.c_str(), GDALDataset::ToHandle(poSrcDS), 174 30 : "color-relief", m_colorMap.c_str(), psOptions, nullptr))); 175 15 : GDALDEMProcessingOptionsFree(psOptions); 176 15 : bOK = poOutDS != nullptr; 177 15 : if (poOutDS) 178 : { 179 14 : m_outputDataset.Set(std::move(poOutDS)); 180 : } 181 : } 182 15 : return bOK; 183 : } 184 : } 185 : 186 : GDALRasterColorMapAlgorithmStandalone:: 187 : ~GDALRasterColorMapAlgorithmStandalone() = default; 188 : 189 : //! @endcond