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 : 15 : #include "gdal_priv.h" 16 : #include "gdal_utils.h" 17 : 18 : #include <cmath> 19 : 20 : //! @cond Doxygen_Suppress 21 : 22 : #ifndef _ 23 : #define _(x) (x) 24 : #endif 25 : 26 : /************************************************************************/ 27 : /* GDALRasterColorMapAlgorithm::GDALRasterColorMapAlgorithm() */ 28 : /************************************************************************/ 29 : 30 26 : GDALRasterColorMapAlgorithm::GDALRasterColorMapAlgorithm(bool standaloneStep) 31 : : GDALRasterPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL, 32 26 : standaloneStep) 33 : { 34 26 : AddBandArg(&m_band).SetDefault(m_band); 35 26 : AddArg("color-map", 0, _("Color map filename"), &m_colorMap); 36 : AddArg("addalpha", 0, _("Adds an alpha mask band to the destination."), 37 26 : &m_addAlpha); 38 : AddArg("color-selection", 0, 39 : _("How to compute output colors from input values"), 40 52 : &m_colorSelection) 41 26 : .SetChoices("interpolate", "exact", "nearest") 42 26 : .SetDefault(m_colorSelection); 43 26 : } 44 : 45 : /************************************************************************/ 46 : /* GDALRasterColorMapAlgorithm::RunStep() */ 47 : /************************************************************************/ 48 : 49 17 : bool GDALRasterColorMapAlgorithm::RunStep(GDALProgressFunc, void *) 50 : { 51 17 : auto poSrcDS = m_inputDataset.GetDatasetRef(); 52 17 : CPLAssert(poSrcDS); 53 17 : CPLAssert(m_outputDataset.GetName().empty()); 54 17 : CPLAssert(!m_outputDataset.GetDatasetRef()); 55 : 56 34 : CPLStringList aosOptions; 57 17 : aosOptions.AddString("-of"); 58 17 : aosOptions.AddString("VRT"); 59 17 : aosOptions.AddString("-b"); 60 17 : aosOptions.AddString(CPLSPrintf("%d", m_band)); 61 : 62 17 : if (m_colorMap.empty()) 63 : { 64 7 : if (poSrcDS->GetRasterBand(m_band)->GetColorTable() == nullptr) 65 : { 66 1 : ReportError(CE_Failure, CPLE_AppDefined, 67 : "Input dataset has no color table and 'color-map' " 68 : "option was not specified."); 69 1 : return false; 70 : } 71 : 72 8 : if (GetArg("color-selection")->IsExplicitlySet() && 73 2 : m_colorSelection != "exact") 74 : { 75 2 : ReportError( 76 : CE_Warning, CPLE_NotSupported, 77 : "When using band color table, 'color-selection' is ignored"); 78 : } 79 : 80 6 : aosOptions.AddString("-expand"); 81 6 : aosOptions.AddString(m_addAlpha ? "rgba" : "rgb"); 82 : 83 : GDALTranslateOptions *psOptions = 84 6 : GDALTranslateOptionsNew(aosOptions.List(), nullptr); 85 : 86 : // Backup error state since GDALTranslate() resets it multiple times 87 6 : const auto nLastErrorNum = CPLGetLastErrorNo(); 88 6 : const auto nLastErrorType = CPLGetLastErrorType(); 89 12 : const std::string osLastErrorMsg = CPLGetLastErrorMsg(); 90 6 : const auto nLastErrorCounter = CPLGetErrorCounter(); 91 : 92 : auto poOutDS = 93 : std::unique_ptr<GDALDataset>(GDALDataset::FromHandle(GDALTranslate( 94 6 : "", GDALDataset::ToHandle(poSrcDS), psOptions, nullptr))); 95 : 96 6 : if (nLastErrorCounter > 0 && CPLGetErrorCounter() == 0) 97 : { 98 2 : CPLErrorSetState(nLastErrorType, nLastErrorNum, 99 : osLastErrorMsg.c_str(), &nLastErrorCounter); 100 : } 101 : 102 6 : GDALTranslateOptionsFree(psOptions); 103 6 : const bool bRet = poOutDS != nullptr; 104 6 : if (poOutDS) 105 : { 106 6 : m_outputDataset.Set(std::move(poOutDS)); 107 : } 108 : 109 6 : return bRet; 110 : } 111 : else 112 : { 113 10 : if (m_addAlpha) 114 2 : aosOptions.AddString("-alpha"); 115 10 : if (m_colorSelection == "exact") 116 2 : aosOptions.AddString("-exact_color_entry"); 117 8 : else if (m_colorSelection == "nearest") 118 2 : aosOptions.AddString("-nearest_color_entry"); 119 : 120 : GDALDEMProcessingOptions *psOptions = 121 10 : GDALDEMProcessingOptionsNew(aosOptions.List(), nullptr); 122 : 123 : auto poOutDS = std::unique_ptr<GDALDataset>(GDALDataset::FromHandle( 124 : GDALDEMProcessing("", GDALDataset::ToHandle(poSrcDS), 125 : "color-relief", m_colorMap.c_str(), psOptions, 126 10 : nullptr))); 127 10 : GDALDEMProcessingOptionsFree(psOptions); 128 10 : const bool bRet = poOutDS != nullptr; 129 10 : if (poOutDS) 130 : { 131 9 : m_outputDataset.Set(std::move(poOutDS)); 132 : } 133 : 134 10 : return bRet; 135 : } 136 : } 137 : 138 : //! @endcond