Coverage Report

Created: 2026-02-14 09:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/miramon/miramon_rasterband.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  MiraMonRaster driver
4
 * Purpose:  Implements MMRRasterBand class: responsible for converting the
5
 *           information stored in an MMRBand into a GDAL RasterBand
6
 * Author:   Abel Pau
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 2025, Xavier Pons
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "miramon_dataset.h"
15
#include "miramon_rasterband.h"
16
#include "miramon_band.h"  // Per a MMRBand
17
18
#include "../miramon_common/mm_gdal_functions.h"  // For MMCheck_REL_FILE()
19
20
/************************************************************************/
21
/*                           MMRRasterBand()                            */
22
/************************************************************************/
23
MMRRasterBand::MMRRasterBand(MMRDataset *poDSIn, int nBandIn)
24
3.27k
    : m_pfRel(poDSIn->GetRel())
25
3.27k
{
26
3.27k
    poDS = poDSIn;
27
3.27k
    nBand = nBandIn;
28
29
3.27k
    eAccess = poDSIn->GetAccess();
30
31
3.27k
    nRatOrCT = poDSIn->GetRatOrCT();
32
33
3.27k
    MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
34
3.27k
    if (poBand == nullptr)
35
0
        return;
36
37
    // Getting some band info
38
3.27k
    m_osBandSection = poBand->GetBandSection();
39
3.27k
    m_eMMRDataTypeMiraMon = poBand->GeteMMDataType();
40
3.27k
    m_eMMBytesPerPixel = poBand->GeteMMBytesPerPixel();
41
3.27k
    SetUnitType(poBand->GetUnits());
42
3.27k
    nBlockXSize = poBand->GetBlockXSize();
43
3.27k
    nBlockYSize = poBand->GetBlockYSize();
44
45
3.27k
    UpdateDataType();
46
47
    // We have a valid RasterBand.
48
3.27k
    m_bIsValid = true;
49
3.27k
}
50
51
/************************************************************************/
52
/*                           ~MMRRasterBand()                           */
53
/************************************************************************/
54
55
MMRRasterBand::~MMRRasterBand()
56
57
3.27k
{
58
3.27k
    FlushCache(true);
59
3.27k
}
60
61
/************************************************************************/
62
/*                           UpdateDataType()                           */
63
/************************************************************************/
64
void MMRRasterBand::UpdateDataType()
65
3.27k
{
66
3.27k
    switch (m_eMMRDataTypeMiraMon)
67
3.27k
    {
68
57
        case MMDataType::DATATYPE_AND_COMPR_BIT:
69
219
        case MMDataType::DATATYPE_AND_COMPR_BYTE:
70
1.48k
        case MMDataType::DATATYPE_AND_COMPR_BYTE_RLE:
71
1.48k
            eDataType = GDT_UInt8;
72
1.48k
            break;
73
74
9
        case MMDataType::DATATYPE_AND_COMPR_UINTEGER:
75
326
        case MMDataType::DATATYPE_AND_COMPR_UINTEGER_RLE:
76
326
            eDataType = GDT_UInt16;
77
326
            break;
78
79
23
        case MMDataType::DATATYPE_AND_COMPR_INTEGER:
80
326
        case MMDataType::DATATYPE_AND_COMPR_INTEGER_RLE:
81
326
        case MMDataType::DATATYPE_AND_COMPR_INTEGER_ASCII:
82
326
            eDataType = GDT_Int16;
83
326
            break;
84
85
13
        case MMDataType::DATATYPE_AND_COMPR_LONG:
86
300
        case MMDataType::DATATYPE_AND_COMPR_LONG_RLE:
87
300
            eDataType = GDT_Int32;
88
300
            break;
89
90
48
        case MMDataType::DATATYPE_AND_COMPR_REAL:
91
319
        case MMDataType::DATATYPE_AND_COMPR_REAL_RLE:
92
319
        case MMDataType::DATATYPE_AND_COMPR_REAL_ASCII:
93
319
            eDataType = GDT_Float32;
94
319
            break;
95
96
26
        case MMDataType::DATATYPE_AND_COMPR_DOUBLE:
97
514
        case MMDataType::DATATYPE_AND_COMPR_DOUBLE_RLE:
98
514
            eDataType = GDT_Float64;
99
514
            break;
100
101
0
        default:
102
0
            eDataType = GDT_UInt8;
103
            // This should really report an error, but this isn't
104
            // so easy from within constructors.
105
0
            CPLDebug("GDAL", "Unsupported pixel type in MMRRasterBand: %d.",
106
0
                     static_cast<int>(m_eMMRDataTypeMiraMon));
107
0
            break;
108
3.27k
    }
109
3.27k
}
110
111
/************************************************************************/
112
/*                           GetNoDataValue()                           */
113
/************************************************************************/
114
115
double MMRRasterBand::GetNoDataValue(int *pbSuccess)
116
117
6.50k
{
118
6.50k
    double dfNoData = 0.0;
119
6.50k
    if (pbSuccess)
120
6.42k
        *pbSuccess = FALSE;
121
122
6.50k
    MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
123
6.50k
    if (!poBand)
124
0
        return dfNoData;
125
126
6.50k
    if (!poBand->BandHasNoData())
127
6.13k
    {
128
6.13k
        if (pbSuccess)
129
6.13k
            *pbSuccess = FALSE;
130
6.13k
        return dfNoData;
131
6.13k
    }
132
133
370
    if (pbSuccess)
134
288
        *pbSuccess = TRUE;
135
370
    return poBand->GetNoDataValue();
136
6.50k
}
137
138
/************************************************************************/
139
/*                             GetMinimum()                             */
140
/************************************************************************/
141
142
double MMRRasterBand::GetMinimum(int *pbSuccess)
143
144
0
{
145
0
    if (pbSuccess)
146
0
        *pbSuccess = FALSE;
147
148
0
    MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
149
0
    if (!poBand || !poBand->GetMinSet())
150
0
        return 0.0;
151
152
0
    if (pbSuccess)
153
0
        *pbSuccess = TRUE;
154
155
0
    return poBand->GetMin();
156
0
}
157
158
/************************************************************************/
159
/*                             GetMaximum()                             */
160
/************************************************************************/
161
162
double MMRRasterBand::GetMaximum(int *pbSuccess)
163
164
0
{
165
0
    if (pbSuccess)
166
0
        *pbSuccess = FALSE;
167
168
0
    MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
169
0
    if (!poBand || !poBand->GetMaxSet())
170
0
        return 0.0;
171
172
0
    if (pbSuccess)
173
0
        *pbSuccess = TRUE;
174
175
0
    return poBand->GetMax();
176
0
}
177
178
/************************************************************************/
179
/*                            GetUnitType()                             */
180
/************************************************************************/
181
182
const char *MMRRasterBand::GetUnitType()
183
184
2.14k
{
185
2.14k
    return m_osUnitType.c_str();
186
2.14k
}
187
188
/************************************************************************/
189
/*                            SetUnitType()                             */
190
/************************************************************************/
191
192
CPLErr MMRRasterBand::SetUnitType(const char *pszUnit)
193
194
3.27k
{
195
3.27k
    if (pszUnit == nullptr)
196
0
        m_osUnitType.clear();
197
3.27k
    else
198
3.27k
        m_osUnitType = pszUnit;
199
200
3.27k
    return CE_None;
201
3.27k
}
202
203
/************************************************************************/
204
/*                             IReadBlock()                             */
205
/************************************************************************/
206
207
CPLErr MMRRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
208
209
38.5k
{
210
38.5k
    CPLErr eErr = CE_None;
211
212
38.5k
    if (nBand < 1 || nBand > m_pfRel->GetNBands())
213
0
        return CE_Failure;
214
215
38.5k
    MMRBand *pBand = m_pfRel->GetBand(nBand - 1);
216
38.5k
    if (!pBand)
217
0
        return CE_Failure;
218
38.5k
    eErr = pBand->GetRasterBlock(nBlockXOff, nBlockYOff, pImage,
219
38.5k
                                 nBlockXSize * nBlockYSize *
220
38.5k
                                     GDALGetDataTypeSizeBytes(eDataType));
221
222
38.5k
    if (eErr == CE_None &&
223
35.9k
        m_eMMRDataTypeMiraMon == MMDataType::DATATYPE_AND_COMPR_BIT)
224
3.13k
    {
225
3.13k
        GByte *pabyData = static_cast<GByte *>(pImage);
226
227
3.13k
        for (int nIAccumulated = nBlockXSize * nBlockYSize - 1;
228
98.0k
             nIAccumulated >= 0; nIAccumulated--)
229
94.9k
        {
230
94.9k
            if ((pabyData[nIAccumulated >> 3] & (1 << (nIAccumulated & 0x7))))
231
40.8k
                pabyData[nIAccumulated] = 1;
232
54.1k
            else
233
54.1k
                pabyData[nIAccumulated] = 0;
234
94.9k
        }
235
3.13k
    }
236
237
38.5k
    return eErr;
238
38.5k
}
239
240
/************************************************************************/
241
/*                           GetColorTable()                            */
242
/************************************************************************/
243
244
GDALColorTable *MMRRasterBand::GetColorTable()
245
324
{
246
    // If user doesn't want the CT, it's skipped
247
324
    if (nRatOrCT != RAT_OR_CT::ALL && nRatOrCT != RAT_OR_CT::CT)
248
0
        return nullptr;
249
250
324
    if (m_bTriedLoadColorTable)
251
0
        return m_poCT.get();
252
253
324
    m_bTriedLoadColorTable = true;
254
255
324
    m_Palette = std::make_unique<MMRPalettes>(*m_pfRel, nBand);
256
257
324
    if (!m_Palette->IsValid())
258
298
    {
259
298
        m_Palette = nullptr;
260
298
        return nullptr;
261
298
    }
262
263
26
    m_poCT = std::make_unique<GDALColorTable>();
264
265
    /*
266
    * GDALPaletteInterp
267
    */
268
269
26
    if (CE_None != UpdateTableColorsFromPalette())
270
0
    {
271
        // No color table available. Perhaps some attribute table with the colors?
272
0
        m_poCT = nullptr;
273
0
        return m_poCT.get();
274
0
    }
275
276
26
    ConvertColorsFromPaletteToColorTable();
277
278
26
    return m_poCT.get();
279
26
}
280
281
/************************************************************************/
282
/*                       GetColorInterpretation()                       */
283
/************************************************************************/
284
285
GDALColorInterp MMRRasterBand::GetColorInterpretation()
286
324
{
287
324
    GDALColorTable *ct = GetColorTable();
288
289
324
    if (ct)
290
26
        return GCI_PaletteIndex;
291
292
298
    return GCI_GrayIndex;
293
324
}
294
295
/************************************************************************/
296
/*                           GetDefaultRAT()                            */
297
/************************************************************************/
298
299
GDALRasterAttributeTable *MMRRasterBand::GetDefaultRAT()
300
301
0
{
302
    // If user doesn't want the RAT, it's skipped
303
0
    if (nRatOrCT != RAT_OR_CT::ALL && nRatOrCT != RAT_OR_CT::RAT)
304
0
        return nullptr;
305
306
0
    if (m_poDefaultRAT != nullptr)
307
0
        return m_poDefaultRAT.get();
308
309
0
    m_poDefaultRAT = std::make_unique<GDALDefaultRasterAttributeTable>();
310
311
0
    if (CE_None != FillRATFromPalette())
312
0
    {
313
0
        m_poDefaultRAT = nullptr;
314
0
    }
315
316
0
    return m_poDefaultRAT.get();
317
0
}
318
319
CPLErr MMRRasterBand::FillRATFromPalette()
320
321
0
{
322
0
    CPLString os_IndexJoin;
323
324
0
    MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
325
0
    if (poBand == nullptr)
326
0
        return CE_None;
327
328
0
    GetColorTable();
329
0
    if (poBand->GetShortRATName().empty() && !m_poCT)
330
0
    {
331
        // I don't have any associated attribute table but
332
        // perhaps I can create an attribute table with
333
        // the colors (if I have them and are not at the color table)
334
        // assigned to the pixels).
335
0
        if (CE_None != UpdateAttributeColorsFromPalette())
336
0
            return CE_Failure;
337
338
0
        return CE_None;
339
0
    }
340
341
    // Let's see the conditions to have a RAT
342
0
    CPLString osRELName, osDBFName, osAssociateRel;
343
0
    if (CE_None != GetRATName(osRELName, osDBFName, osAssociateRel) ||
344
0
        osDBFName.empty() || osAssociateRel.empty())
345
0
    {
346
0
        return CE_Failure;
347
0
    }
348
349
    // Let's create and fill the RAT
350
0
    if (CE_None != CreateRATFromDBF(osRELName, osDBFName, osAssociateRel))
351
0
        return CE_Failure;
352
353
0
    return CE_None;
354
0
}
355
356
CPLErr MMRRasterBand::UpdateAttributeColorsFromPalette()
357
358
0
{
359
    // If there is no palette, let's get one
360
0
    if (!m_Palette)
361
0
    {
362
0
        m_Palette = std::make_unique<MMRPalettes>(*m_pfRel, nBand);
363
364
0
        if (!m_Palette->IsValid())
365
0
        {
366
0
            m_Palette = nullptr;
367
0
            return CE_None;
368
0
        }
369
0
    }
370
371
0
    return FromPaletteToAttributeTable();
372
0
}
373
374
CPLErr MMRRasterBand::CreateRATFromDBF(const CPLString &osRELName,
375
                                       const CPLString &osDBFName,
376
                                       const CPLString &osAssociateRel)
377
0
{
378
    // If there is no palette, let's try to get one
379
    // and try to get a normal RAT.
380
0
    if (!m_Palette)
381
0
    {
382
0
        m_Palette = std::make_unique<MMRPalettes>(*m_pfRel, nBand);
383
384
0
        if (!m_Palette->IsValid() || !m_Palette->IsCategorical())
385
0
            m_Palette = nullptr;
386
0
    }
387
388
0
    struct MM_DATA_BASE_XP oAttributteTable;
389
0
    memset(&oAttributteTable, 0, sizeof(oAttributteTable));
390
391
0
    if (!osRELName.empty())
392
0
    {
393
0
        if (MM_ReadExtendedDBFHeaderFromFile(
394
0
                osDBFName.c_str(), &oAttributteTable, osRELName.c_str()))
395
0
        {
396
0
            CPLError(CE_Failure, CPLE_NotSupported,
397
0
                     "Error reading attribute table \"%s\".",
398
0
                     osDBFName.c_str());
399
0
            return CE_None;
400
0
        }
401
0
    }
402
0
    else
403
0
    {
404
0
        if (MM_ReadExtendedDBFHeaderFromFile(osDBFName.c_str(),
405
0
                                             &oAttributteTable, nullptr))
406
0
        {
407
0
            CPLError(CE_Failure, CPLE_NotSupported,
408
0
                     "Error reading attribute table \"%s\".",
409
0
                     osDBFName.c_str());
410
0
            return CE_None;
411
0
        }
412
0
    }
413
414
0
    MM_EXT_DBF_N_FIELDS nIField;
415
0
    MM_EXT_DBF_N_FIELDS nFieldIndex = oAttributteTable.nFields;
416
0
    MM_EXT_DBF_N_FIELDS nCategIndex = oAttributteTable.nFields;
417
0
    for (nIField = 0; nIField < oAttributteTable.nFields; nIField++)
418
0
    {
419
0
        if (EQUAL(oAttributteTable.pField[nIField].FieldName, osAssociateRel))
420
0
        {
421
0
            nFieldIndex = nIField;
422
0
            if (nIField + 1 < oAttributteTable.nFields)
423
0
                nCategIndex = nIField + 1;
424
0
            else if (nIField > 1)
425
0
                nCategIndex = nIField - 1;
426
0
            break;
427
0
        }
428
0
    }
429
430
0
    if (nFieldIndex == oAttributteTable.nFields)
431
0
    {
432
0
        CPLError(CE_Failure, CPLE_AppDefined, "Invalid attribute table: \"%s\"",
433
0
                 oAttributteTable.szFileName);
434
0
        return CE_Failure;
435
0
    }
436
437
0
    if (oAttributteTable.pField[nFieldIndex].FieldType != 'N')
438
0
    {
439
0
        CPLError(CE_Failure, CPLE_AppDefined,
440
0
                 "Invalid attribute table field: \"%s\"",
441
0
                 oAttributteTable.szFileName);
442
0
        return CE_Failure;
443
0
    }
444
445
0
    int nNRATColumns = 0;
446
    // 0 column: category value
447
0
    if (oAttributteTable.pField[nFieldIndex].DecimalsIfFloat)
448
0
    {
449
0
        if (CE_None != m_poDefaultRAT->CreateColumn(
450
0
                           oAttributteTable.pField[nFieldIndex].FieldName,
451
0
                           GFT_Real, GFU_MinMax))
452
0
            return CE_Failure;
453
454
0
        nNRATColumns++;
455
0
    }
456
0
    else
457
0
    {
458
0
        if (CE_None != m_poDefaultRAT->CreateColumn(
459
0
                           oAttributteTable.pField[nFieldIndex].FieldName,
460
0
                           GFT_Integer, GFU_MinMax))
461
0
            return CE_Failure;
462
463
0
        nNRATColumns++;
464
0
    }
465
466
0
    GDALRATFieldUsage eFieldUsage;
467
0
    GDALRATFieldType eFieldType;
468
469
0
    for (nIField = 0; nIField < oAttributteTable.nFields; nIField++)
470
0
    {
471
0
        if (nIField == nFieldIndex)
472
0
            continue;
473
474
0
        if (oAttributteTable.pField[nIField].FieldType == 'N')
475
0
        {
476
0
            eFieldUsage = GFU_MinMax;
477
0
            if (oAttributteTable.pField[nIField].DecimalsIfFloat)
478
0
                eFieldType = GFT_Real;
479
0
            else
480
0
                eFieldType = GFT_Integer;
481
0
        }
482
0
        else
483
0
        {
484
0
            eFieldUsage = GFU_Generic;
485
0
            eFieldType = GFT_String;
486
0
        }
487
0
        if (nIField == nCategIndex)
488
0
            eFieldUsage = GFU_Name;
489
490
0
        if (CE_None != m_poDefaultRAT->CreateColumn(
491
0
                           oAttributteTable.pField[nIField].FieldName,
492
0
                           eFieldType, eFieldUsage))
493
0
            return CE_Failure;
494
495
0
        nNRATColumns++;
496
0
    }
497
498
0
    VSIFSeekL(oAttributteTable.pfDataBase,
499
0
              static_cast<vsi_l_offset>(oAttributteTable.FirstRecordOffset),
500
0
              SEEK_SET);
501
0
    m_poDefaultRAT->SetRowCount(nNRATColumns);
502
503
0
    MM_ACCUMULATED_BYTES_TYPE_DBF nBufferSize =
504
0
        oAttributteTable.BytesPerRecord + 1;
505
0
    char *pzsRecord = static_cast<char *>(VSI_CALLOC_VERBOSE(1, nBufferSize));
506
0
    if (!pzsRecord)
507
0
    {
508
0
        CPLError(CE_Failure, CPLE_OutOfMemory,
509
0
                 "Out of memory allocating working buffer");
510
0
        VSIFCloseL(oAttributteTable.pfDataBase);
511
0
        MM_ReleaseMainFields(&oAttributteTable);
512
0
    }
513
514
0
    char *pszField = static_cast<char *>(VSI_CALLOC_VERBOSE(1, nBufferSize));
515
0
    if (!pszField)
516
0
    {
517
0
        CPLError(CE_Failure, CPLE_OutOfMemory,
518
0
                 "Out of memory allocating working buffer");
519
0
        VSIFree(pzsRecord);
520
0
        VSIFCloseL(oAttributteTable.pfDataBase);
521
0
        MM_ReleaseMainFields(&oAttributteTable);
522
0
    }
523
524
0
    for (int nIRecord = 0;
525
0
         nIRecord < static_cast<int>(oAttributteTable.nRecords); nIRecord++)
526
0
    {
527
0
        if (oAttributteTable.BytesPerRecord !=
528
0
            VSIFReadL(pzsRecord, sizeof(unsigned char),
529
0
                      oAttributteTable.BytesPerRecord,
530
0
                      oAttributteTable.pfDataBase))
531
0
        {
532
0
            CPLError(CE_Failure, CPLE_AppDefined,
533
0
                     "Invalid attribute table: \"%s\"", osDBFName.c_str());
534
535
0
            VSIFree(pzsRecord);
536
0
            VSIFree(pszField);
537
0
            VSIFCloseL(oAttributteTable.pfDataBase);
538
0
            MM_ReleaseMainFields(&oAttributteTable);
539
0
            return CE_Failure;
540
0
        }
541
542
        // Category index
543
0
        memcpy(pszField,
544
0
               pzsRecord +
545
0
                   oAttributteTable.pField[nFieldIndex].AccumulatedBytes,
546
0
               oAttributteTable.pField[nFieldIndex].BytesPerField);
547
0
        pszField[oAttributteTable.pField[nFieldIndex].BytesPerField] = '\0';
548
0
        CPLString osCatField = pszField;
549
550
0
        int nCatField;
551
0
        if (1 != sscanf(osCatField, "%d", &nCatField))
552
0
        {
553
0
            CPLError(CE_Failure, CPLE_AppDefined,
554
0
                     "Invalid attribute table: \"%s\"", osDBFName.c_str());
555
556
0
            VSIFree(pzsRecord);
557
0
            VSIFree(pszField);
558
0
            VSIFCloseL(oAttributteTable.pfDataBase);
559
0
            MM_ReleaseMainFields(&oAttributteTable);
560
0
            return CE_Failure;
561
0
        }
562
0
        m_poDefaultRAT->SetValue(nCatField, 0, osCatField.c_str());
563
564
0
        int nIOrderedField = 1;
565
0
        for (nIField = 0; nIField < oAttributteTable.nFields; nIField++)
566
0
        {
567
0
            if (nIField == nFieldIndex)
568
0
                continue;
569
570
            // Category value
571
0
            memcpy(pszField,
572
0
                   pzsRecord +
573
0
                       oAttributteTable.pField[nIField].AccumulatedBytes,
574
0
                   oAttributteTable.pField[nIField].BytesPerField);
575
0
            pszField[oAttributteTable.pField[nIField].BytesPerField] = '\0';
576
577
0
            if (oAttributteTable.CharSet == MM_JOC_CARAC_OEM850_DBASE)
578
0
                MM_oemansi(pszField);
579
580
0
            CPLString osField = pszField;
581
0
            osField.Trim();
582
583
0
            if (oAttributteTable.CharSet != MM_JOC_CARAC_UTF8_DBF &&
584
0
                oAttributteTable.pField[nIField].FieldType != 'N')
585
0
            {
586
                // MiraMon encoding is ISO 8859-1 (Latin1) -> Recode to UTF-8
587
0
                osField.Recode(CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
588
0
            }
589
590
0
            if (1 != sscanf(osCatField, "%d", &nCatField))
591
0
            {
592
0
                CPLError(CE_Failure, CPLE_AppDefined,
593
0
                         "Invalid attribute table: \"%s\"", osDBFName.c_str());
594
595
0
                VSIFree(pzsRecord);
596
0
                VSIFree(pszField);
597
0
                VSIFCloseL(oAttributteTable.pfDataBase);
598
0
                MM_ReleaseMainFields(&oAttributteTable);
599
0
                return CE_Failure;
600
0
            }
601
0
            m_poDefaultRAT->SetValue(nCatField, nIOrderedField,
602
0
                                     osField.c_str());
603
0
            nIOrderedField++;
604
0
        }
605
0
    }
606
607
0
    VSIFree(pszField);
608
0
    VSIFree(pzsRecord);
609
0
    VSIFCloseL(oAttributteTable.pfDataBase);
610
0
    MM_ReleaseMainFields(&oAttributteTable);
611
612
0
    return CE_None;
613
0
}
614
615
CPLErr MMRRasterBand::UpdateTableColorsFromPalette()
616
617
26
{
618
26
    if (!m_Palette || !m_Palette->IsValid())
619
0
        return CE_Failure;
620
621
26
    if (m_Palette->IsConstantColor())
622
2
        return AssignUniformColorTable();
623
624
24
    CPLErr peErr;
625
24
    if (m_Palette->IsCategorical())
626
24
        peErr = FromPaletteToColorTableCategoricalMode();
627
0
    else
628
0
        peErr = FromPaletteToColorTableContinuousMode();
629
630
24
    return peErr;
631
26
}
632
633
CPLErr MMRRasterBand::AssignUniformColorTable()
634
635
2
{
636
2
    MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
637
2
    if (!poBand)
638
0
        return CE_Failure;
639
640
    // Only for 1 or 2 bytes images
641
2
    if (m_eMMBytesPerPixel !=
642
2
            MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_BYTE_I_RLE &&
643
1
        m_eMMBytesPerPixel !=
644
1
            MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_INTEGER_I_RLE)
645
1
    {
646
1
        return CE_None;
647
1
    }
648
649
1
    const int nNPossibleValues = 1
650
1
                                 << (8 * static_cast<int>(m_eMMBytesPerPixel));
651
5
    for (int iColumn = 0; iColumn < 4; iColumn++)
652
4
    {
653
4
        try
654
4
        {
655
4
            m_aadfPCT[iColumn].resize(nNPossibleValues);
656
4
        }
657
4
        catch (std::bad_alloc &e)
658
4
        {
659
0
            CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
660
0
            return CE_Failure;
661
0
        }
662
4
    }
663
664
257
    for (int nITableColor = 0; nITableColor < nNPossibleValues; nITableColor++)
665
256
    {
666
256
        if (poBand->BandHasNoData() && nITableColor == poBand->GetNoDataValue())
667
0
        {
668
0
            m_aadfPCT[0][nITableColor] = 0;
669
0
            m_aadfPCT[1][nITableColor] = 0;
670
0
            m_aadfPCT[2][nITableColor] = 0;
671
0
            m_aadfPCT[3][nITableColor] = 0;
672
0
        }
673
256
        else
674
256
        {
675
            // Before the minimum, we apply the color of the first
676
            // element (as a placeholder).
677
256
            m_aadfPCT[0][nITableColor] = m_Palette->GetConstantColorRGB().c1;
678
256
            m_aadfPCT[1][nITableColor] = m_Palette->GetConstantColorRGB().c2;
679
256
            m_aadfPCT[2][nITableColor] = m_Palette->GetConstantColorRGB().c3;
680
256
            m_aadfPCT[3][nITableColor] = 255;
681
256
        }
682
256
    }
683
684
1
    return CE_None;
685
1
}
686
687
// Converts palette Colors to Colors of pixels
688
CPLErr MMRRasterBand::FromPaletteToColorTableCategoricalMode()
689
690
24
{
691
24
    if (!m_Palette)
692
0
        return CE_Failure;
693
694
24
    if (!m_Palette->IsCategorical())
695
0
        return CE_Failure;
696
697
    // If the palette is not loaded, then, ignore the conversion silently
698
24
    if (m_Palette->GetSizeOfPaletteColors() == 0)
699
0
        return CE_Failure;
700
701
24
    if (m_Palette->GetColorScaling() == ColorTreatment::DEFAULT_SCALING)
702
0
        m_Palette->SetColorScaling(ColorTreatment::DIRECT_ASSIGNATION);
703
24
    else if (m_Palette->GetColorScaling() != ColorTreatment::DIRECT_ASSIGNATION)
704
0
        return CE_Failure;
705
706
    // Getting number of color in the palette
707
24
    int nNPaletteColors = m_Palette->GetSizeOfPaletteColors();
708
24
    int nNPossibleValues;
709
710
24
    if (m_eMMRDataTypeMiraMon != MMDataType::DATATYPE_AND_COMPR_BYTE &&
711
23
        m_eMMRDataTypeMiraMon != MMDataType::DATATYPE_AND_COMPR_BYTE_RLE &&
712
21
        m_eMMRDataTypeMiraMon != MMDataType::DATATYPE_AND_COMPR_UINTEGER &&
713
21
        m_eMMRDataTypeMiraMon != MMDataType::DATATYPE_AND_COMPR_UINTEGER_RLE)
714
20
    {
715
        // Rare case where its a not byte or uinteger img file
716
        // but it has a categorical palettte.
717
20
        nNPossibleValues = nNPaletteColors;
718
20
    }
719
4
    else
720
4
    {
721
        // To relax Coverity Scan (CID 1620826)
722
4
        MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
723
4
        if (!poBand)
724
0
            return CE_Failure;
725
726
4
        if (m_Palette->IsAutomatic() && poBand->GetMaxSet())
727
0
        {
728
            // In that case (byte, uint) we can limit the number
729
            // of colours at the maximum value that the band has.
730
0
            nNPossibleValues = static_cast<int>(poBand->GetMax()) + 1;
731
0
        }
732
4
        else
733
4
        {
734
4
            CPLAssert(static_cast<int>(m_eMMBytesPerPixel) > 0);
735
4
            nNPossibleValues = 1 << (8 * static_cast<int>(m_eMMBytesPerPixel));
736
4
        }
737
4
    }
738
739
120
    for (int iColumn = 0; iColumn < 4; iColumn++)
740
96
    {
741
96
        try
742
96
        {
743
96
            m_aadfPCT[iColumn].resize(nNPossibleValues);
744
96
        }
745
96
        catch (std::bad_alloc &e)
746
96
        {
747
0
            CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
748
0
            return CE_Failure;
749
0
        }
750
96
    }
751
752
    // No more colors than needed.
753
24
    if (nNPaletteColors > nNPossibleValues)
754
0
        nNPaletteColors = nNPossibleValues;
755
756
24
    int nIPaletteColor = 0;
757
6.16k
    for (nIPaletteColor = 0; nIPaletteColor < nNPaletteColors; nIPaletteColor++)
758
6.14k
    {
759
6.14k
        m_aadfPCT[0][nIPaletteColor] =
760
6.14k
            m_Palette->GetPaletteColorsValue(0, nIPaletteColor);
761
6.14k
        m_aadfPCT[1][nIPaletteColor] =
762
6.14k
            m_Palette->GetPaletteColorsValue(1, nIPaletteColor);
763
6.14k
        m_aadfPCT[2][nIPaletteColor] =
764
6.14k
            m_Palette->GetPaletteColorsValue(2, nIPaletteColor);
765
6.14k
        m_aadfPCT[3][nIPaletteColor] =
766
6.14k
            m_Palette->GetPaletteColorsValue(3, nIPaletteColor);
767
6.14k
    }
768
769
    // Rest of colors
770
65.3k
    for (; nIPaletteColor < nNPossibleValues; nIPaletteColor++)
771
65.2k
    {
772
65.2k
        m_aadfPCT[0][nIPaletteColor] = m_Palette->GetDefaultColorRGB().c1;
773
65.2k
        m_aadfPCT[1][nIPaletteColor] = m_Palette->GetDefaultColorRGB().c2;
774
65.2k
        m_aadfPCT[2][nIPaletteColor] = m_Palette->GetDefaultColorRGB().c3;
775
65.2k
        m_aadfPCT[3][nIPaletteColor] = m_Palette->GetDefaultColorRGB().c4;
776
65.2k
    }
777
778
24
    return CE_None;
779
24
}
780
781
// Converts paletteColors to Colors of pixels for the Color Table
782
CPLErr MMRRasterBand::FromPaletteToColorTableContinuousMode()
783
784
0
{
785
0
    if (!m_Palette)
786
0
        return CE_Failure;
787
788
0
    if (m_Palette->IsCategorical())
789
0
        return CE_Failure;
790
791
    // TODO: more types of scaling
792
0
    if (m_Palette->GetColorScaling() != ColorTreatment::LINEAR_SCALING &&
793
0
        m_Palette->GetColorScaling() != ColorTreatment::DIRECT_ASSIGNATION)
794
0
        return CE_Failure;
795
796
0
    MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
797
0
    if (!poBand)
798
0
        return CE_Failure;
799
800
0
    bool bAcceptPalette = false;
801
0
    if ((m_eMMRDataTypeMiraMon == MMDataType::DATATYPE_AND_COMPR_BYTE ||
802
0
         m_eMMRDataTypeMiraMon == MMDataType::DATATYPE_AND_COMPR_BYTE_RLE) &&
803
0
        (m_Palette->GetColorScaling() == ColorTreatment::LINEAR_SCALING ||
804
0
         m_Palette->GetColorScaling() == ColorTreatment::DIRECT_ASSIGNATION))
805
0
        bAcceptPalette = true;
806
0
    else if ((m_eMMRDataTypeMiraMon ==
807
0
                  MMDataType::DATATYPE_AND_COMPR_UINTEGER ||
808
0
              m_eMMRDataTypeMiraMon ==
809
0
                  MMDataType::DATATYPE_AND_COMPR_UINTEGER_RLE) &&
810
0
             m_Palette->GetColorScaling() == ColorTreatment::DIRECT_ASSIGNATION)
811
0
        bAcceptPalette = true;
812
813
0
    if (!bAcceptPalette)
814
0
        return CE_Failure;  // Attribute table
815
816
    // Some necessary information
817
0
    if (!poBand->GetVisuMinSet() || !poBand->GetVisuMaxSet())
818
0
        return CE_Failure;
819
820
    // To relax Coverity Scan (CID 1620843)
821
0
    CPLAssert(static_cast<int>(m_eMMBytesPerPixel) > 0);
822
823
0
    const int nNPossibleValues = 1
824
0
                                 << (8 * static_cast<int>(m_eMMBytesPerPixel));
825
0
    for (int iColumn = 0; iColumn < 4; iColumn++)
826
0
    {
827
0
        try
828
0
        {
829
0
            m_aadfPCT[iColumn].resize(nNPossibleValues);
830
0
        }
831
0
        catch (std::bad_alloc &e)
832
0
        {
833
0
            CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
834
0
            return CE_Failure;
835
0
        }
836
0
    }
837
838
0
    if (static_cast<int>(m_eMMBytesPerPixel) > 2 &&
839
0
        m_Palette->GetNumberOfColors() < nNPossibleValues)
840
0
        return CE_Failure;
841
842
0
    if (m_Palette->GetNumberOfColors() < 1)
843
0
        return CE_Failure;
844
845
0
    int nFirstValidPaletteIndex;
846
0
    unsigned short nIndexColor;
847
0
    double dfSlope = 1, dfIntercept = 0;
848
849
0
    if (m_Palette->HasNodata() && m_Palette->GetNoDataPaletteIndex() == 0)
850
0
        nFirstValidPaletteIndex = 1;
851
0
    else
852
0
        nFirstValidPaletteIndex = 0;
853
854
0
    int nIPaletteColorNoData = 0;
855
0
    if (static_cast<int>(m_eMMBytesPerPixel) == 2 ||
856
0
        m_Palette->GetColorScaling() != ColorTreatment::DIRECT_ASSIGNATION)
857
0
    {
858
        // A scaling is applied between the minimum and maximum display values.
859
0
        dfSlope = (static_cast<double>(m_Palette->GetNumberOfColors()) - 1) /
860
0
                  (poBand->GetVisuMax() - poBand->GetVisuMin());
861
862
0
        dfIntercept = -dfSlope * poBand->GetVisuMin();
863
864
0
        if (poBand->BandHasNoData())
865
0
        {
866
0
            if (m_Palette->GetNoDataPaletteIndex() ==
867
0
                m_Palette->GetNumberOfColors())
868
0
                nIPaletteColorNoData = nNPossibleValues - 1;
869
0
        }
870
0
    }
871
872
0
    for (int nIPaletteColor = 0; nIPaletteColor < nNPossibleValues;
873
0
         nIPaletteColor++)
874
0
    {
875
0
        if (poBand->BandHasNoData() && nIPaletteColor == nIPaletteColorNoData)
876
0
        {
877
0
            if (m_Palette->HasNodata())
878
0
                AssignRGBColor(nIPaletteColor,
879
0
                               m_Palette->GetNoDataPaletteIndex());
880
0
            else
881
0
                AssignRGBColorDirectly(nIPaletteColor, 255);
882
0
        }
883
0
        else
884
0
        {
885
0
            if (nIPaletteColor < static_cast<int>(poBand->GetVisuMin()))
886
0
            {
887
                // Before the minimum, we apply the color of the first
888
                // element (as a placeholder).
889
0
                AssignRGBColor(nIPaletteColor, 0);
890
0
            }
891
0
            else if (nIPaletteColor <= static_cast<int>(poBand->GetVisuMax()))
892
0
            {
893
                // Between the minimum and maximum, we apply the value
894
                // read from the table.
895
0
                if (static_cast<int>(m_eMMBytesPerPixel) < 2 ||
896
0
                    m_Palette->GetColorScaling() ==
897
0
                        ColorTreatment::DIRECT_ASSIGNATION)
898
0
                {
899
                    // The value is applied directly.
900
0
                    AssignRGBColor(nIPaletteColor, nFirstValidPaletteIndex);
901
0
                    nFirstValidPaletteIndex++;
902
0
                }
903
0
                else
904
0
                {
905
                    // The value is applied according to the scaling.
906
0
                    nIndexColor = static_cast<unsigned short>(
907
0
                        dfSlope * nIPaletteColor + dfIntercept);
908
0
                    if (nIndexColor > m_Palette->GetNumberOfColors())
909
0
                        nIndexColor = static_cast<unsigned short>(
910
0
                            m_Palette->GetNumberOfColors());
911
0
                    AssignRGBColor(nIPaletteColor, nIndexColor);
912
0
                }
913
0
            }
914
0
            else
915
0
            {
916
                // After the maximum, we apply the value of the last
917
                // element (as a placeholder).
918
0
                AssignRGBColor(nIPaletteColor,
919
0
                               m_Palette->GetNumberOfColors() - 1);
920
0
            }
921
0
        }
922
0
    }
923
924
0
    return CE_None;
925
0
}
926
927
CPLErr MMRRasterBand::GetRATName(CPLString &osRELName, CPLString &osDBFName,
928
                                 CPLString &osAssociateREL)
929
0
{
930
0
    MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
931
0
    if (!poBand)
932
0
        return CE_Failure;
933
934
0
    if (poBand->GetShortRATName().empty())
935
0
        return CE_None;  // There is no RAT
936
937
0
    CPLString osExtension = CPLGetExtensionSafe(poBand->GetShortRATName());
938
0
    if (osExtension.tolower() == "rel")
939
0
    {
940
        // Get path relative to REL file
941
0
        osRELName = CPLFormFilenameSafe(
942
0
            CPLGetPathSafe(m_pfRel->GetRELNameChar()).c_str(),
943
0
            poBand->GetShortRATName(), "");
944
945
        // Getting information from the associated REL
946
0
        MMRRel localRel(osRELName, false);
947
0
        CPLString osShortDBFName;
948
949
0
        if (!localRel.GetMetadataValue(SECTION_TAULA_PRINCIPAL, KEY_NomFitxer,
950
0
                                       osShortDBFName) ||
951
0
            osShortDBFName.empty())
952
0
        {
953
0
            osRELName = "";
954
0
            return CE_Failure;
955
0
        }
956
957
        // Get path relative to REL file
958
0
        osDBFName = CPLFormFilenameSafe(
959
0
            CPLGetPathSafe(localRel.GetRELNameChar()).c_str(), osShortDBFName,
960
0
            "");
961
962
0
        if (!localRel.GetMetadataValue(SECTION_TAULA_PRINCIPAL, "AssociatRel",
963
0
                                       osAssociateREL) ||
964
0
            osAssociateREL.empty())
965
0
        {
966
0
            osRELName = "";
967
0
            return CE_Failure;
968
0
        }
969
970
0
        CPLString osSection = SECTION_TAULA_PRINCIPAL;
971
0
        osSection.append(":");
972
0
        osSection.append(osAssociateREL);
973
974
0
        CPLString osTactVar;
975
976
0
        if (localRel.GetMetadataValue(osSection, KEY_TractamentVariable,
977
0
                                      osTactVar) &&
978
0
            osTactVar == "Categoric")
979
0
            m_poDefaultRAT->SetTableType(GRTT_THEMATIC);
980
0
        else
981
0
        {
982
0
            osRELName = "";
983
0
            return CE_Failure;
984
0
        }
985
986
0
        return CE_None;
987
0
    }
988
989
0
    osExtension = CPLGetExtensionSafe(poBand->GetShortRATName());
990
0
    if (osExtension.tolower() == "dbf")
991
0
    {
992
0
        if (CPLIsFilenameRelative(poBand->GetShortRATName()))
993
0
        {
994
            // Get path relative to REL file
995
0
            osDBFName = CPLFormFilenameSafe(
996
0
                CPLGetPathSafe(m_pfRel->GetRELNameChar()).c_str(),
997
0
                poBand->GetShortRATName(), "");
998
0
        }
999
0
        else
1000
0
            osDBFName = poBand->GetShortRATName();
1001
1002
0
        osAssociateREL = poBand->GetAssociateREL();
1003
0
        if (osAssociateREL.empty())
1004
0
        {
1005
0
            osRELName = "";
1006
0
            osDBFName = "";
1007
0
            return CE_Failure;
1008
0
        }
1009
0
        m_poDefaultRAT->SetTableType(GRTT_THEMATIC);
1010
0
        return CE_None;
1011
0
    }
1012
1013
0
    osRELName = "";
1014
0
    osDBFName = "";
1015
0
    osAssociateREL = "";
1016
0
    return CE_Failure;
1017
0
}
1018
1019
// Converts paletteColors to Colors of pixels in the attribute table
1020
CPLErr MMRRasterBand::FromPaletteToAttributeTable()
1021
1022
0
{
1023
0
    if (!m_Palette)
1024
0
        return CE_None;
1025
1026
    // TODO: more types of scaling
1027
0
    if (m_Palette->GetColorScaling() != ColorTreatment::LINEAR_SCALING &&
1028
0
        m_Palette->GetColorScaling() != ColorTreatment::DIRECT_ASSIGNATION)
1029
0
        return CE_Failure;
1030
1031
0
    MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
1032
0
    if (!poBand)
1033
0
        return CE_Failure;
1034
1035
0
    if (m_Palette->IsConstantColor())
1036
0
        return FromPaletteToAttributeTableConstant();
1037
1038
0
    if (m_Palette->GetNumberOfColors() <= 0)
1039
0
        return CE_Failure;
1040
1041
0
    if (m_Palette->GetColorScaling() == ColorTreatment::DIRECT_ASSIGNATION)
1042
0
        return FromPaletteToAttributeTableDirectAssig();
1043
1044
    // A scaling is applied between the minimum and maximum display values.
1045
0
    return FromPaletteToAttributeTableLinear();
1046
0
}
1047
1048
CPLErr MMRRasterBand::FromPaletteToAttributeTableConstant()
1049
0
{
1050
0
    MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
1051
0
    if (!poBand)
1052
0
        return CE_Failure;
1053
1054
    // Some necessary information
1055
0
    if (!poBand->GetVisuMinSet() || !poBand->GetVisuMaxSet())
1056
0
        return CE_Failure;
1057
1058
0
    m_poDefaultRAT->CreateColumn("MIN", GFT_Real, GFU_Min);
1059
0
    m_poDefaultRAT->CreateColumn("MAX", GFT_Real, GFU_Max);
1060
0
    m_poDefaultRAT->CreateColumn("Red", GFT_Integer, GFU_Red);
1061
0
    m_poDefaultRAT->CreateColumn("Green", GFT_Integer, GFU_Green);
1062
0
    m_poDefaultRAT->CreateColumn("Blue", GFT_Integer, GFU_Blue);
1063
1064
0
    m_poDefaultRAT->SetTableType(GRTT_THEMATIC);
1065
1066
0
    int nRow = 0;
1067
0
    if (poBand->BandHasNoData())
1068
0
    {
1069
0
        m_poDefaultRAT->SetRowCount(2);
1070
1071
0
        m_poDefaultRAT->SetValue(0, 0, poBand->GetNoDataValue());
1072
0
        m_poDefaultRAT->SetValue(0, 1, poBand->GetNoDataValue());
1073
0
        m_poDefaultRAT->SetValue(0, 2, m_Palette->GetNoDataDefaultColor().c1);
1074
0
        m_poDefaultRAT->SetValue(0, 3, m_Palette->GetNoDataDefaultColor().c2);
1075
0
        m_poDefaultRAT->SetValue(0, 4, m_Palette->GetNoDataDefaultColor().c3);
1076
0
        nRow++;
1077
0
    }
1078
0
    else
1079
0
        m_poDefaultRAT->SetRowCount(1);
1080
1081
    // Sets the constant color from min to max
1082
0
    m_poDefaultRAT->SetValue(nRow, 0, poBand->GetVisuMin());
1083
0
    m_poDefaultRAT->SetValue(nRow, 1, poBand->GetVisuMax());
1084
0
    m_poDefaultRAT->SetValue(nRow, 2, m_Palette->GetConstantColorRGB().c1);
1085
0
    m_poDefaultRAT->SetValue(nRow, 3, m_Palette->GetConstantColorRGB().c2);
1086
0
    m_poDefaultRAT->SetValue(nRow, 4, m_Palette->GetConstantColorRGB().c3);
1087
1088
0
    return CE_None;
1089
0
}
1090
1091
CPLErr MMRRasterBand::FromPaletteToAttributeTableDirectAssig()
1092
0
{
1093
0
    MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
1094
0
    if (!poBand)
1095
0
        return CE_Failure;
1096
1097
0
    if (!m_Palette)
1098
0
        return CE_Failure;
1099
1100
0
    if (m_Palette->GetNumberOfColors() <= 0)
1101
0
        return CE_Failure;
1102
1103
0
    m_poDefaultRAT->SetTableType(GRTT_THEMATIC);
1104
1105
0
    m_poDefaultRAT->CreateColumn("MIN_MAX", GFT_Real, GFU_MinMax);
1106
0
    m_poDefaultRAT->CreateColumn("Red", GFT_Integer, GFU_Red);
1107
0
    m_poDefaultRAT->CreateColumn("Green", GFT_Integer, GFU_Green);
1108
0
    m_poDefaultRAT->CreateColumn("Blue", GFT_Integer, GFU_Blue);
1109
1110
0
    m_poDefaultRAT->SetRowCount(static_cast<int>(
1111
0
        m_Palette->GetNumberOfColorsIncludingNodata()));  // +1 for last element
1112
1113
    // Nodata color assignation
1114
0
    int nIRow = 0;
1115
0
    if (poBand->BandHasNoData() && m_Palette->HasNodata())
1116
0
    {
1117
0
        m_poDefaultRAT->SetValue(nIRow, 0, poBand->GetNoDataValue());
1118
0
        m_poDefaultRAT->SetValue(nIRow, 1,
1119
0
                                 m_Palette->GetPaletteColorsValue(
1120
0
                                     0, m_Palette->GetNoDataPaletteIndex()));
1121
0
        m_poDefaultRAT->SetValue(nIRow, 2,
1122
0
                                 m_Palette->GetPaletteColorsValue(
1123
0
                                     1, m_Palette->GetNoDataPaletteIndex()));
1124
0
        m_poDefaultRAT->SetValue(nIRow, 3,
1125
0
                                 m_Palette->GetPaletteColorsValue(
1126
0
                                     2, m_Palette->GetNoDataPaletteIndex()));
1127
0
        nIRow++;
1128
0
    }
1129
1130
0
    int nIPaletteColor = 0;
1131
0
    for (; nIPaletteColor < m_Palette->GetNumberOfColors(); nIPaletteColor++)
1132
0
    {
1133
0
        if (nIPaletteColor == m_Palette->GetNoDataPaletteIndex())
1134
0
            continue;
1135
1136
0
        m_poDefaultRAT->SetValue(nIRow, 0, nIPaletteColor);
1137
1138
0
        m_poDefaultRAT->SetValue(
1139
0
            nIRow, 1, m_Palette->GetPaletteColorsValue(0, nIPaletteColor));
1140
0
        m_poDefaultRAT->SetValue(
1141
0
            nIRow, 2, m_Palette->GetPaletteColorsValue(1, nIPaletteColor));
1142
0
        m_poDefaultRAT->SetValue(
1143
0
            nIRow, 3, m_Palette->GetPaletteColorsValue(2, nIPaletteColor));
1144
1145
0
        nIRow++;
1146
0
    }
1147
1148
0
    return CE_None;
1149
0
}
1150
1151
CPLErr MMRRasterBand::FromPaletteToAttributeTableLinear()
1152
0
{
1153
0
    MMRBand *poBand = m_pfRel->GetBand(nBand - 1);
1154
0
    if (!poBand)
1155
0
        return CE_Failure;
1156
1157
0
    if (!m_Palette)
1158
0
        return CE_Failure;
1159
1160
0
    if (m_Palette->GetNumberOfColors() <= 0)
1161
0
        return CE_Failure;
1162
1163
    // Some necessary information
1164
0
    if (!poBand->GetVisuMinSet() || !poBand->GetVisuMaxSet())
1165
0
        return CE_Failure;
1166
1167
0
    m_poDefaultRAT->SetTableType(GRTT_ATHEMATIC);
1168
0
    m_poDefaultRAT->CreateColumn("MIN", GFT_Real, GFU_Min);
1169
0
    m_poDefaultRAT->CreateColumn("MAX", GFT_Real, GFU_Max);
1170
0
    m_poDefaultRAT->CreateColumn("Red", GFT_Integer, GFU_Red);
1171
0
    m_poDefaultRAT->CreateColumn("Green", GFT_Integer, GFU_Green);
1172
0
    m_poDefaultRAT->CreateColumn("Blue", GFT_Integer, GFU_Blue);
1173
1174
0
    m_poDefaultRAT->SetRowCount(m_Palette->GetNumberOfColorsIncludingNodata() +
1175
0
                                1);  // +1 for last element
1176
1177
    // Nodata color assignation
1178
0
    int nIRow = 0;
1179
0
    if (poBand->BandHasNoData() && m_Palette->HasNodata())
1180
0
    {
1181
0
        m_poDefaultRAT->SetValue(nIRow, 0, poBand->GetNoDataValue());
1182
0
        m_poDefaultRAT->SetValue(nIRow, 1, poBand->GetNoDataValue());
1183
0
        m_poDefaultRAT->SetValue(nIRow, 2,
1184
0
                                 m_Palette->GetPaletteColorsValue(
1185
0
                                     0, m_Palette->GetNoDataPaletteIndex()));
1186
0
        m_poDefaultRAT->SetValue(nIRow, 3,
1187
0
                                 m_Palette->GetPaletteColorsValue(
1188
0
                                     1, m_Palette->GetNoDataPaletteIndex()));
1189
0
        m_poDefaultRAT->SetValue(nIRow, 4,
1190
0
                                 m_Palette->GetPaletteColorsValue(
1191
0
                                     2, m_Palette->GetNoDataPaletteIndex()));
1192
0
        nIRow++;
1193
0
    }
1194
1195
0
    double dfInterval =
1196
0
        (poBand->GetVisuMax() - poBand->GetVisuMin()) /
1197
0
        (static_cast<double>(m_Palette->GetNumberOfColors()) + 1);
1198
1199
0
    int nIPaletteColorNoData = 0;
1200
0
    if (poBand->BandHasNoData())
1201
0
    {
1202
0
        if (m_Palette->GetNoDataPaletteIndex() ==
1203
0
            m_Palette->GetNumberOfColors())
1204
0
            nIPaletteColorNoData =
1205
0
                m_Palette->GetNumberOfColorsIncludingNodata();
1206
0
    }
1207
1208
0
    bool bFirstIteration = true;
1209
0
    int nIPaletteColor = 0;
1210
0
    for (; nIPaletteColor < m_Palette->GetNumberOfColors() - 1;
1211
0
         nIPaletteColor++)
1212
0
    {
1213
0
        if (poBand->BandHasNoData() && m_Palette->HasNodata() &&
1214
0
            nIPaletteColor == nIPaletteColorNoData)
1215
0
            continue;
1216
0
        if (bFirstIteration)
1217
0
        {
1218
0
            m_poDefaultRAT->SetValue(
1219
0
                nIRow, 0, poBand->GetVisuMin() + dfInterval * nIPaletteColor);
1220
0
        }
1221
0
        else
1222
0
        {
1223
0
            if (IsInteger())
1224
0
            {
1225
0
                m_poDefaultRAT->SetValue(
1226
0
                    nIRow, 0,
1227
0
                    ceil(poBand->GetVisuMin() + dfInterval * nIPaletteColor));
1228
0
            }
1229
0
            else
1230
0
            {
1231
0
                m_poDefaultRAT->SetValue(nIRow, 0,
1232
0
                                         poBand->GetVisuMin() +
1233
0
                                             dfInterval * nIPaletteColor);
1234
0
            }
1235
0
        }
1236
0
        bFirstIteration = false;
1237
1238
0
        if (IsInteger())
1239
0
        {
1240
0
            m_poDefaultRAT->SetValue(
1241
0
                nIRow, 1,
1242
0
                ceil(poBand->GetVisuMin() +
1243
0
                     dfInterval * (static_cast<double>(nIPaletteColor) + 1)));
1244
0
        }
1245
0
        else
1246
0
        {
1247
0
            m_poDefaultRAT->SetValue(
1248
0
                nIRow, 1,
1249
0
                poBand->GetVisuMin() +
1250
0
                    dfInterval * (static_cast<double>(nIPaletteColor) + 1));
1251
0
        }
1252
1253
0
        m_poDefaultRAT->SetValue(
1254
0
            nIRow, 2, m_Palette->GetPaletteColorsValue(0, nIPaletteColor));
1255
0
        m_poDefaultRAT->SetValue(
1256
0
            nIRow, 3, m_Palette->GetPaletteColorsValue(1, nIPaletteColor));
1257
0
        m_poDefaultRAT->SetValue(
1258
0
            nIRow, 4, m_Palette->GetPaletteColorsValue(2, nIPaletteColor));
1259
1260
0
        nIRow++;
1261
0
    }
1262
1263
    // Last interval
1264
0
    if (IsInteger())
1265
0
    {
1266
0
        m_poDefaultRAT->SetValue(
1267
0
            nIRow, 0,
1268
0
            ceil(
1269
0
                poBand->GetVisuMin() +
1270
0
                dfInterval *
1271
0
                    (static_cast<double>(m_Palette->GetNumberOfColors()) - 1)));
1272
0
    }
1273
0
    else
1274
0
    {
1275
0
        m_poDefaultRAT->SetValue(
1276
0
            nIRow, 0,
1277
0
            poBand->GetVisuMin() +
1278
0
                dfInterval *
1279
0
                    (static_cast<double>(m_Palette->GetNumberOfColors()) - 1));
1280
0
    }
1281
0
    m_poDefaultRAT->SetValue(nIRow, 1, poBand->GetVisuMax());
1282
0
    m_poDefaultRAT->SetValue(
1283
0
        nIRow, 2, m_Palette->GetPaletteColorsValue(0, nIPaletteColor - 1));
1284
0
    m_poDefaultRAT->SetValue(
1285
0
        nIRow, 3, m_Palette->GetPaletteColorsValue(1, nIPaletteColor - 1));
1286
0
    m_poDefaultRAT->SetValue(
1287
0
        nIRow, 4, m_Palette->GetPaletteColorsValue(2, nIPaletteColor - 1));
1288
1289
0
    nIRow++;
1290
1291
    // Last value
1292
0
    m_poDefaultRAT->SetValue(nIRow, 0, poBand->GetVisuMax());
1293
0
    m_poDefaultRAT->SetValue(nIRow, 1, poBand->GetVisuMax());
1294
0
    m_poDefaultRAT->SetValue(
1295
0
        nIRow, 2, m_Palette->GetPaletteColorsValue(0, nIPaletteColor - 1));
1296
0
    m_poDefaultRAT->SetValue(
1297
0
        nIRow, 3, m_Palette->GetPaletteColorsValue(1, nIPaletteColor - 1));
1298
0
    m_poDefaultRAT->SetValue(
1299
0
        nIRow, 4, m_Palette->GetPaletteColorsValue(2, nIPaletteColor - 1));
1300
1301
0
    return CE_None;
1302
0
}
1303
1304
void MMRRasterBand::ConvertColorsFromPaletteToColorTable()
1305
26
{
1306
26
    int nColors = static_cast<int>(GetPCT_Red().size());
1307
1308
26
    if (nColors > 0)
1309
25
    {
1310
71.7k
        for (int iColor = 0; iColor < nColors; iColor++)
1311
71.6k
        {
1312
71.6k
            GDALColorEntry sEntry = {
1313
71.6k
                static_cast<short int>(GetPCT_Red()[iColor]),
1314
71.6k
                static_cast<short int>(GetPCT_Green()[iColor]),
1315
71.6k
                static_cast<short int>(GetPCT_Blue()[iColor]),
1316
71.6k
                static_cast<short int>(GetPCT_Alpha()[iColor])};
1317
1318
71.6k
            if ((sEntry.c1 < 0 || sEntry.c1 > 255) ||
1319
71.6k
                (sEntry.c2 < 0 || sEntry.c2 > 255) ||
1320
71.6k
                (sEntry.c3 < 0 || sEntry.c3 > 255) ||
1321
71.6k
                (sEntry.c4 < 0 || sEntry.c4 > 255))
1322
0
            {
1323
0
                CPLError(CE_Failure, CPLE_AppDefined,
1324
0
                         "Color table entry appears to be corrupt, skipping "
1325
0
                         "the rest. ");
1326
0
                break;
1327
0
            }
1328
1329
71.6k
            m_poCT->SetColorEntry(iColor, &sEntry);
1330
71.6k
        }
1331
25
    }
1332
26
}
1333
1334
void MMRRasterBand::AssignRGBColor(int nIndexDstCT, int nIndexSrcPalette)
1335
0
{
1336
0
    m_aadfPCT[0][nIndexDstCT] =
1337
0
        m_Palette->GetPaletteColorsValue(0, nIndexSrcPalette);
1338
0
    m_aadfPCT[1][nIndexDstCT] =
1339
0
        m_Palette->GetPaletteColorsValue(1, nIndexSrcPalette);
1340
0
    m_aadfPCT[2][nIndexDstCT] =
1341
0
        m_Palette->GetPaletteColorsValue(2, nIndexSrcPalette);
1342
0
    m_aadfPCT[3][nIndexDstCT] =
1343
0
        m_Palette->GetPaletteColorsValue(3, nIndexSrcPalette);
1344
0
}
1345
1346
void MMRRasterBand::AssignRGBColorDirectly(int nIndexDstCT, double dfValue)
1347
0
{
1348
0
    m_aadfPCT[0][nIndexDstCT] = dfValue;
1349
0
    m_aadfPCT[1][nIndexDstCT] = dfValue;
1350
0
    m_aadfPCT[2][nIndexDstCT] = dfValue;
1351
0
    m_aadfPCT[3][nIndexDstCT] = dfValue;
1352
0
}