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 210940 : static GDALColorTable *NITFMakeColorTable(NITFImage *psImage,
45 : NITFBandInfo *psBandInfo)
46 : {
47 210940 : GDALColorTable *poColorTable = nullptr;
48 :
49 210940 : 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 210940 : 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 210940 : 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 210940 : NITFRasterBand::NITFRasterBand(NITFDataset *poDSIn, int nBandIn)
370 210940 : : psImage(poDSIn->psImage), poColorTable(nullptr), pUnpackData(nullptr),
371 210940 : bScanlineAccess(FALSE)
372 : {
373 210940 : NITFBandInfo *psBandInfo = poDSIn->psImage->pasBandInfo + nBandIn - 1;
374 :
375 210940 : poDS = poDSIn;
376 210940 : nBand = nBandIn;
377 210940 : eAccess = poDSIn->eAccess;
378 :
379 : /* -------------------------------------------------------------------- */
380 : /* Translate data type(s). */
381 : /* -------------------------------------------------------------------- */
382 210940 : if (psImage->nBitsPerSample <= 8)
383 210801 : eDataType = GDT_Byte;
384 139 : else if (psImage->nBitsPerSample == 16 && EQUAL(psImage->szPVType, "SI"))
385 27 : eDataType = GDT_Int16;
386 112 : else if (psImage->nBitsPerSample == 16)
387 20 : eDataType = GDT_UInt16;
388 92 : else if (psImage->nBitsPerSample == 12)
389 16 : eDataType = GDT_UInt16;
390 76 : else if (psImage->nBitsPerSample == 32 && EQUAL(psImage->szPVType, "SI"))
391 12 : eDataType = GDT_Int32;
392 64 : else if (psImage->nBitsPerSample == 32 && EQUAL(psImage->szPVType, "R"))
393 31 : eDataType = GDT_Float32;
394 33 : else if (psImage->nBitsPerSample == 32)
395 12 : eDataType = GDT_UInt32;
396 21 : else if (psImage->nBitsPerSample == 64 && EQUAL(psImage->szPVType, "R"))
397 12 : eDataType = GDT_Float64;
398 9 : else if (psImage->nBitsPerSample == 64 && EQUAL(psImage->szPVType, "C"))
399 9 : eDataType = GDT_CFloat32;
400 : /* ERO : note I'm not sure if CFloat64 can be transmitted as NBPP is only 2
401 : * characters */
402 : else
403 : {
404 : int bOpenUnderlyingDS =
405 0 : CPLTestBool(CPLGetConfigOption("NITF_OPEN_UNDERLYING_DS", "YES"));
406 0 : if (!bOpenUnderlyingDS && psImage->nBitsPerSample > 8 &&
407 0 : psImage->nBitsPerSample < 16)
408 : {
409 0 : if (EQUAL(psImage->szPVType, "SI"))
410 0 : eDataType = GDT_Int16;
411 : else
412 0 : eDataType = GDT_UInt16;
413 : }
414 : else
415 : {
416 0 : eDataType = GDT_Unknown;
417 0 : CPLError(CE_Warning, CPLE_AppDefined,
418 : "Unsupported combination of PVTYPE(%s) and NBPP(%d).",
419 0 : psImage->szPVType, psImage->nBitsPerSample);
420 : }
421 : }
422 :
423 : /* -------------------------------------------------------------------- */
424 : /* Work out block size. If the image is all one big block we */
425 : /* handle via the scanline access API. */
426 : /* -------------------------------------------------------------------- */
427 210940 : if (psImage->nBlocksPerRow == 1 && psImage->nBlocksPerColumn == 1 &&
428 210852 : psImage->nBitsPerSample >= 8 && EQUAL(psImage->szIC, "NC"))
429 : {
430 210732 : bScanlineAccess = TRUE;
431 210732 : nBlockXSize = psImage->nBlockWidth;
432 210732 : nBlockYSize = 1;
433 : }
434 : else
435 : {
436 208 : bScanlineAccess = FALSE;
437 208 : nBlockXSize = psImage->nBlockWidth;
438 208 : nBlockYSize = psImage->nBlockHeight;
439 : }
440 :
441 : /* -------------------------------------------------------------------- */
442 : /* Do we have a color table? */
443 : /* -------------------------------------------------------------------- */
444 210940 : poColorTable = NITFMakeColorTable(psImage, psBandInfo);
445 :
446 210940 : if (psImage->nABPP != 8 && psImage->nABPP != 16 && psImage->nABPP != 32 &&
447 31 : psImage->nABPP != 64)
448 : {
449 10 : SetMetadataItem("NBITS", CPLString().Printf("%d", psImage->nABPP),
450 : "IMAGE_STRUCTURE");
451 : }
452 :
453 210940 : if (psImage->nBitsPerSample == 3 || psImage->nBitsPerSample == 5 ||
454 210908 : psImage->nBitsPerSample == 6 || psImage->nBitsPerSample == 7)
455 : {
456 64 : if (nBlockXSize > (INT_MAX - 7) / nBlockYSize)
457 : {
458 0 : eDataType = GDT_Unknown;
459 : }
460 : else
461 : {
462 64 : pUnpackData = static_cast<GByte *>(
463 64 : VSI_MALLOC_VERBOSE(((nBlockXSize * nBlockYSize + 7) / 8) * 8));
464 64 : if (pUnpackData == nullptr)
465 0 : eDataType = GDT_Unknown;
466 : }
467 : }
468 210940 : }
469 :
470 : /************************************************************************/
471 : /* ~NITFRasterBand() */
472 : /************************************************************************/
473 :
474 421875 : NITFRasterBand::~NITFRasterBand()
475 :
476 : {
477 210940 : if (poColorTable != nullptr)
478 53 : delete poColorTable;
479 :
480 210940 : VSIFree(pUnpackData);
481 421875 : }
482 :
483 : /************************************************************************/
484 : /* IReadBlock() */
485 : /************************************************************************/
486 :
487 18630 : CPLErr NITFRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
488 :
489 : {
490 18630 : NITFDataset *poGDS = reinterpret_cast<NITFDataset *>(poDS);
491 :
492 : /* -------------------------------------------------------------------- */
493 : /* Special case for JPEG blocks. */
494 : /* -------------------------------------------------------------------- */
495 18630 : if (EQUAL(psImage->szIC, "C3") || EQUAL(psImage->szIC, "M3"))
496 : {
497 128 : CPLErr eErr = poGDS->ReadJPEGBlock(nBlockXOff, nBlockYOff);
498 128 : const int nBlockBandSize = psImage->nBlockWidth *
499 128 : psImage->nBlockHeight *
500 128 : GDALGetDataTypeSizeBytes(eDataType);
501 :
502 128 : if (eErr != CE_None)
503 0 : return eErr;
504 :
505 128 : memcpy(pImage, poGDS->pabyJPEGBlock + (nBand - 1) * nBlockBandSize,
506 : nBlockBandSize);
507 :
508 128 : return eErr;
509 : }
510 :
511 : /* -------------------------------------------------------------------- */
512 : /* Read the line/block */
513 : /* -------------------------------------------------------------------- */
514 : int nBlockResult;
515 :
516 18502 : if (bScanlineAccess)
517 : {
518 15950 : nBlockResult = NITFReadImageLine(psImage, nBlockYOff, nBand, pImage);
519 : }
520 : else
521 : {
522 : nBlockResult =
523 2552 : NITFReadImageBlock(psImage, nBlockXOff, nBlockYOff, nBand, pImage);
524 : }
525 :
526 18502 : if (nBlockResult == BLKREAD_OK)
527 : {
528 18070 : if (psImage->nBitsPerSample % 8)
529 68 : Unpack(reinterpret_cast<GByte *>(pImage));
530 :
531 18070 : return CE_None;
532 : }
533 :
534 432 : if (nBlockResult == BLKREAD_FAIL)
535 0 : return CE_Failure;
536 :
537 : /* -------------------------------------------------------------------- */
538 : /* If we got a null/missing block, try to fill it in with the */
539 : /* nodata value. It seems this only really works properly for */
540 : /* 8bit. */
541 : /* -------------------------------------------------------------------- */
542 432 : if (psImage->bNoDataSet)
543 432 : memset(pImage, psImage->nNoDataValue,
544 432 : static_cast<size_t>(psImage->nWordSize) * psImage->nBlockWidth *
545 432 : psImage->nBlockHeight);
546 : else
547 0 : memset(pImage, 0,
548 0 : static_cast<size_t>(psImage->nWordSize) * psImage->nBlockWidth *
549 0 : psImage->nBlockHeight);
550 :
551 432 : return CE_None;
552 : }
553 :
554 : /************************************************************************/
555 : /* IWriteBlock() */
556 : /************************************************************************/
557 :
558 16775 : CPLErr NITFRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff, void *pImage)
559 :
560 : {
561 : /* -------------------------------------------------------------------- */
562 : /* Write the line/block */
563 : /* -------------------------------------------------------------------- */
564 : int nBlockResult;
565 :
566 16775 : if (bScanlineAccess)
567 : {
568 16131 : nBlockResult = NITFWriteImageLine(psImage, nBlockYOff, nBand, pImage);
569 : }
570 : else
571 : {
572 : nBlockResult =
573 644 : NITFWriteImageBlock(psImage, nBlockXOff, nBlockYOff, nBand, pImage);
574 : }
575 :
576 16775 : if (nBlockResult == BLKREAD_OK)
577 16775 : return CE_None;
578 :
579 0 : return CE_Failure;
580 : }
581 :
582 : /************************************************************************/
583 : /* GetNoDataValue() */
584 : /************************************************************************/
585 :
586 118 : double NITFRasterBand::GetNoDataValue(int *pbSuccess)
587 :
588 : {
589 118 : if (pbSuccess != nullptr)
590 117 : *pbSuccess = psImage->bNoDataSet;
591 :
592 118 : if (psImage->bNoDataSet)
593 22 : return psImage->nNoDataValue;
594 :
595 96 : return GDALPamRasterBand::GetNoDataValue(pbSuccess);
596 : }
597 :
598 : /************************************************************************/
599 : /* GetColorInterpretation() */
600 : /************************************************************************/
601 :
602 156 : GDALColorInterp NITFRasterBand::GetColorInterpretation()
603 :
604 : {
605 156 : NITFBandInfo *psBandInfo = psImage->pasBandInfo + nBand - 1;
606 :
607 156 : if (poColorTable != nullptr)
608 21 : return GCI_PaletteIndex;
609 :
610 135 : if (EQUAL(psBandInfo->szIREPBAND, "R"))
611 20 : return GCI_RedBand;
612 115 : if (EQUAL(psBandInfo->szIREPBAND, "G"))
613 20 : return GCI_GreenBand;
614 95 : if (EQUAL(psBandInfo->szIREPBAND, "B"))
615 20 : return GCI_BlueBand;
616 75 : if (EQUAL(psBandInfo->szIREPBAND, "M"))
617 69 : return GCI_GrayIndex;
618 6 : if (EQUAL(psBandInfo->szIREPBAND, "Y"))
619 2 : return GCI_YCbCr_YBand;
620 4 : if (EQUAL(psBandInfo->szIREPBAND, "Cb"))
621 2 : return GCI_YCbCr_CbBand;
622 2 : if (EQUAL(psBandInfo->szIREPBAND, "Cr"))
623 2 : return GCI_YCbCr_CrBand;
624 :
625 0 : return GCI_Undefined;
626 : }
627 :
628 : /************************************************************************/
629 : /* NITFSetColorInterpretation() */
630 : /************************************************************************/
631 :
632 33 : CPLErr NITFSetColorInterpretation(NITFImage *psImage, int nBand,
633 : GDALColorInterp eInterp)
634 :
635 : {
636 33 : const char *pszREP = nullptr;
637 :
638 33 : if (eInterp == GCI_RedBand)
639 11 : pszREP = "R";
640 22 : else if (eInterp == GCI_GreenBand)
641 11 : pszREP = "G";
642 11 : else if (eInterp == GCI_BlueBand)
643 11 : pszREP = "B";
644 0 : else if (eInterp == GCI_GrayIndex)
645 0 : pszREP = "M";
646 0 : else if (eInterp == GCI_YCbCr_YBand)
647 0 : pszREP = "Y";
648 0 : else if (eInterp == GCI_YCbCr_CbBand)
649 0 : pszREP = "Cb";
650 0 : else if (eInterp == GCI_YCbCr_CrBand)
651 0 : pszREP = "Cr";
652 0 : else if (eInterp == GCI_Undefined)
653 0 : return CE_None;
654 :
655 33 : if (pszREP == nullptr)
656 : {
657 0 : CPLError(CE_Failure, CPLE_NotSupported,
658 : "Requested color interpretation (%s) not supported in NITF.",
659 : GDALGetColorInterpretationName(eInterp));
660 0 : return CE_Failure;
661 : }
662 :
663 : /* -------------------------------------------------------------------- */
664 : /* Where does this go in the file? */
665 : /* -------------------------------------------------------------------- */
666 33 : NITFBandInfo *psBandInfo = psImage->pasBandInfo + nBand - 1;
667 33 : strcpy(psBandInfo->szIREPBAND, pszREP);
668 33 : GUIntBig nOffset = NITFIHFieldOffset(psImage, "IREPBAND");
669 :
670 33 : if (nOffset != 0)
671 33 : nOffset += (nBand - 1) * 13;
672 :
673 : /* -------------------------------------------------------------------- */
674 : /* write it (space padded). */
675 : /* -------------------------------------------------------------------- */
676 : char szPadded[4];
677 33 : strcpy(szPadded, pszREP);
678 33 : strcat(szPadded, " ");
679 :
680 33 : if (nOffset != 0)
681 : {
682 66 : if (VSIFSeekL(psImage->psFile->fp, nOffset, SEEK_SET) != 0 ||
683 33 : VSIFWriteL(reinterpret_cast<void *>(szPadded), 1, 2,
684 33 : psImage->psFile->fp) != 2)
685 : {
686 0 : CPLError(CE_Failure, CPLE_AppDefined,
687 : "IO failure writing new IREPBAND value to NITF file.");
688 0 : return CE_Failure;
689 : }
690 : }
691 :
692 33 : return CE_None;
693 : }
694 :
695 : /************************************************************************/
696 : /* SetColorInterpretation() */
697 : /************************************************************************/
698 :
699 30 : CPLErr NITFRasterBand::SetColorInterpretation(GDALColorInterp eInterp)
700 :
701 : {
702 30 : return NITFSetColorInterpretation(psImage, nBand, eInterp);
703 : }
704 :
705 : /************************************************************************/
706 : /* GetColorTable() */
707 : /************************************************************************/
708 :
709 54 : GDALColorTable *NITFRasterBand::GetColorTable()
710 :
711 : {
712 54 : return poColorTable;
713 : }
714 :
715 : /************************************************************************/
716 : /* SetColorTable() */
717 : /************************************************************************/
718 :
719 2 : CPLErr NITFRasterBand::SetColorTable(GDALColorTable *poNewCT)
720 :
721 : {
722 2 : NITFDataset *poGDS = reinterpret_cast<NITFDataset *>(poDS);
723 2 : if (poGDS->bInLoadXML)
724 0 : return GDALPamRasterBand::SetColorTable(poNewCT);
725 :
726 2 : if (poNewCT == nullptr)
727 0 : return CE_Failure;
728 :
729 : GByte abyNITFLUT[768];
730 2 : memset(abyNITFLUT, 0, 768);
731 :
732 2 : const int nCount = std::min(256, poNewCT->GetColorEntryCount());
733 135 : for (int i = 0; i < nCount; i++)
734 : {
735 : GDALColorEntry sEntry;
736 :
737 133 : poNewCT->GetColorEntryAsRGB(i, &sEntry);
738 133 : abyNITFLUT[i] = (GByte)sEntry.c1;
739 133 : abyNITFLUT[i + 256] = (GByte)sEntry.c2;
740 133 : abyNITFLUT[i + 512] = (GByte)sEntry.c3;
741 : }
742 :
743 2 : if (NITFWriteLUT(psImage, nBand, nCount, abyNITFLUT))
744 2 : return CE_None;
745 :
746 0 : return CE_Failure;
747 : }
748 :
749 : /************************************************************************/
750 : /* Unpack() */
751 : /************************************************************************/
752 :
753 68 : void NITFRasterBand::Unpack(GByte *pData)
754 : {
755 68 : const int n = nBlockXSize * nBlockYSize;
756 :
757 68 : GByte abyTempData[7] = {0, 0, 0, 0, 0, 0, 0};
758 68 : const GByte *pDataSrc = pData;
759 68 : if (n < psImage->nBitsPerSample && psImage->nBitsPerSample < 8)
760 : {
761 21 : memcpy(abyTempData, pData, n);
762 21 : pDataSrc = abyTempData;
763 : }
764 :
765 68 : switch (psImage->nBitsPerSample)
766 : {
767 12 : case 1:
768 : {
769 : // unpack 1-bit in-place in reverse
770 : // DANGER: Non-standard decrement of counter in the test section of
771 : // for.
772 1050510 : for (int i = n; --i >= 0;)
773 1050500 : pData[i] = (pData[i >> 3] & (0x80 >> (i & 7))) != 0;
774 :
775 12 : break;
776 : }
777 8 : case 2:
778 : {
779 8 : constexpr int s_Shift2[] = {6, 4, 2, 0};
780 : // unpack 2-bit in-place in reverse
781 : // DANGER: Non-standard decrement of counter in the test section of
782 : // for.
783 44 : for (int i = n; --i >= 0;)
784 36 : pData[i] = (pData[i >> 2] >> (GByte)s_Shift2[i & 3]) & 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] = (pData[i >> 1] >> (GByte)s_Shift4[i & 1]) & 0x0f;
796 :
797 8 : break;
798 : }
799 8 : case 3:
800 : {
801 : // unpacks 8 pixels (3 bytes) at time
802 8 : int i = 0;
803 8 : int k = 0;
804 9 : for (; i + 7 < n; i += 8, k += 3)
805 : {
806 1 : pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 5));
807 1 : pUnpackData[i + 1] = ((pDataSrc[k + 0] >> 2) & 0x07);
808 1 : pUnpackData[i + 2] =
809 1 : ((pDataSrc[k + 0] << 1) & 0x07) | (pDataSrc[k + 1] >> 7);
810 1 : pUnpackData[i + 3] = ((pDataSrc[k + 1] >> 4) & 0x07);
811 1 : pUnpackData[i + 4] = ((pDataSrc[k + 1] >> 1) & 0x07);
812 1 : pUnpackData[i + 5] =
813 1 : ((pDataSrc[k + 1] << 2) & 0x07) | (pDataSrc[k + 2] >> 6);
814 1 : pUnpackData[i + 6] = ((pDataSrc[k + 2] >> 3) & 0x07);
815 1 : pUnpackData[i + 7] = ((pDataSrc[k + 2]) & 0x7);
816 : }
817 8 : if (i < n)
818 : {
819 7 : pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 5));
820 7 : if (i + 1 < n)
821 6 : pUnpackData[i + 1] = ((pDataSrc[k + 0] >> 2) & 0x07);
822 7 : if (i + 2 < n)
823 5 : pUnpackData[i + 2] = ((pDataSrc[k + 0] << 1) & 0x07) |
824 5 : (pDataSrc[k + 1] >> 7);
825 7 : if (i + 3 < n)
826 4 : pUnpackData[i + 3] = ((pDataSrc[k + 1] >> 4) & 0x07);
827 7 : if (i + 4 < n)
828 3 : pUnpackData[i + 4] = ((pDataSrc[k + 1] >> 1) & 0x07);
829 7 : if (i + 5 < n)
830 2 : pUnpackData[i + 5] = ((pDataSrc[k + 1] << 2) & 0x07) |
831 2 : (pDataSrc[k + 2] >> 6);
832 7 : if (i + 6 < n)
833 1 : pUnpackData[i + 6] = ((pDataSrc[k + 2] >> 3) & 0x07);
834 : }
835 :
836 8 : memcpy(pData, pUnpackData, n);
837 8 : break;
838 : }
839 8 : case 5:
840 : {
841 : // unpacks 8 pixels (5 bytes) at time
842 8 : int i = 0;
843 8 : int k = 0;
844 9 : for (; i + 7 < n; i += 8, k += 5)
845 : {
846 1 : pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 3));
847 1 : pUnpackData[i + 1] =
848 1 : ((pDataSrc[k + 0] << 2) & 0x1f) | (pDataSrc[k + 1] >> 6);
849 1 : pUnpackData[i + 2] = ((pDataSrc[k + 1] >> 1) & 0x1f);
850 1 : pUnpackData[i + 3] =
851 1 : ((pDataSrc[k + 1] << 4) & 0x1f) | (pDataSrc[k + 2] >> 4);
852 1 : pUnpackData[i + 4] =
853 1 : ((pDataSrc[k + 2] << 1) & 0x1f) | (pDataSrc[k + 3] >> 7);
854 1 : pUnpackData[i + 5] = ((pDataSrc[k + 3] >> 2) & 0x1f);
855 1 : pUnpackData[i + 6] =
856 1 : ((pDataSrc[k + 3] << 3) & 0x1f) | (pDataSrc[k + 4] >> 5);
857 1 : pUnpackData[i + 7] = ((pDataSrc[k + 4]) & 0x1f);
858 : }
859 8 : if (i < n)
860 : {
861 7 : pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 3));
862 7 : if (i + 1 < n)
863 6 : pUnpackData[i + 1] = ((pDataSrc[k + 0] << 2) & 0x1f) |
864 6 : (pDataSrc[k + 1] >> 6);
865 7 : if (i + 2 < n)
866 5 : pUnpackData[i + 2] = ((pDataSrc[k + 1] >> 1) & 0x1f);
867 7 : if (i + 3 < n)
868 4 : pUnpackData[i + 3] = ((pDataSrc[k + 1] << 4) & 0x1f) |
869 4 : (pDataSrc[k + 2] >> 4);
870 7 : if (i + 4 < n)
871 3 : pUnpackData[i + 4] = ((pDataSrc[k + 2] << 1) & 0x1f) |
872 3 : (pDataSrc[k + 3] >> 7);
873 7 : if (i + 5 < n)
874 2 : pUnpackData[i + 5] = ((pDataSrc[k + 3] >> 2) & 0x1f);
875 7 : if (i + 6 < n)
876 1 : pUnpackData[i + 6] = ((pDataSrc[k + 3] << 3) & 0x1f) |
877 1 : (pDataSrc[k + 4] >> 5);
878 : }
879 :
880 8 : memcpy(pData, pUnpackData, n);
881 8 : break;
882 : }
883 8 : case 6:
884 : {
885 : // unpacks 4 pixels (3 bytes) at time
886 8 : int i = 0;
887 8 : int k = 0;
888 14 : for (; i + 3 < n; i += 4, k += 3)
889 : {
890 6 : pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 2));
891 6 : pUnpackData[i + 1] =
892 6 : ((pDataSrc[k + 0] << 4) & 0x3f) | (pDataSrc[k + 1] >> 4);
893 6 : pUnpackData[i + 2] =
894 6 : ((pDataSrc[k + 1] << 2) & 0x3f) | (pDataSrc[k + 2] >> 6);
895 6 : pUnpackData[i + 3] = ((pDataSrc[k + 2]) & 0x3f);
896 : }
897 8 : if (i < n)
898 : {
899 6 : pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 2));
900 6 : if (i + 1 < n)
901 4 : pUnpackData[i + 1] = ((pDataSrc[k + 0] << 4) & 0x3f) |
902 4 : (pDataSrc[k + 1] >> 4);
903 6 : if (i + 2 < n)
904 2 : pUnpackData[i + 2] = ((pDataSrc[k + 1] << 2) & 0x3f) |
905 2 : (pDataSrc[k + 2] >> 6);
906 : }
907 :
908 8 : memcpy(pData, pUnpackData, n);
909 8 : break;
910 : }
911 8 : case 7:
912 : {
913 : // unpacks 8 pixels (7 bytes) at time
914 8 : int i = 0;
915 8 : int k = 0;
916 9 : for (; i + 7 < n; i += 8, k += 7)
917 : {
918 1 : pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 1));
919 1 : pUnpackData[i + 1] =
920 1 : ((pDataSrc[k + 0] << 6) & 0x7f) | (pDataSrc[k + 1] >> 2);
921 1 : pUnpackData[i + 2] =
922 1 : ((pDataSrc[k + 1] << 5) & 0x7f) | (pDataSrc[k + 2] >> 3);
923 1 : pUnpackData[i + 3] =
924 1 : ((pDataSrc[k + 2] << 4) & 0x7f) | (pDataSrc[k + 3] >> 4);
925 1 : pUnpackData[i + 4] =
926 1 : ((pDataSrc[k + 3] << 3) & 0x7f) | (pDataSrc[k + 4] >> 5);
927 1 : pUnpackData[i + 5] =
928 1 : ((pDataSrc[k + 4] << 2) & 0x7f) | (pDataSrc[k + 5] >> 6);
929 1 : pUnpackData[i + 6] =
930 1 : ((pDataSrc[k + 5] << 1) & 0x7f) | (pDataSrc[k + 6] >> 7);
931 1 : pUnpackData[i + 7] = ((pDataSrc[k + 6]) & 0x7f);
932 : }
933 8 : if (i < n)
934 : {
935 7 : pUnpackData[i + 0] = ((pDataSrc[k + 0] >> 1));
936 7 : if (i + 1 < n)
937 6 : pUnpackData[i + 1] = ((pDataSrc[k + 0] << 6) & 0x7f) |
938 6 : (pDataSrc[k + 1] >> 2);
939 7 : if (i + 2 < n)
940 5 : pUnpackData[i + 2] = ((pDataSrc[k + 1] << 5) & 0x7f) |
941 5 : (pDataSrc[k + 2] >> 3);
942 7 : if (i + 3 < n)
943 4 : pUnpackData[i + 3] = ((pDataSrc[k + 2] << 4) & 0x7f) |
944 4 : (pDataSrc[k + 3] >> 4);
945 7 : if (i + 4 < n)
946 3 : pUnpackData[i + 4] = ((pDataSrc[k + 3] << 3) & 0x7f) |
947 3 : (pDataSrc[k + 4] >> 5);
948 7 : if (i + 5 < n)
949 2 : pUnpackData[i + 5] = ((pDataSrc[k + 4] << 2) & 0x7f) |
950 2 : (pDataSrc[k + 5] >> 6);
951 7 : if (i + 6 < n)
952 1 : pUnpackData[i + 6] = ((pDataSrc[k + 5] << 1) & 0x7f) |
953 1 : (pDataSrc[k + 6] >> 7);
954 : }
955 :
956 8 : memcpy(pData, pUnpackData, n);
957 8 : break;
958 : }
959 8 : case 12:
960 : {
961 8 : GByte *pabyImage = reinterpret_cast<GByte *>(pData);
962 8 : GUInt16 *panImage = reinterpret_cast<GUInt16 *>(pData);
963 : // DANGER: Non-standard decrement of counter in the test section of
964 : // for.
965 44 : for (int i = n; --i >= 0;)
966 : {
967 36 : const long iOffset = i * 3 / 2;
968 36 : if (i % 2 == 0)
969 20 : panImage[i] = pabyImage[iOffset] +
970 20 : (pabyImage[iOffset + 1] & 0xf0) * 16;
971 : else
972 16 : panImage[i] = (pabyImage[iOffset] & 0x0f) * 16 +
973 16 : (pabyImage[iOffset + 1] & 0xf0) / 16 +
974 16 : (pabyImage[iOffset + 1] & 0x0f) * 256;
975 : }
976 :
977 8 : break;
978 : }
979 : }
980 68 : }
981 :
982 : /************************************************************************/
983 : /* ==================================================================== */
984 : /* NITFWrapperRasterBand */
985 : /* ==================================================================== */
986 : /************************************************************************/
987 :
988 : /************************************************************************/
989 : /* NITFWrapperRasterBand() */
990 : /************************************************************************/
991 :
992 107 : NITFWrapperRasterBand::NITFWrapperRasterBand(NITFDataset *poDSIn,
993 : GDALRasterBand *poBaseBandIn,
994 107 : int nBandIn)
995 : : poBaseBand(poBaseBandIn), poColorTable(nullptr),
996 214 : eInterp(poBaseBandIn->GetColorInterpretation()),
997 321 : bIsJPEG(poBaseBandIn->GetDataset() != nullptr &&
998 214 : poBaseBandIn->GetDataset()->GetDriver() != nullptr &&
999 107 : EQUAL(poBaseBandIn->GetDataset()->GetDriver()->GetDescription(),
1000 107 : "JPEG"))
1001 : {
1002 107 : poDS = poDSIn;
1003 107 : nBand = nBandIn;
1004 107 : poBaseBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
1005 107 : eDataType = poBaseBandIn->GetRasterDataType();
1006 107 : }
1007 :
1008 : /************************************************************************/
1009 : /* ~NITFWrapperRasterBand() */
1010 : /************************************************************************/
1011 :
1012 214 : NITFWrapperRasterBand::~NITFWrapperRasterBand()
1013 : {
1014 107 : if (poColorTable != nullptr)
1015 0 : delete poColorTable;
1016 214 : }
1017 :
1018 : /************************************************************************/
1019 : /* RefUnderlyingRasterBand() */
1020 : /************************************************************************/
1021 :
1022 : /* We don't need ref-counting. Just return the base band */
1023 574 : GDALRasterBand *NITFWrapperRasterBand::RefUnderlyingRasterBand()
1024 : {
1025 574 : return poBaseBand;
1026 : }
1027 :
1028 : /************************************************************************/
1029 : /* GetColorTable() */
1030 : /************************************************************************/
1031 :
1032 16 : GDALColorTable *NITFWrapperRasterBand::GetColorTable()
1033 : {
1034 16 : return poColorTable;
1035 : }
1036 :
1037 : /************************************************************************/
1038 : /* SetColorTableFromNITFBandInfo() */
1039 : /************************************************************************/
1040 :
1041 0 : void NITFWrapperRasterBand::SetColorTableFromNITFBandInfo()
1042 : {
1043 0 : NITFDataset *poGDS = reinterpret_cast<NITFDataset *>(poDS);
1044 0 : poColorTable = NITFMakeColorTable(poGDS->psImage,
1045 0 : poGDS->psImage->pasBandInfo + nBand - 1);
1046 0 : }
1047 :
1048 : /************************************************************************/
1049 : /* GetColorInterpretation() */
1050 : /************************************************************************/
1051 :
1052 60 : GDALColorInterp NITFWrapperRasterBand::GetColorInterpretation()
1053 : {
1054 60 : return eInterp;
1055 : }
1056 :
1057 : /************************************************************************/
1058 : /* SetColorInterpretation() */
1059 : /************************************************************************/
1060 :
1061 108 : CPLErr NITFWrapperRasterBand::SetColorInterpretation(GDALColorInterp eInterpIn)
1062 : {
1063 108 : this->eInterp = eInterpIn;
1064 108 : if (poBaseBand->GetDataset() != nullptr &&
1065 216 : poBaseBand->GetDataset()->GetDriver() != nullptr &&
1066 108 : EQUAL(poBaseBand->GetDataset()->GetDriver()->GetDescription(),
1067 : "JP2ECW"))
1068 19 : poBaseBand->SetColorInterpretation(eInterp);
1069 108 : return CE_None;
1070 : }
1071 :
1072 : /************************************************************************/
1073 : /* GetOverviewCount() */
1074 : /************************************************************************/
1075 :
1076 6 : int NITFWrapperRasterBand::GetOverviewCount()
1077 : {
1078 6 : if (bIsJPEG)
1079 : {
1080 4 : if ((reinterpret_cast<NITFDataset *>(poDS))
1081 2 : ->ExposeUnderlyingJPEGDatasetOverviews())
1082 0 : return NITFProxyPamRasterBand::GetOverviewCount();
1083 :
1084 2 : return GDALPamRasterBand::GetOverviewCount();
1085 : }
1086 :
1087 4 : return NITFProxyPamRasterBand::GetOverviewCount();
1088 : }
1089 :
1090 : /************************************************************************/
1091 : /* GetOverview() */
1092 : /************************************************************************/
1093 :
1094 3 : GDALRasterBand *NITFWrapperRasterBand::GetOverview(int iOverview)
1095 : {
1096 3 : if (bIsJPEG)
1097 : {
1098 2 : if ((reinterpret_cast<NITFDataset *>(poDS))
1099 1 : ->ExposeUnderlyingJPEGDatasetOverviews())
1100 0 : return NITFProxyPamRasterBand::GetOverview(iOverview);
1101 :
1102 1 : return GDALPamRasterBand::GetOverview(iOverview);
1103 : }
1104 :
1105 2 : return NITFProxyPamRasterBand::GetOverview(iOverview);
1106 : }
1107 :
1108 : /************************************************************************/
1109 : /* NITFComplexRasterBand() */
1110 : /************************************************************************/
1111 :
1112 5 : NITFComplexRasterBand::NITFComplexRasterBand(NITFDataset *poDSIn,
1113 : GDALRasterBand *poBandI,
1114 : GDALRasterBand *poBandQ,
1115 5 : int nIBand, int nQBand)
1116 5 : : NITFRasterBand(poDSIn, nIBand)
1117 : {
1118 :
1119 5 : CPLAssert(poBandI->GetRasterDataType() == poBandQ->GetRasterDataType());
1120 5 : underlyingDataType = poBandI->GetRasterDataType();
1121 :
1122 : //add the I and Q bands to an intermediate dataset
1123 5 : poIntermediateDS = std::make_unique<NITFDataset>();
1124 5 : poIntermediateDS->nRasterXSize = poDSIn->nRasterXSize;
1125 5 : poIntermediateDS->nRasterYSize = poDSIn->nRasterYSize;
1126 5 : poIntermediateDS->eAccess = poDSIn->eAccess;
1127 :
1128 5 : poIntermediateDS->SetBand(nIBand, poBandI);
1129 5 : poIntermediateDS->SetBand(nQBand, poBandQ);
1130 :
1131 5 : anBandMap[0] = nIBand;
1132 5 : anBandMap[1] = nQBand;
1133 :
1134 : //set the new datatype
1135 5 : switch (underlyingDataType)
1136 : {
1137 0 : case GDT_Int16:
1138 0 : eDataType = GDT_CInt16;
1139 0 : break;
1140 0 : case GDT_Int32:
1141 0 : eDataType = GDT_CInt32;
1142 0 : break;
1143 5 : case GDT_Float32:
1144 5 : eDataType = GDT_CFloat32;
1145 5 : break;
1146 0 : case GDT_Float64:
1147 0 : eDataType = GDT_CFloat64;
1148 0 : break;
1149 0 : default:
1150 0 : eDataType = GDT_Unknown;
1151 0 : CPLError(CE_Failure, CPLE_NotSupported,
1152 : "Unsupported complex datatype");
1153 0 : break;
1154 : }
1155 :
1156 5 : complexDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1157 5 : underlyingDataTypeSize = GDALGetDataTypeSizeBytes(underlyingDataType);
1158 5 : CPLAssert(underlyingDataTypeSize * 2 == complexDataTypeSize);
1159 :
1160 5 : poBandI->GetBlockSize(&nBlockXSize, &nBlockYSize);
1161 5 : }
1162 :
1163 : /************************************************************************/
1164 : /* IReadBlock() */
1165 : /************************************************************************/
1166 :
1167 40 : CPLErr NITFComplexRasterBand::IBlockIO(int nBlockXOff, int nBlockYOff,
1168 : void *pImage, GDALRWFlag rwFlag)
1169 :
1170 : {
1171 : int nRequestYSize;
1172 : int nRequestXSize;
1173 40 : bool bMemset = false;
1174 :
1175 : /* -------------------------------------------------------------------- */
1176 : /* If the last strip is partial, we need to avoid */
1177 : /* over-requesting. We also need to initialize the extra part */
1178 : /* of the block to zero. */
1179 : /* -------------------------------------------------------------------- */
1180 40 : if ((nBlockYOff + 1) * nBlockYSize > nRasterYSize)
1181 : {
1182 0 : nRequestYSize = nRasterYSize - nBlockYOff * nBlockYSize;
1183 0 : if (rwFlag == GF_Read)
1184 0 : bMemset = true;
1185 : }
1186 : else
1187 : {
1188 40 : nRequestYSize = nBlockYSize;
1189 : }
1190 :
1191 : /*-------------------------------------------------------------------- */
1192 : /* If the input imagery is tiled, also need to avoid over- */
1193 : /* requesting in the X-direction. */
1194 : /* ------------------------------------------------------------------- */
1195 40 : if ((nBlockXOff + 1) * nBlockXSize > nRasterXSize)
1196 : {
1197 0 : nRequestXSize = nRasterXSize - nBlockXOff * nBlockXSize;
1198 0 : if (rwFlag == GF_Read)
1199 0 : bMemset = true;
1200 : }
1201 : else
1202 : {
1203 40 : nRequestXSize = nBlockXSize;
1204 : }
1205 :
1206 40 : if (bMemset)
1207 : {
1208 0 : memset(pImage, 0,
1209 0 : static_cast<size_t>(GDALGetDataTypeSizeBytes(eDataType)) *
1210 0 : nBlockXSize * nBlockYSize);
1211 : }
1212 :
1213 : //read/write both bands with interleaved pixels
1214 40 : return poIntermediateDS->RasterIO(
1215 40 : rwFlag, nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize,
1216 : nRequestXSize, nRequestYSize, pImage, nRequestXSize, nRequestYSize,
1217 40 : underlyingDataType, 2, &anBandMap[0], complexDataTypeSize,
1218 40 : static_cast<GSpacing>(complexDataTypeSize) * nBlockXSize,
1219 80 : underlyingDataTypeSize, nullptr);
1220 : }
1221 :
1222 : /************************************************************************/
1223 : /* IReadBlock() */
1224 : /************************************************************************/
1225 :
1226 40 : CPLErr NITFComplexRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff,
1227 : void *pImage)
1228 :
1229 : {
1230 40 : return IBlockIO(nBlockXOff, nBlockYOff, pImage, GF_Read);
1231 : }
1232 :
1233 : /************************************************************************/
1234 : /* IWriteBlock() */
1235 : /************************************************************************/
1236 :
1237 0 : CPLErr NITFComplexRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff,
1238 : void *pImage)
1239 :
1240 : {
1241 0 : return IBlockIO(nBlockXOff, nBlockYOff, pImage, GF_Write);
1242 : }
|