Apply an RGB renderer to a raster layer to enhance feature visibility.
      
  
    
Use case
An RGB renderer is used to adjust the color bands of a multispectral image. Remote sensing images acquired from satellites often contain values representing the reflection of multiple spectrums of light. Changing the RGB renderer of such rasters can be used to differentiate and highlight particular features that reflect light differently, such as different vegetation types, or turbidity in water.
How to use the sample
Choose one of the stretch parameter types. The other options will adjust based on the chosen type. Add your inputs and select the 'Update' button to update the renderer.
How it works
- Create a 
Rasterfrom a from a multispectral raster file. - Create a 
RasterLayerfrom the raster. - Create a 
Basemapfrom the raster layer and set it to the map. - Create an 
RGBRenderer, specifying theStretchParametersand other properties. - Set the 
Rendereron the raster layer withrasterLayer.renderer = renderer. 
Relevant API
- Basemap
 - Raster
 - RasterLayer
 - RGBRenderer
 - StretchParameters
 
Offline Data
To set up the sample's offline data, see the Use offline data in the samples section of the Qt Samples repository overview.
| Link | Local Location | 
|---|---|
| Shasta.tif raster | <userhome>/ArcGIS/Runtime/Data/raster/Shasta.tif | 
About the data
The raster used in this sample shows an area in the south of the Shasta-Trinity National Forest, California.
Tags
analysis, color, composite, imagery, multiband, multispectral, pan-sharpen, photograph, raster, spectrum, stretch, visualization
Sample Code
// [WriteFile Name=RasterRgbRenderer, Category=Layers]
// [Legal]
// Copyright 2017 Esri.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// [Legal]
import QtQuick 2.6
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.2
import Esri.ArcGISRuntime 100.15
import Esri.ArcGISExtras 1.1
Rectangle {
    id: rootRectangle
    clip: true
    width: 800
    height: 600
    readonly property string dataPath: System.userHomePath + "/ArcGIS/Runtime/Data/raster"
    readonly property string minMax: "Min Max"
    readonly property string percentClip: "Percent Clip"
    readonly property string stdDeviation: "Standard Deviation"
    readonly property var stretchTypes: [minMax, percentClip, stdDeviation]
    property bool editingRenderer: false
    property string selectedType: stretchTypeCombo.currentText
    states: [
        State {
            name: "orientHorizontal"
            when: width > height
            PropertyChanges {
                target: layout
                flow: GridLayout.LeftToRight
                labelAlignment: Qt.AlignRight
                columns: 4
            }
        },
        State {
            name: "orientVertical"
            when: width <= height
            PropertyChanges {
                target: layout
                flow: GridLayout.TopToBottom
                labelAlignment: Qt.AlignLeft
                rows: 4
            }
        }
    ]
    MapView {
        anchors.fill: parent
        Component.onCompleted: {
            // Set the focus on MapView to initially enable keyboard navigation
            forceActiveFocus();
        }
        Map {
            Basemap {
                RasterLayer {
                    id: rasterLayer
                    Raster {
                        path: dataPath + "/Shasta.tif"
                    }
                }
            }
        }
    }
    MinMaxStretchParameters {
        id: minMaxParams
    }
    PercentClipStretchParameters {
        id: percentClipParams
    }
    StandardDeviationStretchParameters {
        id: stdDevParams
    }
    Rectangle {
        visible: editButton.visible
        anchors.centerIn: editButton
        radius: 8
        height: editButton.height + (16)
        width: editButton.width + (16)
        color: "lightgrey"
        border.color: "darkgrey"
        border.width: 2
        opacity: 0.75
    }
    Button {
        id: editButton
        anchors {
            bottom: parent.bottom
            horizontalCenter: parent.horizontalCenter
            margins: 32
        }
        visible: rendererBox.width === 0
        text: "Edit Renderer"
        onClicked: editingRenderer = true;
    }
    Rectangle {
        id: rendererBox
        clip: true
        anchors {
            right: parent.right
            top: parent.top
            bottom: parent.bottom
        }
        color: "white"
        opacity: 0.75
        width: editingRenderer ? parent.width : 0
        visible: width > 0
        ComboBox {
            id: stretchTypeCombo
            anchors {
                bottom: layout.top
                left: layout.left
                right: layout.right
                margins: 5
            }
            model: stretchTypes
            property int modelWidth: 0
            Layout.minimumWidth: modelWidth + leftPadding + rightPadding + indicator.width
            Component.onCompleted : {
                for (let i = 0; i < model.length; ++i) {
                    metrics.text = model[i];
                    modelWidth = Math.max(modelWidth, metrics.width);
                }
            }
            TextMetrics {
                id: metrics
                font: stretchTypeCombo.font
            }
        }
        GridLayout {
            id: layout
            property int labelAlignment
            anchors {
                centerIn: parent
                margins: 24
            }
            Text {
                text: "Min"
                Layout.alignment: layout.labelAlignment
                visible: selectedType === minMax
            }
            Repeater {
                id: minMaxMin
                model: 3
                SpinBox {
                    editable: true
                    visible: selectedType === minMax
                    from: 0
                    to: 255
                    value: from
                }
            }
            Text {
                text: "Max"
                Layout.alignment: layout.labelAlignment
                visible: selectedType === minMax
            }
            Repeater {
                id: minMaxMax
                model: 3
                SpinBox {
                    editable: true
                    visible: selectedType === minMax
                    from: 0
                    to: 255
                    value: to
                }
            }
            Text {
                text: "Min"
                Layout.alignment: layout.labelAlignment
                visible: selectedType === percentClip
            }
            SpinBox {
                id: percentClipMin
                editable: true
                visible: selectedType === percentClip
                Layout.columnSpan: 3
                from: 0
                to: 100
                value: from
            }
            Text {
                text: "Max"
                Layout.alignment: layout.labelAlignment
                visible: selectedType === percentClip
            }
            SpinBox {
                id: percentClipMax
                editable: true
                visible: selectedType === percentClip
                Layout.columnSpan: 3
                from: 0
                to: 100
                value: to
            }
            Text {
                text: "Factor"
                Layout.alignment: layout.labelAlignment
                visible: selectedType === stdDeviation
            }
            SpinBox {
                id: sdFactor
                editable: true
                visible: selectedType === stdDeviation
                Layout.columnSpan: 3
                property int decimals: 2
                property real realValue: value / 100
                from: 0
                to: 25 * 100
                value: 0
                validator: DoubleValidator {
                    bottom: Math.min(sdFactor.from, sdFactor.to)
                    top: Math.min(sdFactor.from, sdFactor.to)
                }
                textFromValue: function(value, locale) {
                    return Number(value / 100).toLocaleString(locale, 'f', sdFactor.decimals);
                }
                valueFromText: function(text, locale) {
                    return Number.fromLocaleString(locale, text) * 100;
                }
            }
        }
        Button {
            text: "Render"
            anchors {
                top: layout.bottom
                left: layout.left
                right: layout.right
                margins: 5
            }
            onClicked: {
                editingRenderer = false;
                applyRendererSettings();
            }
        }
        Behavior on width { PropertyAnimation { duration: 500 } }
    }
    function applyRendererSettings(){
        const rgbRenderer = ArcGISRuntimeEnvironment.createObject("RGBRenderer");
        if (stretchTypeCombo.currentText === minMax){
            minMaxParams.minValues = [minMaxMin.itemAt(0).value, minMaxMin.itemAt(1).value, minMaxMin.itemAt(2).value];
            minMaxParams.maxValues = [minMaxMax.itemAt(0).value, minMaxMax.itemAt(1).value, minMaxMax.itemAt(2).value];
            rgbRenderer.stretchParameters = minMaxParams;
        }
        else if (stretchTypeCombo.currentText === percentClip){
            percentClipParams.min =  percentClipMin.value;
            percentClipParams.max = 100 - percentClipMax.value;
            rgbRenderer.stretchParameters = percentClipParams;
        }
        else if (stretchTypeCombo.currentText === stdDeviation){
            stdDevParams.factor =  sdFactor.realValue;
            rgbRenderer.stretchParameters = stdDevParams;
        }
        rasterLayer.renderer = rgbRenderer;
    }
}