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