• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 15885686134

25 Jun 2025 07:44PM UTC coverage: 71.084%. Remained the same
15885686134

push

github

rouault
gdal_priv.h: fix C++11 compatibility

573814 of 807237 relevant lines covered (71.08%)

250621.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.03
/apps/gdalenhance.cpp
1
/******************************************************************************
2
 *
3
 * Project:  GDAL Utilities
4
 * Purpose:  Command line application to do image enhancement.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 * ****************************************************************************
8
 * Copyright (c) 2007, Frank Warmerdam <warmerdam@pobox.com>
9
 * Copyright (c) 2007-2011, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13

14
#include "cpl_string.h"
15
#include "cpl_conv.h"
16
#include "cpl_multiproc.h"
17
#include "gdal_version.h"
18
#include "gdal.h"
19
#include "vrtdataset.h"
20
#include "commonutils.h"
21

22
#include <algorithm>
23

24
static int ComputeEqualizationLUTs(GDALDatasetH hDataset, int nLUTBins,
25
                                   double **ppadfScaleMin,
26
                                   double **padfScaleMax, int ***ppapanLUTs,
27
                                   GDALProgressFunc pfnProgress);
28

29
static CPLErr ReadLUTs(const char *pszConfigFile, int nBandCount, int nLUTBins,
30
                       int ***ppapanLUTs, double **ppadfScaleMin,
31
                       double **ppadfScaleMax);
32
static void WriteLUTs(int **papanLUTs, int nBandCount, int nLUTBins,
33
                      double *padfScaleMin, double *padfScaleMax,
34
                      const char *pszConfigFile);
35
static CPLErr WriteEnhanced(GDALDatasetH hDataset, int **papanLUTs,
36
                            int nLUTBins, double *padfScaleMin,
37
                            double *padfScaleMax, GDALDataType eOutputType,
38
                            GDALDriverH hDriver, const char *pszDest,
39
                            char **papszCreateOptions,
40
                            GDALProgressFunc pfnProgress);
41

42
static CPLErr EnhancerCallback(void *hCBData, int nXOff, int nYOff, int nXSize,
43
                               int nYSize, void *pData);
44

45
typedef struct
46
{
47
    GDALRasterBand *poSrcBand;
48
    GDALDataType eWrkType;
49
    double dfScaleMin;
50
    double dfScaleMax;
51
    int nLUTBins;
52
    const int *panLUT;
53
} EnhanceCBInfo;
54

55
/* ******************************************************************** */
56
/*                               Usage()                                */
57
/* ******************************************************************** */
58

59
static void Usage()
1✔
60

61
{
62
    printf("Usage: gdalenhance [--help] [--help-general]\n"
1✔
63
           "       [-of <format>] [-co <NAME>=<VALUE>]...\n"
64
           "       [-ot {Byte/Int16/UInt16/UInt32/Int32/Float32/Float64/\n"
65
           "             CInt16/CInt32/CFloat32/CFloat64}]\n"
66
           //            "       [-src_scale[_n] src_min src_max]\n"
67
           //            "       [-dst_scale[_n] dst_min dst_max]\n"
68
           //            "       [-lutbins count]\n"
69
           //            "       [-s_nodata[_n] value]\n"
70
           //            "       [-stddev multiplier]\n"
71
           "       [-equalize]\n"
72
           "       [-config <filename>]\n"
73
           "       <src_dataset> <dst_dataset>\n\n");
74
    printf("%s\n\n", GDALVersionInfo("--version"));
1✔
75
    exit(1);
1✔
76
}
77

78
/************************************************************************/
79
/*                             ProxyMain()                              */
80
/************************************************************************/
81

82
MAIN_START(argc, argv)
10✔
83

84
{
85
    GDALDatasetH hDataset = nullptr;
10✔
86
    const char *pszSource = nullptr, *pszDest = nullptr, *pszFormat = nullptr;
10✔
87
    GDALDriverH hDriver = nullptr;
10✔
88
    GDALDataType eOutputType = GDT_Unknown;
10✔
89
    char **papszCreateOptions = nullptr;
10✔
90
    GDALProgressFunc pfnProgress = GDALTermProgress;
10✔
91
    int nBandCount = 0;
10✔
92
    int nLUTBins = 256;
10✔
93
    const char *pszMethod = "minmax";
10✔
94
    //    double              dfStdDevMult = 0.0;
95
    double *padfScaleMin = nullptr;
10✔
96
    double *padfScaleMax = nullptr;
10✔
97
    int **papanLUTs = nullptr;
10✔
98
    const char *pszConfigFile = nullptr;
10✔
99
    int nRetCode = 0;
10✔
100

101
    /* Check strict compilation and runtime library version as we use C++ API */
102
    if (!GDAL_CHECK_VERSION(argv[0]))
10✔
103
        exit(1);
×
104
    /* -------------------------------------------------------------------- */
105
    /*      Register standard GDAL drivers, and process generic GDAL        */
106
    /*      command options.                                                */
107
    /* -------------------------------------------------------------------- */
108
    GDALAllRegister();
10✔
109
    argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
10✔
110
    if (argc < 1)
10✔
111
    {
112
        GDALDestroyDriverManager();
1✔
113
        exit(0);
1✔
114
    }
115

116
    /* -------------------------------------------------------------------- */
117
    /*      Handle command line arguments.                                  */
118
    /* -------------------------------------------------------------------- */
119
    for (int i = 1; i < argc; i++)
42✔
120
    {
121
        if (EQUAL(argv[i], "--utility_version"))
33✔
122
        {
123
            printf("%s was compiled against GDAL %s and is running against "
×
124
                   "GDAL %s\n",
125
                   argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
126
            goto exit;
×
127
        }
128
        else if (EQUAL(argv[i], "--help"))
33✔
129
        {
130
            Usage();
×
131
        }
132
        else if (i < argc - 1 &&
33✔
133
                 (EQUAL(argv[i], "-of") || EQUAL(argv[i], "-f")))
27✔
134
        {
135
            pszFormat = argv[++i];
×
136
        }
137

138
        else if (i < argc - 1 && EQUAL(argv[i], "-ot"))
33✔
139
        {
140
            for (int iType = 1; iType < GDT_TypeCount; iType++)
17✔
141
            {
142
                if (GDALGetDataTypeName(static_cast<GDALDataType>(iType)) !=
16✔
143
                        nullptr &&
32✔
144
                    EQUAL(GDALGetDataTypeName(static_cast<GDALDataType>(iType)),
16✔
145
                          argv[i + 1]))
146
                {
147
                    eOutputType = static_cast<GDALDataType>(iType);
1✔
148
                }
149
            }
150

151
            if (eOutputType == GDT_Unknown)
1✔
152
            {
153
                printf("Unknown output pixel type: %s\n", argv[i + 1]);
×
154
                Usage();
×
155
            }
156
            i++;
1✔
157
        }
158

159
        else if (STARTS_WITH_CI(argv[i], "-s_nodata"))
32✔
160
        {
161
            // TODO
162
            i += 1;
×
163
        }
164

165
        else if (i < argc - 1 && EQUAL(argv[i], "-co"))
32✔
166
        {
167
            papszCreateOptions = CSLAddString(papszCreateOptions, argv[++i]);
1✔
168
        }
169

170
        else if (i < argc - 1 && STARTS_WITH_CI(argv[i], "-src_scale"))
31✔
171
        {
172
            // TODO
173
            i += 2;
×
174
        }
175

176
        else if (i < argc - 2 && STARTS_WITH_CI(argv[i], "-dst_scale"))
31✔
177
        {
178
            // TODO
179
            i += 2;
×
180
        }
181

182
        else if (i < argc - 1 && EQUAL(argv[i], "-config"))
31✔
183
        {
184
            pszConfigFile = argv[++i];
5✔
185
        }
186

187
        else if (EQUAL(argv[i], "-equalize"))
26✔
188
        {
189
            pszMethod = "equalize";
4✔
190
        }
191

192
        else if (EQUAL(argv[i], "-quiet"))
22✔
193
        {
194
            pfnProgress = GDALDummyProgress;
6✔
195
        }
196

197
        else if (argv[i][0] == '-')
16✔
198
        {
199
            printf("Option %s incomplete, or not recognised.\n\n", argv[i]);
×
200
            Usage();
×
201
        }
202
        else if (pszSource == nullptr)
16✔
203
        {
204
            pszSource = argv[i];
9✔
205
        }
206
        else if (pszDest == nullptr)
7✔
207
        {
208
            pszDest = argv[i];
7✔
209
        }
210

211
        else
212
        {
213
            printf("Too many command options.\n\n");
×
214
            Usage();
×
215
        }
216
    }
217

218
    if (pszSource == nullptr)
9✔
219
    {
220
        Usage();
×
221
    }
222

223
    /* -------------------------------------------------------------------- */
224
    /*      Attempt to open source file.                                    */
225
    /* -------------------------------------------------------------------- */
226

227
    hDataset = GDALOpenShared(pszSource, GA_ReadOnly);
9✔
228

229
    if (hDataset == nullptr)
9✔
230
    {
231
        fprintf(stderr, "GDALOpen failed - %d\n%s\n", CPLGetLastErrorNo(),
×
232
                CPLGetLastErrorMsg());
233
        goto exit;
×
234
    }
235

236
    nBandCount = GDALGetRasterCount(hDataset);
9✔
237

238
    /* -------------------------------------------------------------------- */
239
    /*      Find the output driver.                                         */
240
    /* -------------------------------------------------------------------- */
241
    {
242
        CPLString osFormat;
9✔
243
        if (pszFormat == nullptr && pszDest != nullptr)
9✔
244
        {
245
            osFormat = GetOutputDriverForRaster(pszDest);
7✔
246
            if (osFormat.empty())
7✔
247
            {
248
                GDALDestroyDriverManager();
×
249
                exit(1);
×
250
            }
251
        }
252
        else if (pszFormat != nullptr)
2✔
253
        {
254
            osFormat = pszFormat;
×
255
        }
256

257
        if (!osFormat.empty())
9✔
258
        {
259
            hDriver = GDALGetDriverByName(osFormat);
7✔
260
            if (hDriver == nullptr)
7✔
261
            {
262
                int iDr;
263

264
                printf("Output driver `%s' not recognised.\n",
×
265
                       osFormat.c_str());
266
                printf("The following format drivers are enabled and support "
×
267
                       "writing:\n");
268
                for (iDr = 0; iDr < GDALGetDriverCount(); iDr++)
×
269
                {
270
                    hDriver = GDALGetDriver(iDr);
×
271

272
                    if (GDALGetMetadataItem(hDriver, GDAL_DCAP_RASTER,
×
273
                                            nullptr) != nullptr &&
×
274
                        (GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE,
×
275
                                             nullptr) != nullptr ||
×
276
                         GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATECOPY,
×
277
                                             nullptr) != nullptr))
278
                    {
279
                        printf("  %s: %s\n", GDALGetDriverShortName(hDriver),
×
280
                               GDALGetDriverLongName(hDriver));
281
                    }
282
                }
283
                printf("\n");
×
284
                goto exit;
×
285
            }
286
        }
287
    }
288

289
    /* -------------------------------------------------------------------- */
290
    /*      If histogram equalization is requested, do it now.              */
291
    /* -------------------------------------------------------------------- */
292
    if (EQUAL(pszMethod, "equalize"))
9✔
293
    {
294
        ComputeEqualizationLUTs(hDataset, nLUTBins, &padfScaleMin,
4✔
295
                                &padfScaleMax, &papanLUTs, pfnProgress);
296
    }
297

298
    /* -------------------------------------------------------------------- */
299
    /*      If we have a config file, assume it is for input and read       */
300
    /*      it.                                                             */
301
    /* -------------------------------------------------------------------- */
302
    else if (pszConfigFile != nullptr)
5✔
303
    {
304
        if (ReadLUTs(pszConfigFile, nBandCount, nLUTBins, &papanLUTs,
4✔
305
                     &padfScaleMin, &padfScaleMax) != CE_None)
4✔
306
        {
307
            nRetCode = 1;
2✔
308
            goto exit;
2✔
309
        }
310
    }
311

312
    if (padfScaleMin == nullptr || padfScaleMax == nullptr)
7✔
313
    {
314
        fprintf(stderr, "-equalize or -config filename command line options "
1✔
315
                        "must be specified.\n");
316
        Usage();
1✔
317
    }
318

319
    /* -------------------------------------------------------------------- */
320
    /*      If there is no destination, just report the scaling values      */
321
    /*      and luts.                                                       */
322
    /* -------------------------------------------------------------------- */
323
    if (pszDest == nullptr)
6✔
324
    {
325
        WriteLUTs(papanLUTs, nBandCount, nLUTBins, padfScaleMin, padfScaleMax,
2✔
326
                  pszConfigFile);
327
    }
328
    else
329
    {
330
        if (WriteEnhanced(hDataset, papanLUTs, nLUTBins, padfScaleMin,
4✔
331
                          padfScaleMax, eOutputType, hDriver, pszDest,
332
                          papszCreateOptions, pfnProgress) != CE_None)
4✔
333
        {
334
            nRetCode = 1;
1✔
335
        }
336
    }
337

338
    /* -------------------------------------------------------------------- */
339
    /*      Cleanup and exit.                                               */
340
    /* -------------------------------------------------------------------- */
341
exit:
3✔
342
    GDALClose(hDataset);
8✔
343
    GDALDumpOpenDatasets(stderr);
8✔
344
    GDALDestroyDriverManager();
8✔
345
    CSLDestroy(argv);
8✔
346
    CSLDestroy(papszCreateOptions);
8✔
347
    if (papanLUTs)
8✔
348
    {
349
        for (int iBand = 0; iBand < nBandCount; iBand++)
28✔
350
        {
351
            CPLFree(papanLUTs[iBand]);
21✔
352
        }
353
        CPLFree(papanLUTs);
7✔
354
    }
355
    CPLFree(padfScaleMin);
8✔
356
    CPLFree(padfScaleMax);
8✔
357

358
    exit(nRetCode);
8✔
359
}
360

361
MAIN_END
×
362

363
/************************************************************************/
364
/*                      ComputeEqualizationLUTs()                       */
365
/*                                                                      */
366
/*      Get an image histogram, and compute equalization luts from      */
367
/*      it.                                                             */
368
/************************************************************************/
369

370
static int ComputeEqualizationLUTs(GDALDatasetH hDataset, int nLUTBins,
4✔
371
                                   double **ppadfScaleMin,
372
                                   double **ppadfScaleMax, int ***ppapanLUTs,
373
                                   GDALProgressFunc pfnProgress)
374

375
{
376
    int nBandCount = GDALGetRasterCount(hDataset);
4✔
377

378
    // For now we always compute min/max
379
    *ppadfScaleMin =
4✔
380
        static_cast<double *>(CPLCalloc(sizeof(double), nBandCount));
4✔
381
    *ppadfScaleMax =
4✔
382
        static_cast<double *>(CPLCalloc(sizeof(double), nBandCount));
4✔
383

384
    *ppapanLUTs = static_cast<int **>(CPLCalloc(sizeof(int *), nBandCount));
4✔
385

386
    /* ==================================================================== */
387
    /*      Process all bands.                                              */
388
    /* ==================================================================== */
389
    for (int iBand = 0; iBand < nBandCount; iBand++)
16✔
390
    {
391
        GDALRasterBandH hBand = GDALGetRasterBand(hDataset, iBand + 1);
12✔
392
        GUIntBig *panHistogram = nullptr;
12✔
393
        int nHistSize = 0;
12✔
394

395
        /* ----------------------------------------------------------------- */
396
        /*      Get a reasonable histogram.                                  */
397
        /* ----------------------------------------------------------------- */
398
        const CPLErr eErr = GDALGetDefaultHistogramEx(
24✔
399
            hBand, *ppadfScaleMin + iBand, *ppadfScaleMax + iBand, &nHistSize,
12✔
400
            &panHistogram, TRUE, pfnProgress, nullptr);
401

402
        if (eErr != CE_None)
12✔
403
            return FALSE;
×
404

405
        panHistogram[0] = 0;  // zero out extremes (nodata, etc)
12✔
406
        panHistogram[nHistSize - 1] = 0;
12✔
407

408
        /* ----------------------------------------------------------------- */
409
        /*      Total histogram count, and build cumulative histogram.       */
410
        /*      We take care to use big integers as there may be more than 4 */
411
        /*      Gigapixels.                                                  */
412
        /* ----------------------------------------------------------------- */
413
        GUIntBig *panCumHist = static_cast<GUIntBig *>(
414
            VSI_CALLOC_VERBOSE(sizeof(GUIntBig), nHistSize));
12✔
415
        if (!panCumHist)
12✔
416
            return FALSE;
×
417
        GUIntBig nTotal = 0;
12✔
418

419
        for (int iHist = 0; iHist < nHistSize; iHist++)
3,084✔
420
        {
421
            panCumHist[iHist] = nTotal + panHistogram[iHist] / 2;
3,072✔
422
            nTotal += panHistogram[iHist];
3,072✔
423
        }
424

425
        CPLFree(panHistogram);
12✔
426

427
        if (nTotal == 0)
12✔
428
        {
429
            CPLError(CE_Warning, CPLE_AppDefined,
×
430
                     "Zero value entries in histogram, results will not be "
431
                     "meaningful.");
432
            nTotal = 1;
×
433
        }
434

435
        /* ----------------------------------------------------------------- */
436
        /*      Now compute a LUT from the cumulative histogram.             */
437
        /* ----------------------------------------------------------------- */
438
        int *panLUT =
439
            static_cast<int *>(VSI_CALLOC_VERBOSE(sizeof(int), nLUTBins));
12✔
440
        if (!panLUT)
12✔
441
        {
442
            CPLFree(panCumHist);
×
443
            return FALSE;
×
444
        }
445

446
        for (int iLUT = 0; iLUT < nLUTBins; iLUT++)
3,084✔
447
        {
448
            const int iHist = static_cast<int>(
3,072✔
449
                (static_cast<int64_t>(iLUT) * nHistSize) / nLUTBins);
3,072✔
450
            const int nValue =
3,072✔
451
                static_cast<int>((panCumHist[iHist] * nLUTBins) / nTotal);
3,072✔
452

453
            panLUT[iLUT] = std::max(0, std::min(nLUTBins - 1, nValue));
3,072✔
454
        }
455

456
        CPLFree(panCumHist);
12✔
457

458
        (*ppapanLUTs)[iBand] = panLUT;
12✔
459
    }
460

461
    return TRUE;
4✔
462
}
463

464
/************************************************************************/
465
/*                          EnhancerCallback()                          */
466
/*                                                                      */
467
/*      This is the VRT callback that actually does the image rescaling.*/
468
/************************************************************************/
469

470
static CPLErr EnhancerCallback(void *hCBData, int nXOff, int nYOff, int nXSize,
10✔
471
                               int nYSize, void *pData)
472

473
{
474
    const EnhanceCBInfo *psEInfo = static_cast<const EnhanceCBInfo *>(hCBData);
10✔
475

476
    if (psEInfo->eWrkType != GDT_Byte)
10✔
477
    {
478
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
479
                 "Currently gdalenhance only supports Byte output.");
480
        return CE_Failure;
1✔
481
    }
482

483
    GByte *pabyOutImage = static_cast<GByte *>(pData);
9✔
484
    float *pafSrcImage = static_cast<float *>(
485
        VSI_MALLOC3_VERBOSE(sizeof(float), nXSize, nYSize));
9✔
486
    if (!pafSrcImage)
9✔
487
        return CE_Failure;
×
488

489
    CPLErr eErr = psEInfo->poSrcBand->RasterIO(
9✔
490
        GF_Read, nXOff, nYOff, nXSize, nYSize, pafSrcImage, nXSize, nYSize,
491
        GDT_Float32, 0, 0, nullptr);
492

493
    if (eErr != CE_None)
9✔
494
    {
495
        CPLFree(pafSrcImage);
×
496
        return eErr;
×
497
    }
498

499
    const size_t nPixelCount = static_cast<size_t>(nXSize) * nYSize;
9✔
500
    int bHaveNoData;
501
    const float fNoData =
502
        static_cast<float>(psEInfo->poSrcBand->GetNoDataValue(&bHaveNoData));
9✔
503
    const double dfScale =
9✔
504
        psEInfo->nLUTBins / (psEInfo->dfScaleMax - psEInfo->dfScaleMin);
9✔
505

506
    for (size_t iPixel = 0; iPixel < nPixelCount; iPixel++)
22,509✔
507
    {
508
        if (bHaveNoData && pafSrcImage[iPixel] == fNoData)
22,500✔
509
        {
510
            pabyOutImage[iPixel] = static_cast<GByte>(fNoData);
×
511
            continue;
×
512
        }
513

514
        const double dfBin =
22,500✔
515
            (pafSrcImage[iPixel] - psEInfo->dfScaleMin) * dfScale;
22,500✔
516
        int iBin = 0;
22,500✔
517
        if (!(dfBin > 0))
22,500✔
518
        {
519
            // nothing to do
520
        }
521
        else if (!(dfBin < psEInfo->nLUTBins - 1))
22,500✔
522
        {
523
            iBin = psEInfo->nLUTBins - 1;
×
524
        }
525
        else
526
        {
527
            iBin = static_cast<int>(dfBin);
22,500✔
528
        }
529

530
        if (psEInfo->panLUT)
22,500✔
531
            pabyOutImage[iPixel] = static_cast<GByte>(psEInfo->panLUT[iBin]);
22,500✔
532
        else
533
            pabyOutImage[iPixel] = static_cast<GByte>(iBin);
×
534
    }
535

536
    CPLFree(pafSrcImage);
9✔
537

538
    return CE_None;
9✔
539
}
540

541
/************************************************************************/
542
/*                      ReadLUTs()                                      */
543
/*                                                                      */
544
/*               Read a LUT for each band from a file.                  */
545
/************************************************************************/
546

547
CPLErr ReadLUTs(const char *pszConfigFile, int nBandCount, int nLUTBins,
4✔
548
                int ***ppapanLUTs, double **ppadfScaleMin,
549
                double **ppadfScaleMax)
550
{
551
    const CPLStringList aosLines(CSLLoad(pszConfigFile));
8✔
552

553
    if (aosLines.size() != nBandCount)
4✔
554
    {
555
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
556
                 "Did not get %d lines in config file as expected.\n",
557
                 nBandCount);
558
        return CE_Failure;
1✔
559
    }
560

561
    *ppadfScaleMin =
3✔
562
        static_cast<double *>(CPLCalloc(nBandCount, sizeof(double)));
3✔
563
    *ppadfScaleMax =
3✔
564
        static_cast<double *>(CPLCalloc(nBandCount, sizeof(double)));
3✔
565
    *ppapanLUTs = static_cast<int **>(CPLCalloc(sizeof(int *), nBandCount));
3✔
566

567
    for (int iBand = 0; iBand < nBandCount; iBand++)
10✔
568
    {
569
        const CPLStringList aosTokens(CSLTokenizeString(aosLines[iBand]));
8✔
570

571
        if (aosTokens.size() < (nLUTBins + 3) ||
15✔
572
            atoi(aosTokens[0]) != iBand + 1)
7✔
573
        {
574
            CPLError(CE_Failure, CPLE_AppDefined,
1✔
575
                     "Line %d seems to be corrupt.\n", iBand + 1);
576
            return CE_Failure;
1✔
577
        }
578

579
        // Process scale min/max
580

581
        (*ppadfScaleMin)[iBand] = CPLAtof(aosTokens[1]);
7✔
582
        (*ppadfScaleMax)[iBand] = CPLAtof(aosTokens[2]);
7✔
583

584
        // process lut
585

586
        (*ppapanLUTs)[iBand] =
14✔
587
            static_cast<int *>(CPLCalloc(nLUTBins, sizeof(int)));
7✔
588

589
        for (int iLUT = 0; iLUT < nLUTBins; iLUT++)
1,799✔
590
            (*ppapanLUTs)[iBand][iLUT] = atoi(aosTokens[iLUT + 3]);
1,792✔
591
    }
592

593
    return CE_None;
2✔
594
}
595

596
/************************************************************************/
597
/*                      WriteLUTs()                                     */
598
/*                                                                      */
599
/*      Write the LUT for each band to a file or stdout.                */
600
/************************************************************************/
601

602
void WriteLUTs(int **papanLUTs, int nBandCount, int nLUTBins,
2✔
603
               double *padfScaleMin, double *padfScaleMax,
604
               const char *pszConfigFile)
605
{
606
    FILE *fpConfig = stdout;
2✔
607
    if (pszConfigFile)
2✔
608
        fpConfig = fopen(pszConfigFile, "w");
1✔
609

610
    for (int iBand = 0; iBand < nBandCount; iBand++)
8✔
611
    {
612
        fprintf(fpConfig, "%d:Band ", iBand + 1);
6✔
613
        fprintf(fpConfig, "%g:ScaleMin %g:ScaleMax ", padfScaleMin[iBand],
6✔
614
                padfScaleMax[iBand]);
6✔
615

616
        if (papanLUTs)
6✔
617
        {
618
            for (int iLUT = 0; iLUT < nLUTBins; iLUT++)
1,542✔
619
                fprintf(fpConfig, "%d ", papanLUTs[iBand][iLUT]);
1,536✔
620
        }
621
        fprintf(fpConfig, "\n");
6✔
622
    }
623

624
    if (pszConfigFile)
2✔
625
        fclose(fpConfig);
1✔
626
}
2✔
627

628
/************************************************************************/
629
/*                      WriteEnhanced()                                 */
630
/*                                                                      */
631
/*      Write an enhanced image using the provided LUTs.                */
632
/************************************************************************/
633

634
CPLErr WriteEnhanced(GDALDatasetH hDataset, int **papanLUTs, int nLUTBins,
4✔
635
                     double *padfScaleMin, double *padfScaleMax,
636
                     GDALDataType eOutputType, GDALDriverH hDriver,
637
                     const char *pszDest, char **papszCreateOptions,
638
                     GDALProgressFunc pfnProgress)
639
{
640
    int nBandCount = GDALGetRasterCount(hDataset);
4✔
641

642
    EnhanceCBInfo *pasEInfo = static_cast<EnhanceCBInfo *>(
643
        CPLCalloc(nBandCount, sizeof(EnhanceCBInfo)));
4✔
644

645
    /* -------------------------------------------------------------------- */
646
    /*      Make a virtual clone.                                           */
647
    /* -pixe------------------------------------------------------------------- */
648
    VRTDataset *poVDS = new VRTDataset(GDALGetRasterXSize(hDataset),
4✔
649
                                       GDALGetRasterYSize(hDataset));
4✔
650

651
    if (GDALGetGCPCount(hDataset) == 0)
4✔
652
    {
653
        const char *pszProjection = GDALGetProjectionRef(hDataset);
4✔
654
        if (pszProjection != nullptr && strlen(pszProjection) > 0)
4✔
655
            poVDS->SetProjection(pszProjection);
4✔
656

657
        GDALGeoTransform gt;
4✔
658
        if (GDALDataset::FromHandle(hDataset)->GetGeoTransform(gt) == CE_None)
4✔
659
            poVDS->SetGeoTransform(gt);
4✔
660
    }
661
    else
662
    {
663
        poVDS->SetGCPs(GDALGetGCPCount(hDataset), GDALGetGCPs(hDataset),
×
664
                       GDALGetGCPProjection(hDataset));
665
    }
666

667
    poVDS->SetMetadata(GDALDataset::FromHandle(hDataset)->GetMetadata());
4✔
668

669
    for (int iBand = 0; iBand < nBandCount; iBand++)
16✔
670
    {
671
        VRTSourcedRasterBand *poVRTBand;
672
        GDALRasterBand *poSrcBand;
673
        GDALDataType eBandType;
674

675
        poSrcBand = GDALDataset::FromHandle(hDataset)->GetRasterBand(iBand + 1);
12✔
676

677
        /* ---------------------------------------------------------------- */
678
        /*      Select output data type to match source.                    */
679
        /* ---------------------------------------------------------------- */
680
        if (eOutputType == GDT_Unknown)
12✔
681
            eBandType = GDT_Byte;
9✔
682
        else
683
            eBandType = eOutputType;
3✔
684

685
        /* ---------------------------------------------------------------- */
686
        /*      Create this band.                                           */
687
        /* ---------------------------------------------------------------- */
688
        poVDS->AddBand(eBandType, nullptr);
12✔
689
        poVRTBand = cpl::down_cast<VRTSourcedRasterBand *>(
12✔
690
            poVDS->GetRasterBand(iBand + 1));
691

692
        /* ---------------------------------------------------------------- */
693
        /*     Create a function based source with info on how to apply the */
694
        /*     enhancement.                                                 */
695
        /* ---------------------------------------------------------------- */
696
        pasEInfo[iBand].poSrcBand = poSrcBand;
12✔
697
        pasEInfo[iBand].eWrkType = eBandType;
12✔
698
        pasEInfo[iBand].dfScaleMin = padfScaleMin[iBand];
12✔
699
        pasEInfo[iBand].dfScaleMax = padfScaleMax[iBand];
12✔
700
        pasEInfo[iBand].nLUTBins = nLUTBins;
12✔
701

702
        if (papanLUTs)
12✔
703
            pasEInfo[iBand].panLUT = papanLUTs[iBand];
12✔
704

705
        poVRTBand->AddFuncSource(EnhancerCallback, pasEInfo + iBand);
12✔
706

707
        /* ---------------------------------------------------------------- */
708
        /*      copy over some other information of interest.               */
709
        /* ---------------------------------------------------------------- */
710
        poVRTBand->CopyCommonInfoFrom(poSrcBand);
12✔
711
    }
712

713
    /* -------------------------------------------------------------------- */
714
    /*      Write to the output file using CopyCreate().                    */
715
    /* -------------------------------------------------------------------- */
716
    GDALDatasetH hOutDS =
717
        GDALCreateCopy(hDriver, pszDest, static_cast<GDALDatasetH>(poVDS),
4✔
718
                       FALSE, papszCreateOptions, pfnProgress, nullptr);
719
    CPLErr eErr = CE_None;
4✔
720
    if (hOutDS == nullptr)
4✔
721
    {
722
        eErr = CE_Failure;
1✔
723
    }
724
    else
725
    {
726
        GDALClose(hOutDS);
3✔
727
    }
728

729
    GDALClose(poVDS);
4✔
730
    CPLFree(pasEInfo);
4✔
731

732
    return eErr;
4✔
733
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc