Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: NITF Read/Write Translator
4 : * Purpose: NITFRasterBand (and related proxy band) implementations.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2002, Frank Warmerdam
9 : * Copyright (c) 2011-2013, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * Portions Copyright (c) Her majesty the Queen in right of Canada as
12 : * represented by the Minister of National Defence, 2006, 2020
13 : *
14 : * SPDX-License-Identifier: MIT
15 : ****************************************************************************/
16 :
17 : #include "cpl_port.h"
18 : #include "nitfdataset.h"
19 :
20 : #include <climits>
21 : #include <cstring>
22 : #if HAVE_FCNTL_H
23 : #include <fcntl.h>
24 : #endif
25 : #include <algorithm>
26 : #include <map>
27 : #include <utility>
28 :
29 : #include "cpl_conv.h"
30 : #include "cpl_csv.h"
31 : #include "cpl_error.h"
32 : #include "cpl_progress.h"
33 : #include "cpl_string.h"
34 : #include "cpl_vsi.h"
35 : #include "gdal.h"
36 : #include "gdal_pam.h"
37 : #include "gdal_priv.h"
38 : #include "nitflib.h"
39 :
40 : /************************************************************************/
41 : /* NITFMakeColorTable() */
42 : /************************************************************************/
43 :
44 210943 : static GDALColorTable *NITFMakeColorTable(NITFImage *psImage,
45 : NITFBandInfo *psBandInfo)
46 : {
47 210943 : GDALColorTable *poColorTable = nullptr;
48 :
49 210943 : if (psBandInfo->nSignificantLUTEntries > 0)
50 : {
51 33 : poColorTable = new GDALColorTable();
52 :
53 5780 : for (int iColor = 0; iColor < psBandInfo->nSignificantLUTEntries;
54 : iColor++)
55 : {
56 : GDALColorEntry sEntry;
57 5747 : sEntry.c1 = psBandInfo->pabyLUT[0 + iColor];
58 5747 : sEntry.c2 = psBandInfo->pabyLUT[256 + iColor];
59 5747 : sEntry.c3 = psBandInfo->pabyLUT[512 + iColor];
60 5747 : sEntry.c4 = 255;
61 :
62 5747 : poColorTable->SetColorEntry(iColor, &sEntry);
63 : }
64 :
65 33 : if (psImage->bNoDataSet)
66 : {
67 29 : GDALColorEntry sEntry = {0, 0, 0, 0};
68 29 : poColorTable->SetColorEntry(psImage->nNoDataValue, &sEntry);
69 : }
70 : }
71 :
72 : /* -------------------------------------------------------------------- */
73 : /* We create a color table for 1 bit data too... */
74 : /* -------------------------------------------------------------------- */
75 210943 : if (poColorTable == nullptr && psImage->nBitsPerSample == 1)
76 : {
77 20 : poColorTable = new GDALColorTable();
78 :
79 : GDALColorEntry sEntry;
80 20 : sEntry.c1 = 0;
81 20 : sEntry.c2 = 0;
82 20 : sEntry.c3 = 0;
83 20 : sEntry.c4 = 255;
84 20 : poColorTable->SetColorEntry(0, &sEntry);
85 :
86 20 : sEntry.c1 = 255;
87 20 : sEntry.c2 = 255;
88 20 : sEntry.c3 = 255;
89 20 : sEntry.c4 = 255;
90 20 : poColorTable->SetColorEntry(1, &sEntry);
91 : }
92 :
93 210943 : return poColorTable;
94 : }
95 :
96 : /************************************************************************/
97 : /* ==================================================================== */
98 : /* NITFProxyPamRasterBand */
99 : /* ==================================================================== */
100 : /************************************************************************/
101 :
102 107 : NITFProxyPamRasterBand::~NITFProxyPamRasterBand()
103 : {
104 107 : std::map<CPLString, char **>::iterator oIter = oMDMap.begin();
105 112 : while (oIter != oMDMap.end())
106 : {
107 5 : CSLDestroy(oIter->second);
108 5 : ++oIter;
109 : }
110 107 : }
111 :
112 6 : char **NITFProxyPamRasterBand::GetMetadata(const char *pszDomain)
113 : {
114 6 : GDALRasterBand *_poSrcBand = RefUnderlyingRasterBand();
115 6 : if (_poSrcBand)
116 : {
117 : /* Let's merge metadata of PAM and the underlying band */
118 : /* PAM metadata should override underlying band metadata */
119 6 : char **papszMD = CSLDuplicate(_poSrcBand->GetMetadata(pszDomain));
120 6 : papszMD = CSLMerge(papszMD, GDALPamRasterBand::GetMetadata(pszDomain));
121 :
122 6 : if (pszDomain == nullptr)
123 0 : pszDomain = "";
124 :
125 6 : std::map<CPLString, char **>::iterator oIter = oMDMap.find(pszDomain);
126 6 : if (oIter != oMDMap.end())
127 1 : CSLDestroy(oIter->second);
128 6 : oMDMap[pszDomain] = papszMD;
129 6 : UnrefUnderlyingRasterBand(_poSrcBand);
130 :
131 6 : return papszMD;
132 : }
133 :
134 0 : return GDALPamRasterBand::GetMetadata(pszDomain);
135 : }
136 :
137 11 : const char *NITFProxyPamRasterBand::GetMetadataItem(const char *pszName,
138 : const char *pszDomain)
139 : {
140 11 : const char *pszRet = GDALPamRasterBand::GetMetadataItem(pszName, pszDomain);
141 11 : if (pszRet)
142 0 : return pszRet;
143 :
144 11 : GDALRasterBand *_poSrcBand = RefUnderlyingRasterBand();
145 11 : if (_poSrcBand)
146 : {
147 11 : if (!m_bEnablePixelTypeSignedByteWarning)
148 0 : _poSrcBand->EnablePixelTypeSignedByteWarning(false);
149 11 : pszRet = _poSrcBand->GetMetadataItem(pszName, pszDomain);
150 11 : _poSrcBand->EnablePixelTypeSignedByteWarning(true);
151 11 : UnrefUnderlyingRasterBand(_poSrcBand);
152 : }
153 :
154 11 : return pszRet;
155 : }
156 :
157 2 : CPLErr NITFProxyPamRasterBand::GetStatistics(int bApproxOK, int bForce,
158 : double *pdfMin, double *pdfMax,
159 : double *pdfMean, double *pdfStdDev)
160 : {
161 : /* -------------------------------------------------------------------- */
162 : /* Do we already have metadata items for the requested values? */
163 : /* -------------------------------------------------------------------- */
164 4 : if ((pdfMin == nullptr ||
165 2 : GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
166 0 : (pdfMax == nullptr ||
167 0 : GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
168 4 : (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
169 0 : (pdfStdDev == nullptr ||
170 0 : GetMetadataItem("STATISTICS_STDDEV") != nullptr))
171 : {
172 0 : return GDALPamRasterBand::GetStatistics(bApproxOK, bForce, pdfMin,
173 0 : pdfMax, pdfMean, pdfStdDev);
174 : }
175 :
176 2 : GDALRasterBand *_poSrcBand = RefUnderlyingRasterBand();
177 2 : if (_poSrcBand)
178 : {
179 4 : CPLErr ret = _poSrcBand->GetStatistics(bApproxOK, bForce, pdfMin,
180 2 : pdfMax, pdfMean, pdfStdDev);
181 2 : if (ret == CE_None)
182 : {
183 : /* Report underlying statistics at PAM level */
184 2 : SetMetadataItem("STATISTICS_MINIMUM",
185 2 : _poSrcBand->GetMetadataItem("STATISTICS_MINIMUM"));
186 2 : SetMetadataItem("STATISTICS_MAXIMUM",
187 2 : _poSrcBand->GetMetadataItem("STATISTICS_MAXIMUM"));
188 2 : SetMetadataItem("STATISTICS_MEAN",
189 2 : _poSrcBand->GetMetadataItem("STATISTICS_MEAN"));
190 2 : SetMetadataItem("STATISTICS_STDDEV",
191 2 : _poSrcBand->GetMetadataItem("STATISTICS_STDDEV"));
192 : }
193 2 : UnrefUnderlyingRasterBand(_poSrcBand);
194 2 : return ret;
195 : }
196 :
197 0 : return CE_Failure;
198 : }
199 :
200 0 : CPLErr NITFProxyPamRasterBand::ComputeStatistics(
201 : int bApproxOK, double *pdfMin, double *pdfMax, double *pdfMean,
202 : double *pdfStdDev, GDALProgressFunc pfn, void *pProgressData)
203 : {
204 0 : GDALRasterBand *_poSrcBand = RefUnderlyingRasterBand();
205 0 : if (_poSrcBand)
206 : {
207 0 : CPLErr ret = _poSrcBand->ComputeStatistics(
208 0 : bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev, pfn, pProgressData);
209 0 : if (ret == CE_None)
210 : {
211 : /* Report underlying statistics at PAM level */
212 0 : SetMetadataItem("STATISTICS_MINIMUM",
213 0 : _poSrcBand->GetMetadataItem("STATISTICS_MINIMUM"));
214 0 : SetMetadataItem("STATISTICS_MAXIMUM",
215 0 : _poSrcBand->GetMetadataItem("STATISTICS_MAXIMUM"));
216 0 : SetMetadataItem("STATISTICS_MEAN",
217 0 : _poSrcBand->GetMetadataItem("STATISTICS_MEAN"));
218 0 : SetMetadataItem("STATISTICS_STDDEV",
219 0 : _poSrcBand->GetMetadataItem("STATISTICS_STDDEV"));
220 : }
221 0 : UnrefUnderlyingRasterBand(_poSrcBand);
222 0 : return ret;
223 : }
224 :
225 0 : return CE_Failure;
226 : }
227 :
228 : #define RB_PROXY_METHOD_GET_DBL_WITH_SUCCESS(methodName) \
229 : double NITFProxyPamRasterBand::methodName(int *pbSuccess) \
230 : { \
231 : int bSuccess = FALSE; \
232 : double dfRet = GDALPamRasterBand::methodName(&bSuccess); \
233 : if (bSuccess) \
234 : { \
235 : if (pbSuccess) \
236 : *pbSuccess = TRUE; \
237 : return dfRet; \
238 : } \
239 : GDALRasterBand *_poSrcBand = RefUnderlyingRasterBand(); \
240 : if (_poSrcBand) \
241 : { \
242 : dfRet = _poSrcBand->methodName(pbSuccess); \
243 : UnrefUnderlyingRasterBand(_poSrcBand); \
244 : } \
245 : else \
246 : { \
247 : dfRet = 0; \
248 : } \
249 : return dfRet; \
250 : }
251 :
252 15 : RB_PROXY_METHOD_GET_DBL_WITH_SUCCESS(GetNoDataValue)
253 0 : RB_PROXY_METHOD_GET_DBL_WITH_SUCCESS(GetMinimum)
254 0 : RB_PROXY_METHOD_GET_DBL_WITH_SUCCESS(GetMaximum)
255 :
256 : #define RB_PROXY_METHOD_WITH_RET_AND_CALL_OTHER_METHOD( \
257 : retType, retErrValue, methodName, underlyingMethodName, argList, \
258 : argParams) \
259 : retType NITFProxyPamRasterBand::methodName argList \
260 : { \
261 : retType ret; \
262 : GDALRasterBand *_poSrcBand = RefUnderlyingRasterBand(); \
263 : if (_poSrcBand) \
264 : { \
265 : ret = _poSrcBand->underlyingMethodName argParams; \
266 : UnrefUnderlyingRasterBand(_poSrcBand); \
267 : } \
268 : else \
269 : { \
270 : ret = retErrValue; \
271 : } \
272 : return ret; \
273 : }
274 :
275 0 : RB_PROXY_METHOD_WITH_RET_AND_CALL_OTHER_METHOD(CPLErr, CE_Failure, IReadBlock,
276 : ReadBlock,
277 : (int nXBlockOff, int nYBlockOff,
278 : void *pImage),
279 : (nXBlockOff, nYBlockOff, pImage))
280 0 : RB_PROXY_METHOD_WITH_RET_AND_CALL_OTHER_METHOD(CPLErr, CE_Failure, IWriteBlock,
281 : WriteBlock,
282 : (int nXBlockOff, int nYBlockOff,
283 : void *pImage),
284 : (nXBlockOff, nYBlockOff, pImage))
285 403 : RB_PROXY_METHOD_WITH_RET_AND_CALL_OTHER_METHOD(
286 : CPLErr, CE_Failure, IRasterIO, RasterIO,
287 : (GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
288 : void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
289 : GSpacing nPixelSpace, GSpacing nLineSpace,
290 : GDALRasterIOExtraArg *psExtraArg),
291 : (eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
292 : eBufType, nPixelSpace, nLineSpace, psExtraArg))
293 :
294 : #define RB_PROXY_METHOD_WITH_RET(retType, retErrValue, methodName, argList, \
295 : argParams) \
296 : retType NITFProxyPamRasterBand::methodName argList \
297 : { \
298 : retType ret; \
299 : GDALRasterBand *_poSrcBand = RefUnderlyingRasterBand(); \
300 : if (_poSrcBand) \
301 : { \
302 : ret = _poSrcBand->methodName argParams; \
303 : UnrefUnderlyingRasterBand(_poSrcBand); \
304 : } \
305 : else \
306 : { \
307 : ret = retErrValue; \
308 : } \
309 : return ret; \
310 : }
311 :
312 110 : RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, FlushCache, (bool bAtClosing),
313 : (bAtClosing))
314 :
315 0 : RB_PROXY_METHOD_WITH_RET(GDALColorInterp, GCI_Undefined, GetColorInterpretation,
316 : (), ())
317 0 : RB_PROXY_METHOD_WITH_RET(GDALColorTable *, nullptr, GetColorTable, (), ())
318 0 : RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, Fill,
319 : (double dfRealValue, double dfImaginaryValue),
320 : (dfRealValue, dfImaginaryValue))
321 :
322 1 : RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, ComputeRasterMinMax,
323 : (int arg1, double *arg2), (arg1, arg2))
324 :
325 0 : RB_PROXY_METHOD_WITH_RET(int, 0, HasArbitraryOverviews, (), ())
326 4 : RB_PROXY_METHOD_WITH_RET(int, 0, GetOverviewCount, (), ())
327 2 : RB_PROXY_METHOD_WITH_RET(GDALRasterBand *, nullptr, GetOverview, (int arg1),
328 : (arg1))
329 0 : RB_PROXY_METHOD_WITH_RET(GDALRasterBand *, nullptr, GetRasterSampleOverview,
330 : (GUIntBig arg1), (arg1))
331 :
332 0 : RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, BuildOverviews,
333 : (const char *arg1, int arg2, const int *arg3,
334 : GDALProgressFunc arg4, void *arg5,
335 : CSLConstList papszOptions),
336 : (arg1, arg2, arg3, arg4, arg5, papszOptions))
337 :
338 4 : RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, AdviseRead,
339 : (int nXOff, int nYOff, int nXSize, int nYSize,
340 : int nBufXSize, int nBufYSize, GDALDataType eDT,
341 : char **papszOptions),
342 : (nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
343 : eDT, papszOptions))
344 :
345 0 : RB_PROXY_METHOD_WITH_RET(GDALRasterBand *, nullptr, GetMaskBand, (), ())
346 16 : RB_PROXY_METHOD_WITH_RET(int, 0, GetMaskFlags, (), ())
347 0 : RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, CreateMaskBand, (int nFlagsIn),
348 : (nFlagsIn))
349 :
350 : /************************************************************************/
351 : /* UnrefUnderlyingRasterBand() */
352 : /************************************************************************/
353 :
354 574 : void NITFProxyPamRasterBand::UnrefUnderlyingRasterBand(
355 : CPL_UNUSED GDALRasterBand *poUnderlyingRasterBand)
356 : {
357 574 : }
358 :
359 : /************************************************************************/
360 : /* ==================================================================== */
361 : /* NITFRasterBand */
362 : /* ==================================================================== */
363 : /************************************************************************/
364 :
365 : /************************************************************************/
366 : /* NITFRasterBand() */
367 : /************************************************************************/
368 :
369 210943 : NITFRasterBand::NITFRasterBand(NITFDataset *poDSIn, int nBandIn)
370 210943 : : psImage(poDSIn->psImage)
371 : {
372 210943 : NITFBandInfo *psBandInfo = poDSIn->psImage->pasBandInfo + nBandIn - 1;
373 :
374 210943 : poDS = poDSIn;
375 210943 : nBand = nBandIn;
376 210943 : eAccess = poDSIn->eAccess;
377 :
378 : /* -------------------------------------------------------------------- */
379 : /* Translate data type(s). */
380 : /* -------------------------------------------------------------------- */
381 210943 : if (psImage->nBitsPerSample <= 8)
382 210804 : eDataType = GDT_Byte;
383 139 : else if (psImage->nBitsPerSample == 16 && EQUAL(psImage->szPVType, "SI"))
384 27 : eDataType = GDT_Int16;
385 112 : else if (psImage->nBitsPerSample == 16)
386 20 : eDataType = GDT_UInt16;
387 92 : else if (psImage->nBitsPerSample == 12)
388 16 : eDataType = GDT_UInt16;
389 76 : else if (psImage->nBitsPerSample == 32 && EQUAL(psImage->szPVType, "SI"))
390 12 : eDataType = GDT_Int32;
391 64 : else if (psImage->nBitsPerSample == 32 && EQUAL(psImage->szPVType, "R"))
392 31 : eDataType = GDT_Float32;
393 33 : else if (psImage->nBitsPerSample == 32)
394 12 : eDataType = GDT_UInt32;
395 21 : else if (psImage->nBitsPerSample == 64 && EQUAL(psImage->szPVType, "R"))
396 12 : eDataType = GDT_Float64;
397 9 : else if (psImage->nBitsPerSample == 64 && EQUAL(psImage->szPVType, "C"))
398 9 : eDataType = GDT_CFloat32;
399 : /* ERO : note I'm not sure if CFloat64 can be transmitted as NBPP is only 2
400 : * characters */
401 : else
402 : {
403 : int bOpenUnderlyingDS =
404 0 : CPLTestBool(CPLGetConfigOption("NITF_OPEN_UNDERLYING_DS", "YES"));
405 0 : if (!bOpenUnderlyingDS && psImage->nBitsPerSample > 8 &&
406 0 : psImage->nBitsPerSample < 16)
407 : {
408 0 : if (EQUAL(psImage->szPVType, "SI"))
409 0 : eDataType = GDT_Int16;
410 : else
411 0 : eDataType = GDT_UInt16;
412 : }
413 : else
414 : {
415 0 : eDataType = GDT_Unknown;
416 0 : CPLError(CE_Warning, CPLE_AppDefined,
417 : "Unsupported combination of PVTYPE(%s) and NBPP(%d).",
418 0 : psImage->szPVType, psImage->nBitsPerSample);
419 : }
420 : }
421 :
422 : /* -------------------------------------------------------------------- */
423 : /* Work out block size. If the image is all one big block we */
424 : /* handle via the scanline access API. */
425 : /* -------------------------------------------------------------------- */
426 210943 : if (psImage->nBlocksPerRow == 1 && psImage->nBlocksPerColumn == 1 &&
427 210855 : psImage->nBitsPerSample >= 8 && EQUAL(psImage->szIC, "NC"))
428 : {
429 210735 : bScanlineAccess = TRUE;
430 210735 : nBlockXSize = psImage->nBlockWidth;
431 210735 : nBlockYSize = 1;
432 : }
433 : else
434 : {
435 208 : bScanlineAccess = FALSE;
436 208 : nBlockXSize = psImage->nBlockWidth;
437 208 : nBlockYSize = psImage->nBlockHeight;
438 : }
439 :
440 : /* -------------------------------------------------------------------- */
441 : /* Do we have a color table? */
442 : /* -------------------------------------------------------------------- */
443 210943 : poColorTable = NITFMakeColorTable(psImage, psBandInfo);
444 :
445 210943 : if (psImage->nABPP != 8 && psImage->nABPP != 16 && psImage->nABPP != 32 &&
446 31 : psImage->nABPP != 64)
447 : {
448 10 : SetMetadataItem("NBITS", CPLString().Printf("%d", psImage->nABPP),
449 : "IMAGE_STRUCTURE");
450 : }
451 :
452 210943 : if (psImage->nBitsPerSample == 3 || psImage->nBitsPerSample == 5 ||
453 210911 : psImage->nBitsPerSample == 6 || psImage->nBitsPerSample == 7)
454 : {
455 64 : if (nBlockXSize > (INT_MAX - 7) / nBlockYSize)
456 : {
457 0 : eDataType = GDT_Unknown;
458 : }
459 : else
460 : {
461 64 : pUnpackData = static_cast<GByte *>(
462 64 : VSI_MALLOC_VERBOSE(((nBlockXSize * nBlockYSize + 7) / 8) * 8));
463 64 : if (pUnpackData == nullptr)
464 0 : eDataType = GDT_Unknown;
465 : }
466 : }
467 210943 : }
468 :
469 : /************************************************************************/
470 : /* ~NITFRasterBand() */
471 : /************************************************************************/
472 :
473 421881 : NITFRasterBand::~NITFRasterBand()
474 :
475 : {
476 210943 : if (poColorTable != nullptr)
477 53 : delete poColorTable;
478 :
479 210943 : VSIFree(pUnpackData);
480 421881 : }
481 :
482 : /************************************************************************/
483 : /* IReadBlock() */
484 : /************************************************************************/
485 :
486 18631 : CPLErr NITFRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
487 :
488 : {
489 18631 : NITFDataset *poGDS = reinterpret_cast<NITFDataset *>(poDS);
490 :
491 : /* -------------------------------------------------------------------- */
492 : /* Special case for JPEG blocks. */
493 : /* -------------------------------------------------------------------- */
494 18631 : if (EQUAL(psImage->szIC, "C3") || EQUAL(psImage->szIC, "M3"))
495 : {
496 128 : CPLErr eErr = poGDS->ReadJPEGBlock(nBlockXOff, nBlockYOff);
497 128 : const int nBlockBandSize = psImage->nBlockWidth *
498 128 : psImage->nBlockHeight *
499 128 : GDALGetDataTypeSizeBytes(eDataType);
500 :
501 128 : if (eErr != CE_None)
502 0 : return eErr;
503 :
504 128 : memcpy(pImage, poGDS->pabyJPEGBlock + (nBand - 1) * nBlockBandSize,
505 : nBlockBandSize);
506 :
507 128 : return eErr;
508 : }
509 :
510 : /* -------------------------------------------------------------------- */
511 : /* Read the line/block */
512 : /* -------------------------------------------------------------------- */
513 : int nBlockResult;
514 :
515 18503 : if (bScanlineAccess)
516 : {
517 15951 : nBlockResult = NITFReadImageLine(psImage, nBlockYOff, nBand, pImage);
518 : }
519 : else
520 : {
521 : nBlockResult =
522 2552 : NITFReadImageBlock(psImage, nBlockXOff, nBlockYOff, nBand, pImage);
523 : }
524 :
525 18503 : if (nBlockResult == BLKREAD_OK)
526 : {
527 18071 : if (psImage->nBitsPerSample % 8)
528 68 : Unpack(reinterpret_cast<GByte *>(pImage));
529 :
530 18071 : return CE_None;
531 : }
532 :
533 432 : if (nBlockResult == BLKREAD_FAIL)
534 0 : return CE_Failure;
535 :
536 : /* -------------------------------------------------------------------- */
537 : /* If we got a null/missing block, try to fill it in with the */
538 : /* nodata value. It seems this only really works properly for */
539 : /* 8bit. */
540 : /* -------------------------------------------------------------------- */
541 432 : if (psImage->bNoDataSet)
542 432 : memset(pImage, psImage->nNoDataValue,
543 432 : static_cast<size_t>(psImage->nWordSize) * psImage->nBlockWidth *
544 432 : psImage->nBlockHeight);
545 : else
546 0 : memset(pImage, 0,
547 0 : static_cast<size_t>(psImage->nWordSize) * psImage->nBlockWidth *
548 0 : psImage->nBlockHeight);
549 :
550 432 : return CE_None;
551 : }
552 :
553 : /************************************************************************/
554 : /* IWriteBlock() */
555 : /************************************************************************/
556 :
557 16904 : CPLErr NITFRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff, void *pImage)
558 :
559 : {
560 : /* -------------------------------------------------------------------- */
561 : /* Write the line/block */
562 : /* -------------------------------------------------------------------- */
563 : int nBlockResult;
564 :
565 16904 : if (bScanlineAccess)
566 : {
567 16260 : nBlockResult = NITFWriteImageLine(psImage, nBlockYOff, nBand, pImage);
568 : }
569 : else
570 : {
571 : nBlockResult =
572 644 : NITFWriteImageBlock(psImage, nBlockXOff, nBlockYOff, nBand, pImage);
573 : }
574 :
575 16904 : if (nBlockResult == BLKREAD_OK)
576 16904 : return CE_None;
577 :
578 0 : return CE_Failure;
579 : }
580 :
581 : /************************************************************************/
582 : /* GetNoDataValue() */
583 : /************************************************************************/
584 :
585 118 : double NITFRasterBand::GetNoDataValue(int *pbSuccess)
586 :
587 : {
588 118 : if (pbSuccess != nullptr)
589 117 : *pbSuccess = psImage->bNoDataSet;
590 :
591 118 : if (psImage->bNoDataSet)
592 22 : return psImage->nNoDataValue;
593 :
594 96 : return GDALPamRasterBand::GetNoDataValue(pbSuccess);
595 : }
596 :
597 : /************************************************************************/
598 : /* GetColorInterpretation() */
599 : /************************************************************************/
600 :
601 157 : GDALColorInterp NITFRasterBand::GetColorInterpretation()
602 :
603 : {
604 157 : NITFBandInfo *psBandInfo = psImage->pasBandInfo + nBand - 1;
605 :
606 157 : if (poColorTable != nullptr)
607 21 : return GCI_PaletteIndex;
608 :
609 136 : if (EQUAL(psBandInfo->szIREPBAND, "R"))
610 20 : return GCI_RedBand;
611 116 : if (EQUAL(psBandInfo->szIREPBAND, "G"))
612 20 : return GCI_GreenBand;
613 96 : if (EQUAL(psBandInfo->szIREPBAND, "B"))
614 20 : return GCI_BlueBand;
615 76 : if (EQUAL(psBandInfo->szIREPBAND, "M"))
616 70 : return GCI_GrayIndex;
617 6 : if (EQUAL(psBandInfo->szIREPBAND, "Y"))
618 2 : return GCI_YCbCr_YBand;
619 4 : if (EQUAL(psBandInfo->szIREPBAND, "Cb"))
620 2 : return GCI_YCbCr_CbBand;
621 2 : if (EQUAL(psBandInfo->szIREPBAND, "Cr"))
622 2 : return GCI_YCbCr_CrBand;
623 :
624 0 : return GCI_Undefined;
625 : }
626 :
627 : /************************************************************************/
628 : /* NITFSetColorInterpretation() */
629 : /************************************************************************/
630 :
631 33 : CPLErr NITFSetColorInterpretation(NITFImage *psImage, int nBand,
632 : GDALColorInterp eInterp)
633 :
634 : {
635 33 : const char *pszREP = nullptr;
636 :
637 33 : if (eInterp == GCI_RedBand)
638 11 : pszREP = "R";
639 22 : else if (eInterp == GCI_GreenBand)
640 11 : pszREP = "G";
641 11 : else if (eInterp == GCI_BlueBand)
642 11 : pszREP = "B";
643 0 : else if (eInterp == GCI_GrayIndex)
644 0 : pszREP = "M";
645 0 : else if (eInterp == GCI_YCbCr_YBand)
646 0 : pszREP = "Y";
647 0 : else if (eInterp == GCI_YCbCr_CbBand)
648 0 : pszREP = "Cb";
649 0 : else if (eInterp == GCI_YCbCr_CrBand)
650 0 : pszREP = "Cr";
651 0 : else if (eInterp == GCI_Undefined)
652 0 : return CE_None;
653 :
654 33 : if (pszREP == nullptr)
655 : {
656 0 : CPLError(CE_Failure, CPLE_NotSupported,
657 : "Requested color interpretation (%s) not supported in NITF.",
658 : GDALGetColorInterpretationName(eInterp));
659 0 : return CE_Failure;
660 : }
661 :
662 : /* -------------------------------------------------------------------- */
663 : /* Where does this go in the file? */
664 : /* -------------------------------------------------------------------- */
665 33 : NITFBandInfo *psBandInfo = psImage->pasBandInfo + nBand - 1;
666 33 : strcpy(psBandInfo->szIREPBAND, pszREP);
667 33 : GUIntBig nOffset = NITFIHFieldOffset(psImage, "IREPBAND");
668 :
669 33 : if (nOffset != 0)
670 33 : nOffset += (nBand - 1) * 13;
671 :
672 : /* -------------------------------------------------------------------- */
673 : /* write it (space padded). */
674 : /* -------------------------------------------------------------------- */
675 : char szPadded[4];
676 33 : strcpy(szPadded, pszREP);
677 33 : strcat(szPadded, " ");
678 :
679 33 : if (nOffset != 0)
680 : {
681 66 : if (VSIFSeekL(psImage->psFile->fp, nOffset, SEEK_SET) != 0 ||
682 33 : VSIFWriteL(reinterpret_cast<void *>(szPadded), 1, 2,
683 33 : psImage->psFile->fp) != 2)
684 : {
685 0 : CPLError(CE_Failure, CPLE_AppDefined,
686 : "IO failure writing new IREPBAND value to NITF file.");
687 0 : return CE_Failure;
688 : }
689 : }
690 :
691 33 : return CE_None;
692 : }
693 :
694 : /************************************************************************/
695 : /* SetColorInterpretation() */
696 : /************************************************************************/
697 :
698 30 : CPLErr NITFRasterBand::SetColorInterpretation(GDALColorInterp eInterp)
699 :
700 : {
701 30 : return NITFSetColorInterpretation(psImage, nBand, eInterp);
702 : }
703 :
704 : /************************************************************************/
705 : /* GetColorTable() */
706 : /************************************************************************/
707 :
708 54 : GDALColorTable *NITFRasterBand::GetColorTable()
709 :
710 : {
711 54 : return poColorTable;
712 : }
713 :
714 : /************************************************************************/
715 : /* SetColorTable() */
716 : /************************************************************************/
717 :
718 2 : CPLErr NITFRasterBand::SetColorTable(GDALColorTable *poNewCT)
719 :
720 : {
721 2 : NITFDataset *poGDS = reinterpret_cast<NITFDataset *>(poDS);
722 2 : if (poGDS->bInLoadXML)
723 0 : return GDALPamRasterBand::SetColorTable(poNewCT);
724 :
725 2 : if (poNewCT == nullptr)
726 0 : return CE_Failure;
727 :
728 4 : std::vector<GByte> abyNITFLUT(768);
729 :
730 2 : const int nCount = std::min(256, poNewCT->GetColorEntryCount());
731 135 : for (int i = 0; i < nCount; i++)
732 : {
733 : GDALColorEntry sEntry;
734 :
735 133 : poNewCT->GetColorEntryAsRGB(i, &sEntry);
736 133 : abyNITFLUT[i + 256 * 0] = static_cast<GByte>(sEntry.c1);
737 133 : abyNITFLUT[i + 256 * 1] = static_cast<GByte>(sEntry.c2);
738 133 : abyNITFLUT[i + 256 * 2] = static_cast<GByte>(sEntry.c3);
739 : }
740 :
741 2 : if (NITFWriteLUT(psImage, nBand, nCount, abyNITFLUT.data()))
742 2 : return CE_None;
743 :
744 0 : return CE_Failure;
745 : }
746 :
747 : /************************************************************************/
748 : /* Unpack() */
749 : /************************************************************************/
750 :
751 68 : void NITFRasterBand::Unpack(GByte *pData)
752 : {
753 68 : const int n = nBlockXSize * nBlockYSize;
754 :
755 68 : GByte abyTempData[7] = {0, 0, 0, 0, 0, 0, 0};
756 68 : const GByte *pDataSrc = pData;
757 68 : if (n < psImage->nBitsPerSample && psImage->nBitsPerSample < 8)
758 : {
759 21 : memcpy(abyTempData, pData, n);
760 21 : pDataSrc = abyTempData;
761 : }
762 :
763 68 : switch (psImage->nBitsPerSample)
764 : {
765 12 : case 1:
766 : {
767 : // unpack 1-bit in-place in reverse
768 : // DANGER: Non-standard decrement of counter in the test section of
769 : // for.
770 1050510 : for (int i = n; --i >= 0;)
771 1050500 : pData[i] = (pData[i >> 3] & (0x80 >> (i & 7))) != 0;
772 :
773 12 : break;
774 : }
775 8 : case 2:
776 : {
777 8 : constexpr int s_Shift2[] = {6, 4, 2, 0};
778 : // unpack 2-bit in-place in reverse
779 : // DANGER: Non-standard decrement of counter in the test section of
780 : // for.
781 44 : for (int i = n; --i >= 0;)
782 36 : pData[i] =
783 36 : (pData[i >> 2] >> static_cast<GByte>(s_Shift2[i & 3])) &
784 : 0x03;
785 :
786 8 : break;
787 : }
788 8 : case 4:
789 : {
790 8 : constexpr int s_Shift4[] = {4, 0};
791 : // unpack 4-bit in-place in reverse
792 : // DANGER: Non-standard decrement of counter in the test section of
793 : // for.
794 44 : for (int i = n; --i >= 0;)
795 36 : pData[i] =
796 36 : (pData[i >> 1] >> static_cast<GByte>(s_Shift4[i & 1])) &
797 : 0x0f;
798 :
799 8 : break;
800 : }
801 8 : case 3:
802 : {
803 : // unpacks 8 pixels (3 bytes) at time
804 8 : int i = 0;
805 8 : int k = 0;
806 9 : for (; i + 7 < n; i += 8, k += 3)
807 : {
808 1 : pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 5));
809 1 : pUnpackData[i + 1] = ((pDataSrc[k + 0] >> 2) & 0x07);
810 1 : pUnpackData[i + 2] =
811 1 : ((pDataSrc[k + 0] << 1) & 0x07) | (pDataSrc[k + 1] >> 7);
812 1 : pUnpackData[i + 3] = ((pDataSrc[k + 1] >> 4) & 0x07);
813 1 : pUnpackData[i + 4] = ((pDataSrc[k + 1] >> 1) & 0x07);
814 1 : pUnpackData[i + 5] =
815 1 : ((pDataSrc[k + 1] << 2) & 0x07) | (pDataSrc[k + 2] >> 6);
816 1 : pUnpackData[i + 6] = ((pDataSrc[k + 2] >> 3) & 0x07);
817 1 : pUnpackData[i + 7] = ((pDataSrc[k + 2]) & 0x7);
818 : }
819 8 : if (i < n)
820 : {
821 7 : pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 5));
822 7 : if (i + 1 < n)
823 6 : pUnpackData[i + 1] = ((pDataSrc[k + 0] >> 2) & 0x07);
824 7 : if (i + 2 < n)
825 5 : pUnpackData[i + 2] = ((pDataSrc[k + 0] << 1) & 0x07) |
826 5 : (pDataSrc[k + 1] >> 7);
827 7 : if (i + 3 < n)
828 4 : pUnpackData[i + 3] = ((pDataSrc[k + 1] >> 4) & 0x07);
829 7 : if (i + 4 < n)
830 3 : pUnpackData[i + 4] = ((pDataSrc[k + 1] >> 1) & 0x07);
831 7 : if (i + 5 < n)
832 2 : pUnpackData[i + 5] = ((pDataSrc[k + 1] << 2) & 0x07) |
833 2 : (pDataSrc[k + 2] >> 6);
834 7 : if (i + 6 < n)
835 1 : pUnpackData[i + 6] = ((pDataSrc[k + 2] >> 3) & 0x07);
836 : }
837 :
838 8 : memcpy(pData, pUnpackData, n);
839 8 : break;
840 : }
841 8 : case 5:
842 : {
843 : // unpacks 8 pixels (5 bytes) at time
844 8 : int i = 0;
845 8 : int k = 0;
846 9 : for (; i + 7 < n; i += 8, k += 5)
847 : {
848 1 : pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 3));
849 1 : pUnpackData[i + 1] =
850 1 : ((pDataSrc[k + 0] << 2) & 0x1f) | (pDataSrc[k + 1] >> 6);
851 1 : pUnpackData[i + 2] = ((pDataSrc[k + 1] >> 1) & 0x1f);
852 1 : pUnpackData[i + 3] =
853 1 : ((pDataSrc[k + 1] << 4) & 0x1f) | (pDataSrc[k + 2] >> 4);
854 1 : pUnpackData[i + 4] =
855 1 : ((pDataSrc[k + 2] << 1) & 0x1f) | (pDataSrc[k + 3] >> 7);
856 1 : pUnpackData[i + 5] = ((pDataSrc[k + 3] >> 2) & 0x1f);
857 1 : pUnpackData[i + 6] =
858 1 : ((pDataSrc[k + 3] << 3) & 0x1f) | (pDataSrc[k + 4] >> 5);
859 1 : pUnpackData[i + 7] = ((pDataSrc[k + 4]) & 0x1f);
860 : }
861 8 : if (i < n)
862 : {
863 7 : pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 3));
864 7 : if (i + 1 < n)
865 6 : pUnpackData[i + 1] = ((pDataSrc[k + 0] << 2) & 0x1f) |
866 6 : (pDataSrc[k + 1] >> 6);
867 7 : if (i + 2 < n)
868 5 : pUnpackData[i + 2] = ((pDataSrc[k + 1] >> 1) & 0x1f);
869 7 : if (i + 3 < n)
870 4 : pUnpackData[i + 3] = ((pDataSrc[k + 1] << 4) & 0x1f) |
871 4 : (pDataSrc[k + 2] >> 4);
872 7 : if (i + 4 < n)
873 3 : pUnpackData[i + 4] = ((pDataSrc[k + 2] << 1) & 0x1f) |
874 3 : (pDataSrc[k + 3] >> 7);
875 7 : if (i + 5 < n)
876 2 : pUnpackData[i + 5] = ((pDataSrc[k + 3] >> 2) & 0x1f);
877 7 : if (i + 6 < n)
878 1 : pUnpackData[i + 6] = ((pDataSrc[k + 3] << 3) & 0x1f) |
879 1 : (pDataSrc[k + 4] >> 5);
880 : }
881 :
882 8 : memcpy(pData, pUnpackData, n);
883 8 : break;
884 : }
885 8 : case 6:
886 : {
887 : // unpacks 4 pixels (3 bytes) at time
888 8 : int i = 0;
889 8 : int k = 0;
890 14 : for (; i + 3 < n; i += 4, k += 3)
891 : {
892 6 : pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 2));
893 6 : pUnpackData[i + 1] =
894 6 : ((pDataSrc[k + 0] << 4) & 0x3f) | (pDataSrc[k + 1] >> 4);
895 6 : pUnpackData[i + 2] =
896 6 : ((pDataSrc[k + 1] << 2) & 0x3f) | (pDataSrc[k + 2] >> 6);
897 6 : pUnpackData[i + 3] = ((pDataSrc[k + 2]) & 0x3f);
898 : }
899 8 : if (i < n)
900 : {
901 6 : pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 2));
902 6 : if (i + 1 < n)
903 4 : pUnpackData[i + 1] = ((pDataSrc[k + 0] << 4) & 0x3f) |
904 4 : (pDataSrc[k + 1] >> 4);
905 6 : if (i + 2 < n)
906 2 : pUnpackData[i + 2] = ((pDataSrc[k + 1] << 2) & 0x3f) |
907 2 : (pDataSrc[k + 2] >> 6);
908 : }
909 :
910 8 : memcpy(pData, pUnpackData, n);
911 8 : break;
912 : }
913 8 : case 7:
914 : {
915 : // unpacks 8 pixels (7 bytes) at time
916 8 : int i = 0;
917 8 : int k = 0;
918 9 : for (; i + 7 < n; i += 8, k += 7)
919 : {
920 1 : pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 1));
921 1 : pUnpackData[i + 1] =
922 1 : ((pDataSrc[k + 0] << 6) & 0x7f) | (pDataSrc[k + 1] >> 2);
923 1 : pUnpackData[i + 2] =
924 1 : ((pDataSrc[k + 1] << 5) & 0x7f) | (pDataSrc[k + 2] >> 3);
925 1 : pUnpackData[i + 3] =
926 1 : ((pDataSrc[k + 2] << 4) & 0x7f) | (pDataSrc[k + 3] >> 4);
927 1 : pUnpackData[i + 4] =
928 1 : ((pDataSrc[k + 3] << 3) & 0x7f) | (pDataSrc[k + 4] >> 5);
929 1 : pUnpackData[i + 5] =
930 1 : ((pDataSrc[k + 4] << 2) & 0x7f) | (pDataSrc[k + 5] >> 6);
931 1 : pUnpackData[i + 6] =
932 1 : ((pDataSrc[k + 5] << 1) & 0x7f) | (pDataSrc[k + 6] >> 7);
933 1 : pUnpackData[i + 7] = ((pDataSrc[k + 6]) & 0x7f);
934 : }
935 8 : if (i < n)
936 : {
937 7 : pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 1));
938 7 : if (i + 1 < n)
939 6 : pUnpackData[i + 1] = ((pDataSrc[k + 0] << 6) & 0x7f) |
940 6 : (pDataSrc[k + 1] >> 2);
941 7 : if (i + 2 < n)
942 5 : pUnpackData[i + 2] = ((pDataSrc[k + 1] << 5) & 0x7f) |
943 5 : (pDataSrc[k + 2] >> 3);
944 7 : if (i + 3 < n)
945 4 : pUnpackData[i + 3] = ((pDataSrc[k + 2] << 4) & 0x7f) |
946 4 : (pDataSrc[k + 3] >> 4);
947 7 : if (i + 4 < n)
948 3 : pUnpackData[i + 4] = ((pDataSrc[k + 3] << 3) & 0x7f) |
949 3 : (pDataSrc[k + 4] >> 5);
950 7 : if (i + 5 < n)
951 2 : pUnpackData[i + 5] = ((pDataSrc[k + 4] << 2) & 0x7f) |
952 2 : (pDataSrc[k + 5] >> 6);
953 7 : if (i + 6 < n)
954 1 : pUnpackData[i + 6] = ((pDataSrc[k + 5] << 1) & 0x7f) |
955 1 : (pDataSrc[k + 6] >> 7);
956 : }
957 :
958 8 : memcpy(pData, pUnpackData, n);
959 8 : break;
960 : }
961 8 : case 12:
962 : {
963 8 : GByte *pabyImage = reinterpret_cast<GByte *>(pData);
964 8 : GUInt16 *panImage = reinterpret_cast<GUInt16 *>(pData);
965 : // DANGER: Non-standard decrement of counter in the test section of
966 : // for.
967 44 : for (int i = n; --i >= 0;)
968 : {
969 36 : const long iOffset = i * 3 / 2;
970 36 : if (i % 2 == 0)
971 20 : panImage[i] = pabyImage[iOffset] +
972 20 : (pabyImage[iOffset + 1] & 0xf0) * 16;
973 : else
974 16 : panImage[i] = (pabyImage[iOffset] & 0x0f) * 16 +
975 16 : (pabyImage[iOffset + 1] & 0xf0) / 16 +
976 16 : (pabyImage[iOffset + 1] & 0x0f) * 256;
977 : }
978 :
979 8 : break;
980 : }
981 : }
982 68 : }
983 :
984 : /************************************************************************/
985 : /* ==================================================================== */
986 : /* NITFWrapperRasterBand */
987 : /* ==================================================================== */
988 : /************************************************************************/
989 :
990 : /************************************************************************/
991 : /* NITFWrapperRasterBand() */
992 : /************************************************************************/
993 :
994 107 : NITFWrapperRasterBand::NITFWrapperRasterBand(NITFDataset *poDSIn,
995 : GDALRasterBand *poBaseBandIn,
996 107 : int nBandIn)
997 214 : : poBaseBand(poBaseBandIn), eInterp(poBaseBandIn->GetColorInterpretation()),
998 321 : bIsJPEG(poBaseBandIn->GetDataset() != nullptr &&
999 214 : poBaseBandIn->GetDataset()->GetDriver() != nullptr &&
1000 107 : EQUAL(poBaseBandIn->GetDataset()->GetDriver()->GetDescription(),
1001 107 : "JPEG"))
1002 : {
1003 107 : poDS = poDSIn;
1004 107 : nBand = nBandIn;
1005 107 : poBaseBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
1006 107 : eDataType = poBaseBandIn->GetRasterDataType();
1007 107 : }
1008 :
1009 : /************************************************************************/
1010 : /* ~NITFWrapperRasterBand() */
1011 : /************************************************************************/
1012 :
1013 214 : NITFWrapperRasterBand::~NITFWrapperRasterBand()
1014 : {
1015 107 : if (poColorTable != nullptr)
1016 0 : delete poColorTable;
1017 214 : }
1018 :
1019 : /************************************************************************/
1020 : /* RefUnderlyingRasterBand() */
1021 : /************************************************************************/
1022 :
1023 : /* We don't need ref-counting. Just return the base band */
1024 574 : GDALRasterBand *NITFWrapperRasterBand::RefUnderlyingRasterBand()
1025 : {
1026 574 : return poBaseBand;
1027 : }
1028 :
1029 : /************************************************************************/
1030 : /* GetColorTable() */
1031 : /************************************************************************/
1032 :
1033 16 : GDALColorTable *NITFWrapperRasterBand::GetColorTable()
1034 : {
1035 16 : return poColorTable;
1036 : }
1037 :
1038 : /************************************************************************/
1039 : /* SetColorTableFromNITFBandInfo() */
1040 : /************************************************************************/
1041 :
1042 0 : void NITFWrapperRasterBand::SetColorTableFromNITFBandInfo()
1043 : {
1044 0 : NITFDataset *poGDS = reinterpret_cast<NITFDataset *>(poDS);
1045 0 : poColorTable = NITFMakeColorTable(poGDS->psImage,
1046 0 : poGDS->psImage->pasBandInfo + nBand - 1);
1047 0 : }
1048 :
1049 : /************************************************************************/
1050 : /* GetColorInterpretation() */
1051 : /************************************************************************/
1052 :
1053 60 : GDALColorInterp NITFWrapperRasterBand::GetColorInterpretation()
1054 : {
1055 60 : return eInterp;
1056 : }
1057 :
1058 : /************************************************************************/
1059 : /* SetColorInterpretation() */
1060 : /************************************************************************/
1061 :
1062 108 : CPLErr NITFWrapperRasterBand::SetColorInterpretation(GDALColorInterp eInterpIn)
1063 : {
1064 108 : this->eInterp = eInterpIn;
1065 108 : if (poBaseBand->GetDataset() != nullptr &&
1066 216 : poBaseBand->GetDataset()->GetDriver() != nullptr &&
1067 108 : EQUAL(poBaseBand->GetDataset()->GetDriver()->GetDescription(),
1068 : "JP2ECW"))
1069 19 : poBaseBand->SetColorInterpretation(eInterp);
1070 108 : return CE_None;
1071 : }
1072 :
1073 : /************************************************************************/
1074 : /* GetOverviewCount() */
1075 : /************************************************************************/
1076 :
1077 6 : int NITFWrapperRasterBand::GetOverviewCount()
1078 : {
1079 6 : if (bIsJPEG)
1080 : {
1081 4 : if ((reinterpret_cast<NITFDataset *>(poDS))
1082 2 : ->ExposeUnderlyingJPEGDatasetOverviews())
1083 0 : return NITFProxyPamRasterBand::GetOverviewCount();
1084 :
1085 2 : return GDALPamRasterBand::GetOverviewCount();
1086 : }
1087 :
1088 4 : return NITFProxyPamRasterBand::GetOverviewCount();
1089 : }
1090 :
1091 : /************************************************************************/
1092 : /* GetOverview() */
1093 : /************************************************************************/
1094 :
1095 3 : GDALRasterBand *NITFWrapperRasterBand::GetOverview(int iOverview)
1096 : {
1097 3 : if (bIsJPEG)
1098 : {
1099 2 : if ((reinterpret_cast<NITFDataset *>(poDS))
1100 1 : ->ExposeUnderlyingJPEGDatasetOverviews())
1101 0 : return NITFProxyPamRasterBand::GetOverview(iOverview);
1102 :
1103 1 : return GDALPamRasterBand::GetOverview(iOverview);
1104 : }
1105 :
1106 2 : return NITFProxyPamRasterBand::GetOverview(iOverview);
1107 : }
1108 :
1109 : /************************************************************************/
1110 : /* NITFComplexRasterBand() */
1111 : /************************************************************************/
1112 :
1113 5 : NITFComplexRasterBand::NITFComplexRasterBand(NITFDataset *poDSIn,
1114 : GDALRasterBand *poBandI,
1115 : GDALRasterBand *poBandQ,
1116 5 : int nIBand, int nQBand)
1117 5 : : NITFRasterBand(poDSIn, nIBand)
1118 : {
1119 :
1120 5 : CPLAssert(poBandI->GetRasterDataType() == poBandQ->GetRasterDataType());
1121 5 : underlyingDataType = poBandI->GetRasterDataType();
1122 :
1123 : //add the I and Q bands to an intermediate dataset
1124 5 : poIntermediateDS = std::make_unique<NITFDataset>();
1125 5 : poIntermediateDS->nRasterXSize = poDSIn->nRasterXSize;
1126 5 : poIntermediateDS->nRasterYSize = poDSIn->nRasterYSize;
1127 5 : poIntermediateDS->eAccess = poDSIn->eAccess;
1128 :
1129 5 : poIntermediateDS->SetBand(nIBand, poBandI);
1130 5 : poIntermediateDS->SetBand(nQBand, poBandQ);
1131 :
1132 5 : anBandMap[0] = nIBand;
1133 5 : anBandMap[1] = nQBand;
1134 :
1135 : //set the new datatype
1136 5 : switch (underlyingDataType)
1137 : {
1138 0 : case GDT_Int16:
1139 0 : eDataType = GDT_CInt16;
1140 0 : break;
1141 0 : case GDT_Int32:
1142 0 : eDataType = GDT_CInt32;
1143 0 : break;
1144 5 : case GDT_Float32:
1145 5 : eDataType = GDT_CFloat32;
1146 5 : break;
1147 0 : case GDT_Float64:
1148 0 : eDataType = GDT_CFloat64;
1149 0 : break;
1150 0 : default:
1151 0 : eDataType = GDT_Unknown;
1152 0 : CPLError(CE_Failure, CPLE_NotSupported,
1153 : "Unsupported complex datatype");
1154 0 : break;
1155 : }
1156 :
1157 5 : complexDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1158 5 : underlyingDataTypeSize = GDALGetDataTypeSizeBytes(underlyingDataType);
1159 5 : CPLAssert(underlyingDataTypeSize * 2 == complexDataTypeSize);
1160 :
1161 5 : poBandI->GetBlockSize(&nBlockXSize, &nBlockYSize);
1162 5 : }
1163 :
1164 : /************************************************************************/
1165 : /* IReadBlock() */
1166 : /************************************************************************/
1167 :
1168 40 : CPLErr NITFComplexRasterBand::IBlockIO(int nBlockXOff, int nBlockYOff,
1169 : void *pImage, GDALRWFlag rwFlag)
1170 :
1171 : {
1172 : int nRequestYSize;
1173 : int nRequestXSize;
1174 40 : bool bMemset = false;
1175 :
1176 : /* -------------------------------------------------------------------- */
1177 : /* If the last strip is partial, we need to avoid */
1178 : /* over-requesting. We also need to initialize the extra part */
1179 : /* of the block to zero. */
1180 : /* -------------------------------------------------------------------- */
1181 40 : if ((nBlockYOff + 1) * nBlockYSize > nRasterYSize)
1182 : {
1183 0 : nRequestYSize = nRasterYSize - nBlockYOff * nBlockYSize;
1184 0 : if (rwFlag == GF_Read)
1185 0 : bMemset = true;
1186 : }
1187 : else
1188 : {
1189 40 : nRequestYSize = nBlockYSize;
1190 : }
1191 :
1192 : /*-------------------------------------------------------------------- */
1193 : /* If the input imagery is tiled, also need to avoid over- */
1194 : /* requesting in the X-direction. */
1195 : /* ------------------------------------------------------------------- */
1196 40 : if ((nBlockXOff + 1) * nBlockXSize > nRasterXSize)
1197 : {
1198 0 : nRequestXSize = nRasterXSize - nBlockXOff * nBlockXSize;
1199 0 : if (rwFlag == GF_Read)
1200 0 : bMemset = true;
1201 : }
1202 : else
1203 : {
1204 40 : nRequestXSize = nBlockXSize;
1205 : }
1206 :
1207 40 : if (bMemset)
1208 : {
1209 0 : memset(pImage, 0,
1210 0 : static_cast<size_t>(GDALGetDataTypeSizeBytes(eDataType)) *
1211 0 : nBlockXSize * nBlockYSize);
1212 : }
1213 :
1214 : //read/write both bands with interleaved pixels
1215 40 : return poIntermediateDS->RasterIO(
1216 40 : rwFlag, nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize,
1217 : nRequestXSize, nRequestYSize, pImage, nRequestXSize, nRequestYSize,
1218 40 : underlyingDataType, 2, &anBandMap[0], complexDataTypeSize,
1219 40 : static_cast<GSpacing>(complexDataTypeSize) * nBlockXSize,
1220 80 : underlyingDataTypeSize, nullptr);
1221 : }
1222 :
1223 : /************************************************************************/
1224 : /* IReadBlock() */
1225 : /************************************************************************/
1226 :
1227 40 : CPLErr NITFComplexRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff,
1228 : void *pImage)
1229 :
1230 : {
1231 40 : return IBlockIO(nBlockXOff, nBlockYOff, pImage, GF_Read);
1232 : }
1233 :
1234 : /************************************************************************/
1235 : /* IWriteBlock() */
1236 : /************************************************************************/
1237 :
1238 0 : CPLErr NITFComplexRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff,
1239 : void *pImage)
1240 :
1241 : {
1242 0 : return IBlockIO(nBlockXOff, nBlockYOff, pImage, GF_Write);
1243 : }
|