Coverage Report

Created: 2026-02-14 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/apps/gdalalg_raster_resize.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL
4
 * Purpose:  "resize" 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_resize.h"
14
15
#include "gdal_priv.h"
16
#include "gdal_utils.h"
17
18
//! @cond Doxygen_Suppress
19
20
#ifndef _
21
0
#define _(x) (x)
22
#endif
23
24
/************************************************************************/
25
/*        GDALRasterResizeAlgorithm::GDALRasterResizeAlgorithm()        */
26
/************************************************************************/
27
28
GDALRasterResizeAlgorithm::GDALRasterResizeAlgorithm(bool standaloneStep)
29
0
    : GDALRasterPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
30
0
                                      standaloneStep)
31
0
{
32
0
    AddArg("resolution", 0, _("Target resolution (in destination CRS units)"),
33
0
           &m_resolution)
34
0
        .SetMinCount(2)
35
0
        .SetMaxCount(2)
36
0
        .SetMinValueExcluded(0)
37
0
        .SetRepeatedArgAllowed(false)
38
0
        .SetDisplayHintAboutRepetition(false)
39
0
        .SetMetaVar("<xres>,<yres>")
40
0
        .SetMutualExclusionGroup("resolution-size");
41
42
0
    AddArg("size", 0,
43
0
           _("Target size in pixels (or percentage if using '%' suffix)"),
44
0
           &m_size)
45
0
        .SetMinCount(2)
46
0
        .SetMaxCount(2)
47
0
        .SetRequired()
48
0
        .SetMinValueIncluded(0)
49
0
        .SetRepeatedArgAllowed(false)
50
0
        .SetDisplayHintAboutRepetition(false)
51
0
        .SetMetaVar("<width[%]>,<height[%]>")
52
0
        .SetMutualExclusionGroup("resolution-size")
53
0
        .AddValidationAction(
54
0
            [this]()
55
0
            {
56
0
                for (const auto &s : m_size)
57
0
                {
58
0
                    char *endptr = nullptr;
59
0
                    const double val = CPLStrtod(s.c_str(), &endptr);
60
0
                    bool ok = false;
61
0
                    if (endptr == s.c_str() + s.size())
62
0
                    {
63
0
                        if (val >= 0 && val <= INT_MAX &&
64
0
                            static_cast<int>(val) == val)
65
0
                        {
66
0
                            ok = true;
67
0
                        }
68
0
                    }
69
0
                    else if (endptr && ((endptr[0] == ' ' && endptr[1] == '%' &&
70
0
                                         endptr + 2 == s.c_str() + s.size()) ||
71
0
                                        (endptr[0] == '%' &&
72
0
                                         endptr + 1 == s.c_str() + s.size())))
73
0
                    {
74
0
                        if (val >= 0)
75
0
                        {
76
0
                            ok = true;
77
0
                        }
78
0
                    }
79
0
                    if (!ok)
80
0
                    {
81
0
                        ReportError(CE_Failure, CPLE_IllegalArg,
82
0
                                    "Invalid size value: %s'", s.c_str());
83
0
                        return false;
84
0
                    }
85
0
                }
86
0
                return true;
87
0
            });
88
0
    AddArg("resampling", 'r', _("Resampling method"), &m_resampling)
89
0
        .SetChoices("nearest", "bilinear", "cubic", "cubicspline", "lanczos",
90
0
                    "average", "mode")
91
0
        .SetDefault("nearest")
92
0
        .SetHiddenChoices("near");
93
0
}
94
95
/************************************************************************/
96
/*                 GDALRasterResizeAlgorithm::RunStep()                 */
97
/************************************************************************/
98
99
bool GDALRasterResizeAlgorithm::RunStep(GDALPipelineStepRunContext &)
100
0
{
101
0
    const auto poSrcDS = m_inputDataset[0].GetDatasetRef();
102
0
    CPLAssert(poSrcDS);
103
0
    CPLAssert(m_outputDataset.GetName().empty());
104
0
    CPLAssert(!m_outputDataset.GetDatasetRef());
105
106
0
    CPLStringList aosOptions;
107
0
    aosOptions.AddString("-of");
108
0
    aosOptions.AddString("VRT");
109
0
    if (!m_size.empty())
110
0
    {
111
0
        aosOptions.AddString("-outsize");
112
0
        aosOptions.AddString(m_size[0]);
113
0
        aosOptions.AddString(m_size[1]);
114
0
    }
115
0
    if (!m_resolution.empty())
116
0
    {
117
0
        aosOptions.AddString("-tr");
118
0
        aosOptions.AddString(CPLSPrintf("%.17g", m_resolution[0]));
119
0
        aosOptions.AddString(CPLSPrintf("%.17g", m_resolution[1]));
120
0
    }
121
0
    if (!m_resampling.empty())
122
0
    {
123
0
        aosOptions.AddString("-r");
124
0
        aosOptions.AddString(m_resampling.c_str());
125
0
    }
126
127
0
    GDALTranslateOptions *psOptions =
128
0
        GDALTranslateOptionsNew(aosOptions.List(), nullptr);
129
130
0
    auto poOutDS = std::unique_ptr<GDALDataset>(GDALDataset::FromHandle(
131
0
        GDALTranslate("", GDALDataset::ToHandle(poSrcDS), psOptions, nullptr)));
132
0
    GDALTranslateOptionsFree(psOptions);
133
0
    const bool bRet = poOutDS != nullptr;
134
0
    if (poOutDS)
135
0
    {
136
0
        m_outputDataset.Set(std::move(poOutDS));
137
0
    }
138
139
0
    return bRet;
140
0
}
141
142
0
GDALRasterResizeAlgorithmStandalone::~GDALRasterResizeAlgorithmStandalone() =
143
    default;
144
145
//! @endcond