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