Coverage Report

Created: 2026-07-25 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/apps/gdalalg_raster_polygonize.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL
4
 * Purpose:  gdal "raster polygonize" subcommand
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_polygonize.h"
14
#include "gdalalg_vector_write.h"
15
16
#include "cpl_conv.h"
17
#include "gdal_priv.h"
18
#include "gdal_alg.h"
19
#include "ogrsf_frmts.h"
20
21
//! @cond Doxygen_Suppress
22
23
#ifndef _
24
0
#define _(x) (x)
25
#endif
26
27
/************************************************************************/
28
/*    GDALRasterPolygonizeAlgorithm::GDALRasterPolygonizeAlgorithm()    */
29
/************************************************************************/
30
31
GDALRasterPolygonizeAlgorithm::GDALRasterPolygonizeAlgorithm(
32
    bool standaloneStep)
33
0
    : GDALPipelineStepAlgorithm(
34
0
          NAME, DESCRIPTION, HELP_URL,
35
0
          ConstructorOptions()
36
0
              .SetStandaloneStep(standaloneStep)
37
0
              .SetAddUpsertArgument(false)
38
0
              .SetAddSkipErrorsArgument(false)
39
0
              .SetOutputLayerNameAvailableInPipelineStep(true)
40
0
              .SetOutputFormatCreateCapability(GDAL_DCAP_CREATE))
41
0
{
42
0
    if (standaloneStep)
43
0
    {
44
0
        AddProgressArg();
45
0
        AddRasterInputArgs(false, false);
46
0
        AddVectorOutputArgs(false, false);
47
0
    }
48
0
    else
49
0
    {
50
0
        AddRasterHiddenInputDatasetArg();
51
0
        AddOutputLayerNameArg(/* hiddenForCLI = */ false,
52
0
                              /* shortNameOutputLayerAllowed = */ false);
53
0
    }
54
55
    // gdal_polygonize specific options
56
0
    AddBandArg(&m_band).SetDefault(m_band);
57
0
    AddArg("attribute-name", 0, _("Name of the field with the pixel value"),
58
0
           &m_attributeName)
59
0
        .SetDefault(m_attributeName);
60
61
0
    AddArg("connect-diagonal-pixels", 'c',
62
0
           _("Consider diagonal pixels as connected"), &m_connectDiagonalPixels)
63
0
        .SetDefault(m_connectDiagonalPixels);
64
65
0
    AddArg("commit-interval", 0, _("Commit interval"), &m_commitInterval)
66
0
        .SetHidden();
67
0
}
68
69
bool GDALRasterPolygonizeAlgorithm::CanHandleNextStep(
70
    GDALPipelineStepAlgorithm *poNextStep) const
71
0
{
72
0
    return poNextStep->GetName() == GDALVectorWriteAlgorithm::NAME &&
73
0
           poNextStep->GetOutputFormat() != "stream";
74
0
}
75
76
/************************************************************************/
77
/*               GDALRasterPolygonizeAlgorithm::RunImpl()               */
78
/************************************************************************/
79
80
bool GDALRasterPolygonizeAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
81
                                            void *pProgressData)
82
0
{
83
0
    GDALPipelineStepRunContext stepCtxt;
84
0
    stepCtxt.m_pfnProgress = pfnProgress;
85
0
    stepCtxt.m_pProgressData = pProgressData;
86
0
    return RunPreStepPipelineValidations() && RunStep(stepCtxt);
87
0
}
88
89
/************************************************************************/
90
/*               GDALRasterPolygonizeAlgorithm::RunStep()               */
91
/************************************************************************/
92
93
bool GDALRasterPolygonizeAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
94
0
{
95
0
    auto poSrcDS = m_inputDataset[0].GetDatasetRef();
96
0
    CPLAssert(poSrcDS);
97
98
0
    auto poWriteStep = ctxt.m_poNextUsableStep ? ctxt.m_poNextUsableStep : this;
99
100
0
    GDALDataset *poDstDS = nullptr;
101
0
    bool bTemporaryFile = false;
102
0
    std::unique_ptr<GDALDataset> poNewRetDS;
103
0
    std::string outputLayerName;
104
0
    OGRLayer *poDstLayer = nullptr;
105
0
    if (!CreateDatasetSingleOutputLayerIfNeeded(ctxt, "polygonize", poDstDS,
106
0
                                                bTemporaryFile, poNewRetDS,
107
0
                                                outputLayerName, poDstLayer))
108
0
    {
109
0
        return false;
110
0
    }
111
112
0
    auto poSrcBand = poSrcDS->GetRasterBand(m_band);
113
0
    const auto eDT = poSrcBand->GetRasterDataType();
114
115
0
    if (!poDstLayer)
116
0
    {
117
0
        poDstLayer = poDstDS->CreateLayer(
118
0
            outputLayerName.c_str(), poSrcDS->GetSpatialRef(), wkbPolygon,
119
0
            CPLStringList(poWriteStep->GetLayerCreationOptions()).List());
120
0
        if (!poDstLayer)
121
0
        {
122
0
            ReportError(CE_Failure, CPLE_AppDefined, "Cannot create layer '%s'",
123
0
                        outputLayerName.c_str());
124
0
            return false;
125
0
        }
126
127
0
        OGRFieldDefn oFieldDefn(m_attributeName.c_str(),
128
0
                                !GDALDataTypeIsInteger(eDT) ? OFTReal
129
0
                                : eDT == GDT_Int64 || eDT == GDT_UInt64
130
0
                                    ? OFTInteger64
131
0
                                    : OFTInteger);
132
0
        if (poDstLayer->CreateField(&oFieldDefn) != OGRERR_NONE)
133
0
        {
134
0
            ReportError(CE_Failure, CPLE_AppDefined,
135
0
                        "Cannot create field '%s' in layer '%s'",
136
0
                        m_attributeName.c_str(), outputLayerName.c_str());
137
0
            return false;
138
0
        }
139
0
    }
140
141
0
    const int iPixValField =
142
0
        poDstLayer->GetLayerDefn()->GetFieldIndex(m_attributeName.c_str());
143
0
    if (iPixValField < 0)
144
0
    {
145
0
        ReportError(CE_Failure, CPLE_AppDefined,
146
0
                    "Cannot find field '%s' in layer '%s'",
147
0
                    m_attributeName.c_str(), outputLayerName.c_str());
148
0
        return false;
149
0
    }
150
151
0
    CPLStringList aosPolygonizeOptions;
152
0
    if (m_connectDiagonalPixels)
153
0
    {
154
0
        aosPolygonizeOptions.SetNameValue("8CONNECTED", "8");
155
0
    }
156
0
    if (m_commitInterval)
157
0
    {
158
0
        aosPolygonizeOptions.SetNameValue("COMMIT_INTERVAL",
159
0
                                          CPLSPrintf("%d", m_commitInterval));
160
0
    }
161
162
0
    bool ret;
163
0
    if (GDALDataTypeIsInteger(eDT))
164
0
    {
165
0
        ret = GDALPolygonize(GDALRasterBand::ToHandle(poSrcBand),
166
0
                             GDALRasterBand::ToHandle(poSrcBand->GetMaskBand()),
167
0
                             OGRLayer::ToHandle(poDstLayer), iPixValField,
168
0
                             aosPolygonizeOptions.List(), ctxt.m_pfnProgress,
169
0
                             ctxt.m_pProgressData) == CE_None;
170
0
    }
171
0
    else
172
0
    {
173
0
        ret =
174
0
            GDALFPolygonize(GDALRasterBand::ToHandle(poSrcBand),
175
0
                            GDALRasterBand::ToHandle(poSrcBand->GetMaskBand()),
176
0
                            OGRLayer::ToHandle(poDstLayer), iPixValField,
177
0
                            aosPolygonizeOptions.List(), ctxt.m_pfnProgress,
178
0
                            ctxt.m_pProgressData) == CE_None;
179
0
    }
180
181
0
    if (ret && poNewRetDS)
182
0
    {
183
0
        if (bTemporaryFile)
184
0
        {
185
0
            ret = poNewRetDS->FlushCache() == CE_None;
186
0
#if !defined(__APPLE__)
187
            // For some unknown reason, unlinking the file on MacOSX
188
            // leads to later "disk I/O error". See https://github.com/OSGeo/gdal/issues/13794
189
0
            VSIUnlink(poNewRetDS->GetDescription());
190
0
#endif
191
0
        }
192
193
0
        m_outputDataset.Set(std::move(poNewRetDS));
194
0
    }
195
196
0
    return ret;
197
0
}
198
199
GDALRasterPolygonizeAlgorithmStandalone::
200
0
    ~GDALRasterPolygonizeAlgorithmStandalone() = default;
201
202
//! @endcond