1 : /******************************************************************************
2 : * $Id: nitfdataset.cpp 18312 2009-12-16 05:31:55Z warmerdam $
3 : *
4 : * Project: NITF Read/Write Translator
5 : * Purpose: GDALDataset/GDALRasterBand implementation on top of "nitflib".
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2002, Frank Warmerdam
10 : *
11 : * Portions Copyright (c) Her majesty the Queen in right of Canada as
12 : * represented by the Minister of National Defence, 2006.
13 : *
14 : * Permission is hereby granted, free of charge, to any person obtaining a
15 : * copy of this software and associated documentation files (the "Software"),
16 : * to deal in the Software without restriction, including without limitation
17 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 : * and/or sell copies of the Software, and to permit persons to whom the
19 : * Software is furnished to do so, subject to the following conditions:
20 : *
21 : * The above copyright notice and this permission notice shall be included
22 : * in all copies or substantial portions of the Software.
23 : *
24 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 : * DEALINGS IN THE SOFTWARE.
31 : ****************************************************************************/
32 :
33 : #include "gdal_pam.h"
34 : #include "nitflib.h"
35 : #include "ogr_spatialref.h"
36 : #include "cpl_string.h"
37 : #include "cpl_csv.h"
38 : #include "gdal_proxy.h"
39 :
40 : CPL_CVSID("$Id: nitfdataset.cpp 18312 2009-12-16 05:31:55Z warmerdam $");
41 :
42 : static void NITFPatchImageLength( const char *pszFilename,
43 : GUIntBig nImageOffset,
44 : GIntBig nPixelCount, const char *pszIC );
45 : static void NITFWriteTextSegments( const char *pszFilename, char **papszList );
46 :
47 : static CPLErr NITFSetColorInterpretation( NITFImage *psImage,
48 : int nBand,
49 : GDALColorInterp eInterp );
50 : #ifdef JPEG_SUPPORTED
51 : static int NITFWriteJPEGImage( GDALDataset *, FILE *, vsi_l_offset, char **,
52 : GDALProgressFunc pfnProgress,
53 : void * pProgressData );
54 : #endif
55 :
56 : /************************************************************************/
57 : /* ==================================================================== */
58 : /* NITFDataset */
59 : /* ==================================================================== */
60 : /************************************************************************/
61 :
62 : class NITFRasterBand;
63 : class NITFWrapperRasterBand;
64 :
65 : class NITFDataset : public GDALPamDataset
66 : {
67 : friend class NITFRasterBand;
68 : friend class NITFWrapperRasterBand;
69 :
70 : NITFFile *psFile;
71 : NITFImage *psImage;
72 :
73 : GDALPamDataset *poJ2KDataset;
74 : int bJP2Writing;
75 :
76 : GDALPamDataset *poJPEGDataset;
77 :
78 : int bGotGeoTransform;
79 : double adfGeoTransform[6];
80 :
81 : char *pszProjection;
82 :
83 : int nGCPCount;
84 : GDAL_GCP *pasGCPList;
85 : char *pszGCPProjection;
86 :
87 : GDALMultiDomainMetadata oSpecialMD;
88 :
89 : void InitializeCGMMetadata();
90 : void InitializeTextMetadata();
91 : void InitializeTREMetadata();
92 :
93 : GIntBig *panJPEGBlockOffset;
94 : GByte *pabyJPEGBlock;
95 : int nQLevel;
96 :
97 : int ScanJPEGQLevel( GUIntBig *pnDataStart );
98 : CPLErr ScanJPEGBlocks( void );
99 : CPLErr ReadJPEGBlock( int, int );
100 : void CheckGeoSDEInfo();
101 :
102 : int nIMIndex;
103 : CPLString osNITFFilename;
104 :
105 : public:
106 : NITFDataset();
107 : ~NITFDataset();
108 :
109 : virtual CPLErr AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
110 : int nBufXSize, int nBufYSize,
111 : GDALDataType eDT,
112 : int nBandCount, int *panBandList,
113 : char **papszOptions );
114 :
115 : virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
116 : void *, int, int, GDALDataType,
117 : int, int *, int, int, int );
118 :
119 : virtual const char *GetProjectionRef(void);
120 : virtual CPLErr SetProjection( const char * );
121 : virtual CPLErr GetGeoTransform( double * );
122 : virtual CPLErr SetGeoTransform( double * );
123 :
124 : virtual int GetGCPCount();
125 : virtual const char *GetGCPProjection();
126 : virtual const GDAL_GCP *GetGCPs();
127 :
128 : virtual char **GetMetadata( const char * pszDomain = "" );
129 : virtual const char *GetMetadataItem( const char * pszName,
130 : const char * pszDomain = "" );
131 : virtual void FlushCache();
132 : virtual CPLErr IBuildOverviews( const char *, int, int *,
133 : int, int *, GDALProgressFunc, void * );
134 :
135 : static int Identify( GDALOpenInfo * );
136 : static GDALDataset *Open( GDALOpenInfo *, GDALDataset *poWritableJ2KDataset);
137 : static GDALDataset *Open( GDALOpenInfo * );
138 : static GDALDataset *
139 : NITFCreateCopy( const char *pszFilename, GDALDataset *poSrcDS,
140 : int bStrict, char **papszOptions,
141 : GDALProgressFunc pfnProgress, void * pProgressData );
142 :
143 : };
144 :
145 : /************************************************************************/
146 : /* NITFMakeColorTable() */
147 : /************************************************************************/
148 :
149 210253 : static GDALColorTable* NITFMakeColorTable(NITFImage* psImage, NITFBandInfo *psBandInfo)
150 : {
151 210253 : GDALColorTable* poColorTable = NULL;
152 :
153 210253 : if( psBandInfo->nSignificantLUTEntries > 0 )
154 : {
155 : int iColor;
156 :
157 32 : poColorTable = new GDALColorTable();
158 :
159 6151 : for( iColor = 0; iColor < psBandInfo->nSignificantLUTEntries; iColor++)
160 : {
161 : GDALColorEntry sEntry;
162 :
163 6119 : sEntry.c1 = psBandInfo->pabyLUT[ 0 + iColor];
164 6119 : sEntry.c2 = psBandInfo->pabyLUT[256 + iColor];
165 6119 : sEntry.c3 = psBandInfo->pabyLUT[512 + iColor];
166 6119 : sEntry.c4 = 255;
167 :
168 6119 : poColorTable->SetColorEntry( iColor, &sEntry );
169 : }
170 :
171 32 : if (psImage->bNoDataSet)
172 : {
173 : GDALColorEntry sEntry;
174 26 : sEntry.c1 = sEntry.c2 = sEntry.c3 = sEntry.c4 = 0;
175 26 : poColorTable->SetColorEntry( psImage->nNoDataValue, &sEntry );
176 : }
177 : }
178 :
179 : /* -------------------------------------------------------------------- */
180 : /* We create a color table for 1 bit data too... */
181 : /* -------------------------------------------------------------------- */
182 210253 : if( poColorTable == NULL && psImage->nBitsPerSample == 1 )
183 : {
184 : GDALColorEntry sEntry;
185 :
186 2 : poColorTable = new GDALColorTable();
187 :
188 2 : sEntry.c1 = 0;
189 2 : sEntry.c2 = 0;
190 2 : sEntry.c3 = 0;
191 2 : sEntry.c4 = 255;
192 2 : poColorTable->SetColorEntry( 0, &sEntry );
193 :
194 2 : sEntry.c1 = 255;
195 2 : sEntry.c2 = 255;
196 2 : sEntry.c3 = 255;
197 2 : sEntry.c4 = 255;
198 2 : poColorTable->SetColorEntry( 1, &sEntry );
199 : }
200 :
201 210253 : return poColorTable;
202 : }
203 :
204 : /************************************************************************/
205 : /* ==================================================================== */
206 : /* NITFRasterBand */
207 : /* ==================================================================== */
208 : /************************************************************************/
209 :
210 : class NITFRasterBand : public GDALPamRasterBand
211 : {
212 : friend class NITFDataset;
213 :
214 : NITFImage *psImage;
215 :
216 : GDALColorTable *poColorTable;
217 :
218 : GByte *pUnpackData;
219 :
220 : public:
221 : NITFRasterBand( NITFDataset *, int );
222 : ~NITFRasterBand();
223 :
224 : virtual CPLErr IReadBlock( int, int, void * );
225 : virtual CPLErr IWriteBlock( int, int, void * );
226 :
227 : virtual GDALColorInterp GetColorInterpretation();
228 : virtual CPLErr SetColorInterpretation( GDALColorInterp );
229 : virtual GDALColorTable *GetColorTable();
230 : virtual CPLErr SetColorTable( GDALColorTable * );
231 : virtual double GetNoDataValue( int *pbSuccess = NULL );
232 :
233 : void Unpack(GByte* pData);
234 : };
235 :
236 : /************************************************************************/
237 : /* NITFRasterBand() */
238 : /************************************************************************/
239 :
240 210249 : NITFRasterBand::NITFRasterBand( NITFDataset *poDS, int nBand )
241 :
242 : {
243 210249 : NITFBandInfo *psBandInfo = poDS->psImage->pasBandInfo + nBand - 1;
244 :
245 210249 : this->poDS = poDS;
246 210249 : this->nBand = nBand;
247 :
248 210249 : this->eAccess = poDS->eAccess;
249 210249 : this->psImage = poDS->psImage;
250 :
251 : /* -------------------------------------------------------------------- */
252 : /* Translate data type(s). */
253 : /* -------------------------------------------------------------------- */
254 210249 : if( psImage->nBitsPerSample <= 8 )
255 210212 : eDataType = GDT_Byte;
256 45 : else if( psImage->nBitsPerSample == 16
257 : && EQUAL(psImage->szPVType,"SI") )
258 8 : eDataType = GDT_Int16;
259 29 : else if( psImage->nBitsPerSample == 16 )
260 5 : eDataType = GDT_UInt16;
261 24 : else if( psImage->nBitsPerSample == 12 )
262 2 : eDataType = GDT_UInt16;
263 27 : else if( psImage->nBitsPerSample == 32
264 : && EQUAL(psImage->szPVType,"SI") )
265 5 : eDataType = GDT_Int32;
266 22 : else if( psImage->nBitsPerSample == 32
267 : && EQUAL(psImage->szPVType,"R") )
268 5 : eDataType = GDT_Float32;
269 12 : else if( psImage->nBitsPerSample == 32 )
270 5 : eDataType = GDT_UInt32;
271 12 : else if( psImage->nBitsPerSample == 64
272 : && EQUAL(psImage->szPVType,"R") )
273 5 : eDataType = GDT_Float64;
274 4 : else if( psImage->nBitsPerSample == 64
275 : && EQUAL(psImage->szPVType,"C") )
276 2 : eDataType = GDT_CFloat32;
277 : /* ERO : note I'm not sure if CFloat64 can be transmitted as NBPP is only 2 characters */
278 : else
279 : {
280 0 : eDataType = GDT_Unknown;
281 : CPLError( CE_Warning, CPLE_AppDefined,
282 : "Unsupported combination of PVTYPE(%s) and NBPP(%d).",
283 0 : psImage->szPVType, psImage->nBitsPerSample );
284 : }
285 :
286 : /* -------------------------------------------------------------------- */
287 : /* Work out block size. If the image is all one big block we */
288 : /* handle via the scanline access API. */
289 : /* -------------------------------------------------------------------- */
290 420414 : if( psImage->nBlocksPerRow == 1
291 : && psImage->nBlocksPerColumn == 1
292 : && psImage->nBitsPerSample >= 8
293 : && EQUAL(psImage->szIC,"NC") )
294 : {
295 210165 : nBlockXSize = psImage->nBlockWidth;
296 210165 : nBlockYSize = 1;
297 : }
298 : else
299 : {
300 84 : nBlockXSize = psImage->nBlockWidth;
301 84 : nBlockYSize = psImage->nBlockHeight;
302 : }
303 :
304 : /* -------------------------------------------------------------------- */
305 : /* Do we have a color table? */
306 : /* -------------------------------------------------------------------- */
307 : poColorTable = NITFMakeColorTable(psImage,
308 210249 : psBandInfo);
309 :
310 210249 : if( psImage->nBitsPerSample == 1
311 : || psImage->nBitsPerSample == 3
312 : || psImage->nBitsPerSample == 5
313 : || psImage->nBitsPerSample == 6
314 : || psImage->nBitsPerSample == 7
315 : || psImage->nBitsPerSample == 12 )
316 6 : SetMetadataItem( "NBITS", CPLString().Printf("%d", psImage->nBitsPerSample), "IMAGE_STRUCTURE" );
317 :
318 210249 : pUnpackData = 0;
319 210249 : if (psImage->nBitsPerSample == 3
320 : || psImage->nBitsPerSample == 5
321 : || psImage->nBitsPerSample == 6
322 : || psImage->nBitsPerSample == 7)
323 0 : pUnpackData = new GByte[((nBlockXSize*nBlockYSize+7)/8)*8];
324 210249 : }
325 :
326 : /************************************************************************/
327 : /* ~NITFRasterBand() */
328 : /************************************************************************/
329 :
330 420498 : NITFRasterBand::~NITFRasterBand()
331 :
332 : {
333 210249 : if( poColorTable != NULL )
334 30 : delete poColorTable;
335 :
336 210249 : delete[] pUnpackData;
337 420498 : }
338 :
339 : /************************************************************************/
340 : /* IReadBlock() */
341 : /************************************************************************/
342 :
343 3822 : CPLErr NITFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
344 : void * pImage )
345 :
346 : {
347 : int nBlockResult;
348 3822 : NITFDataset *poGDS = (NITFDataset *) poDS;
349 :
350 : /* -------------------------------------------------------------------- */
351 : /* Special case for JPEG blocks. */
352 : /* -------------------------------------------------------------------- */
353 3822 : if( EQUAL(psImage->szIC,"C3") || EQUAL(psImage->szIC,"M3") )
354 : {
355 55 : CPLErr eErr = poGDS->ReadJPEGBlock( nBlockXOff, nBlockYOff );
356 : int nBlockBandSize = psImage->nBlockWidth*psImage->nBlockHeight*
357 55 : (GDALGetDataTypeSize(eDataType)/8);
358 :
359 55 : if( eErr != CE_None )
360 0 : return eErr;
361 :
362 : memcpy( pImage,
363 : poGDS->pabyJPEGBlock + (nBand - 1) * nBlockBandSize,
364 55 : nBlockBandSize );
365 :
366 55 : return eErr;
367 : }
368 :
369 : /* -------------------------------------------------------------------- */
370 : /* Read the line/block */
371 : /* -------------------------------------------------------------------- */
372 3767 : if( nBlockYSize == 1 )
373 : {
374 : nBlockResult =
375 1912 : NITFReadImageLine(psImage, nBlockYOff, nBand, pImage);
376 : }
377 : else
378 : {
379 : nBlockResult =
380 1855 : NITFReadImageBlock(psImage, nBlockXOff, nBlockYOff, nBand, pImage);
381 : }
382 :
383 3767 : if( nBlockResult == BLKREAD_OK )
384 : {
385 3596 : if( psImage->nBitsPerSample % 8 )
386 8 : Unpack((GByte*)pImage);
387 :
388 3596 : return CE_None;
389 : }
390 :
391 171 : if( nBlockResult == BLKREAD_FAIL )
392 0 : return CE_Failure;
393 :
394 : /* -------------------------------------------------------------------- */
395 : /* If we got a null/missing block, try to fill it in with the */
396 : /* nodata value. It seems this only really works properly for */
397 : /* 8bit. */
398 : /* -------------------------------------------------------------------- */
399 171 : if( psImage->bNoDataSet )
400 : memset( pImage, psImage->nNoDataValue,
401 171 : psImage->nWordSize*psImage->nBlockWidth*psImage->nBlockHeight);
402 : else
403 : memset( pImage, 0,
404 0 : psImage->nWordSize*psImage->nBlockWidth*psImage->nBlockHeight);
405 :
406 171 : return CE_None;
407 : }
408 :
409 : /************************************************************************/
410 : /* IWriteBlock() */
411 : /************************************************************************/
412 :
413 3107 : CPLErr NITFRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
414 : void * pImage )
415 :
416 : {
417 : int nBlockResult;
418 :
419 : /* -------------------------------------------------------------------- */
420 : /* Write the line/block */
421 : /* -------------------------------------------------------------------- */
422 3107 : if( nBlockYSize == 1 )
423 : {
424 : nBlockResult =
425 2502 : NITFWriteImageLine(psImage, nBlockYOff, nBand, pImage);
426 : }
427 : else
428 : {
429 : nBlockResult =
430 605 : NITFWriteImageBlock(psImage, nBlockXOff, nBlockYOff, nBand,pImage);
431 : }
432 :
433 3107 : if( nBlockResult == BLKREAD_OK )
434 3107 : return CE_None;
435 : else
436 0 : return CE_Failure;
437 : }
438 :
439 : /************************************************************************/
440 : /* GetNoDataValue() */
441 : /************************************************************************/
442 :
443 59 : double NITFRasterBand::GetNoDataValue( int *pbSuccess )
444 :
445 : {
446 59 : if( pbSuccess != NULL )
447 58 : *pbSuccess = psImage->bNoDataSet;
448 :
449 59 : if( psImage->bNoDataSet )
450 19 : return psImage->nNoDataValue;
451 : else
452 40 : return GDALPamRasterBand::GetNoDataValue( pbSuccess );
453 : }
454 :
455 : /************************************************************************/
456 : /* GetColorInterpretation() */
457 : /************************************************************************/
458 :
459 108 : GDALColorInterp NITFRasterBand::GetColorInterpretation()
460 :
461 : {
462 108 : NITFBandInfo *psBandInfo = psImage->pasBandInfo + nBand - 1;
463 :
464 108 : if( poColorTable != NULL )
465 17 : return GCI_PaletteIndex;
466 :
467 91 : if( EQUAL(psBandInfo->szIREPBAND,"R") )
468 16 : return GCI_RedBand;
469 75 : if( EQUAL(psBandInfo->szIREPBAND,"G") )
470 16 : return GCI_GreenBand;
471 59 : if( EQUAL(psBandInfo->szIREPBAND,"B") )
472 16 : return GCI_BlueBand;
473 43 : if( EQUAL(psBandInfo->szIREPBAND,"M") )
474 25 : return GCI_GrayIndex;
475 18 : if( EQUAL(psBandInfo->szIREPBAND,"Y") )
476 2 : return GCI_YCbCr_YBand;
477 16 : if( EQUAL(psBandInfo->szIREPBAND,"Cb") )
478 2 : return GCI_YCbCr_CbBand;
479 14 : if( EQUAL(psBandInfo->szIREPBAND,"Cr") )
480 2 : return GCI_YCbCr_CrBand;
481 :
482 12 : return GCI_Undefined;
483 : }
484 :
485 : /************************************************************************/
486 : /* NITFSetColorInterpretation() */
487 : /************************************************************************/
488 :
489 21 : static CPLErr NITFSetColorInterpretation( NITFImage *psImage,
490 : int nBand,
491 : GDALColorInterp eInterp )
492 :
493 : {
494 21 : NITFBandInfo *psBandInfo = psImage->pasBandInfo + nBand - 1;
495 21 : const char *pszREP = NULL;
496 : GUIntBig nOffset;
497 :
498 21 : if( eInterp == GCI_RedBand )
499 7 : pszREP = "R";
500 14 : else if( eInterp == GCI_GreenBand )
501 7 : pszREP = "G";
502 7 : else if( eInterp == GCI_BlueBand )
503 7 : pszREP = "B";
504 0 : else if( eInterp == GCI_GrayIndex )
505 0 : pszREP = "M";
506 0 : else if( eInterp == GCI_YCbCr_YBand )
507 0 : pszREP = "Y";
508 0 : else if( eInterp == GCI_YCbCr_CbBand )
509 0 : pszREP = "Cb";
510 0 : else if( eInterp == GCI_YCbCr_CrBand )
511 0 : pszREP = "Cr";
512 0 : else if( eInterp == GCI_Undefined )
513 0 : return CE_None;
514 :
515 21 : if( pszREP == NULL )
516 : {
517 : CPLError( CE_Failure, CPLE_NotSupported,
518 : "Requested color interpretation (%s) not supported in NITF.",
519 0 : GDALGetColorInterpretationName( eInterp ) );
520 0 : return CE_Failure;
521 : }
522 :
523 : /* -------------------------------------------------------------------- */
524 : /* Where does this go in the file? */
525 : /* -------------------------------------------------------------------- */
526 21 : strcpy( psBandInfo->szIREPBAND, pszREP );
527 21 : nOffset = NITFIHFieldOffset( psImage, "IREPBAND" );
528 :
529 21 : if( nOffset != 0 )
530 21 : nOffset += (nBand - 1) * 13;
531 :
532 : /* -------------------------------------------------------------------- */
533 : /* write it (space padded). */
534 : /* -------------------------------------------------------------------- */
535 : char szPadded[4];
536 21 : strcpy( szPadded, pszREP );
537 21 : strcat( szPadded, " " );
538 :
539 21 : if( nOffset != 0 )
540 : {
541 21 : if( VSIFSeekL( psImage->psFile->fp, nOffset, SEEK_SET ) != 0
542 : || VSIFWriteL( (void *) szPadded, 1, 2, psImage->psFile->fp ) != 2 )
543 : {
544 : CPLError( CE_Failure, CPLE_AppDefined,
545 0 : "IO failure writing new IREPBAND value to NITF file." );
546 0 : return CE_Failure;
547 : }
548 : }
549 :
550 21 : return CE_None;
551 : }
552 :
553 : /************************************************************************/
554 : /* SetColorInterpretation() */
555 : /************************************************************************/
556 :
557 18 : CPLErr NITFRasterBand::SetColorInterpretation( GDALColorInterp eInterp )
558 :
559 : {
560 18 : return NITFSetColorInterpretation( psImage, nBand, eInterp );
561 : }
562 :
563 : /************************************************************************/
564 : /* GetColorTable() */
565 : /************************************************************************/
566 :
567 29 : GDALColorTable *NITFRasterBand::GetColorTable()
568 :
569 : {
570 29 : return poColorTable;
571 : }
572 :
573 : /************************************************************************/
574 : /* SetColorTable() */
575 : /************************************************************************/
576 :
577 2 : CPLErr NITFRasterBand::SetColorTable( GDALColorTable *poNewCT )
578 :
579 : {
580 2 : if( poNewCT == NULL )
581 0 : return CE_Failure;
582 :
583 : GByte abyNITFLUT[768];
584 : int i;
585 2 : int nCount = MIN(256,poNewCT->GetColorEntryCount());
586 :
587 2 : memset( abyNITFLUT, 0, 768 );
588 135 : for( i = 0; i < nCount; i++ )
589 : {
590 : GDALColorEntry sEntry;
591 :
592 133 : poNewCT->GetColorEntryAsRGB( i, &sEntry );
593 133 : abyNITFLUT[i ] = (GByte) sEntry.c1;
594 133 : abyNITFLUT[i+256] = (GByte) sEntry.c2;
595 133 : abyNITFLUT[i+512] = (GByte) sEntry.c3;
596 : }
597 :
598 2 : if( NITFWriteLUT( psImage, nBand, nCount, abyNITFLUT ) )
599 2 : return CE_None;
600 : else
601 0 : return CE_Failure;
602 : }
603 :
604 : /************************************************************************/
605 : /* Unpack() */
606 : /************************************************************************/
607 :
608 8 : void NITFRasterBand::Unpack( GByte* pData )
609 : {
610 8 : long n = nBlockXSize*nBlockYSize;
611 : long i;
612 : long k;
613 8 : switch (psImage->nBitsPerSample)
614 : {
615 : case 1:
616 : {
617 : // unpack 1-bit in-place in reverse
618 1050474 : for (i = n; --i >= 0; )
619 1050466 : pData[i] = (pData[i>>3] & (0x80 >> (i&7))) != 0;
620 :
621 4 : break;
622 : }
623 : case 2:
624 : {
625 : static const int s_Shift2[] = {6, 4, 2, 0};
626 : // unpack 2-bit in-place in reverse
627 0 : for (i = n; --i >= 0; )
628 0 : pData[i] = (pData[i>>2] >> (GByte)s_Shift2[i&3]) & 0x03;
629 :
630 0 : break;
631 : }
632 : case 4:
633 : {
634 : static const int s_Shift4[] = {4, 0};
635 : // unpack 4-bit in-place in reverse
636 0 : for (i = n; --i >= 0; )
637 0 : pData[i] = (pData[i>>1] >> (GByte)s_Shift4[i&1]) & 0x07;
638 :
639 0 : break;
640 : }
641 : case 3:
642 : {
643 : // unpacks 8 pixels (3 bytes) at time
644 0 : for (i = 0, k = 0; i < n; i += 8, k += 3)
645 : {
646 0 : pUnpackData[i+0] = ((pData[k+0] >> 5));
647 0 : pUnpackData[i+1] = ((pData[k+0] >> 2) & 0x07);
648 0 : pUnpackData[i+2] = ((pData[k+0] << 1) & 0x07) | (pData[k+1] >> 7);
649 0 : pUnpackData[i+3] = ((pData[k+1] >> 4) & 0x07);
650 0 : pUnpackData[i+4] = ((pData[k+1] >> 1) & 0x07);
651 0 : pUnpackData[i+5] = ((pData[k+1] << 2) & 0x07) | (pData[k+2] >> 6);
652 0 : pUnpackData[i+6] = ((pData[k+2] >> 3) & 0x07);
653 0 : pUnpackData[i+7] = ((pData[k+2]) & 0x7);
654 : }
655 :
656 0 : memcpy(pData, pUnpackData, n);
657 0 : break;
658 : }
659 : case 5:
660 : {
661 : // unpacks 8 pixels (5 bytes) at time
662 0 : for (i = 0, k = 0; i < n; i += 8, k += 5)
663 : {
664 0 : pUnpackData[i+0] = ((pData[k+0] >> 3));
665 0 : pUnpackData[i+1] = ((pData[k+0] << 2) & 0x1f) | (pData[k+1] >> 6);
666 0 : pUnpackData[i+2] = ((pData[k+1] >> 1) & 0x1f);
667 0 : pUnpackData[i+3] = ((pData[k+1] << 4) & 0x1f) | (pData[k+2] >> 4);
668 0 : pUnpackData[i+4] = ((pData[k+2] << 1) & 0x1f) | (pData[k+3] >> 7);
669 0 : pUnpackData[i+5] = ((pData[k+3] >> 2) & 0x1f);
670 0 : pUnpackData[i+6] = ((pData[k+3] << 3) & 0x1f) | (pData[k+4] >> 5);
671 0 : pUnpackData[i+7] = ((pData[k+4]) & 0x1f);
672 : }
673 :
674 0 : memcpy(pData, pUnpackData, n);
675 0 : break;
676 : }
677 : case 6:
678 : {
679 : // unpacks 4 pixels (3 bytes) at time
680 0 : for (i = 0, k = 0; i < n; i += 4, k += 3)
681 : {
682 0 : pUnpackData[i+0] = ((pData[k+0] >> 2));
683 0 : pUnpackData[i+1] = ((pData[k+0] << 4) & 0x3f) | (pData[k+1] >> 4);
684 0 : pUnpackData[i+2] = ((pData[k+1] << 2) & 0x3f) | (pData[k+2] >> 6);
685 0 : pUnpackData[i+3] = ((pData[k+2]) & 0x3f);
686 : }
687 :
688 0 : memcpy(pData, pUnpackData, n);
689 0 : break;
690 : }
691 : case 7:
692 : {
693 : // unpacks 8 pixels (7 bytes) at time
694 0 : for (i = 0, k = 0; i < n; i += 8, k += 7)
695 : {
696 0 : pUnpackData[i+0] = ((pData[k+0] >> 1));
697 0 : pUnpackData[i+1] = ((pData[k+0] << 6) & 0x7f) | (pData[k+1] >> 2);
698 0 : pUnpackData[i+2] = ((pData[k+1] << 5) & 0x7f) | (pData[k+2] >> 3) ;
699 0 : pUnpackData[i+3] = ((pData[k+2] << 4) & 0x7f) | (pData[k+3] >> 4);
700 0 : pUnpackData[i+4] = ((pData[k+3] << 3) & 0x7f) | (pData[k+4] >> 5);
701 0 : pUnpackData[i+5] = ((pData[k+4] << 2) & 0x7f) | (pData[k+5] >> 6);
702 0 : pUnpackData[i+6] = ((pData[k+5] << 1) & 0x7f) | (pData[k+6] >> 7);
703 0 : pUnpackData[i+7] = ((pData[k+6]) & 0x7f);
704 : }
705 :
706 0 : memcpy(pData, pUnpackData, n);
707 0 : break;
708 : }
709 : case 12:
710 : {
711 4 : GByte* pabyImage = (GByte *)pData;
712 4 : GUInt16* panImage = (GUInt16*)pData;
713 1048584 : for (i = n; --i >= 0; )
714 : {
715 1048576 : long iOffset = i*3 / 2;
716 1048576 : if (i % 2 == 0)
717 524288 : panImage[i] = pabyImage[iOffset] + (pabyImage[iOffset+1] & 0xf0) * 16;
718 : else
719 524288 : panImage[i] = (pabyImage[iOffset] & 0x0f) * 16
720 524288 : + (pabyImage[iOffset+1] & 0xf0) / 16
721 1048576 : + (pabyImage[iOffset+1] & 0x0f) * 256;
722 : }
723 :
724 : break;
725 : }
726 : }
727 8 : }
728 :
729 : /************************************************************************/
730 : /* ==================================================================== */
731 : /* NITFWrapperRasterBand */
732 : /* ==================================================================== */
733 : /************************************************************************/
734 :
735 : /* This class is used to wrap bands from JPEG or JPEG2000 datasets in */
736 : /* bands of the NITF dataset. Previously a trick was applied in the */
737 : /* relevant drivers to define a SetColorInterpretation() method and */
738 : /* to make sure they keep the proper pointer to their "natural" dataset */
739 : /* This trick is no longer necessary with the NITFWrapperRasterBand */
740 : /* We just override the few specific methods where we want that */
741 : /* the NITFWrapperRasterBand behaviour differs from the JPEG/JPEG2000 one */
742 :
743 : class NITFWrapperRasterBand : public GDALProxyRasterBand
744 : {
745 : GDALRasterBand* poBaseBand;
746 : GDALColorTable* poColorTable;
747 : GDALColorInterp eInterp;
748 :
749 : protected:
750 : /* Pure virtual method of the GDALProxyRasterBand */
751 : virtual GDALRasterBand* RefUnderlyingRasterBand();
752 :
753 : public:
754 : NITFWrapperRasterBand( NITFDataset * poDS,
755 : GDALRasterBand* poBaseBand,
756 : int nBand);
757 : ~NITFWrapperRasterBand();
758 :
759 : /* Methods from GDALRasterBand we want to override */
760 : virtual GDALColorInterp GetColorInterpretation();
761 : virtual CPLErr SetColorInterpretation( GDALColorInterp );
762 :
763 : virtual GDALColorTable *GetColorTable();
764 :
765 : /* Specific method */
766 : void SetColorTableFromNITFBandInfo();
767 : };
768 :
769 : /************************************************************************/
770 : /* NITFWrapperRasterBand() */
771 : /************************************************************************/
772 :
773 54 : NITFWrapperRasterBand::NITFWrapperRasterBand( NITFDataset * poDS,
774 : GDALRasterBand* poBaseBand,
775 54 : int nBand)
776 : {
777 54 : this->poDS = poDS;
778 54 : this->nBand = nBand;
779 54 : this->poBaseBand = poBaseBand;
780 54 : eDataType = poBaseBand->GetRasterDataType();
781 54 : poBaseBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
782 54 : poColorTable = NULL;
783 54 : eInterp = poBaseBand->GetColorInterpretation();
784 54 : }
785 :
786 : /************************************************************************/
787 : /* ~NITFWrapperRasterBand() */
788 : /************************************************************************/
789 :
790 108 : NITFWrapperRasterBand::~NITFWrapperRasterBand()
791 : {
792 54 : if( poColorTable != NULL )
793 4 : delete poColorTable;
794 108 : }
795 :
796 : /************************************************************************/
797 : /* RefUnderlyingRasterBand() */
798 : /************************************************************************/
799 :
800 : /* We don't need ref-counting. Just return the base band */
801 10604 : GDALRasterBand* NITFWrapperRasterBand::RefUnderlyingRasterBand()
802 : {
803 10604 : return poBaseBand;
804 : }
805 :
806 : /************************************************************************/
807 : /* GetColorTable() */
808 : /************************************************************************/
809 :
810 12 : GDALColorTable *NITFWrapperRasterBand::GetColorTable()
811 : {
812 12 : return poColorTable;
813 : }
814 :
815 : /************************************************************************/
816 : /* SetColorTableFromNITFBandInfo() */
817 : /************************************************************************/
818 :
819 4 : void NITFWrapperRasterBand::SetColorTableFromNITFBandInfo()
820 : {
821 4 : NITFDataset* poGDS = (NITFDataset* )poDS;
822 : poColorTable = NITFMakeColorTable(poGDS->psImage,
823 4 : poGDS->psImage->pasBandInfo + nBand - 1);
824 4 : }
825 :
826 : /************************************************************************/
827 : /* GetColorInterpretation() */
828 : /************************************************************************/
829 :
830 22 : GDALColorInterp NITFWrapperRasterBand::GetColorInterpretation()
831 : {
832 22 : return eInterp;
833 : }
834 :
835 : /************************************************************************/
836 : /* SetColorInterpretation() */
837 : /************************************************************************/
838 :
839 48 : CPLErr NITFWrapperRasterBand::SetColorInterpretation( GDALColorInterp eInterp)
840 : {
841 48 : this->eInterp = eInterp;
842 48 : return CE_None;
843 : }
844 :
845 : /************************************************************************/
846 : /* ==================================================================== */
847 : /* NITFDataset */
848 : /* ==================================================================== */
849 : /************************************************************************/
850 :
851 : /************************************************************************/
852 : /* NITFDataset() */
853 : /************************************************************************/
854 :
855 188 : NITFDataset::NITFDataset()
856 :
857 : {
858 188 : psFile = NULL;
859 188 : psImage = NULL;
860 188 : bGotGeoTransform = FALSE;
861 188 : pszProjection = CPLStrdup("");
862 188 : poJ2KDataset = NULL;
863 188 : bJP2Writing = FALSE;
864 188 : poJPEGDataset = NULL;
865 :
866 188 : panJPEGBlockOffset = NULL;
867 188 : pabyJPEGBlock = NULL;
868 188 : nQLevel = 0;
869 :
870 188 : nGCPCount = 0;
871 188 : pasGCPList = NULL;
872 188 : pszGCPProjection = NULL;
873 :
874 188 : adfGeoTransform[0] = 0.0;
875 188 : adfGeoTransform[1] = 1.0;
876 188 : adfGeoTransform[2] = 0.0;
877 188 : adfGeoTransform[3] = 0.0;
878 188 : adfGeoTransform[4] = 0.0;
879 188 : adfGeoTransform[5] = 1.0;
880 :
881 188 : poDriver = (GDALDriver*) GDALGetDriverByName("NITF");
882 188 : }
883 :
884 : /************************************************************************/
885 : /* ~NITFDataset() */
886 : /************************************************************************/
887 :
888 376 : NITFDataset::~NITFDataset()
889 :
890 : {
891 188 : FlushCache();
892 :
893 : /* -------------------------------------------------------------------- */
894 : /* If we have been writing to a JPEG2000 file, check if the */
895 : /* color interpretations were set. If so, apply the settings */
896 : /* to the NITF file. */
897 : /* -------------------------------------------------------------------- */
898 188 : if( poJ2KDataset != NULL && bJP2Writing )
899 : {
900 : int i;
901 :
902 4 : for( i = 0; i < nBands && papoBands != NULL; i++ )
903 : {
904 3 : if( papoBands[i]->GetColorInterpretation() != GCI_Undefined )
905 : NITFSetColorInterpretation( psImage, i+1,
906 3 : papoBands[i]->GetColorInterpretation() );
907 : }
908 : }
909 :
910 : /* -------------------------------------------------------------------- */
911 : /* Close the underlying NITF file. */
912 : /* -------------------------------------------------------------------- */
913 188 : GUIntBig nImageStart = 0;
914 188 : if( psFile != NULL )
915 : {
916 188 : if (psFile->nSegmentCount > 0)
917 188 : nImageStart = psFile->pasSegmentInfo[0].nSegmentStart;
918 :
919 188 : NITFClose( psFile );
920 188 : psFile = NULL;
921 : }
922 :
923 : /* -------------------------------------------------------------------- */
924 : /* Free datastructures. */
925 : /* -------------------------------------------------------------------- */
926 188 : CPLFree( pszProjection );
927 :
928 188 : GDALDeinitGCPs( nGCPCount, pasGCPList );
929 188 : CPLFree( pasGCPList );
930 :
931 : /* -------------------------------------------------------------------- */
932 : /* If we have a jpeg2000 output file, make sure it gets closed */
933 : /* and flushed out. */
934 : /* -------------------------------------------------------------------- */
935 188 : if( poJ2KDataset != NULL )
936 : {
937 22 : GDALClose( (GDALDatasetH) poJ2KDataset );
938 : }
939 :
940 : /* -------------------------------------------------------------------- */
941 : /* Update file length, and COMRAT for JPEG2000 files we are */
942 : /* writing to. */
943 : /* -------------------------------------------------------------------- */
944 188 : if( bJP2Writing )
945 : {
946 : GIntBig nPixelCount = nRasterXSize * ((GIntBig) nRasterYSize) *
947 1 : nBands;
948 :
949 : NITFPatchImageLength( GetDescription(), nImageStart, nPixelCount,
950 1 : "C8" );
951 : }
952 :
953 : /* -------------------------------------------------------------------- */
954 : /* If we have a jpeg output file, make sure it gets closed */
955 : /* and flushed out. */
956 : /* -------------------------------------------------------------------- */
957 188 : if( poJPEGDataset != NULL )
958 : {
959 12 : GDALClose( (GDALDatasetH) poJPEGDataset );
960 : }
961 :
962 188 : CPLFree( panJPEGBlockOffset );
963 188 : CPLFree( pabyJPEGBlock );
964 376 : }
965 :
966 : /************************************************************************/
967 : /* FlushCache() */
968 : /************************************************************************/
969 :
970 188 : void NITFDataset::FlushCache()
971 :
972 : {
973 : // If the JPEG/JP2K dataset has dirty pam info, then we should consider
974 : // ourselves to as well.
975 188 : if( poJPEGDataset != NULL
976 : && (poJPEGDataset->GetPamFlags() & GPF_DIRTY) )
977 3 : MarkPamDirty();
978 188 : if( poJ2KDataset != NULL
979 : && (poJ2KDataset->GetPamFlags() & GPF_DIRTY) )
980 1 : MarkPamDirty();
981 :
982 188 : if( poJ2KDataset != NULL && bJP2Writing)
983 1 : poJ2KDataset->FlushCache();
984 :
985 188 : GDALPamDataset::FlushCache();
986 188 : }
987 :
988 : /************************************************************************/
989 : /* Identify() */
990 : /************************************************************************/
991 :
992 10419 : int NITFDataset::Identify( GDALOpenInfo * poOpenInfo )
993 :
994 : {
995 10419 : const char *pszFilename = poOpenInfo->pszFilename;
996 :
997 : /* -------------------------------------------------------------------- */
998 : /* Is this a dataset selector? If so, it is obviously NITF. */
999 : /* -------------------------------------------------------------------- */
1000 10419 : if( EQUALN(pszFilename, "NITF_IM:",8) )
1001 9 : return TRUE;
1002 :
1003 : /* -------------------------------------------------------------------- */
1004 : /* First we check to see if the file has the expected header */
1005 : /* bytes. */
1006 : /* -------------------------------------------------------------------- */
1007 10410 : if( poOpenInfo->nHeaderBytes < 4 )
1008 8693 : return FALSE;
1009 :
1010 1717 : if( !EQUALN((char *) poOpenInfo->pabyHeader,"NITF",4)
1011 : && !EQUALN((char *) poOpenInfo->pabyHeader,"NSIF",4)
1012 : && !EQUALN((char *) poOpenInfo->pabyHeader,"NITF",4) )
1013 1537 : return FALSE;
1014 :
1015 : int i;
1016 : /* Check that it's not in fact a NITF A.TOC file, which is handled by the RPFTOC driver */
1017 182254 : for(i=0;i<(int)poOpenInfo->nHeaderBytes-(int)strlen("A.TOC");i++)
1018 : {
1019 182074 : if (EQUALN((const char*)poOpenInfo->pabyHeader + i, "A.TOC", strlen("A.TOC")))
1020 0 : return FALSE;
1021 : }
1022 :
1023 180 : return TRUE;
1024 : }
1025 :
1026 : /************************************************************************/
1027 : /* Open() */
1028 : /************************************************************************/
1029 :
1030 2663 : GDALDataset *NITFDataset::Open( GDALOpenInfo * poOpenInfo )
1031 : {
1032 2663 : return Open(poOpenInfo, NULL);
1033 : }
1034 :
1035 2688 : GDALDataset *NITFDataset::Open( GDALOpenInfo * poOpenInfo, GDALDataset *poWritableJ2KDataset)
1036 :
1037 : {
1038 2688 : int nIMIndex = -1;
1039 2688 : const char *pszFilename = poOpenInfo->pszFilename;
1040 :
1041 2688 : if( !Identify( poOpenInfo ) )
1042 2499 : return NULL;
1043 :
1044 : /* -------------------------------------------------------------------- */
1045 : /* Select a specific subdataset. */
1046 : /* -------------------------------------------------------------------- */
1047 189 : if( EQUALN(pszFilename, "NITF_IM:",8) )
1048 : {
1049 9 : pszFilename += 8;
1050 9 : nIMIndex = atoi(pszFilename);
1051 :
1052 31 : while( *pszFilename != '\0' && *pszFilename != ':' )
1053 13 : pszFilename++;
1054 :
1055 9 : if( *pszFilename == ':' )
1056 9 : pszFilename++;
1057 : }
1058 :
1059 : /* -------------------------------------------------------------------- */
1060 : /* Open the file with library. */
1061 : /* -------------------------------------------------------------------- */
1062 : NITFFile *psFile;
1063 :
1064 189 : psFile = NITFOpen( pszFilename, poOpenInfo->eAccess == GA_Update );
1065 189 : if( psFile == NULL )
1066 : {
1067 1 : return NULL;
1068 : }
1069 :
1070 188 : NITFCollectAttachments( psFile );
1071 188 : NITFReconcileAttachments( psFile );
1072 :
1073 : /* -------------------------------------------------------------------- */
1074 : /* Is there an image to operate on? */
1075 : /* -------------------------------------------------------------------- */
1076 188 : int iSegment, nThisIM = 0;
1077 188 : NITFImage *psImage = NULL;
1078 :
1079 2203 : for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
1080 : {
1081 2200 : if( EQUAL(psFile->pasSegmentInfo[iSegment].szSegmentType,"IM")
1082 : && (nThisIM++ == nIMIndex || nIMIndex == -1) )
1083 : {
1084 185 : psImage = NITFImageAccess( psFile, iSegment );
1085 185 : if( psImage == NULL )
1086 : {
1087 0 : NITFClose( psFile );
1088 0 : return NULL;
1089 : }
1090 185 : break;
1091 : }
1092 : }
1093 :
1094 : /* -------------------------------------------------------------------- */
1095 : /* If no image segments found report this to the user. */
1096 : /* -------------------------------------------------------------------- */
1097 188 : if( psImage == NULL )
1098 : {
1099 : CPLError( CE_Warning, CPLE_AppDefined,
1100 : "The file %s appears to be an NITF file, but no image\n"
1101 : "blocks were found on it.",
1102 3 : poOpenInfo->pszFilename );
1103 : }
1104 :
1105 : /* -------------------------------------------------------------------- */
1106 : /* Create a corresponding GDALDataset. */
1107 : /* -------------------------------------------------------------------- */
1108 : NITFDataset *poDS;
1109 :
1110 188 : poDS = new NITFDataset();
1111 :
1112 188 : poDS->psFile = psFile;
1113 188 : poDS->psImage = psImage;
1114 188 : poDS->eAccess = poOpenInfo->eAccess;
1115 376 : poDS->osNITFFilename = pszFilename;
1116 188 : poDS->nIMIndex = nIMIndex;
1117 :
1118 188 : if( psImage )
1119 : {
1120 185 : if (psImage->nCols <= 0 || psImage->nRows <= 0 ||
1121 : psImage->nBlockWidth <= 0 || psImage->nBlockHeight <= 0)
1122 : {
1123 : CPLError( CE_Failure, CPLE_AppDefined,
1124 : "Bad values in NITF image : nCols=%d, nRows=%d, nBlockWidth=%d, nBlockHeight=%d",
1125 0 : psImage->nCols, psImage->nRows, psImage->nBlockWidth, psImage->nBlockHeight);
1126 0 : delete poDS;
1127 0 : return NULL;
1128 : }
1129 :
1130 185 : poDS->nRasterXSize = psImage->nCols;
1131 185 : poDS->nRasterYSize = psImage->nRows;
1132 : }
1133 : else
1134 : {
1135 3 : poDS->nRasterXSize = 1;
1136 3 : poDS->nRasterYSize = 1;
1137 : }
1138 :
1139 : /* -------------------------------------------------------------------- */
1140 : /* If the image is JPEG2000 (C8) compressed, we will need to */
1141 : /* open the image data as a JPEG2000 dataset. */
1142 : /* -------------------------------------------------------------------- */
1143 188 : int nUsableBands = 0;
1144 : int iBand;
1145 188 : int bSetColorInterpretation = TRUE;
1146 188 : int bSetColorTable = FALSE;
1147 :
1148 188 : if( psImage )
1149 185 : nUsableBands = psImage->nBands;
1150 :
1151 210 : if( psImage != NULL && EQUAL(psImage->szIC,"C8") )
1152 : {
1153 22 : CPLString osDSName;
1154 :
1155 : osDSName.Printf( "/vsisubfile/" CPL_FRMT_GUIB "_" CPL_FRMT_GUIB ",%s",
1156 22 : psFile->pasSegmentInfo[iSegment].nSegmentStart,
1157 22 : psFile->pasSegmentInfo[iSegment].nSegmentSize,
1158 44 : pszFilename );
1159 :
1160 22 : if( poWritableJ2KDataset != NULL )
1161 : {
1162 1 : poDS->poJ2KDataset = (GDALPamDataset *) poWritableJ2KDataset;
1163 1 : poDS->bJP2Writing = TRUE;
1164 1 : poWritableJ2KDataset = NULL;
1165 : }
1166 : else
1167 : {
1168 : poDS->poJ2KDataset = (GDALPamDataset *)
1169 21 : GDALOpen( osDSName, GA_ReadOnly );
1170 :
1171 21 : if( poDS->poJ2KDataset == NULL )
1172 : {
1173 : CPLError( CE_Failure, CPLE_AppDefined,
1174 : "Unable to open JPEG2000 image within NITF file.\n"
1175 0 : "Is the JP2KAK driver available?" );
1176 0 : delete poDS;
1177 0 : return NULL;
1178 : }
1179 :
1180 : poDS->poJ2KDataset->SetPamFlags(
1181 21 : poDS->poJ2KDataset->GetPamFlags() | GPF_NOSAVE );
1182 : }
1183 :
1184 22 : if( poDS->GetRasterXSize() != poDS->poJ2KDataset->GetRasterXSize()
1185 : || poDS->GetRasterYSize() != poDS->poJ2KDataset->GetRasterYSize())
1186 : {
1187 : CPLError( CE_Failure, CPLE_AppDefined,
1188 0 : "JPEG2000 data stream has not the same dimensions as the NITF file.");
1189 0 : delete poDS;
1190 0 : return NULL;
1191 : }
1192 :
1193 22 : if ( nUsableBands == 1)
1194 : {
1195 17 : const char* pszIREP = CSLFetchNameValue(psImage->papszMetadata, "NITF_IREP");
1196 17 : if (pszIREP != NULL && EQUAL(pszIREP, "RGB/LUT"))
1197 : {
1198 6 : if (poDS->poJ2KDataset->GetRasterCount() == 3)
1199 : {
1200 : /* Test case : http://www.gwg.nga.mil/ntb/baseline/software/testfile/Jpeg2000/jp2_09/file9_jp2_2places.ntf */
1201 : /* 256-entry palette/LUT in both JP2 Header and image Subheader */
1202 : /* In this case, the JPEG2000 driver will probably do the RGB expension */
1203 2 : nUsableBands = 3;
1204 2 : bSetColorInterpretation = FALSE;
1205 : }
1206 12 : else if (poDS->poJ2KDataset->GetRasterCount() == 1 &&
1207 4 : psImage->pasBandInfo[0].nSignificantLUTEntries > 0 &&
1208 4 : poDS->poJ2KDataset->GetRasterBand(1)->GetColorTable() == NULL)
1209 : {
1210 : /* Test case : http://www.gwg.nga.mil/ntb/baseline/software/testfile/Jpeg2000/jp2_09/file9_j2c.ntf */
1211 : /* 256-entry/LUT in Image Subheader, JP2 header completely removed */
1212 : /* The JPEG2000 driver will decode it as a grey band */
1213 : /* So we must set the color table on the wrapper band */
1214 4 : bSetColorTable = TRUE;
1215 : }
1216 : }
1217 : }
1218 :
1219 22 : if( poDS->poJ2KDataset->GetRasterCount() < nUsableBands )
1220 : {
1221 : CPLError( CE_Warning, CPLE_AppDefined,
1222 : "JPEG2000 data stream has less useful bands than expected, likely\n"
1223 0 : "because some channels have differing resolutions." );
1224 :
1225 0 : nUsableBands = poDS->poJ2KDataset->GetRasterCount();
1226 0 : }
1227 : }
1228 :
1229 : /* -------------------------------------------------------------------- */
1230 : /* If the image is JPEG (C3) compressed, we will need to open */
1231 : /* the image data as a JPEG dataset. */
1232 : /* -------------------------------------------------------------------- */
1233 166 : else if( psImage != NULL
1234 : && EQUAL(psImage->szIC,"C3")
1235 : && psImage->nBlocksPerRow == 1
1236 : && psImage->nBlocksPerColumn == 1 )
1237 : {
1238 12 : GUIntBig nJPEGStart = psFile->pasSegmentInfo[iSegment].nSegmentStart;
1239 :
1240 12 : poDS->nQLevel = poDS->ScanJPEGQLevel( &nJPEGStart );
1241 :
1242 12 : CPLString osDSName;
1243 :
1244 : osDSName.Printf( "JPEG_SUBFILE:Q%d," CPL_FRMT_GUIB "," CPL_FRMT_GUIB ",%s",
1245 : poDS->nQLevel, nJPEGStart,
1246 12 : psFile->pasSegmentInfo[iSegment].nSegmentSize
1247 12 : - (nJPEGStart - psFile->pasSegmentInfo[iSegment].nSegmentStart),
1248 24 : pszFilename );
1249 :
1250 : CPLDebug( "GDAL",
1251 12 : "NITFDataset::Open() as IC=C3 (JPEG compressed)\n");
1252 :
1253 12 : poDS->poJPEGDataset = (GDALPamDataset*) GDALOpen(osDSName,GA_ReadOnly);
1254 12 : if( poDS->poJPEGDataset == NULL )
1255 : {
1256 : CPLError( CE_Failure, CPLE_AppDefined,
1257 : "Unable to open JPEG image within NITF file.\n"
1258 0 : "Is the JPEG driver available?" );
1259 0 : delete poDS;
1260 0 : return NULL;
1261 : }
1262 :
1263 12 : if( poDS->GetRasterXSize() != poDS->poJPEGDataset->GetRasterXSize()
1264 : || poDS->GetRasterYSize() != poDS->poJPEGDataset->GetRasterYSize())
1265 : {
1266 : CPLError( CE_Failure, CPLE_AppDefined,
1267 0 : "JPEG data stream has not the same dimensions as the NITF file.");
1268 0 : delete poDS;
1269 0 : return NULL;
1270 : }
1271 :
1272 : poDS->poJPEGDataset->SetPamFlags(
1273 12 : poDS->poJPEGDataset->GetPamFlags() | GPF_NOSAVE );
1274 :
1275 12 : if( poDS->poJPEGDataset->GetRasterCount() < nUsableBands )
1276 : {
1277 : CPLError( CE_Warning, CPLE_AppDefined,
1278 : "JPEG data stream has less useful bands than expected, likely\n"
1279 0 : "because some channels have differing resolutions." );
1280 :
1281 0 : nUsableBands = poDS->poJPEGDataset->GetRasterCount();
1282 0 : }
1283 : }
1284 :
1285 : /* -------------------------------------------------------------------- */
1286 : /* Create band information objects. */
1287 : /* -------------------------------------------------------------------- */
1288 :
1289 188 : GDALDataset* poBaseDS = NULL;
1290 188 : if (poDS->poJ2KDataset != NULL)
1291 22 : poBaseDS = poDS->poJ2KDataset;
1292 166 : else if (poDS->poJPEGDataset != NULL)
1293 12 : poBaseDS = poDS->poJPEGDataset;
1294 :
1295 210491 : for( iBand = 0; iBand < nUsableBands; iBand++ )
1296 : {
1297 210303 : if( poBaseDS != NULL)
1298 : {
1299 : GDALRasterBand* poBaseBand =
1300 54 : poBaseDS->GetRasterBand(iBand+1);
1301 : NITFWrapperRasterBand* poBand =
1302 54 : new NITFWrapperRasterBand(poDS, poBaseBand, iBand+1 );
1303 :
1304 54 : NITFBandInfo *psBandInfo = psImage->pasBandInfo + iBand;
1305 54 : if (bSetColorInterpretation)
1306 : {
1307 : /* FIXME? Does it make sense if the JPEG/JPEG2000 driver decodes */
1308 : /* YCbCr data as RGB. We probably don't want to set */
1309 : /* the color interpretation as Y, Cb, Cr */
1310 48 : if( EQUAL(psBandInfo->szIREPBAND,"R") )
1311 2 : poBand->SetColorInterpretation( GCI_RedBand );
1312 48 : if( EQUAL(psBandInfo->szIREPBAND,"G") )
1313 2 : poBand->SetColorInterpretation( GCI_GreenBand );
1314 48 : if( EQUAL(psBandInfo->szIREPBAND,"B") )
1315 2 : poBand->SetColorInterpretation( GCI_BlueBand );
1316 48 : if( EQUAL(psBandInfo->szIREPBAND,"M") )
1317 23 : poBand->SetColorInterpretation( GCI_GrayIndex );
1318 48 : if( EQUAL(psBandInfo->szIREPBAND,"Y") )
1319 4 : poBand->SetColorInterpretation( GCI_YCbCr_YBand );
1320 48 : if( EQUAL(psBandInfo->szIREPBAND,"Cb") )
1321 4 : poBand->SetColorInterpretation( GCI_YCbCr_CbBand );
1322 48 : if( EQUAL(psBandInfo->szIREPBAND,"Cr") )
1323 4 : poBand->SetColorInterpretation( GCI_YCbCr_CrBand );
1324 : }
1325 54 : if (bSetColorTable)
1326 : {
1327 4 : poBand->SetColorTableFromNITFBandInfo();
1328 4 : poBand->SetColorInterpretation( GCI_PaletteIndex );
1329 : }
1330 :
1331 54 : poDS->SetBand( iBand+1, poBand );
1332 : }
1333 : else
1334 : {
1335 210249 : GDALRasterBand* poBand = new NITFRasterBand( poDS, iBand+1 );
1336 210249 : if (poBand->GetRasterDataType() == GDT_Unknown)
1337 : {
1338 0 : delete poBand;
1339 0 : delete poDS;
1340 0 : return NULL;
1341 : }
1342 210249 : poDS->SetBand( iBand+1, poBand );
1343 : }
1344 : }
1345 :
1346 : /* -------------------------------------------------------------------- */
1347 : /* Report problems with odd bit sizes. */
1348 : /* -------------------------------------------------------------------- */
1349 188 : if( psImage != NULL
1350 : && psImage->nBitsPerSample != 1
1351 : && psImage->nBitsPerSample != 12
1352 : && (psImage->nBitsPerSample < 8 || psImage->nBitsPerSample % 8 != 0)
1353 : && poDS->poJPEGDataset == NULL
1354 : && poDS->poJ2KDataset == NULL )
1355 : {
1356 : CPLError( CE_Warning, CPLE_AppDefined,
1357 : "Image with %d bits per sample will not be interpreted properly.",
1358 0 : psImage->nBitsPerSample );
1359 : }
1360 :
1361 : /* -------------------------------------------------------------------- */
1362 : /* Process the projection from the ICORDS. */
1363 : /* -------------------------------------------------------------------- */
1364 188 : OGRSpatialReference oSRSWork;
1365 :
1366 188 : if( psImage == NULL )
1367 : {
1368 : /* nothing */
1369 : }
1370 262 : else if( psImage->chICORDS == 'G' || psImage->chICORDS == 'D' )
1371 : {
1372 77 : CPLFree( poDS->pszProjection );
1373 77 : poDS->pszProjection = NULL;
1374 :
1375 77 : oSRSWork.SetWellKnownGeogCS( "WGS84" );
1376 77 : oSRSWork.exportToWkt( &(poDS->pszProjection) );
1377 : }
1378 108 : else if( psImage->chICORDS == 'C' )
1379 : {
1380 0 : CPLFree( poDS->pszProjection );
1381 0 : poDS->pszProjection = NULL;
1382 :
1383 0 : oSRSWork.SetWellKnownGeogCS( "WGS84" );
1384 0 : oSRSWork.exportToWkt( &(poDS->pszProjection) );
1385 :
1386 : /* convert latitudes from geocentric to geodetic form. */
1387 :
1388 : psImage->dfULY =
1389 : NITF_WGS84_Geocentric_Latitude_To_Geodetic_Latitude(
1390 0 : psImage->dfULY );
1391 : psImage->dfLLY =
1392 : NITF_WGS84_Geocentric_Latitude_To_Geodetic_Latitude(
1393 0 : psImage->dfLLY );
1394 : psImage->dfURY =
1395 : NITF_WGS84_Geocentric_Latitude_To_Geodetic_Latitude(
1396 0 : psImage->dfURY );
1397 : psImage->dfLRY =
1398 : NITF_WGS84_Geocentric_Latitude_To_Geodetic_Latitude(
1399 0 : psImage->dfLRY );
1400 : }
1401 143 : else if( psImage->chICORDS == 'S' || psImage->chICORDS == 'N' )
1402 : {
1403 35 : CPLFree( poDS->pszProjection );
1404 35 : poDS->pszProjection = NULL;
1405 :
1406 35 : oSRSWork.SetUTM( psImage->nZone, psImage->chICORDS == 'N' );
1407 35 : oSRSWork.SetWellKnownGeogCS( "WGS84" );
1408 35 : oSRSWork.exportToWkt( &(poDS->pszProjection) );
1409 : }
1410 73 : else if( psImage->chICORDS == 'U' && psImage->nZone != 0 )
1411 : {
1412 0 : CPLFree( poDS->pszProjection );
1413 0 : poDS->pszProjection = NULL;
1414 :
1415 0 : oSRSWork.SetUTM( ABS(psImage->nZone), psImage->nZone > 0 );
1416 0 : oSRSWork.SetWellKnownGeogCS( "WGS84" );
1417 0 : oSRSWork.exportToWkt( &(poDS->pszProjection) );
1418 : }
1419 :
1420 :
1421 : /* -------------------------------------------------------------------- */
1422 : /* Try looking for a .nfw file. */
1423 : /* -------------------------------------------------------------------- */
1424 188 : if( psImage
1425 : && GDALReadWorldFile( pszFilename, "nfw",
1426 : poDS->adfGeoTransform ) )
1427 : {
1428 : const char *pszHDR;
1429 : FILE *fpHDR;
1430 : char **papszLines;
1431 : int isNorth;
1432 : int zone;
1433 :
1434 0 : poDS->bGotGeoTransform = TRUE;
1435 :
1436 : /* If nfw found, try looking for a header with projection info */
1437 : /* in space imaging style format */
1438 0 : pszHDR = CPLResetExtension( pszFilename, "hdr" );
1439 :
1440 0 : fpHDR = VSIFOpenL( pszHDR, "rt" );
1441 :
1442 : #ifndef WIN32
1443 0 : if( fpHDR == NULL )
1444 : {
1445 0 : pszHDR = CPLResetExtension( pszFilename, "HDR" );
1446 0 : fpHDR = VSIFOpenL( pszHDR, "rt" );
1447 : }
1448 : #endif
1449 :
1450 0 : if( fpHDR != NULL )
1451 : {
1452 0 : VSIFCloseL( fpHDR );
1453 0 : papszLines=CSLLoad2(pszHDR, 16, 200, NULL);
1454 0 : if (CSLCount(papszLines) == 16)
1455 : {
1456 :
1457 0 : if (psImage->chICORDS == 'N')
1458 0 : isNorth=1;
1459 0 : else if (psImage->chICORDS =='S')
1460 0 : isNorth=0;
1461 : else
1462 : {
1463 0 : if (psImage->dfLLY+psImage->dfLRY+psImage->dfULY+psImage->dfURY < 0)
1464 0 : isNorth=0;
1465 : else
1466 0 : isNorth=1;
1467 : }
1468 0 : if( (EQUALN(papszLines[7],
1469 : "Selected Projection: Universal Transverse Mercator",50)) &&
1470 0 : (EQUALN(papszLines[8],"Zone: ",6)) &&
1471 0 : (strlen(papszLines[8]) >= 7))
1472 : {
1473 0 : CPLFree( poDS->pszProjection );
1474 0 : poDS->pszProjection = NULL;
1475 0 : zone=atoi(&(papszLines[8][6]));
1476 0 : oSRSWork.SetUTM( zone, isNorth );
1477 0 : oSRSWork.SetWellKnownGeogCS( "WGS84" );
1478 0 : oSRSWork.exportToWkt( &(poDS->pszProjection) );
1479 : }
1480 : else
1481 : {
1482 : /* Couldn't find associated projection info.
1483 : Go back to original file for geotransform.
1484 : */
1485 0 : poDS->bGotGeoTransform = FALSE;
1486 : }
1487 : }
1488 : else
1489 0 : poDS->bGotGeoTransform = FALSE;
1490 0 : CSLDestroy(papszLines);
1491 : }
1492 : else
1493 0 : poDS->bGotGeoTransform = FALSE;
1494 : }
1495 :
1496 : /* -------------------------------------------------------------------- */
1497 : /* Does this look like a CADRG polar tile ? (#2940) */
1498 : /* -------------------------------------------------------------------- */
1499 188 : const char* pszIID1 = (psImage) ? CSLFetchNameValue(psImage->papszMetadata, "NITF_IID1") : NULL;
1500 188 : const char* pszITITLE = (psImage) ? CSLFetchNameValue(psImage->papszMetadata, "NITF_ITITLE") : NULL;
1501 206 : if( psImage != NULL && !poDS->bGotGeoTransform &&
1502 : (psImage->chICORDS == 'G' || psImage->chICORDS == 'D') &&
1503 : pszIID1 != NULL && EQUAL(pszIID1, "CADRG") &&
1504 18 : pszITITLE != NULL && strlen(pszITITLE) >= 12 && pszITITLE[strlen(pszITITLE) - 1] == '9' )
1505 : {
1506 : /* To get a perfect rectangle in Azimuthal Equidistant projection, we must use */
1507 : /* the sphere and not WGS84 ellipsoid. That's a big strange... */
1508 0 : const char* pszNorthPolarProjection = "+proj=aeqd +lat_0=90 +lon_0=0 +x_0=0 +y_0=0 +a=6378137 +b=6378137 +units=m +no_defs";
1509 0 : const char* pszSouthPolarProjection = "+proj=aeqd +lat_0=-90 +lon_0=0 +x_0=0 +y_0=0 +a=6378137 +b=6378137 +units=m +no_defs";
1510 :
1511 0 : OGRSpatialReference oSRS_AEQD, oSRS_WGS84;
1512 :
1513 0 : const char *pszPolarProjection = (psImage->dfULY > 0) ? pszNorthPolarProjection : pszSouthPolarProjection;
1514 0 : oSRS_AEQD.importFromProj4(pszPolarProjection);
1515 :
1516 0 : oSRS_WGS84.SetWellKnownGeogCS( "WGS84" );
1517 :
1518 : OGRCoordinateTransformationH hCT =
1519 0 : (OGRCoordinateTransformationH)OGRCreateCoordinateTransformation(&oSRS_WGS84, &oSRS_AEQD);
1520 0 : if (hCT)
1521 : {
1522 0 : double dfULX_AEQD = psImage->dfULX;
1523 0 : double dfULY_AEQD = psImage->dfULY;
1524 0 : double dfURX_AEQD = psImage->dfURX;
1525 0 : double dfURY_AEQD = psImage->dfURY;
1526 0 : double dfLLX_AEQD = psImage->dfLLX;
1527 0 : double dfLLY_AEQD = psImage->dfLLY;
1528 0 : double dfLRX_AEQD = psImage->dfLRX;
1529 0 : double dfLRY_AEQD = psImage->dfLRY;
1530 0 : double z = 0;
1531 0 : int bSuccess = TRUE;
1532 0 : bSuccess &= OCTTransform(hCT, 1, &dfULX_AEQD, &dfULY_AEQD, &z);
1533 0 : bSuccess &= OCTTransform(hCT, 1, &dfURX_AEQD, &dfURY_AEQD, &z);
1534 0 : bSuccess &= OCTTransform(hCT, 1, &dfLLX_AEQD, &dfLLY_AEQD, &z);
1535 0 : bSuccess &= OCTTransform(hCT, 1, &dfLRX_AEQD, &dfLRY_AEQD, &z);
1536 0 : if (bSuccess)
1537 : {
1538 : /* Check that the coordinates of the 4 corners in Azimuthal Equidistant projection */
1539 : /* are a rectangle */
1540 0 : if (fabs((dfULX_AEQD - dfLLX_AEQD) / dfLLX_AEQD) < 1e-6 &&
1541 : fabs((dfURX_AEQD - dfLRX_AEQD) / dfLRX_AEQD) < 1e-6 &&
1542 : fabs((dfULY_AEQD - dfURY_AEQD) / dfURY_AEQD) < 1e-6 &&
1543 : fabs((dfLLY_AEQD - dfLRY_AEQD) / dfLRY_AEQD) < 1e-6)
1544 : {
1545 0 : CPLFree(poDS->pszProjection);
1546 0 : oSRS_AEQD.exportToWkt( &(poDS->pszProjection) );
1547 :
1548 0 : poDS->bGotGeoTransform = TRUE;
1549 0 : poDS->adfGeoTransform[0] = dfULX_AEQD;
1550 0 : poDS->adfGeoTransform[1] = (dfURX_AEQD - dfULX_AEQD) / poDS->nRasterXSize;
1551 0 : poDS->adfGeoTransform[2] = 0;
1552 0 : poDS->adfGeoTransform[3] = dfULY_AEQD;
1553 0 : poDS->adfGeoTransform[4] = 0;
1554 0 : poDS->adfGeoTransform[5] = (dfLLY_AEQD - dfULY_AEQD) / poDS->nRasterYSize;
1555 : }
1556 : }
1557 0 : OCTDestroyCoordinateTransformation(hCT);
1558 0 : }
1559 : }
1560 :
1561 : /* -------------------------------------------------------------------- */
1562 : /* Do we have IGEOLO data that can be treated as a */
1563 : /* geotransform? Our approach should support images in an */
1564 : /* affine rotated frame of reference. */
1565 : /* -------------------------------------------------------------------- */
1566 188 : int nGCPCount = 0;
1567 188 : GDAL_GCP *psGCPs = NULL;
1568 :
1569 188 : if( psImage && !poDS->bGotGeoTransform && psImage->chICORDS != ' ' )
1570 : {
1571 112 : nGCPCount = 4;
1572 :
1573 112 : psGCPs = (GDAL_GCP *) CPLMalloc(sizeof(GDAL_GCP) * nGCPCount);
1574 112 : GDALInitGCPs( nGCPCount, psGCPs );
1575 :
1576 112 : psGCPs[0].dfGCPPixel = 0.0;
1577 112 : psGCPs[0].dfGCPLine = 0.0;
1578 112 : psGCPs[0].dfGCPX = psImage->dfULX;
1579 112 : psGCPs[0].dfGCPY = psImage->dfULY;
1580 :
1581 112 : psGCPs[1].dfGCPPixel = poDS->nRasterXSize;
1582 112 : psGCPs[1].dfGCPLine = 0.0;
1583 112 : psGCPs[1].dfGCPX = psImage->dfURX;
1584 112 : psGCPs[1].dfGCPY = psImage->dfURY;
1585 :
1586 112 : psGCPs[2].dfGCPPixel = poDS->nRasterXSize;
1587 112 : psGCPs[2].dfGCPLine = poDS->nRasterYSize;
1588 112 : psGCPs[2].dfGCPX = psImage->dfLRX;
1589 112 : psGCPs[2].dfGCPY = psImage->dfLRY;
1590 :
1591 112 : psGCPs[3].dfGCPPixel = 0.0;
1592 112 : psGCPs[3].dfGCPLine = poDS->nRasterYSize;
1593 112 : psGCPs[3].dfGCPX = psImage->dfLLX;
1594 112 : psGCPs[3].dfGCPY = psImage->dfLLY;
1595 : }
1596 :
1597 : /* -------------------------------------------------------------------- */
1598 : /* Convert the GCPs into a geotransform definition, if possible. */
1599 : /* -------------------------------------------------------------------- */
1600 188 : if( !psImage )
1601 : {
1602 : /* nothing */
1603 : }
1604 185 : else if( poDS->bGotGeoTransform == FALSE
1605 : && nGCPCount > 0
1606 : && GDALGCPsToGeoTransform( nGCPCount, psGCPs,
1607 : poDS->adfGeoTransform, TRUE ) )
1608 : {
1609 112 : poDS->bGotGeoTransform = TRUE;
1610 : }
1611 :
1612 : /* -------------------------------------------------------------------- */
1613 : /* If we have IGEOLO that isn't north up, return it as GCPs. */
1614 : /* -------------------------------------------------------------------- */
1615 73 : else if( (psImage->dfULX != 0 || psImage->dfURX != 0
1616 : || psImage->dfLRX != 0 || psImage->dfLLX != 0)
1617 : && psImage->chICORDS != ' ' &&
1618 : ( poDS->bGotGeoTransform == FALSE ) )
1619 : {
1620 : CPLDebug( "GDAL",
1621 : "NITFDataset::Open() wasn't able to derive a first order\n"
1622 0 : "geotransform. It will be returned as GCPs.");
1623 :
1624 0 : poDS->nGCPCount = 4;
1625 : poDS->pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),
1626 0 : poDS->nGCPCount);
1627 0 : GDALInitGCPs( 4, poDS->pasGCPList );
1628 :
1629 0 : poDS->pasGCPList[0].dfGCPX = psImage->dfULX;
1630 0 : poDS->pasGCPList[0].dfGCPY = psImage->dfULY;
1631 0 : poDS->pasGCPList[0].dfGCPPixel = 0;
1632 0 : poDS->pasGCPList[0].dfGCPLine = 0;
1633 0 : CPLFree( poDS->pasGCPList[0].pszId );
1634 0 : poDS->pasGCPList[0].pszId = CPLStrdup( "UpperLeft" );
1635 :
1636 0 : poDS->pasGCPList[1].dfGCPX = psImage->dfURX;
1637 0 : poDS->pasGCPList[1].dfGCPY = psImage->dfURY;
1638 0 : poDS->pasGCPList[1].dfGCPPixel = poDS->nRasterXSize;
1639 0 : poDS->pasGCPList[1].dfGCPLine = 0;
1640 0 : CPLFree( poDS->pasGCPList[1].pszId );
1641 0 : poDS->pasGCPList[1].pszId = CPLStrdup( "UpperRight" );
1642 :
1643 0 : poDS->pasGCPList[2].dfGCPX = psImage->dfLLX;
1644 0 : poDS->pasGCPList[2].dfGCPY = psImage->dfLLY;
1645 0 : poDS->pasGCPList[2].dfGCPPixel = 0;
1646 0 : poDS->pasGCPList[2].dfGCPLine = poDS->nRasterYSize;
1647 0 : CPLFree( poDS->pasGCPList[2].pszId );
1648 0 : poDS->pasGCPList[2].pszId = CPLStrdup( "LowerLeft" );
1649 :
1650 0 : poDS->pasGCPList[3].dfGCPX = psImage->dfLRX;
1651 0 : poDS->pasGCPList[3].dfGCPY = psImage->dfLRY;
1652 0 : poDS->pasGCPList[3].dfGCPPixel = poDS->nRasterXSize;
1653 0 : poDS->pasGCPList[3].dfGCPLine = poDS->nRasterYSize;
1654 0 : CPLFree( poDS->pasGCPList[3].pszId );
1655 0 : poDS->pasGCPList[3].pszId = CPLStrdup( "LowerRight" );
1656 :
1657 0 : poDS->pszGCPProjection = CPLStrdup( poDS->pszProjection );
1658 : }
1659 :
1660 : // This cleans up the original copy of the GCPs used to test if
1661 : // this IGEOLO could be used for a geotransform.
1662 188 : if( nGCPCount > 0 )
1663 : {
1664 112 : GDALDeinitGCPs( nGCPCount, psGCPs );
1665 112 : CPLFree( psGCPs );
1666 : }
1667 :
1668 : /* -------------------------------------------------------------------- */
1669 : /* Do we have PRJPSB and MAPLOB TREs to get better */
1670 : /* georeferencing from? */
1671 : /* -------------------------------------------------------------------- */
1672 188 : if (psImage)
1673 185 : poDS->CheckGeoSDEInfo();
1674 :
1675 : /* -------------------------------------------------------------------- */
1676 : /* Do we have metadata. */
1677 : /* -------------------------------------------------------------------- */
1678 : char **papszMergedMD;
1679 : char **papszUSE00A_MD;
1680 :
1681 : // File and Image level metadata.
1682 188 : papszMergedMD = CSLDuplicate( poDS->psFile->papszMetadata );
1683 :
1684 188 : if( psImage )
1685 : {
1686 : papszMergedMD = CSLInsertStrings( papszMergedMD,
1687 : CSLCount( papszMergedMD ),
1688 185 : psImage->papszMetadata );
1689 :
1690 : // Comments.
1691 185 : if( psImage->pszComments != NULL && strlen(psImage->pszComments) != 0 )
1692 : papszMergedMD = CSLSetNameValue(
1693 9 : papszMergedMD, "NITF_IMAGE_COMMENTS", psImage->pszComments );
1694 :
1695 : // Compression code.
1696 : papszMergedMD = CSLSetNameValue( papszMergedMD, "NITF_IC",
1697 185 : psImage->szIC );
1698 :
1699 : // IMODE
1700 : char szIMODE[2];
1701 185 : szIMODE[0] = psImage->chIMODE;
1702 185 : szIMODE[1] = '\0';
1703 185 : papszMergedMD = CSLSetNameValue( papszMergedMD, "NITF_IMODE", szIMODE );
1704 :
1705 : // ILOC/Attachment info
1706 185 : if( psImage->nIDLVL != 0 )
1707 : {
1708 : NITFSegmentInfo *psSegInfo
1709 184 : = psFile->pasSegmentInfo + psImage->iSegment;
1710 :
1711 : papszMergedMD =
1712 : CSLSetNameValue( papszMergedMD, "NITF_IDLVL",
1713 184 : CPLString().Printf("%d",psImage->nIDLVL) );
1714 : papszMergedMD =
1715 : CSLSetNameValue( papszMergedMD, "NITF_IALVL",
1716 184 : CPLString().Printf("%d",psImage->nIALVL) );
1717 : papszMergedMD =
1718 : CSLSetNameValue( papszMergedMD, "NITF_ILOC_ROW",
1719 184 : CPLString().Printf("%d",psImage->nILOCRow) );
1720 : papszMergedMD =
1721 : CSLSetNameValue( papszMergedMD, "NITF_ILOC_COLUMN",
1722 184 : CPLString().Printf("%d",psImage->nILOCColumn));
1723 : papszMergedMD =
1724 : CSLSetNameValue( papszMergedMD, "NITF_CCS_ROW",
1725 184 : CPLString().Printf("%d",psSegInfo->nCCS_R) );
1726 : papszMergedMD =
1727 : CSLSetNameValue( papszMergedMD, "NITF_CCS_COLUMN",
1728 184 : CPLString().Printf("%d", psSegInfo->nCCS_C));
1729 : papszMergedMD =
1730 : CSLSetNameValue( papszMergedMD, "NITF_IMAG",
1731 184 : psImage->szIMAG );
1732 : }
1733 :
1734 : // USE00A
1735 185 : papszUSE00A_MD = NITFReadUSE00A( psImage );
1736 185 : if( papszUSE00A_MD != NULL )
1737 : {
1738 : papszMergedMD = CSLInsertStrings( papszMergedMD,
1739 : CSLCount( papszUSE00A_MD ),
1740 0 : papszUSE00A_MD );
1741 0 : CSLDestroy( papszUSE00A_MD );
1742 : }
1743 :
1744 : // BLOCKA
1745 185 : papszUSE00A_MD = NITFReadBLOCKA( psImage );
1746 185 : if( papszUSE00A_MD != NULL )
1747 : {
1748 : papszMergedMD = CSLInsertStrings( papszMergedMD,
1749 : CSLCount( papszUSE00A_MD ),
1750 8 : papszUSE00A_MD );
1751 8 : CSLDestroy( papszUSE00A_MD );
1752 : }
1753 :
1754 185 : papszUSE00A_MD = NITFReadSTDIDC( psImage );
1755 185 : if( papszUSE00A_MD != NULL )
1756 : {
1757 : papszMergedMD = CSLInsertStrings( papszMergedMD,
1758 : CSLCount( papszUSE00A_MD ),
1759 0 : papszUSE00A_MD );
1760 0 : CSLDestroy( papszUSE00A_MD );
1761 : }
1762 : }
1763 :
1764 188 : poDS->SetMetadata( papszMergedMD );
1765 188 : CSLDestroy( papszMergedMD );
1766 :
1767 : /* -------------------------------------------------------------------- */
1768 : /* Image structure metadata. */
1769 : /* -------------------------------------------------------------------- */
1770 188 : if( psImage == NULL )
1771 : /* do nothing */;
1772 185 : else if( psImage->szIC[1] == '1' )
1773 : poDS->SetMetadataItem( "COMPRESSION", "BILEVEL",
1774 1 : "IMAGE_STRUCTURE" );
1775 184 : else if( psImage->szIC[1] == '2' )
1776 : poDS->SetMetadataItem( "COMPRESSION", "ARIDPCM",
1777 2 : "IMAGE_STRUCTURE" );
1778 182 : else if( psImage->szIC[1] == '3' )
1779 : poDS->SetMetadataItem( "COMPRESSION", "JPEG",
1780 21 : "IMAGE_STRUCTURE" );
1781 161 : else if( psImage->szIC[1] == '4' )
1782 : poDS->SetMetadataItem( "COMPRESSION", "VECTOR QUANTIZATION",
1783 19 : "IMAGE_STRUCTURE" );
1784 142 : else if( psImage->szIC[1] == '5' )
1785 : poDS->SetMetadataItem( "COMPRESSION", "LOSSLESS JPEG",
1786 0 : "IMAGE_STRUCTURE" );
1787 142 : else if( psImage->szIC[1] == '8' )
1788 : poDS->SetMetadataItem( "COMPRESSION", "JPEG2000",
1789 22 : "IMAGE_STRUCTURE" );
1790 :
1791 : /* -------------------------------------------------------------------- */
1792 : /* Do we have RPC info. */
1793 : /* -------------------------------------------------------------------- */
1794 : NITFRPC00BInfo sRPCInfo;
1795 :
1796 188 : if( psImage
1797 : && NITFReadRPC00B( psImage, &sRPCInfo ) && sRPCInfo.SUCCESS )
1798 : {
1799 : char szValue[1280];
1800 : int i;
1801 :
1802 0 : sprintf( szValue, "%.16g", sRPCInfo.LINE_OFF );
1803 0 : poDS->SetMetadataItem( "LINE_OFF", szValue, "RPC" );
1804 :
1805 0 : sprintf( szValue, "%.16g", sRPCInfo.LINE_SCALE );
1806 0 : poDS->SetMetadataItem( "LINE_SCALE", szValue, "RPC" );
1807 :
1808 0 : sprintf( szValue, "%.16g", sRPCInfo.SAMP_OFF );
1809 0 : poDS->SetMetadataItem( "SAMP_OFF", szValue, "RPC" );
1810 :
1811 0 : sprintf( szValue, "%.16g", sRPCInfo.SAMP_SCALE );
1812 0 : poDS->SetMetadataItem( "SAMP_SCALE", szValue, "RPC" );
1813 :
1814 0 : sprintf( szValue, "%.16g", sRPCInfo.LONG_OFF );
1815 0 : poDS->SetMetadataItem( "LONG_OFF", szValue, "RPC" );
1816 :
1817 0 : sprintf( szValue, "%.16g", sRPCInfo.LONG_SCALE );
1818 0 : poDS->SetMetadataItem( "LONG_SCALE", szValue, "RPC" );
1819 :
1820 0 : sprintf( szValue, "%.16g", sRPCInfo.LAT_OFF );
1821 0 : poDS->SetMetadataItem( "LAT_OFF", szValue, "RPC" );
1822 :
1823 0 : sprintf( szValue, "%.16g", sRPCInfo.LAT_SCALE );
1824 0 : poDS->SetMetadataItem( "LAT_SCALE", szValue, "RPC" );
1825 :
1826 0 : sprintf( szValue, "%.16g", sRPCInfo.HEIGHT_OFF );
1827 0 : poDS->SetMetadataItem( "HEIGHT_OFF", szValue, "RPC" );
1828 :
1829 0 : sprintf( szValue, "%.16g", sRPCInfo.HEIGHT_SCALE );
1830 0 : poDS->SetMetadataItem( "HEIGHT_SCALE", szValue, "RPC" );
1831 :
1832 0 : szValue[0] = '\0';
1833 0 : for( i = 0; i < 20; i++ )
1834 : sprintf( szValue+strlen(szValue), "%.16g ",
1835 0 : sRPCInfo.LINE_NUM_COEFF[i] );
1836 0 : poDS->SetMetadataItem( "LINE_NUM_COEFF", szValue, "RPC" );
1837 :
1838 0 : szValue[0] = '\0';
1839 0 : for( i = 0; i < 20; i++ )
1840 : sprintf( szValue+strlen(szValue), "%.16g ",
1841 0 : sRPCInfo.LINE_DEN_COEFF[i] );
1842 0 : poDS->SetMetadataItem( "LINE_DEN_COEFF", szValue, "RPC" );
1843 :
1844 0 : szValue[0] = '\0';
1845 0 : for( i = 0; i < 20; i++ )
1846 : sprintf( szValue+strlen(szValue), "%.16g ",
1847 0 : sRPCInfo.SAMP_NUM_COEFF[i] );
1848 0 : poDS->SetMetadataItem( "SAMP_NUM_COEFF", szValue, "RPC" );
1849 :
1850 0 : szValue[0] = '\0';
1851 0 : for( i = 0; i < 20; i++ )
1852 : sprintf( szValue+strlen(szValue), "%.16g ",
1853 0 : sRPCInfo.SAMP_DEN_COEFF[i] );
1854 0 : poDS->SetMetadataItem( "SAMP_DEN_COEFF", szValue, "RPC" );
1855 :
1856 : sprintf( szValue, "%.16g",
1857 0 : sRPCInfo.LONG_OFF - ( sRPCInfo.LONG_SCALE / 2.0 ) );
1858 0 : poDS->SetMetadataItem( "MIN_LONG", szValue, "RPC" );
1859 :
1860 : sprintf( szValue, "%.16g",
1861 0 : sRPCInfo.LONG_OFF + ( sRPCInfo.LONG_SCALE / 2.0 ) );
1862 0 : poDS->SetMetadataItem( "MAX_LONG", szValue, "RPC" );
1863 :
1864 : sprintf( szValue, "%.16g",
1865 0 : sRPCInfo.LAT_OFF - ( sRPCInfo.LAT_SCALE / 2.0 ) );
1866 0 : poDS->SetMetadataItem( "MIN_LAT", szValue, "RPC" );
1867 :
1868 : sprintf( szValue, "%.16g",
1869 0 : sRPCInfo.LAT_OFF + ( sRPCInfo.LAT_SCALE / 2.0 ) );
1870 0 : poDS->SetMetadataItem( "MAX_LAT", szValue, "RPC" );
1871 : }
1872 :
1873 : /* -------------------------------------------------------------------- */
1874 : /* Do we have Chip info? */
1875 : /* -------------------------------------------------------------------- */
1876 : NITFICHIPBInfo sChipInfo;
1877 :
1878 188 : if( psImage
1879 : && NITFReadICHIPB( psImage, &sChipInfo ) && sChipInfo.XFRM_FLAG == 0 )
1880 : {
1881 : char szValue[1280];
1882 :
1883 0 : sprintf( szValue, "%.16g", sChipInfo.SCALE_FACTOR );
1884 0 : poDS->SetMetadataItem( "ICHIP_SCALE_FACTOR", szValue );
1885 :
1886 0 : sprintf( szValue, "%d", sChipInfo.ANAMORPH_CORR );
1887 0 : poDS->SetMetadataItem( "ICHIP_ANAMORPH_CORR", szValue );
1888 :
1889 0 : sprintf( szValue, "%d", sChipInfo.SCANBLK_NUM );
1890 0 : poDS->SetMetadataItem( "ICHIP_SCANBLK_NUM", szValue );
1891 :
1892 0 : sprintf( szValue, "%.16g", sChipInfo.OP_ROW_11 );
1893 0 : poDS->SetMetadataItem( "ICHIP_OP_ROW_11", szValue );
1894 :
1895 0 : sprintf( szValue, "%.16g", sChipInfo.OP_COL_11 );
1896 0 : poDS->SetMetadataItem( "ICHIP_OP_COL_11", szValue );
1897 :
1898 0 : sprintf( szValue, "%.16g", sChipInfo.OP_ROW_12 );
1899 0 : poDS->SetMetadataItem( "ICHIP_OP_ROW_12", szValue );
1900 :
1901 0 : sprintf( szValue, "%.16g", sChipInfo.OP_COL_12 );
1902 0 : poDS->SetMetadataItem( "ICHIP_OP_COL_12", szValue );
1903 :
1904 0 : sprintf( szValue, "%.16g", sChipInfo.OP_ROW_21 );
1905 0 : poDS->SetMetadataItem( "ICHIP_OP_ROW_21", szValue );
1906 :
1907 0 : sprintf( szValue, "%.16g", sChipInfo.OP_COL_21 );
1908 0 : poDS->SetMetadataItem( "ICHIP_OP_COL_21", szValue );
1909 :
1910 0 : sprintf( szValue, "%.16g", sChipInfo.OP_ROW_22 );
1911 0 : poDS->SetMetadataItem( "ICHIP_OP_ROW_22", szValue );
1912 :
1913 0 : sprintf( szValue, "%.16g", sChipInfo.OP_COL_22 );
1914 0 : poDS->SetMetadataItem( "ICHIP_OP_COL_22", szValue );
1915 :
1916 0 : sprintf( szValue, "%.16g", sChipInfo.FI_ROW_11 );
1917 0 : poDS->SetMetadataItem( "ICHIP_FI_ROW_11", szValue );
1918 :
1919 0 : sprintf( szValue, "%.16g", sChipInfo.FI_COL_11 );
1920 0 : poDS->SetMetadataItem( "ICHIP_FI_COL_11", szValue );
1921 :
1922 0 : sprintf( szValue, "%.16g", sChipInfo.FI_ROW_12 );
1923 0 : poDS->SetMetadataItem( "ICHIP_FI_ROW_12", szValue );
1924 :
1925 0 : sprintf( szValue, "%.16g", sChipInfo.FI_COL_12 );
1926 0 : poDS->SetMetadataItem( "ICHIP_FI_COL_12", szValue );
1927 :
1928 0 : sprintf( szValue, "%.16g", sChipInfo.FI_ROW_21 );
1929 0 : poDS->SetMetadataItem( "ICHIP_FI_ROW_21", szValue );
1930 :
1931 0 : sprintf( szValue, "%.16g", sChipInfo.FI_COL_21 );
1932 0 : poDS->SetMetadataItem( "ICHIP_FI_COL_21", szValue );
1933 :
1934 0 : sprintf( szValue, "%.16g", sChipInfo.FI_ROW_22 );
1935 0 : poDS->SetMetadataItem( "ICHIP_FI_ROW_22", szValue );
1936 :
1937 0 : sprintf( szValue, "%.16g", sChipInfo.FI_COL_22 );
1938 0 : poDS->SetMetadataItem( "ICHIP_FI_COL_22", szValue );
1939 :
1940 0 : sprintf( szValue, "%d", sChipInfo.FI_ROW );
1941 0 : poDS->SetMetadataItem( "ICHIP_FI_ROW", szValue );
1942 :
1943 0 : sprintf( szValue, "%d", sChipInfo.FI_COL );
1944 0 : poDS->SetMetadataItem( "ICHIP_FI_COL", szValue );
1945 :
1946 : }
1947 :
1948 188 : const NITFSeries* series = NITFGetSeriesInfo(pszFilename);
1949 188 : if (series)
1950 : {
1951 : poDS->SetMetadataItem("NITF_SERIES_ABBREVIATION",
1952 18 : (series->abbreviation) ? series->abbreviation : "Unknown");
1953 : poDS->SetMetadataItem("NITF_SERIES_NAME",
1954 18 : (series->name) ? series->name : "Unknown");
1955 : }
1956 :
1957 : /* -------------------------------------------------------------------- */
1958 : /* If there are multiple image segments, and we are the zeroth, */
1959 : /* then setup the subdataset metadata. */
1960 : /* -------------------------------------------------------------------- */
1961 188 : int nSubDSCount = 0;
1962 :
1963 188 : if( nIMIndex == -1 )
1964 : {
1965 179 : char **papszSubdatasets = NULL;
1966 179 : int nIMCounter = 0;
1967 :
1968 2815 : for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
1969 : {
1970 2636 : if( EQUAL(psFile->pasSegmentInfo[iSegment].szSegmentType,"IM") )
1971 : {
1972 2182 : CPLString oName;
1973 2182 : CPLString oValue;
1974 :
1975 2182 : oName.Printf( "SUBDATASET_%d_NAME", nIMCounter+1 );
1976 2182 : oValue.Printf( "NITF_IM:%d:%s", nIMCounter, pszFilename );
1977 : papszSubdatasets = CSLSetNameValue( papszSubdatasets,
1978 2182 : oName, oValue );
1979 :
1980 2182 : oName.Printf( "SUBDATASET_%d_DESC", nIMCounter+1 );
1981 2182 : oValue.Printf( "Image %d of %s", nIMCounter+1, pszFilename );
1982 : papszSubdatasets = CSLSetNameValue( papszSubdatasets,
1983 2182 : oName, oValue );
1984 :
1985 2182 : nIMCounter++;
1986 : }
1987 : }
1988 :
1989 179 : nSubDSCount = CSLCount(papszSubdatasets) / 2;
1990 179 : if( nSubDSCount > 1 )
1991 : poDS->GDALMajorObject::SetMetadata( papszSubdatasets,
1992 6 : "SUBDATASETS" );
1993 :
1994 179 : CSLDestroy( papszSubdatasets );
1995 : }
1996 :
1997 : /* -------------------------------------------------------------------- */
1998 : /* Initialize any PAM information. */
1999 : /* -------------------------------------------------------------------- */
2000 188 : poDS->SetDescription( poOpenInfo->pszFilename );
2001 :
2002 188 : if( nSubDSCount > 1 || nIMIndex != -1 )
2003 : {
2004 15 : if( nIMIndex == -1 )
2005 6 : nIMIndex = 0;
2006 :
2007 15 : poDS->SetSubdatasetName( CPLString().Printf("%d",nIMIndex) );
2008 15 : poDS->SetPhysicalFilename( pszFilename );
2009 : }
2010 :
2011 188 : poDS->TryLoadXML();
2012 :
2013 : /* -------------------------------------------------------------------- */
2014 : /* If we have jpeg or jpeg2000 bands we may need to set the */
2015 : /* overview file on their dataset. (#3276) */
2016 : /* -------------------------------------------------------------------- */
2017 188 : GDALDataset *poSubDS = poDS->poJ2KDataset;
2018 188 : if( poDS->poJPEGDataset )
2019 12 : poSubDS = poDS->poJPEGDataset;
2020 :
2021 : const char *pszOverviewFile =
2022 188 : poDS->GetMetadataItem( "OVERVIEW_FILE", "OVERVIEWS" );
2023 :
2024 188 : if( poSubDS && pszOverviewFile != NULL )
2025 : {
2026 : poSubDS->SetMetadataItem( "OVERVIEW_FILE",
2027 : pszOverviewFile,
2028 2 : "OVERVIEWS" );
2029 : }
2030 :
2031 : /* -------------------------------------------------------------------- */
2032 : /* If we have jpeg, or jpeg2000 bands we may need to clear */
2033 : /* their PAM dirty flag too. */
2034 : /* -------------------------------------------------------------------- */
2035 188 : if( poDS->poJ2KDataset != NULL )
2036 : poDS->poJ2KDataset->SetPamFlags(
2037 22 : poDS->poJ2KDataset->GetPamFlags() & ~GPF_DIRTY );
2038 188 : if( poDS->poJPEGDataset != NULL )
2039 : poDS->poJPEGDataset->SetPamFlags(
2040 12 : poDS->poJPEGDataset->GetPamFlags() & ~GPF_DIRTY );
2041 :
2042 : /* -------------------------------------------------------------------- */
2043 : /* Check for overviews. */
2044 : /* -------------------------------------------------------------------- */
2045 188 : if( !EQUAL(poOpenInfo->pszFilename,pszFilename) )
2046 9 : poDS->oOvManager.Initialize( poDS, ":::VIRTUAL:::" );
2047 : else
2048 179 : poDS->oOvManager.Initialize( poDS, pszFilename );
2049 :
2050 188 : return( poDS );
2051 : }
2052 :
2053 : /************************************************************************/
2054 : /* LoadDODDatum() */
2055 : /* */
2056 : /* Try to turn a US military datum name into a datum definition. */
2057 : /************************************************************************/
2058 :
2059 0 : static OGRErr LoadDODDatum( OGRSpatialReference *poSRS,
2060 : const char *pszDatumName )
2061 :
2062 : {
2063 : /* -------------------------------------------------------------------- */
2064 : /* The most common case... */
2065 : /* -------------------------------------------------------------------- */
2066 0 : if( EQUALN(pszDatumName,"WGE ",4) )
2067 : {
2068 0 : poSRS->SetWellKnownGeogCS( "WGS84" );
2069 0 : return OGRERR_NONE;
2070 : }
2071 :
2072 : /* -------------------------------------------------------------------- */
2073 : /* All the rest we will try and load from gt_datum.csv */
2074 : /* (Geotrans datum file). */
2075 : /* -------------------------------------------------------------------- */
2076 : char szExpanded[6];
2077 0 : const char *pszGTDatum = CSVFilename( "gt_datum.csv" );
2078 :
2079 0 : strncpy( szExpanded, pszDatumName, 3 );
2080 0 : szExpanded[3] = '\0';
2081 0 : if( pszDatumName[3] != ' ' )
2082 : {
2083 : int nLen;
2084 0 : strcat( szExpanded, "-" );
2085 0 : nLen = strlen(szExpanded);
2086 0 : szExpanded[nLen] = pszDatumName[3];
2087 0 : szExpanded[nLen + 1] = '\0';
2088 : }
2089 :
2090 : CPLString osDName = CSVGetField( pszGTDatum, "CODE", szExpanded,
2091 0 : CC_ApproxString, "NAME" );
2092 0 : if( strlen(osDName) == 0 )
2093 : {
2094 : CPLError( CE_Failure, CPLE_AppDefined,
2095 : "Failed to find datum %s/%s in gt_datum.csv.",
2096 0 : pszDatumName, szExpanded );
2097 0 : return OGRERR_FAILURE;
2098 : }
2099 :
2100 : CPLString osEllipseCode = CSVGetField( pszGTDatum, "CODE", szExpanded,
2101 0 : CC_ApproxString, "ELLIPSOID" );
2102 : double dfDeltaX = CPLAtof(CSVGetField( pszGTDatum, "CODE", szExpanded,
2103 0 : CC_ApproxString, "DELTAX" ) );
2104 : double dfDeltaY = CPLAtof(CSVGetField( pszGTDatum, "CODE", szExpanded,
2105 0 : CC_ApproxString, "DELTAY" ) );
2106 : double dfDeltaZ = CPLAtof(CSVGetField( pszGTDatum, "CODE", szExpanded,
2107 0 : CC_ApproxString, "DELTAZ" ) );
2108 :
2109 : /* -------------------------------------------------------------------- */
2110 : /* Lookup the ellipse code. */
2111 : /* -------------------------------------------------------------------- */
2112 0 : const char *pszGTEllipse = CSVFilename( "gt_ellips.csv" );
2113 :
2114 : CPLString osEName = CSVGetField( pszGTEllipse, "CODE", osEllipseCode,
2115 0 : CC_ApproxString, "NAME" );
2116 0 : if( strlen(osEName) == 0 )
2117 : {
2118 : CPLError( CE_Failure, CPLE_AppDefined,
2119 : "Failed to find datum %s in gt_ellips.csv.",
2120 0 : osEllipseCode.c_str() );
2121 0 : return OGRERR_FAILURE;
2122 : }
2123 :
2124 : double dfA = CPLAtof(CSVGetField( pszGTEllipse, "CODE", osEllipseCode,
2125 0 : CC_ApproxString, "A" ));
2126 : double dfInvF = CPLAtof(CSVGetField( pszGTEllipse, "CODE", osEllipseCode,
2127 0 : CC_ApproxString, "RF" ));
2128 :
2129 : /* -------------------------------------------------------------------- */
2130 : /* Create geographic coordinate system. */
2131 : /* -------------------------------------------------------------------- */
2132 0 : poSRS->SetGeogCS( osDName, osDName, osEName, dfA, dfInvF );
2133 :
2134 0 : poSRS->SetTOWGS84( dfDeltaX, dfDeltaY, dfDeltaZ );
2135 :
2136 0 : return OGRERR_NONE;
2137 : }
2138 :
2139 : /************************************************************************/
2140 : /* CheckGeoSDEInfo() */
2141 : /* */
2142 : /* Check for GeoSDE TREs (GEOPSB/PRJPSB and MAPLOB). If we */
2143 : /* have them, use them to override our coordinate system and */
2144 : /* geotransform info. */
2145 : /************************************************************************/
2146 :
2147 185 : void NITFDataset::CheckGeoSDEInfo()
2148 :
2149 : {
2150 185 : if( !psImage )
2151 0 : return;
2152 :
2153 : /* -------------------------------------------------------------------- */
2154 : /* Do we have the required TREs? */
2155 : /* -------------------------------------------------------------------- */
2156 : const char *pszGEOPSB , *pszPRJPSB, *pszMAPLOB;
2157 185 : OGRSpatialReference oSRS;
2158 : char szName[81];
2159 :
2160 185 : pszGEOPSB = NITFFindTRE( psFile->pachTRE, psFile->nTREBytes,"GEOPSB",NULL);
2161 185 : pszPRJPSB = NITFFindTRE( psFile->pachTRE, psFile->nTREBytes,"PRJPSB",NULL);
2162 185 : pszMAPLOB = NITFFindTRE(psImage->pachTRE,psImage->nTREBytes,"MAPLOB",NULL);
2163 :
2164 185 : if( pszGEOPSB == NULL || pszPRJPSB == NULL || pszMAPLOB == NULL )
2165 : return;
2166 :
2167 : /* -------------------------------------------------------------------- */
2168 : /* Collect projection parameters. */
2169 : /* -------------------------------------------------------------------- */
2170 0 : int nRemainingBytesPRJPSB = psFile->nTREBytes - (pszPRJPSB - psFile->pachTRE);
2171 :
2172 : char szParm[16];
2173 0 : if (nRemainingBytesPRJPSB < 82 + 1)
2174 : {
2175 : CPLError(CE_Failure, CPLE_AppDefined,
2176 0 : "Cannot read PRJPSB TRE. Not enough bytes");
2177 : }
2178 0 : int nParmCount = atoi(NITFGetField(szParm,pszPRJPSB,82,1));
2179 : int i;
2180 0 : double adfParm[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
2181 : double dfFN;
2182 : double dfFE;
2183 0 : if (nRemainingBytesPRJPSB < 83+15*nParmCount+15+15)
2184 : {
2185 : CPLError(CE_Failure, CPLE_AppDefined,
2186 0 : "Cannot read PRJPSB TRE. Not enough bytes");
2187 : }
2188 0 : for( i = 0; i < nParmCount; i++ )
2189 0 : adfParm[i] = atof(NITFGetField(szParm,pszPRJPSB,83+15*i,15));
2190 :
2191 0 : dfFE = atof(NITFGetField(szParm,pszPRJPSB,83+15*nParmCount,15));
2192 0 : dfFN = atof(NITFGetField(szParm,pszPRJPSB,83+15*nParmCount+15,15));
2193 :
2194 : /* -------------------------------------------------------------------- */
2195 : /* Try to handle the projection. */
2196 : /* -------------------------------------------------------------------- */
2197 0 : if( EQUALN(pszPRJPSB+80,"AC",2) )
2198 : oSRS.SetACEA( adfParm[1], adfParm[2], adfParm[3], adfParm[0],
2199 0 : dfFE, dfFN );
2200 :
2201 0 : else if( EQUALN(pszPRJPSB+80,"AK",2) )
2202 0 : oSRS.SetLAEA( adfParm[1], adfParm[0], dfFE, dfFN );
2203 :
2204 0 : else if( EQUALN(pszPRJPSB+80,"AL",2) )
2205 0 : oSRS.SetAE( adfParm[1], adfParm[0], dfFE, dfFN );
2206 :
2207 0 : else if( EQUALN(pszPRJPSB+80,"BF",2) )
2208 0 : oSRS.SetBonne( adfParm[1], adfParm[0], dfFE, dfFN );
2209 :
2210 0 : else if( EQUALN(pszPRJPSB+80,"CP",2) )
2211 0 : oSRS.SetEquirectangular( adfParm[1], adfParm[0], dfFE, dfFN );
2212 :
2213 0 : else if( EQUALN(pszPRJPSB+80,"CS",2) )
2214 0 : oSRS.SetCS( adfParm[1], adfParm[0], dfFE, dfFN );
2215 :
2216 0 : else if( EQUALN(pszPRJPSB+80,"EF",2) )
2217 0 : oSRS.SetEckertIV( adfParm[0], dfFE, dfFN );
2218 :
2219 0 : else if( EQUALN(pszPRJPSB+80,"ED",2) )
2220 0 : oSRS.SetEckertVI( adfParm[0], dfFE, dfFN );
2221 :
2222 0 : else if( EQUALN(pszPRJPSB+80,"GN",2) )
2223 0 : oSRS.SetGnomonic( adfParm[1], adfParm[0], dfFE, dfFN );
2224 :
2225 0 : else if( EQUALN(pszPRJPSB+80,"HX",2) )
2226 : oSRS.SetHOM2PNO( adfParm[1],
2227 : adfParm[3], adfParm[2],
2228 : adfParm[5], adfParm[4],
2229 0 : adfParm[0], dfFE, dfFN );
2230 :
2231 0 : else if( EQUALN(pszPRJPSB+80,"KA",2) )
2232 : oSRS.SetEC( adfParm[1], adfParm[2], adfParm[3], adfParm[0],
2233 0 : dfFE, dfFN );
2234 :
2235 0 : else if( EQUALN(pszPRJPSB+80,"LE",2) )
2236 : oSRS.SetLCC( adfParm[1], adfParm[2], adfParm[3], adfParm[0],
2237 0 : dfFE, dfFN );
2238 :
2239 0 : else if( EQUALN(pszPRJPSB+80,"LI",2) )
2240 0 : oSRS.SetCEA( adfParm[1], adfParm[0], dfFE, dfFN );
2241 :
2242 0 : else if( EQUALN(pszPRJPSB+80,"MC",2) )
2243 0 : oSRS.SetMercator( adfParm[2], adfParm[1], 1.0, dfFE, dfFN );
2244 :
2245 0 : else if( EQUALN(pszPRJPSB+80,"MH",2) )
2246 0 : oSRS.SetMC( 0.0, adfParm[1], dfFE, dfFN );
2247 :
2248 0 : else if( EQUALN(pszPRJPSB+80,"MP",2) )
2249 0 : oSRS.SetMollweide( adfParm[0], dfFE, dfFN );
2250 :
2251 0 : else if( EQUALN(pszPRJPSB+80,"NT",2) )
2252 0 : oSRS.SetNZMG( adfParm[1], adfParm[0], dfFE, dfFN );
2253 :
2254 0 : else if( EQUALN(pszPRJPSB+80,"OD",2) )
2255 0 : oSRS.SetOrthographic( adfParm[1], adfParm[0], dfFE, dfFN );
2256 :
2257 0 : else if( EQUALN(pszPRJPSB+80,"PC",2) )
2258 0 : oSRS.SetPolyconic( adfParm[1], adfParm[0], dfFE, dfFN );
2259 :
2260 0 : else if( EQUALN(pszPRJPSB+80,"PG",2) )
2261 0 : oSRS.SetPS( adfParm[1], adfParm[0], 1.0, dfFE, dfFN );
2262 :
2263 0 : else if( EQUALN(pszPRJPSB+80,"RX",2) )
2264 0 : oSRS.SetRobinson( adfParm[0], dfFE, dfFN );
2265 :
2266 0 : else if( EQUALN(pszPRJPSB+80,"SA",2) )
2267 0 : oSRS.SetSinusoidal( adfParm[0], dfFE, dfFN );
2268 :
2269 0 : else if( EQUALN(pszPRJPSB+80,"TC",2) )
2270 0 : oSRS.SetTM( adfParm[2], adfParm[0], adfParm[1], dfFE, dfFN );
2271 :
2272 0 : else if( EQUALN(pszPRJPSB+80,"VA",2) )
2273 0 : oSRS.SetVDG( adfParm[0], dfFE, dfFN );
2274 :
2275 : else
2276 0 : oSRS.SetLocalCS( NITFGetField(szName,pszPRJPSB,0,80) );
2277 :
2278 : /* -------------------------------------------------------------------- */
2279 : /* Try to apply the datum. */
2280 : /* -------------------------------------------------------------------- */
2281 0 : int nRemainingBytesGEOPSB = psFile->nTREBytes - (pszGEOPSB - psFile->pachTRE);
2282 0 : if (nRemainingBytesGEOPSB < 86 + 4)
2283 : {
2284 : CPLError(CE_Failure, CPLE_AppDefined,
2285 0 : "Cannot read GEOPSB TRE. Not enough bytes");
2286 : }
2287 0 : LoadDODDatum( &oSRS, NITFGetField(szParm,pszGEOPSB,86,4) );
2288 :
2289 : /* -------------------------------------------------------------------- */
2290 : /* Get the geotransform */
2291 : /* -------------------------------------------------------------------- */
2292 : double adfGT[6];
2293 0 : double dfMeterPerUnit = 1.0;
2294 :
2295 0 : int nRemainingBytesMAPLOB = psImage->nTREBytes - (pszMAPLOB - psImage->pachTRE);
2296 0 : if (nRemainingBytesMAPLOB < 28 + 15)
2297 : {
2298 : CPLError(CE_Failure, CPLE_AppDefined,
2299 0 : "Cannot read MAPLOB TRE. Not enough bytes");
2300 : }
2301 :
2302 0 : if( EQUALN(pszMAPLOB+0,"DM ",3) )
2303 0 : dfMeterPerUnit = 0.1;
2304 0 : else if( EQUALN(pszMAPLOB+0,"CM ",3) )
2305 0 : dfMeterPerUnit = 0.01;
2306 0 : else if( EQUALN(pszMAPLOB+0,"MM ",3) )
2307 0 : dfMeterPerUnit = 0.001;
2308 0 : else if( EQUALN(pszMAPLOB+0,"UM ",3) )
2309 0 : dfMeterPerUnit = 0.000001;
2310 0 : else if( EQUALN(pszMAPLOB+0,"KM ",3) )
2311 0 : dfMeterPerUnit = 1000.0;
2312 0 : else if( EQUALN(pszMAPLOB+0,"M ",3) )
2313 0 : dfMeterPerUnit = 1.0;
2314 : else
2315 : {
2316 : CPLError( CE_Warning, CPLE_AppDefined,
2317 : "MAPLOB Unit=%3.3s not regonised, geolocation may be wrong.",
2318 0 : pszMAPLOB+0 );
2319 : }
2320 :
2321 0 : adfGT[0] = atof(NITFGetField(szParm,pszMAPLOB,13,15));
2322 0 : adfGT[1] = atof(NITFGetField(szParm,pszMAPLOB,3,5)) * dfMeterPerUnit;
2323 0 : adfGT[2] = 0.0;
2324 0 : adfGT[3] = atof(NITFGetField(szParm,pszMAPLOB,28,15));
2325 0 : adfGT[4] = 0.0;
2326 0 : adfGT[5] = -atof(NITFGetField(szParm,pszMAPLOB,8,5)) * dfMeterPerUnit;
2327 :
2328 : /* -------------------------------------------------------------------- */
2329 : /* Apply back to dataset. */
2330 : /* -------------------------------------------------------------------- */
2331 0 : CPLFree( pszProjection );
2332 0 : pszProjection = NULL;
2333 :
2334 0 : oSRS.exportToWkt( &pszProjection );
2335 :
2336 0 : memcpy( adfGeoTransform, adfGT, sizeof(double)*6 );
2337 : }
2338 :
2339 : /************************************************************************/
2340 : /* AdviseRead() */
2341 : /************************************************************************/
2342 :
2343 0 : CPLErr NITFDataset::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
2344 : int nBufXSize, int nBufYSize,
2345 : GDALDataType eDT,
2346 : int nBandCount, int *panBandList,
2347 : char **papszOptions )
2348 :
2349 : {
2350 0 : if( poJ2KDataset == NULL )
2351 : return GDALDataset::AdviseRead( nXOff, nYOff, nXSize, nYSize,
2352 : nBufXSize, nBufYSize, eDT,
2353 : nBandCount, panBandList,
2354 0 : papszOptions);
2355 0 : else if( poJPEGDataset != NULL )
2356 : return poJPEGDataset->AdviseRead( nXOff, nYOff, nXSize, nYSize,
2357 : nBufXSize, nBufYSize, eDT,
2358 : nBandCount, panBandList,
2359 0 : papszOptions);
2360 : else
2361 : return poJ2KDataset->AdviseRead( nXOff, nYOff, nXSize, nYSize,
2362 : nBufXSize, nBufYSize, eDT,
2363 : nBandCount, panBandList,
2364 0 : papszOptions);
2365 : }
2366 :
2367 : /************************************************************************/
2368 : /* IRasterIO() */
2369 : /************************************************************************/
2370 :
2371 864 : CPLErr NITFDataset::IRasterIO( GDALRWFlag eRWFlag,
2372 : int nXOff, int nYOff, int nXSize, int nYSize,
2373 : void * pData, int nBufXSize, int nBufYSize,
2374 : GDALDataType eBufType,
2375 : int nBandCount, int *panBandMap,
2376 : int nPixelSpace, int nLineSpace, int nBandSpace)
2377 :
2378 : {
2379 864 : if( poJ2KDataset != NULL )
2380 : return poJ2KDataset->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
2381 : pData, nBufXSize, nBufYSize, eBufType,
2382 : nBandCount, panBandMap,
2383 100 : nPixelSpace, nLineSpace, nBandSpace );
2384 764 : else if( poJPEGDataset != NULL )
2385 : return poJPEGDataset->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
2386 : pData, nBufXSize, nBufYSize, eBufType,
2387 : nBandCount, panBandMap,
2388 64 : nPixelSpace, nLineSpace, nBandSpace );
2389 : else
2390 : return GDALDataset::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
2391 : pData, nBufXSize, nBufYSize, eBufType,
2392 : nBandCount, panBandMap,
2393 700 : nPixelSpace, nLineSpace, nBandSpace );
2394 : }
2395 :
2396 :
2397 : /************************************************************************/
2398 : /* GetGeoTransform() */
2399 : /************************************************************************/
2400 :
2401 63 : CPLErr NITFDataset::GetGeoTransform( double *padfGeoTransform )
2402 :
2403 : {
2404 63 : memcpy( padfGeoTransform, adfGeoTransform, sizeof(double) * 6 );
2405 :
2406 63 : if( bGotGeoTransform )
2407 61 : return CE_None;
2408 : else
2409 2 : return GDALPamDataset::GetGeoTransform( padfGeoTransform );
2410 : }
2411 :
2412 : /************************************************************************/
2413 : /* SetGeoTransform() */
2414 : /************************************************************************/
2415 :
2416 40 : CPLErr NITFDataset::SetGeoTransform( double *padfGeoTransform )
2417 :
2418 : {
2419 : double dfIGEOLOULX, dfIGEOLOULY, dfIGEOLOURX, dfIGEOLOURY,
2420 : dfIGEOLOLRX, dfIGEOLOLRY, dfIGEOLOLLX, dfIGEOLOLLY;
2421 :
2422 40 : bGotGeoTransform = TRUE;
2423 : /* Valgrind would complain because SetGeoTransform() is called */
2424 : /* from SetProjection() with adfGeoTransform as argument */
2425 40 : if (adfGeoTransform != padfGeoTransform)
2426 39 : memcpy( adfGeoTransform, padfGeoTransform, sizeof(double) * 6 );
2427 :
2428 40 : dfIGEOLOULX = padfGeoTransform[0] + 0.5 * padfGeoTransform[1]
2429 40 : + 0.5 * padfGeoTransform[2];
2430 40 : dfIGEOLOULY = padfGeoTransform[3] + 0.5 * padfGeoTransform[4]
2431 40 : + 0.5 * padfGeoTransform[5];
2432 40 : dfIGEOLOURX = dfIGEOLOULX + padfGeoTransform[1] * (nRasterXSize - 1);
2433 40 : dfIGEOLOURY = dfIGEOLOULY + padfGeoTransform[4] * (nRasterXSize - 1);
2434 40 : dfIGEOLOLRX = dfIGEOLOULX + padfGeoTransform[1] * (nRasterXSize - 1)
2435 40 : + padfGeoTransform[2] * (nRasterYSize - 1);
2436 40 : dfIGEOLOLRY = dfIGEOLOULY + padfGeoTransform[4] * (nRasterXSize - 1)
2437 40 : + padfGeoTransform[5] * (nRasterYSize - 1);
2438 40 : dfIGEOLOLLX = dfIGEOLOULX + padfGeoTransform[2] * (nRasterYSize - 1);
2439 40 : dfIGEOLOLLY = dfIGEOLOULY + padfGeoTransform[5] * (nRasterYSize - 1);
2440 :
2441 40 : if( NITFWriteIGEOLO( psImage, psImage->chICORDS,
2442 : psImage->nZone,
2443 : dfIGEOLOULX, dfIGEOLOULY, dfIGEOLOURX, dfIGEOLOURY,
2444 : dfIGEOLOLRX, dfIGEOLOLRY, dfIGEOLOLLX, dfIGEOLOLLY ) )
2445 40 : return CE_None;
2446 : else
2447 0 : return GDALPamDataset::SetGeoTransform( padfGeoTransform );
2448 : }
2449 :
2450 : /************************************************************************/
2451 : /* GetProjectionRef() */
2452 : /************************************************************************/
2453 :
2454 92 : const char *NITFDataset::GetProjectionRef()
2455 :
2456 : {
2457 92 : if( bGotGeoTransform )
2458 88 : return pszProjection;
2459 : else
2460 4 : return GDALPamDataset::GetProjectionRef();
2461 : }
2462 :
2463 : /************************************************************************/
2464 : /* SetProjection() */
2465 : /************************************************************************/
2466 :
2467 1 : CPLErr NITFDataset::SetProjection(const char* _pszProjection)
2468 :
2469 : {
2470 : int bNorth;
2471 1 : OGRSpatialReference oSRS, oSRS_WGS84;
2472 1 : char *pszWKT = (char *) _pszProjection;
2473 :
2474 1 : if( pszWKT != NULL )
2475 1 : oSRS.importFromWkt( &pszWKT );
2476 : else
2477 0 : return CE_Failure;
2478 :
2479 1 : oSRS_WGS84.SetWellKnownGeogCS( "WGS84" );
2480 1 : if ( oSRS.IsSameGeogCS(&oSRS_WGS84) == FALSE)
2481 : {
2482 : CPLError(CE_Failure, CPLE_NotSupported,
2483 0 : "NITF only supports WGS84 geographic and UTM projections.\n");
2484 0 : return CE_Failure;
2485 : }
2486 :
2487 1 : if( oSRS.IsGeographic() && oSRS.GetPrimeMeridian() == 0.0)
2488 : {
2489 0 : if (psImage->chICORDS != 'G')
2490 : {
2491 : CPLError(CE_Failure, CPLE_NotSupported,
2492 0 : "NITF file should have been created with creation option 'ICORDS=G'.\n");
2493 0 : return CE_Failure;
2494 : }
2495 : }
2496 1 : else if( oSRS.GetUTMZone( &bNorth ) > 0)
2497 : {
2498 1 : if (bNorth && psImage->chICORDS != 'N')
2499 : {
2500 : CPLError(CE_Failure, CPLE_NotSupported,
2501 0 : "NITF file should have been created with creation option 'ICORDS=N'.\n");
2502 0 : return CE_Failure;
2503 : }
2504 1 : else if (!bNorth && psImage->chICORDS != 'S')
2505 : {
2506 : CPLError(CE_Failure, CPLE_NotSupported,
2507 0 : "NITF file should have been created with creation option 'ICORDS=S'.\n");
2508 0 : return CE_Failure;
2509 : }
2510 :
2511 1 : psImage->nZone = oSRS.GetUTMZone( NULL );
2512 : }
2513 : else
2514 : {
2515 : CPLError(CE_Failure, CPLE_NotSupported,
2516 0 : "NITF only supports WGS84 geographic and UTM projections.\n");
2517 0 : return CE_Failure;
2518 : }
2519 :
2520 1 : CPLFree(pszProjection);
2521 1 : pszProjection = CPLStrdup(_pszProjection);
2522 :
2523 1 : if (bGotGeoTransform)
2524 1 : SetGeoTransform(adfGeoTransform);
2525 :
2526 1 : return CE_None;
2527 : }
2528 :
2529 : /************************************************************************/
2530 : /* InitializeCGMMetadata() */
2531 : /************************************************************************/
2532 :
2533 4 : void NITFDataset::InitializeCGMMetadata()
2534 :
2535 : {
2536 4 : if( oSpecialMD.GetMetadataItem( "SEGMENT_COUNT", "CGM" ) != NULL )
2537 1 : return;
2538 :
2539 : int iSegment;
2540 3 : int iCGM = 0;
2541 3 : char **papszCGMMetadata = NULL;
2542 :
2543 : papszCGMMetadata =
2544 3 : CSLSetNameValue( papszCGMMetadata, "SEGMENT_COUNT", "0" );
2545 :
2546 : /* ==================================================================== */
2547 : /* Process all graphics segments. */
2548 : /* ==================================================================== */
2549 18 : for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
2550 : {
2551 15 : NITFSegmentInfo *psSegment = psFile->pasSegmentInfo + iSegment;
2552 :
2553 15 : if( !EQUAL(psSegment->szSegmentType,"GR")
2554 : && !EQUAL(psSegment->szSegmentType,"SY") )
2555 4 : continue;
2556 :
2557 : papszCGMMetadata =
2558 : CSLSetNameValue( papszCGMMetadata,
2559 : CPLString().Printf("SEGMENT_%d_SLOC_ROW", iCGM),
2560 11 : CPLString().Printf("%d",psSegment->nLOC_R) );
2561 : papszCGMMetadata =
2562 : CSLSetNameValue( papszCGMMetadata,
2563 : CPLString().Printf("SEGMENT_%d_SLOC_COL", iCGM),
2564 22 : CPLString().Printf("%d",psSegment->nLOC_C) );
2565 :
2566 : papszCGMMetadata =
2567 : CSLSetNameValue( papszCGMMetadata,
2568 : CPLString().Printf("SEGMENT_%d_CCS_ROW", iCGM),
2569 22 : CPLString().Printf("%d",psSegment->nCCS_R) );
2570 : papszCGMMetadata =
2571 : CSLSetNameValue( papszCGMMetadata,
2572 : CPLString().Printf("SEGMENT_%d_CCS_COL", iCGM),
2573 22 : CPLString().Printf("%d",psSegment->nCCS_C) );
2574 :
2575 : papszCGMMetadata =
2576 : CSLSetNameValue( papszCGMMetadata,
2577 : CPLString().Printf("SEGMENT_%d_SDLVL", iCGM),
2578 22 : CPLString().Printf("%d",psSegment->nDLVL) );
2579 : papszCGMMetadata =
2580 : CSLSetNameValue( papszCGMMetadata,
2581 : CPLString().Printf("SEGMENT_%d_SALVL", iCGM),
2582 22 : CPLString().Printf("%d",psSegment->nALVL) );
2583 :
2584 : /* -------------------------------------------------------------------- */
2585 : /* Load the raw CGM data itself. */
2586 : /* -------------------------------------------------------------------- */
2587 : char *pabyCGMData, *pszEscapedCGMData;
2588 :
2589 11 : pabyCGMData = (char *) CPLCalloc(1,(size_t)psSegment->nSegmentSize);
2590 22 : if( VSIFSeekL( psFile->fp, psSegment->nSegmentStart,
2591 : SEEK_SET ) != 0
2592 : || VSIFReadL( pabyCGMData, 1, (size_t)psSegment->nSegmentSize,
2593 : psFile->fp ) != psSegment->nSegmentSize )
2594 : {
2595 : CPLError( CE_Warning, CPLE_FileIO,
2596 : "Failed to read " CPL_FRMT_GUIB " bytes of graphic data at " CPL_FRMT_GUIB ".",
2597 : psSegment->nSegmentSize,
2598 0 : psSegment->nSegmentStart );
2599 0 : return;
2600 : }
2601 :
2602 : pszEscapedCGMData = CPLEscapeString( pabyCGMData,
2603 : (int)psSegment->nSegmentSize,
2604 11 : CPLES_BackslashQuotable );
2605 :
2606 : papszCGMMetadata =
2607 : CSLSetNameValue( papszCGMMetadata,
2608 : CPLString().Printf("SEGMENT_%d_DATA", iCGM),
2609 11 : pszEscapedCGMData );
2610 11 : CPLFree( pszEscapedCGMData );
2611 11 : CPLFree( pabyCGMData );
2612 :
2613 11 : iCGM++;
2614 : }
2615 :
2616 : /* -------------------------------------------------------------------- */
2617 : /* Record the CGM segment count. */
2618 : /* -------------------------------------------------------------------- */
2619 : papszCGMMetadata =
2620 : CSLSetNameValue( papszCGMMetadata,
2621 : "SEGMENT_COUNT",
2622 3 : CPLString().Printf( "%d", iCGM ) );
2623 :
2624 3 : oSpecialMD.SetMetadata( papszCGMMetadata, "CGM" );
2625 :
2626 3 : CSLDestroy( papszCGMMetadata );
2627 : }
2628 :
2629 : /************************************************************************/
2630 : /* InitializeTextMetadata() */
2631 : /************************************************************************/
2632 :
2633 9 : void NITFDataset::InitializeTextMetadata()
2634 :
2635 : {
2636 9 : if( oSpecialMD.GetMetadata( "TEXT" ) != NULL )
2637 2 : return;
2638 :
2639 : int iSegment;
2640 7 : int iText = 0;
2641 :
2642 : /* ==================================================================== */
2643 : /* Process all graphics segments. */
2644 : /* ==================================================================== */
2645 225 : for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
2646 : {
2647 218 : NITFSegmentInfo *psSegment = psFile->pasSegmentInfo + iSegment;
2648 :
2649 218 : if( !EQUAL(psSegment->szSegmentType,"TX") )
2650 210 : continue;
2651 :
2652 : /* -------------------------------------------------------------------- */
2653 : /* Load the raw TEXT data itself. */
2654 : /* -------------------------------------------------------------------- */
2655 : char *pabyTextData;
2656 :
2657 : /* Allocate one extra byte for the NULL terminating character */
2658 8 : pabyTextData = (char *) CPLCalloc(1,(size_t)psSegment->nSegmentSize+1);
2659 8 : if( VSIFSeekL( psFile->fp, psSegment->nSegmentStart,
2660 : SEEK_SET ) != 0
2661 : || VSIFReadL( pabyTextData, 1, (size_t)psSegment->nSegmentSize,
2662 : psFile->fp ) != psSegment->nSegmentSize )
2663 : {
2664 : CPLError( CE_Warning, CPLE_FileIO,
2665 : "Failed to read " CPL_FRMT_GUIB " bytes of text data at " CPL_FRMT_GUIB ".",
2666 : psSegment->nSegmentSize,
2667 0 : psSegment->nSegmentStart );
2668 0 : return;
2669 : }
2670 :
2671 : oSpecialMD.SetMetadataItem( CPLString().Printf( "DATA_%d", iText),
2672 8 : pabyTextData, "TEXT" );
2673 8 : CPLFree( pabyTextData );
2674 :
2675 8 : iText++;
2676 : }
2677 : }
2678 :
2679 : /************************************************************************/
2680 : /* InitializeTREMetadata() */
2681 : /************************************************************************/
2682 :
2683 8 : void NITFDataset::InitializeTREMetadata()
2684 :
2685 : {
2686 8 : if( oSpecialMD.GetMetadata( "TRE" ) != NULL )
2687 2 : return;
2688 :
2689 : /* -------------------------------------------------------------------- */
2690 : /* Loop over TRE sources (file and image). */
2691 : /* -------------------------------------------------------------------- */
2692 : int nTRESrc;
2693 :
2694 18 : for( nTRESrc = 0; nTRESrc < 2; nTRESrc++ )
2695 : {
2696 : int nTREBytes;
2697 : char *pszTREData;
2698 :
2699 12 : if( nTRESrc == 0 )
2700 : {
2701 6 : nTREBytes = psFile->nTREBytes;
2702 6 : pszTREData = psFile->pachTRE;
2703 : }
2704 : else
2705 : {
2706 6 : if( psImage )
2707 : {
2708 6 : nTREBytes = psImage->nTREBytes;
2709 6 : pszTREData = psImage->pachTRE;
2710 : }
2711 : else
2712 : {
2713 0 : nTREBytes = 0;
2714 0 : pszTREData = NULL;
2715 : }
2716 : }
2717 :
2718 : /* -------------------------------------------------------------------- */
2719 : /* Loop over TREs. */
2720 : /* -------------------------------------------------------------------- */
2721 :
2722 28 : while( nTREBytes >= 11 )
2723 : {
2724 : char szTemp[100];
2725 : char szTag[7];
2726 : char *pszEscapedData;
2727 4 : int nThisTRESize = atoi(NITFGetField(szTemp, pszTREData, 6, 5 ));
2728 :
2729 4 : if (nThisTRESize < 0)
2730 : {
2731 0 : NITFGetField(szTemp, pszTREData, 0, 6 );
2732 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid size (%d) for TRE %s",
2733 0 : nThisTRESize, szTemp);
2734 0 : return;
2735 : }
2736 4 : if (nThisTRESize > nTREBytes - 11)
2737 : {
2738 0 : CPLError(CE_Failure, CPLE_AppDefined, "Not enough bytes in TRE");
2739 0 : return;
2740 : }
2741 :
2742 4 : strncpy( szTag, pszTREData, 6 );
2743 4 : szTag[6] = '\0';
2744 :
2745 : // trim white off tag.
2746 8 : while( strlen(szTag) > 0 && szTag[strlen(szTag)-1] == ' ' )
2747 0 : szTag[strlen(szTag)-1] = '\0';
2748 :
2749 : // escape data.
2750 : pszEscapedData = CPLEscapeString( pszTREData + 11,
2751 : nThisTRESize,
2752 4 : CPLES_BackslashQuotable );
2753 :
2754 4 : oSpecialMD.SetMetadataItem( szTag, pszEscapedData, "TRE" );
2755 4 : CPLFree( pszEscapedData );
2756 :
2757 4 : nTREBytes -= (nThisTRESize + 11);
2758 4 : pszTREData += (nThisTRESize + 11);
2759 : }
2760 : }
2761 : }
2762 :
2763 : /************************************************************************/
2764 : /* GetMetadata() */
2765 : /************************************************************************/
2766 :
2767 78 : char **NITFDataset::GetMetadata( const char * pszDomain )
2768 :
2769 : {
2770 78 : if( pszDomain != NULL && EQUAL(pszDomain,"CGM") )
2771 : {
2772 3 : InitializeCGMMetadata();
2773 3 : return oSpecialMD.GetMetadata( pszDomain );
2774 : }
2775 :
2776 75 : if( pszDomain != NULL && EQUAL(pszDomain,"TEXT") )
2777 : {
2778 8 : InitializeTextMetadata();
2779 8 : return oSpecialMD.GetMetadata( pszDomain );
2780 : }
2781 :
2782 67 : if( pszDomain != NULL && EQUAL(pszDomain,"TRE") )
2783 : {
2784 6 : InitializeTREMetadata();
2785 6 : return oSpecialMD.GetMetadata( pszDomain );
2786 : }
2787 :
2788 61 : return GDALPamDataset::GetMetadata( pszDomain );
2789 : }
2790 :
2791 : /************************************************************************/
2792 : /* GetMetadataItem() */
2793 : /************************************************************************/
2794 :
2795 944 : const char *NITFDataset::GetMetadataItem(const char * pszName,
2796 : const char * pszDomain )
2797 :
2798 : {
2799 944 : if( pszDomain != NULL && EQUAL(pszDomain,"CGM") )
2800 : {
2801 1 : InitializeCGMMetadata();
2802 1 : return oSpecialMD.GetMetadataItem( pszName, pszDomain );
2803 : }
2804 :
2805 943 : if( pszDomain != NULL && EQUAL(pszDomain,"TEXT") )
2806 : {
2807 1 : InitializeTextMetadata();
2808 1 : return oSpecialMD.GetMetadataItem( pszName, pszDomain );
2809 : }
2810 :
2811 942 : if( pszDomain != NULL && EQUAL(pszDomain,"TRE") )
2812 : {
2813 2 : InitializeTREMetadata();
2814 2 : return oSpecialMD.GetMetadataItem( pszName, pszDomain );
2815 : }
2816 :
2817 940 : return GDALPamDataset::GetMetadataItem( pszName, pszDomain );
2818 : }
2819 :
2820 :
2821 : /************************************************************************/
2822 : /* GetGCPCount() */
2823 : /************************************************************************/
2824 :
2825 5 : int NITFDataset::GetGCPCount()
2826 :
2827 : {
2828 5 : return nGCPCount;
2829 : }
2830 :
2831 : /************************************************************************/
2832 : /* GetGCPProjection() */
2833 : /************************************************************************/
2834 :
2835 0 : const char *NITFDataset::GetGCPProjection()
2836 :
2837 : {
2838 0 : if( nGCPCount > 0 && pszGCPProjection != NULL )
2839 0 : return pszGCPProjection;
2840 : else
2841 0 : return "";
2842 : }
2843 :
2844 : /************************************************************************/
2845 : /* GetGCP() */
2846 : /************************************************************************/
2847 :
2848 0 : const GDAL_GCP *NITFDataset::GetGCPs()
2849 :
2850 : {
2851 0 : return pasGCPList;
2852 : }
2853 :
2854 : /************************************************************************/
2855 : /* IBuildOverviews() */
2856 : /************************************************************************/
2857 :
2858 3 : CPLErr NITFDataset::IBuildOverviews( const char *pszResampling,
2859 : int nOverviews, int *panOverviewList,
2860 : int nListBands, int *panBandList,
2861 : GDALProgressFunc pfnProgress,
2862 : void * pProgressData )
2863 :
2864 : {
2865 : /* -------------------------------------------------------------------- */
2866 : /* If we have an underlying JPEG2000 dataset (hopefully via */
2867 : /* JP2KAK) we will try and build zero overviews as a way of */
2868 : /* tricking it into clearing existing overviews-from-jpeg2000. */
2869 : /* -------------------------------------------------------------------- */
2870 4 : if( poJ2KDataset != NULL
2871 1 : && !poJ2KDataset->GetMetadataItem( "OVERVIEW_FILE", "OVERVIEWS" ) )
2872 : poJ2KDataset->IBuildOverviews( pszResampling, 0, NULL,
2873 : nListBands, panBandList,
2874 1 : GDALDummyProgress, NULL );
2875 :
2876 : /* -------------------------------------------------------------------- */
2877 : /* Use the overview manager to build requested overviews. */
2878 : /* -------------------------------------------------------------------- */
2879 : CPLErr eErr = GDALPamDataset::IBuildOverviews( pszResampling,
2880 : nOverviews, panOverviewList,
2881 : nListBands, panBandList,
2882 3 : pfnProgress, pProgressData );
2883 :
2884 : /* -------------------------------------------------------------------- */
2885 : /* If we are working with jpeg or jpeg2000, let the underlying */
2886 : /* dataset know about the overview file. */
2887 : /* -------------------------------------------------------------------- */
2888 3 : GDALDataset *poSubDS = poJ2KDataset;
2889 3 : if( poJPEGDataset )
2890 1 : poSubDS = poJPEGDataset;
2891 :
2892 : const char *pszOverviewFile =
2893 3 : GetMetadataItem( "OVERVIEW_FILE", "OVERVIEWS" );
2894 :
2895 5 : if( poSubDS && pszOverviewFile != NULL && eErr == CE_None
2896 2 : && poSubDS->GetMetadataItem( "OVERVIEW_FILE", "OVERVIEWS") == NULL )
2897 : {
2898 : poSubDS->SetMetadataItem( "OVERVIEW_FILE",
2899 : pszOverviewFile,
2900 2 : "OVERVIEWS" );
2901 : }
2902 :
2903 3 : return eErr;
2904 : }
2905 :
2906 : /************************************************************************/
2907 : /* ScanJPEGQLevel() */
2908 : /* */
2909 : /* Search the NITF APP header in the jpeg data stream to find */
2910 : /* out what predefined Q level tables should be used (or -1 if */
2911 : /* they are inline). */
2912 : /************************************************************************/
2913 :
2914 40 : int NITFDataset::ScanJPEGQLevel( GUIntBig *pnDataStart )
2915 :
2916 : {
2917 : GByte abyHeader[100];
2918 :
2919 40 : if( VSIFSeekL( psFile->fp, *pnDataStart,
2920 : SEEK_SET ) != 0 )
2921 : {
2922 : CPLError( CE_Failure, CPLE_FileIO,
2923 0 : "Seek error to jpeg data stream." );
2924 0 : return 0;
2925 : }
2926 :
2927 40 : if( VSIFReadL( abyHeader, 1, sizeof(abyHeader), psFile->fp )
2928 : < sizeof(abyHeader) )
2929 : {
2930 : CPLError( CE_Failure, CPLE_FileIO,
2931 0 : "Read error to jpeg data stream." );
2932 0 : return 0;
2933 : }
2934 :
2935 : /* -------------------------------------------------------------------- */
2936 : /* Scan ahead for jpeg magic code. In some files (eg. NSIF) */
2937 : /* there seems to be some extra junk before the image data stream. */
2938 : /* -------------------------------------------------------------------- */
2939 40 : GUInt32 nOffset = 0;
2940 200 : while( nOffset < sizeof(abyHeader) - 23
2941 40 : && (abyHeader[nOffset+0] != 0xff
2942 40 : || abyHeader[nOffset+1] != 0xd8
2943 40 : || abyHeader[nOffset+2] != 0xff) )
2944 0 : nOffset++;
2945 :
2946 40 : if( nOffset >= sizeof(abyHeader) - 23 )
2947 0 : return 0;
2948 :
2949 40 : *pnDataStart += nOffset;
2950 :
2951 40 : if( nOffset > 0 )
2952 : CPLDebug( "NITF",
2953 : "JPEG data stream at offset %d from start of data segement, NSIF?",
2954 0 : nOffset );
2955 :
2956 : /* -------------------------------------------------------------------- */
2957 : /* Do we have an NITF app tag? If so, pull out the Q level. */
2958 : /* -------------------------------------------------------------------- */
2959 40 : if( !EQUAL((char *)abyHeader+nOffset+6,"NITF") )
2960 34 : return 0;
2961 :
2962 6 : return abyHeader[22+nOffset];
2963 : }
2964 :
2965 : /************************************************************************/
2966 : /* ScanJPEGBlocks() */
2967 : /************************************************************************/
2968 :
2969 3 : CPLErr NITFDataset::ScanJPEGBlocks()
2970 :
2971 : {
2972 : int iBlock;
2973 : GUIntBig nJPEGStart =
2974 3 : psFile->pasSegmentInfo[psImage->iSegment].nSegmentStart;
2975 :
2976 3 : nQLevel = ScanJPEGQLevel( &nJPEGStart );
2977 :
2978 : /* -------------------------------------------------------------------- */
2979 : /* Allocate offset array */
2980 : /* -------------------------------------------------------------------- */
2981 : panJPEGBlockOffset = (GIntBig *)
2982 : CPLCalloc(sizeof(GIntBig),
2983 3 : psImage->nBlocksPerRow*psImage->nBlocksPerColumn);
2984 3 : panJPEGBlockOffset[0] = nJPEGStart;
2985 :
2986 3 : if ( psImage->nBlocksPerRow * psImage->nBlocksPerColumn == 1)
2987 0 : return CE_None;
2988 :
2989 26 : for( iBlock = psImage->nBlocksPerRow * psImage->nBlocksPerColumn - 1;
2990 : iBlock > 0; iBlock-- )
2991 23 : panJPEGBlockOffset[iBlock] = -1;
2992 :
2993 : /* -------------------------------------------------------------------- */
2994 : /* Scan through the whole image data stream identifying all */
2995 : /* block boundaries. Each block starts with 0xFFD8 (SOI). */
2996 : /* They also end with 0xFFD9, but we don't currently look for */
2997 : /* that. */
2998 : /* -------------------------------------------------------------------- */
2999 3 : int iNextBlock = 1;
3000 3 : GIntBig iSegOffset = 2;
3001 3 : GIntBig iSegSize = psFile->pasSegmentInfo[psImage->iSegment].nSegmentSize
3002 3 : - (nJPEGStart - psFile->pasSegmentInfo[psImage->iSegment].nSegmentStart);
3003 : GByte abyBlock[512];
3004 3 : int ignoreBytes = 0;
3005 :
3006 3587 : while( iSegOffset < iSegSize-1 )
3007 : {
3008 3584 : size_t nReadSize = MIN((size_t)sizeof(abyBlock),(size_t)(iSegSize - iSegOffset));
3009 : size_t i;
3010 :
3011 3584 : if( VSIFSeekL( psFile->fp, panJPEGBlockOffset[0] + iSegOffset,
3012 : SEEK_SET ) != 0 )
3013 : {
3014 : CPLError( CE_Failure, CPLE_FileIO,
3015 0 : "Seek error to jpeg data stream." );
3016 0 : return CE_Failure;
3017 : }
3018 :
3019 3584 : if( VSIFReadL( abyBlock, 1, nReadSize, psFile->fp ) < (size_t)nReadSize)
3020 : {
3021 : CPLError( CE_Failure, CPLE_FileIO,
3022 0 : "Read error to jpeg data stream." );
3023 0 : return CE_Failure;
3024 : }
3025 :
3026 1834315 : for( i = 0; i < nReadSize-1; i++ )
3027 : {
3028 1830734 : if (ignoreBytes == 0)
3029 : {
3030 1830564 : if( abyBlock[i] == 0xff )
3031 : {
3032 : /* start-of-image marker */
3033 9981 : if ( abyBlock[i+1] == 0xd8 )
3034 : {
3035 46 : panJPEGBlockOffset[iNextBlock++]
3036 23 : = panJPEGBlockOffset[0] + iSegOffset + i;
3037 :
3038 23 : if( iNextBlock == psImage->nBlocksPerRow*psImage->nBlocksPerColumn)
3039 : {
3040 3 : return CE_None;
3041 : }
3042 : }
3043 : /* Skip application-specific data to avoid false positive while detecting */
3044 : /* start-of-image markers (#2927). The size of the application data is */
3045 : /* found in the two following bytes */
3046 : /* We need this complex mechanism of ignoreBytes for dealing with */
3047 : /* application data crossing several abyBlock ... */
3048 9958 : else if ( abyBlock[i+1] >= 0xe0 && abyBlock[i+1] < 0xf0 )
3049 : {
3050 6 : ignoreBytes = -2;
3051 : }
3052 : }
3053 : }
3054 170 : else if (ignoreBytes < 0)
3055 : {
3056 12 : if (ignoreBytes == -1)
3057 : {
3058 : /* Size of the application data */
3059 6 : ignoreBytes = abyBlock[i]*256 + abyBlock[i+1];
3060 : }
3061 : else
3062 6 : ignoreBytes++;
3063 : }
3064 : else
3065 : {
3066 158 : ignoreBytes--;
3067 : }
3068 : }
3069 :
3070 3581 : iSegOffset += nReadSize - 1;
3071 : }
3072 :
3073 0 : return CE_None;
3074 : }
3075 :
3076 : /************************************************************************/
3077 : /* ReadJPEGBlock() */
3078 : /************************************************************************/
3079 :
3080 55 : CPLErr NITFDataset::ReadJPEGBlock( int iBlockX, int iBlockY )
3081 :
3082 : {
3083 : CPLErr eErr;
3084 :
3085 : /* -------------------------------------------------------------------- */
3086 : /* If this is our first request, do a scan for block boundaries. */
3087 : /* -------------------------------------------------------------------- */
3088 55 : if( panJPEGBlockOffset == NULL )
3089 : {
3090 5 : if (EQUAL(psImage->szIC,"M3"))
3091 : {
3092 : /* -------------------------------------------------------------------- */
3093 : /* When a data mask subheader is present, we don't need to scan */
3094 : /* the whole file. We just use the psImage->panBlockStart table */
3095 : /* -------------------------------------------------------------------- */
3096 : panJPEGBlockOffset = (GIntBig *)
3097 : CPLCalloc(sizeof(GIntBig),
3098 2 : psImage->nBlocksPerRow*psImage->nBlocksPerColumn);
3099 : int i;
3100 31 : for (i=0;i< psImage->nBlocksPerRow*psImage->nBlocksPerColumn;i++)
3101 : {
3102 29 : panJPEGBlockOffset[i] = psImage->panBlockStart[i];
3103 29 : if (panJPEGBlockOffset[i] != -1 && panJPEGBlockOffset[i] != 0xffffffff)
3104 : {
3105 25 : GUIntBig nOffset = panJPEGBlockOffset[i];
3106 25 : nQLevel = ScanJPEGQLevel(&nOffset);
3107 : /* The beginning of the JPEG stream should be the offset */
3108 : /* from the panBlockStart table */
3109 25 : if (nOffset != (GUIntBig)panJPEGBlockOffset[i])
3110 : {
3111 : CPLError(CE_Failure, CPLE_AppDefined,
3112 0 : "JPEG block doesn't start at expected offset");
3113 0 : return CE_Failure;
3114 : }
3115 : }
3116 : }
3117 : }
3118 : else /* 'C3' case */
3119 : {
3120 : /* -------------------------------------------------------------------- */
3121 : /* Scan through the whole image data stream identifying all */
3122 : /* block boundaries. */
3123 : /* -------------------------------------------------------------------- */
3124 3 : eErr = ScanJPEGBlocks();
3125 3 : if( eErr != CE_None )
3126 0 : return eErr;
3127 : }
3128 : }
3129 :
3130 : /* -------------------------------------------------------------------- */
3131 : /* Allocate image data block (where the uncompressed image will go) */
3132 : /* -------------------------------------------------------------------- */
3133 55 : if( pabyJPEGBlock == NULL )
3134 : {
3135 : /* Allocate enough memory to hold 12bit JPEG data */
3136 : pabyJPEGBlock = (GByte *)
3137 : CPLCalloc(psImage->nBands,
3138 5 : psImage->nBlockWidth * psImage->nBlockHeight * 2);
3139 : }
3140 :
3141 :
3142 : /* -------------------------------------------------------------------- */
3143 : /* Read JPEG Chunk. */
3144 : /* -------------------------------------------------------------------- */
3145 55 : CPLString osFilename;
3146 55 : int iBlock = iBlockX + iBlockY * psImage->nBlocksPerRow;
3147 : GDALDataset *poDS;
3148 55 : int anBands[3] = { 1, 2, 3 };
3149 :
3150 55 : if (panJPEGBlockOffset[iBlock] == -1 || panJPEGBlockOffset[iBlock] == 0xffffffff)
3151 : {
3152 4 : memset(pabyJPEGBlock, 0, psImage->nBands*psImage->nBlockWidth*psImage->nBlockHeight*2);
3153 4 : return CE_None;
3154 : }
3155 :
3156 : osFilename.Printf( "JPEG_SUBFILE:Q%d," CPL_FRMT_GIB ",%d,%s",
3157 : nQLevel,
3158 : panJPEGBlockOffset[iBlock], 0,
3159 51 : osNITFFilename.c_str() );
3160 :
3161 51 : poDS = (GDALDataset *) GDALOpen( osFilename, GA_ReadOnly );
3162 51 : if( poDS == NULL )
3163 0 : return CE_Failure;
3164 :
3165 51 : if( poDS->GetRasterXSize() != psImage->nBlockWidth
3166 : || poDS->GetRasterYSize() != psImage->nBlockHeight )
3167 : {
3168 : CPLError( CE_Failure, CPLE_AppDefined,
3169 : "JPEG block %d not same size as NITF blocksize.",
3170 0 : iBlock );
3171 0 : delete poDS;
3172 0 : return CE_Failure;
3173 : }
3174 :
3175 51 : if( poDS->GetRasterCount() < psImage->nBands )
3176 : {
3177 : CPLError( CE_Failure, CPLE_AppDefined,
3178 : "JPEG block %d has not enough bands.",
3179 0 : iBlock );
3180 0 : delete poDS;
3181 0 : return CE_Failure;
3182 : }
3183 :
3184 51 : if( poDS->GetRasterBand(1)->GetRasterDataType() != GetRasterBand(1)->GetRasterDataType())
3185 : {
3186 : CPLError( CE_Failure, CPLE_AppDefined,
3187 : "JPEG block %d data type (%s) not consistant with band data type (%s).",
3188 : iBlock, GDALGetDataTypeName(poDS->GetRasterBand(1)->GetRasterDataType()),
3189 0 : GDALGetDataTypeName(GetRasterBand(1)->GetRasterDataType()) );
3190 0 : delete poDS;
3191 0 : return CE_Failure;
3192 : }
3193 :
3194 : eErr = poDS->RasterIO( GF_Read,
3195 : 0, 0,
3196 : psImage->nBlockWidth, psImage->nBlockHeight,
3197 : pabyJPEGBlock,
3198 : psImage->nBlockWidth, psImage->nBlockHeight,
3199 51 : GetRasterBand(1)->GetRasterDataType(), psImage->nBands, anBands, 0, 0, 0 );
3200 :
3201 51 : delete poDS;
3202 :
3203 51 : return eErr;
3204 : }
3205 :
3206 : /************************************************************************/
3207 : /* GDALToNITFDataType() */
3208 : /************************************************************************/
3209 :
3210 66 : static const char *GDALToNITFDataType( GDALDataType eType )
3211 :
3212 : {
3213 : const char *pszPVType;
3214 :
3215 66 : switch( eType )
3216 : {
3217 : case GDT_Byte:
3218 : case GDT_UInt16:
3219 : case GDT_UInt32:
3220 45 : pszPVType = "INT";
3221 45 : break;
3222 :
3223 : case GDT_Int16:
3224 : case GDT_Int32:
3225 7 : pszPVType = "SI";
3226 7 : break;
3227 :
3228 : case GDT_Float32:
3229 : case GDT_Float64:
3230 6 : pszPVType = "R";
3231 6 : break;
3232 :
3233 : case GDT_CInt16:
3234 : case GDT_CInt32:
3235 : CPLError( CE_Failure, CPLE_AppDefined,
3236 4 : "NITF format does not support complex integer data." );
3237 4 : return NULL;
3238 :
3239 : case GDT_CFloat32:
3240 2 : pszPVType = "C";
3241 2 : break;
3242 :
3243 : default:
3244 : CPLError( CE_Failure, CPLE_AppDefined,
3245 : "Unsupported raster pixel type (%s).",
3246 2 : GDALGetDataTypeName(eType) );
3247 2 : return NULL;
3248 : }
3249 :
3250 60 : return pszPVType;
3251 : }
3252 :
3253 : /************************************************************************/
3254 : /* NITFJP2Options() */
3255 : /* */
3256 : /* Prepare JP2-in-NITF creation options based in part of the */
3257 : /* NITF creation options. */
3258 : /************************************************************************/
3259 :
3260 3 : static char **NITFJP2Options( char **papszOptions )
3261 :
3262 : {
3263 : int i;
3264 3 : char** papszJP2Options = NULL;
3265 :
3266 3 : papszJP2Options = CSLAddString(papszJP2Options, "PROFILE=NPJE");
3267 3 : papszJP2Options = CSLAddString(papszJP2Options, "CODESTREAM_ONLY=TRUE");
3268 :
3269 8 : for( i = 0; papszOptions != NULL && papszOptions[i] != NULL; i++ )
3270 : {
3271 5 : if( EQUALN(papszOptions[i],"PROFILE=",8) )
3272 : {
3273 0 : CPLFree(papszJP2Options[0]);
3274 0 : papszJP2Options[0] = CPLStrdup(papszOptions[i]);
3275 : }
3276 5 : else if( EQUALN(papszOptions[i],"TARGET=",7) )
3277 1 : papszJP2Options = CSLAddString(papszJP2Options, papszOptions[i]);
3278 : }
3279 :
3280 3 : return papszJP2Options;
3281 : }
3282 :
3283 : /************************************************************************/
3284 : /* NITFDatasetCreate() */
3285 : /************************************************************************/
3286 :
3287 : static GDALDataset *
3288 29 : NITFDatasetCreate( const char *pszFilename, int nXSize, int nYSize, int nBands,
3289 : GDALDataType eType, char **papszOptions )
3290 :
3291 : {
3292 29 : const char *pszPVType = GDALToNITFDataType( eType );
3293 29 : const char *pszIC = CSLFetchNameValue( papszOptions, "IC" );
3294 :
3295 29 : if( pszPVType == NULL )
3296 3 : return NULL;
3297 :
3298 : /* -------------------------------------------------------------------- */
3299 : /* We disallow any IC value except NC when creating this way. */
3300 : /* -------------------------------------------------------------------- */
3301 26 : GDALDriver *poJ2KDriver = NULL;
3302 :
3303 27 : if( pszIC != NULL && EQUAL(pszIC,"C8") )
3304 : {
3305 1 : int bHasCreate = FALSE;
3306 :
3307 1 : poJ2KDriver = GetGDALDriverManager()->GetDriverByName( "JP2ECW" );
3308 1 : if( poJ2KDriver != NULL )
3309 : bHasCreate = poJ2KDriver->GetMetadataItem( GDAL_DCAP_CREATE,
3310 1 : NULL ) != NULL;
3311 1 : if( !bHasCreate )
3312 : {
3313 : CPLError( CE_Failure, CPLE_AppDefined,
3314 : "Unable to create JPEG2000 encoded NITF files. The\n"
3315 0 : "JP2ECW driver is unavailable, or missing Create support." );
3316 0 : return NULL;
3317 : }
3318 : }
3319 :
3320 25 : else if( pszIC != NULL && !EQUAL(pszIC,"NC") )
3321 : {
3322 : CPLError( CE_Failure, CPLE_AppDefined,
3323 : "Unsupported compression (IC=%s) used in direct\n"
3324 : "NITF File creation",
3325 0 : pszIC );
3326 0 : return NULL;
3327 : }
3328 :
3329 : /* -------------------------------------------------------------------- */
3330 : /* Create the file. */
3331 : /* -------------------------------------------------------------------- */
3332 :
3333 26 : if( !NITFCreate( pszFilename, nXSize, nYSize, nBands,
3334 : GDALGetDataTypeSize( eType ), pszPVType,
3335 : papszOptions ) )
3336 1 : return NULL;
3337 :
3338 : /* -------------------------------------------------------------------- */
3339 : /* Various special hacks related to JPEG2000 encoded files. */
3340 : /* -------------------------------------------------------------------- */
3341 25 : GDALDataset* poWritableJ2KDataset = NULL;
3342 25 : if( poJ2KDriver )
3343 : {
3344 1 : NITFFile *psFile = NITFOpen( pszFilename, TRUE );
3345 1 : GUIntBig nImageOffset = psFile->pasSegmentInfo[0].nSegmentStart;
3346 :
3347 1 : CPLString osDSName;
3348 :
3349 1 : osDSName.Printf("J2K_SUBFILE:" CPL_FRMT_GUIB ",%d,%s", nImageOffset, -1, pszFilename);
3350 :
3351 1 : NITFClose( psFile );
3352 :
3353 1 : char** papszJP2Options = NITFJP2Options(papszOptions);
3354 : poWritableJ2KDataset =
3355 : poJ2KDriver->Create( osDSName, nXSize, nYSize, nBands, eType,
3356 1 : papszJP2Options );
3357 1 : CSLDestroy(papszJP2Options);
3358 :
3359 1 : if( poWritableJ2KDataset == NULL )
3360 0 : return NULL;
3361 : }
3362 :
3363 : /* -------------------------------------------------------------------- */
3364 : /* Open the dataset in update mode. */
3365 : /* -------------------------------------------------------------------- */
3366 25 : GDALOpenInfo oOpenInfo( pszFilename, GA_Update );
3367 25 : return NITFDataset::Open(&oOpenInfo, poWritableJ2KDataset);
3368 : }
3369 :
3370 : /************************************************************************/
3371 : /* NITFCreateCopy() */
3372 : /************************************************************************/
3373 :
3374 : GDALDataset *
3375 38 : NITFDataset::NITFCreateCopy(
3376 : const char *pszFilename, GDALDataset *poSrcDS,
3377 : int bStrict, char **papszOptions,
3378 : GDALProgressFunc pfnProgress, void * pProgressData )
3379 :
3380 : {
3381 : GDALDataType eType;
3382 : GDALRasterBand *poBand1;
3383 38 : char **papszFullOptions = CSLDuplicate( papszOptions );
3384 38 : int bJPEG2000 = FALSE;
3385 38 : int bJPEG = FALSE;
3386 38 : NITFDataset *poDstDS = NULL;
3387 38 : GDALDriver *poJ2KDriver = NULL;
3388 :
3389 38 : int nBands = poSrcDS->GetRasterCount();
3390 38 : if( nBands == 0 )
3391 : {
3392 : CPLError( CE_Failure, CPLE_NotSupported,
3393 1 : "Unable to export files with zero bands." );
3394 1 : CSLDestroy(papszFullOptions);
3395 1 : return NULL;
3396 : }
3397 :
3398 37 : poBand1 = poSrcDS->GetRasterBand(1);
3399 37 : if( poBand1 == NULL )
3400 : {
3401 0 : CSLDestroy(papszFullOptions);
3402 0 : return NULL;
3403 : }
3404 :
3405 : /* -------------------------------------------------------------------- */
3406 : /* Only allow supported compression values. */
3407 : /* -------------------------------------------------------------------- */
3408 37 : const char* pszIC = CSLFetchNameValue( papszOptions, "IC" );
3409 37 : if( pszIC != NULL )
3410 : {
3411 7 : if( EQUAL(pszIC,"NC") )
3412 : /* ok */;
3413 7 : else if( EQUAL(pszIC,"C8") )
3414 : {
3415 : poJ2KDriver =
3416 3 : GetGDALDriverManager()->GetDriverByName( "JP2ECW" );
3417 3 : if( poJ2KDriver == NULL )
3418 : {
3419 : /* Try with Jasper as an alternate driver */
3420 : poJ2KDriver =
3421 1 : GetGDALDriverManager()->GetDriverByName( "JPEG2000" );
3422 : }
3423 3 : if( poJ2KDriver == NULL )
3424 : {
3425 : CPLError(
3426 : CE_Failure, CPLE_AppDefined,
3427 : "Unable to write JPEG2000 compressed NITF file.\n"
3428 : "No 'subfile' JPEG2000 write supporting drivers are\n"
3429 0 : "configured." );
3430 0 : CSLDestroy(papszFullOptions);
3431 0 : return NULL;
3432 : }
3433 3 : bJPEG2000 = TRUE;
3434 : }
3435 8 : else if( EQUAL(pszIC,"C3") || EQUAL(pszIC,"M3") )
3436 : {
3437 4 : bJPEG = TRUE;
3438 : #ifndef JPEG_SUPPORTED
3439 : CPLError(
3440 : CE_Failure, CPLE_AppDefined,
3441 : "Unable to write JPEG compressed NITF file.\n"
3442 : "Libjpeg is not configured into build." );
3443 : CSLDestroy(papszFullOptions);
3444 : return NULL;
3445 : #endif
3446 : }
3447 : else
3448 : {
3449 : CPLError( CE_Failure, CPLE_AppDefined,
3450 : "Only IC=NC (uncompressed), IC=C3/M3 (JPEG) and IC=C8 (JPEG2000)\n"
3451 0 : "allowed with NITF CreateCopy method." );
3452 0 : CSLDestroy(papszFullOptions);
3453 0 : return NULL;
3454 : }
3455 : }
3456 :
3457 : /* -------------------------------------------------------------------- */
3458 : /* Get the data type. Complex integers isn't supported by */
3459 : /* NITF, so map that to complex float if we aren't in strict */
3460 : /* mode. */
3461 : /* -------------------------------------------------------------------- */
3462 37 : eType = poBand1->GetRasterDataType();
3463 37 : if( !bStrict && (eType == GDT_CInt16 || eType == GDT_CInt32) )
3464 0 : eType = GDT_CFloat32;
3465 :
3466 : /* -------------------------------------------------------------------- */
3467 : /* Copy over other source metadata items as creation options */
3468 : /* that seem useful. */
3469 : /* -------------------------------------------------------------------- */
3470 37 : char **papszSrcMD = poSrcDS->GetMetadata();
3471 : int iMD;
3472 :
3473 328 : for( iMD = 0; papszSrcMD && papszSrcMD[iMD]; iMD++ )
3474 : {
3475 572 : if( EQUALN(papszSrcMD[iMD],"NITF_BLOCKA",11)
3476 281 : || EQUALN(papszSrcMD[iMD],"NITF_FHDR",9) )
3477 : {
3478 14 : char *pszName = NULL;
3479 14 : const char *pszValue = CPLParseNameValue( papszSrcMD[iMD],
3480 28 : &pszName );
3481 14 : if( CSLFetchNameValue( papszFullOptions, pszName+5 ) == NULL )
3482 : papszFullOptions =
3483 13 : CSLSetNameValue( papszFullOptions, pszName+5, pszValue );
3484 14 : CPLFree(pszName);
3485 : }
3486 : }
3487 :
3488 : /* -------------------------------------------------------------------- */
3489 : /* Copy TRE definitions as creation options. */
3490 : /* -------------------------------------------------------------------- */
3491 37 : papszSrcMD = poSrcDS->GetMetadata( "TRE" );
3492 :
3493 38 : for( iMD = 0; papszSrcMD && papszSrcMD[iMD]; iMD++ )
3494 : {
3495 1 : CPLString osTRE;
3496 :
3497 1 : osTRE = "TRE=";
3498 1 : osTRE += papszSrcMD[iMD];
3499 :
3500 1 : papszFullOptions = CSLAddString( papszFullOptions, osTRE );
3501 : }
3502 :
3503 : /* -------------------------------------------------------------------- */
3504 : /* Prepare for text segments. */
3505 : /* -------------------------------------------------------------------- */
3506 37 : int iOpt, nNUMT = 0;
3507 37 : char **papszTextMD = poSrcDS->GetMetadata( "TEXT" );
3508 :
3509 42 : for( iOpt = 0;
3510 3 : papszTextMD != NULL && papszTextMD[iOpt] != NULL;
3511 : iOpt++ )
3512 : {
3513 2 : if( !EQUALN(papszTextMD[iOpt],"DATA_",5) )
3514 0 : continue;
3515 :
3516 2 : nNUMT++;
3517 : }
3518 :
3519 37 : if( nNUMT > 0 )
3520 : {
3521 : papszFullOptions = CSLAddString( papszFullOptions,
3522 : CPLString().Printf( "NUMT=%d",
3523 1 : nNUMT ) );
3524 : }
3525 :
3526 : /* -------------------------------------------------------------------- */
3527 : /* Set if we can set IREP. */
3528 : /* -------------------------------------------------------------------- */
3529 37 : if( CSLFetchNameValue(papszFullOptions,"IREP") == NULL )
3530 : {
3531 60 : if ( ((poSrcDS->GetRasterCount() == 3 && bJPEG) ||
3532 : (poSrcDS->GetRasterCount() >= 3 && !bJPEG)) && eType == GDT_Byte &&
3533 9 : poSrcDS->GetRasterBand(1)->GetColorInterpretation() == GCI_RedBand &&
3534 7 : poSrcDS->GetRasterBand(2)->GetColorInterpretation() == GCI_GreenBand &&
3535 7 : poSrcDS->GetRasterBand(3)->GetColorInterpretation() == GCI_BlueBand)
3536 : {
3537 7 : if( bJPEG )
3538 : papszFullOptions =
3539 3 : CSLSetNameValue( papszFullOptions, "IREP", "YCbCr601" );
3540 : else
3541 : papszFullOptions =
3542 4 : CSLSetNameValue( papszFullOptions, "IREP", "RGB" );
3543 : }
3544 38 : else if( poSrcDS->GetRasterCount() == 1 && eType == GDT_Byte
3545 8 : && poBand1->GetColorTable() != NULL )
3546 : {
3547 : papszFullOptions =
3548 1 : CSLSetNameValue( papszFullOptions, "IREP", "RGB/LUT" );
3549 : papszFullOptions =
3550 : CSLSetNameValue( papszFullOptions, "LUT_SIZE",
3551 : CPLString().Printf(
3552 1 : "%d", poBand1->GetColorTable()->GetColorEntryCount()) );
3553 : }
3554 29 : else if( GDALDataTypeIsComplex(eType) )
3555 : papszFullOptions =
3556 4 : CSLSetNameValue( papszFullOptions, "IREP", "NODISPLY" );
3557 :
3558 : else
3559 : papszFullOptions =
3560 25 : CSLSetNameValue( papszFullOptions, "IREP", "MONO" );
3561 : }
3562 :
3563 : /* -------------------------------------------------------------------- */
3564 : /* Do we have lat/long georeferencing information? */
3565 : /* -------------------------------------------------------------------- */
3566 : double adfGeoTransform[6];
3567 37 : int bWriteGeoTransform = FALSE;
3568 37 : int bNorth, nZone = 0;
3569 37 : OGRSpatialReference oSRS, oSRS_WGS84;
3570 37 : char *pszWKT = (char *) poSrcDS->GetProjectionRef();
3571 :
3572 37 : if( pszWKT != NULL && pszWKT[0] != '\0' )
3573 : {
3574 34 : oSRS.importFromWkt( &pszWKT );
3575 :
3576 : /* NITF is only WGS84 */
3577 34 : oSRS_WGS84.SetWellKnownGeogCS( "WGS84" );
3578 34 : if ( oSRS.IsSameGeogCS(&oSRS_WGS84) == FALSE)
3579 : {
3580 : CPLError((bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
3581 11 : "NITF only supports WGS84 geographic and UTM projections.\n");
3582 11 : if (bStrict)
3583 : {
3584 0 : CSLDestroy(papszFullOptions);
3585 0 : return NULL;
3586 : }
3587 : }
3588 :
3589 57 : if( oSRS.IsGeographic() && oSRS.GetPrimeMeridian() == 0.0
3590 23 : && poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None )
3591 : {
3592 : papszFullOptions =
3593 23 : CSLSetNameValue( papszFullOptions, "ICORDS", "G" );
3594 23 : bWriteGeoTransform = TRUE;
3595 : }
3596 :
3597 22 : else if( oSRS.GetUTMZone( &bNorth ) > 0
3598 11 : && poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None )
3599 : {
3600 11 : if( bNorth )
3601 : papszFullOptions =
3602 11 : CSLSetNameValue( papszFullOptions, "ICORDS", "N" );
3603 : else
3604 : papszFullOptions =
3605 0 : CSLSetNameValue( papszFullOptions, "ICORDS", "S" );
3606 :
3607 11 : nZone = oSRS.GetUTMZone( NULL );
3608 11 : bWriteGeoTransform = TRUE;
3609 : }
3610 : else
3611 : {
3612 : CPLError((bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
3613 0 : "NITF only supports WGS84 geographic and UTM projections.\n");
3614 0 : if (bStrict)
3615 : {
3616 0 : CSLDestroy(papszFullOptions);
3617 0 : return NULL;
3618 : }
3619 : }
3620 : }
3621 :
3622 : /* -------------------------------------------------------------------- */
3623 : /* Create the output file. */
3624 : /* -------------------------------------------------------------------- */
3625 37 : int nXSize = poSrcDS->GetRasterXSize();
3626 37 : int nYSize = poSrcDS->GetRasterYSize();
3627 37 : const char *pszPVType = GDALToNITFDataType( eType );
3628 :
3629 37 : if( pszPVType == NULL )
3630 : {
3631 3 : CSLDestroy(papszFullOptions);
3632 3 : return NULL;
3633 : }
3634 :
3635 34 : if (!NITFCreate( pszFilename, nXSize, nYSize, poSrcDS->GetRasterCount(),
3636 : GDALGetDataTypeSize( eType ), pszPVType,
3637 : papszFullOptions ))
3638 : {
3639 0 : CSLDestroy( papszFullOptions );
3640 0 : return NULL;
3641 : }
3642 :
3643 34 : CSLDestroy( papszFullOptions );
3644 34 : papszFullOptions = NULL;
3645 :
3646 : /* ==================================================================== */
3647 : /* JPEG2000 case. We need to write the data through a J2K */
3648 : /* driver in pixel interleaved form. */
3649 : /* ==================================================================== */
3650 34 : if( bJPEG2000 )
3651 : {
3652 3 : NITFFile *psFile = NITFOpen( pszFilename, TRUE );
3653 3 : GDALDataset *poJ2KDataset = NULL;
3654 3 : GUIntBig nImageOffset = psFile->pasSegmentInfo[0].nSegmentStart;
3655 3 : CPLString osDSName;
3656 :
3657 3 : if (EQUAL(poJ2KDriver->GetDescription(), "JP2ECW"))
3658 : {
3659 : osDSName.Printf( "J2K_SUBFILE:" CPL_FRMT_GUIB ",%d,%s", nImageOffset, -1,
3660 2 : pszFilename );
3661 : }
3662 : else
3663 : {
3664 : /* Jasper case */
3665 : osDSName.Printf( "/vsisubfile/" CPL_FRMT_GUIB "_%d,%s", nImageOffset, -1,
3666 1 : pszFilename );
3667 : }
3668 :
3669 3 : NITFClose( psFile );
3670 :
3671 3 : if (EQUAL(poJ2KDriver->GetDescription(), "JP2ECW"))
3672 : {
3673 2 : char** papszJP2Options = NITFJP2Options(papszOptions);
3674 : poJ2KDataset =
3675 : poJ2KDriver->CreateCopy( osDSName, poSrcDS, FALSE,
3676 : papszJP2Options,
3677 2 : pfnProgress, pProgressData );
3678 2 : CSLDestroy(papszJP2Options);
3679 : }
3680 : else
3681 : {
3682 : /* Jasper case */
3683 1 : const char* apszOptions[] = { "FORMAT=JPC", NULL };
3684 : poJ2KDataset =
3685 : poJ2KDriver->CreateCopy( osDSName, poSrcDS, FALSE,
3686 : (char **)apszOptions,
3687 1 : pfnProgress, pProgressData );
3688 : }
3689 3 : if( poJ2KDataset == NULL )
3690 0 : return NULL;
3691 :
3692 3 : delete poJ2KDataset;
3693 :
3694 : // Now we need to figure out the actual length of the file
3695 : // and correct the image segment size information.
3696 : GIntBig nPixelCount = nXSize * ((GIntBig) nYSize) *
3697 3 : poSrcDS->GetRasterCount();
3698 :
3699 3 : NITFPatchImageLength( pszFilename, nImageOffset, nPixelCount, "C8" );
3700 3 : NITFWriteTextSegments( pszFilename, papszTextMD );
3701 :
3702 3 : GDALOpenInfo oOpenInfo( pszFilename, GA_Update );
3703 3 : poDstDS = (NITFDataset *) Open( &oOpenInfo );
3704 :
3705 3 : if( poDstDS == NULL )
3706 0 : return NULL;
3707 : }
3708 :
3709 : /* ==================================================================== */
3710 : /* Loop copying bands to an uncompressed file. */
3711 : /* ==================================================================== */
3712 31 : else if( bJPEG )
3713 : {
3714 : #ifdef JPEG_SUPPORTED
3715 4 : NITFFile *psFile = NITFOpen( pszFilename, TRUE );
3716 4 : GUIntBig nImageOffset = psFile->pasSegmentInfo[0].nSegmentStart;
3717 : int bSuccess;
3718 :
3719 : bSuccess =
3720 : NITFWriteJPEGImage( poSrcDS, psFile->fp, nImageOffset,
3721 : papszOptions,
3722 4 : pfnProgress, pProgressData );
3723 :
3724 4 : if( !bSuccess )
3725 : {
3726 0 : NITFClose( psFile );
3727 0 : return NULL;
3728 : }
3729 :
3730 : // Now we need to figure out the actual length of the file
3731 : // and correct the image segment size information.
3732 : GIntBig nPixelCount = nXSize * ((GIntBig) nYSize) *
3733 4 : poSrcDS->GetRasterCount();
3734 :
3735 4 : NITFClose( psFile );
3736 :
3737 : NITFPatchImageLength( pszFilename, nImageOffset,
3738 4 : nPixelCount, pszIC );
3739 4 : NITFWriteTextSegments( pszFilename, papszTextMD );
3740 :
3741 4 : GDALOpenInfo oOpenInfo( pszFilename, GA_Update );
3742 4 : poDstDS = (NITFDataset *) Open( &oOpenInfo );
3743 :
3744 4 : if( poDstDS == NULL )
3745 0 : return NULL;
3746 : #endif /* def JPEG_SUPPORTED */
3747 : }
3748 :
3749 : /* ==================================================================== */
3750 : /* Loop copying bands to an uncompressed file. */
3751 : /* ==================================================================== */
3752 : else
3753 : {
3754 27 : NITFWriteTextSegments( pszFilename, papszTextMD );
3755 :
3756 27 : GDALOpenInfo oOpenInfo( pszFilename, GA_Update );
3757 27 : poDstDS = (NITFDataset *) Open( &oOpenInfo );
3758 27 : if( poDstDS == NULL )
3759 0 : return NULL;
3760 :
3761 27 : void *pData = VSIMalloc2(nXSize, (GDALGetDataTypeSize(eType) / 8));
3762 27 : if (pData == NULL)
3763 : {
3764 0 : delete poDstDS;
3765 0 : return NULL;
3766 : }
3767 :
3768 27 : CPLErr eErr = CE_None;
3769 :
3770 70 : for( int iBand = 0; eErr == CE_None && iBand < poSrcDS->GetRasterCount(); iBand++ )
3771 : {
3772 43 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand+1 );
3773 43 : GDALRasterBand *poDstBand = poDstDS->GetRasterBand( iBand+1 );
3774 :
3775 : /* -------------------------------------------------------------------- */
3776 : /* Do we need to copy a colortable or other metadata? */
3777 : /* -------------------------------------------------------------------- */
3778 : GDALColorTable *poCT;
3779 :
3780 43 : poCT = poSrcBand->GetColorTable();
3781 43 : if( poCT != NULL )
3782 1 : poDstBand->SetColorTable( poCT );
3783 :
3784 : /* -------------------------------------------------------------------- */
3785 : /* Copy image data. */
3786 : /* -------------------------------------------------------------------- */
3787 1045 : for( int iLine = 0; iLine < nYSize; iLine++ )
3788 : {
3789 : eErr = poSrcBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
3790 1002 : pData, nXSize, 1, eType, 0, 0 );
3791 1002 : if( eErr != CE_None )
3792 0 : break;
3793 :
3794 : eErr = poDstBand->RasterIO( GF_Write, 0, iLine, nXSize, 1,
3795 1002 : pData, nXSize, 1, eType, 0, 0 );
3796 :
3797 1002 : if( eErr != CE_None )
3798 0 : break;
3799 :
3800 1002 : if( !pfnProgress( (iBand + (iLine+1) / (double) nYSize)
3801 : / (double) poSrcDS->GetRasterCount(),
3802 : NULL, pProgressData ) )
3803 : {
3804 0 : CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
3805 0 : eErr = CE_Failure;
3806 0 : break;
3807 : }
3808 : }
3809 : }
3810 :
3811 27 : CPLFree( pData );
3812 :
3813 27 : if ( eErr != CE_None )
3814 : {
3815 0 : delete poDstDS;
3816 0 : return NULL;
3817 0 : }
3818 : }
3819 :
3820 : /* -------------------------------------------------------------------- */
3821 : /* Set the georeferencing. */
3822 : /* -------------------------------------------------------------------- */
3823 34 : if( bWriteGeoTransform )
3824 : {
3825 31 : poDstDS->psImage->nZone = nZone;
3826 31 : poDstDS->SetGeoTransform( adfGeoTransform );
3827 : }
3828 :
3829 34 : poDstDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
3830 :
3831 34 : return poDstDS;
3832 : }
3833 :
3834 : /************************************************************************/
3835 : /* NITFPatchImageLength() */
3836 : /* */
3837 : /* Fixup various stuff we don't know till we have written the */
3838 : /* imagery. In particular the file length, image data length */
3839 : /* and the compression ratio achieved. */
3840 : /************************************************************************/
3841 :
3842 8 : static void NITFPatchImageLength( const char *pszFilename,
3843 : GUIntBig nImageOffset,
3844 : GIntBig nPixelCount,
3845 : const char *pszIC )
3846 :
3847 : {
3848 8 : FILE *fpVSIL = VSIFOpenL( pszFilename, "r+b" );
3849 8 : if( fpVSIL == NULL )
3850 0 : return;
3851 :
3852 8 : VSIFSeekL( fpVSIL, 0, SEEK_END );
3853 8 : GUIntBig nFileLen = VSIFTellL( fpVSIL );
3854 :
3855 : /* -------------------------------------------------------------------- */
3856 : /* Update total file length. */
3857 : /* -------------------------------------------------------------------- */
3858 8 : if (nFileLen >= (GUIntBig)1e12)
3859 : {
3860 : CPLError(CE_Failure, CPLE_AppDefined,
3861 : "Too big file : " CPL_FRMT_GUIB ". Truncating to 999999999999",
3862 0 : nFileLen);
3863 0 : nFileLen = (GUIntBig)(1e12 - 1);
3864 : }
3865 8 : VSIFSeekL( fpVSIL, 342, SEEK_SET );
3866 8 : CPLString osLen = CPLString().Printf("%012" CPL_FRMT_GB_WITHOUT_PREFIX "u",nFileLen);
3867 8 : VSIFWriteL( (void *) osLen.c_str(), 1, 12, fpVSIL );
3868 :
3869 : /* -------------------------------------------------------------------- */
3870 : /* Update the image data length. */
3871 : /* -------------------------------------------------------------------- */
3872 8 : GUIntBig nImageSize = nFileLen-nImageOffset;
3873 8 : if (GUINTBIG_TO_DOUBLE(nImageSize) >= 1e10)
3874 : {
3875 : CPLError(CE_Failure, CPLE_AppDefined,
3876 : "Too big image size : " CPL_FRMT_GUIB". Truncating to 9999999999",
3877 0 : nImageSize);
3878 0 : nImageSize = (GUIntBig)(1e10 - 1);
3879 : }
3880 8 : VSIFSeekL( fpVSIL, 369, SEEK_SET );
3881 8 : osLen = CPLString().Printf("%010" CPL_FRMT_GB_WITHOUT_PREFIX "u",nImageSize);
3882 8 : VSIFWriteL( (void *) osLen.c_str(), 1, 10, fpVSIL );
3883 :
3884 : /* -------------------------------------------------------------------- */
3885 : /* Update COMRAT, the compression rate variable. It is a bit */
3886 : /* hard to know right here whether we have an IGEOLO segment, */
3887 : /* so the COMRAT will either be at offset 778 or 838. */
3888 : /* -------------------------------------------------------------------- */
3889 : char szICBuf[2];
3890 8 : VSIFSeekL( fpVSIL, 779-2, SEEK_SET );
3891 8 : VSIFReadL( szICBuf, 2, 1, fpVSIL );
3892 8 : if( !EQUALN(szICBuf,pszIC,2) )
3893 : {
3894 7 : VSIFSeekL( fpVSIL, 839-2, SEEK_SET );
3895 7 : VSIFReadL( szICBuf, 2, 1, fpVSIL );
3896 : }
3897 :
3898 : /* The following line works around a "feature" of *BSD libc (at least PC-BSD 7.1) */
3899 : /* that makes the position of the file offset unreliable when executing a */
3900 : /* "seek, read and write" sequence. After the read(), the file offset seen by */
3901 : /* the write() is approximatively the size of a block further... */
3902 8 : VSIFSeekL( fpVSIL, VSIFTellL( fpVSIL ), SEEK_SET );
3903 :
3904 8 : if( !EQUALN(szICBuf,pszIC,2) )
3905 : {
3906 : CPLError( CE_Warning, CPLE_AppDefined,
3907 0 : "Unable to locate COMRAT to update in NITF header." );
3908 : }
3909 : else
3910 : {
3911 : char szCOMRAT[5];
3912 :
3913 8 : if( EQUAL(pszIC,"C8") ) /* jpeg2000 */
3914 : {
3915 4 : double dfRate = (GIntBig)(nFileLen-nImageOffset) * 8 / (double) nPixelCount;
3916 4 : dfRate = MAX(0.01,MIN(99.99,dfRate));
3917 :
3918 : // We emit in wxyz format with an implicit decimal place
3919 : // between wx and yz as per spec for lossy compression.
3920 : // We really should have a special case for lossless compression.
3921 4 : sprintf( szCOMRAT, "%04d", (int) (dfRate * 100));
3922 : }
3923 4 : else if( EQUAL(pszIC, "C3") || EQUAL(pszIC, "M3") ) /* jpeg */
3924 : {
3925 4 : strcpy( szCOMRAT, "00.0" );
3926 : }
3927 :
3928 8 : VSIFWriteL( szCOMRAT, 4, 1, fpVSIL );
3929 : }
3930 :
3931 8 : VSIFCloseL( fpVSIL );
3932 : }
3933 :
3934 : /************************************************************************/
3935 : /* NITFWriteTextSegments() */
3936 : /************************************************************************/
3937 :
3938 34 : static void NITFWriteTextSegments( const char *pszFilename,
3939 : char **papszList )
3940 :
3941 : {
3942 : /* -------------------------------------------------------------------- */
3943 : /* Count the number of apparent text segments to write. There */
3944 : /* is nothing at all to do if there are none to write. */
3945 : /* -------------------------------------------------------------------- */
3946 34 : int iOpt, nNUMT = 0;
3947 :
3948 36 : for( iOpt = 0; papszList != NULL && papszList[iOpt] != NULL; iOpt++ )
3949 : {
3950 2 : if( EQUALN(papszList[iOpt],"DATA_",5) )
3951 2 : nNUMT++;
3952 : }
3953 :
3954 34 : if( nNUMT == 0 )
3955 33 : return;
3956 :
3957 : /* -------------------------------------------------------------------- */
3958 : /* Open the target file. */
3959 : /* -------------------------------------------------------------------- */
3960 1 : FILE *fpVSIL = VSIFOpenL( pszFilename, "r+b" );
3961 :
3962 1 : if( fpVSIL == NULL )
3963 0 : return;
3964 :
3965 : /* -------------------------------------------------------------------- */
3966 : /* Confirm that the NUMT in the file header already matches the */
3967 : /* number of text segements we want to write, and that the */
3968 : /* segment header/data size info is blank. */
3969 : /* -------------------------------------------------------------------- */
3970 : char achNUMT[4];
3971 1 : char *pachLT = (char *) CPLCalloc(nNUMT * 9 + 1, 1);
3972 :
3973 1 : VSIFSeekL( fpVSIL, 385, SEEK_SET );
3974 1 : VSIFReadL( achNUMT, 1, 3, fpVSIL );
3975 1 : achNUMT[3] = '\0';
3976 :
3977 1 : VSIFReadL( pachLT, 1, nNUMT * 9, fpVSIL );
3978 :
3979 1 : if( atoi(achNUMT) != nNUMT )
3980 : {
3981 : CPLError( CE_Failure, CPLE_AppDefined,
3982 : "It appears an attempt was made to add or update text\n"
3983 : "segments on an NITF file with existing segments. This\n"
3984 0 : "is not currently supported by the GDAL NITF driver." );
3985 :
3986 0 : VSIFCloseL( fpVSIL );
3987 0 : CPLFree( pachLT );
3988 0 : return;
3989 : }
3990 :
3991 1 : if( !EQUALN(pachLT," ",9) )
3992 : {
3993 0 : CPLFree( pachLT );
3994 : // presumably the text segments are already written, do nothing.
3995 0 : VSIFCloseL( fpVSIL );
3996 0 : return;
3997 : }
3998 :
3999 : /* -------------------------------------------------------------------- */
4000 : /* At this point we likely ought to confirm NUMDES, NUMRES, */
4001 : /* UDHDL and XHDL are zero. Consider adding later... */
4002 : /* -------------------------------------------------------------------- */
4003 :
4004 : /* ==================================================================== */
4005 : /* Write the text segments at the end of the file. */
4006 : /* ==================================================================== */
4007 : #define PLACE(location,name,text) strncpy(location,text,strlen(text))
4008 1 : int iTextSeg = 0;
4009 :
4010 3 : for( iOpt = 0; papszList != NULL && papszList[iOpt] != NULL; iOpt++ )
4011 : {
4012 : const char *pszTextToWrite;
4013 :
4014 2 : if( !EQUALN(papszList[iOpt],"DATA_",5) )
4015 0 : continue;
4016 :
4017 : /* -------------------------------------------------------------------- */
4018 : /* Prepare and write text header. */
4019 : /* -------------------------------------------------------------------- */
4020 2 : VSIFSeekL( fpVSIL, 0, SEEK_END );
4021 :
4022 : char achTSH[282];
4023 :
4024 2 : memset( achTSH, ' ', sizeof(achTSH) );
4025 :
4026 2 : PLACE( achTSH+ 0, TE , "TE" );
4027 2 : PLACE( achTSH+ 9, TXTALVL , "000" );
4028 2 : PLACE( achTSH+ 12, TXTDT , "00000000000000" );
4029 2 : PLACE( achTSH+106, TSCLAS , "U" );
4030 2 : PLACE( achTSH+273, ENCRYP , "0" );
4031 2 : PLACE( achTSH+274, TXTFMT , "STA" );
4032 2 : PLACE( achTSH+277, TXSHDL , "00000" );
4033 :
4034 2 : VSIFWriteL( achTSH, 1, sizeof(achTSH), fpVSIL );
4035 :
4036 : /* -------------------------------------------------------------------- */
4037 : /* Prepare and write text segment data. */
4038 : /* -------------------------------------------------------------------- */
4039 2 : pszTextToWrite = CPLParseNameValue( papszList[iOpt], NULL );
4040 :
4041 2 : VSIFWriteL( pszTextToWrite, 1, strlen(pszTextToWrite), fpVSIL );
4042 :
4043 : /* -------------------------------------------------------------------- */
4044 : /* Update the subheader and data size info in the file header. */
4045 : /* -------------------------------------------------------------------- */
4046 : sprintf( pachLT + 9*iTextSeg+0, "%04d%05d",
4047 2 : (int) sizeof(achTSH), (int) strlen(pszTextToWrite) );
4048 :
4049 2 : iTextSeg++;
4050 : }
4051 :
4052 : /* -------------------------------------------------------------------- */
4053 : /* Write out the text segment info. */
4054 : /* -------------------------------------------------------------------- */
4055 1 : VSIFSeekL( fpVSIL, 388, SEEK_SET );
4056 1 : VSIFWriteL( pachLT, 1, nNUMT * 9, fpVSIL );
4057 :
4058 : /* -------------------------------------------------------------------- */
4059 : /* Update total file length. */
4060 : /* -------------------------------------------------------------------- */
4061 1 : VSIFSeekL( fpVSIL, 0, SEEK_END );
4062 1 : GUIntBig nFileLen = VSIFTellL( fpVSIL );
4063 :
4064 1 : VSIFSeekL( fpVSIL, 342, SEEK_SET );
4065 1 : if (GUINTBIG_TO_DOUBLE(nFileLen) >= 1e12)
4066 : {
4067 : CPLError(CE_Failure, CPLE_AppDefined,
4068 : "Too big file : " CPL_FRMT_GUIB ". Truncating to 999999999999",
4069 0 : nFileLen);
4070 0 : nFileLen = (GUIntBig)(1e12 - 1);
4071 : }
4072 1 : CPLString osLen = CPLString().Printf("%012" CPL_FRMT_GB_WITHOUT_PREFIX "u",nFileLen);
4073 1 : VSIFWriteL( (void *) osLen.c_str(), 1, 12, fpVSIL );
4074 :
4075 1 : VSIFCloseL( fpVSIL );
4076 1 : CPLFree( pachLT );
4077 : }
4078 :
4079 : /************************************************************************/
4080 : /* NITFWriteJPEGImage() */
4081 : /************************************************************************/
4082 :
4083 : #ifdef JPEG_SUPPORTED
4084 :
4085 : int
4086 : NITFWriteJPEGBlock( GDALDataset *poSrcDS, FILE *fp,
4087 : int nBlockXOff, int nBlockYOff,
4088 : int nBlockXSize, int nBlockYSize,
4089 : int bProgressive, int nQuality,
4090 : GDALProgressFunc pfnProgress, void * pProgressData );
4091 :
4092 : static int
4093 4 : NITFWriteJPEGImage( GDALDataset *poSrcDS, FILE *fp, vsi_l_offset nStartOffset,
4094 : char **papszOptions,
4095 : GDALProgressFunc pfnProgress, void * pProgressData )
4096 : {
4097 4 : int nBands = poSrcDS->GetRasterCount();
4098 4 : int nXSize = poSrcDS->GetRasterXSize();
4099 4 : int nYSize = poSrcDS->GetRasterYSize();
4100 4 : int nQuality = 75;
4101 4 : int bProgressive = FALSE;
4102 :
4103 4 : if( !pfnProgress( 0.0, NULL, pProgressData ) )
4104 0 : return FALSE;
4105 :
4106 : /* -------------------------------------------------------------------- */
4107 : /* Some some rudimentary checks */
4108 : /* -------------------------------------------------------------------- */
4109 4 : if( nBands != 1 && nBands != 3 )
4110 : {
4111 : CPLError( CE_Failure, CPLE_NotSupported,
4112 : "JPEG driver doesn't support %d bands. Must be 1 (grey) "
4113 0 : "or 3 (RGB) bands.\n", nBands );
4114 :
4115 0 : return FALSE;
4116 : }
4117 :
4118 4 : GDALDataType eDT = poSrcDS->GetRasterBand(1)->GetRasterDataType();
4119 :
4120 : #if defined(JPEG_LIB_MK1) || defined(JPEG_DUAL_MODE_8_12)
4121 4 : if( eDT != GDT_Byte && eDT != GDT_UInt16 )
4122 : {
4123 : CPLError( CE_Failure, CPLE_NotSupported,
4124 : "JPEG driver doesn't support data type %s. "
4125 : "Only eight and twelve bit bands supported (Mk1 libjpeg).\n",
4126 : GDALGetDataTypeName(
4127 0 : poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
4128 :
4129 0 : return FALSE;
4130 : }
4131 :
4132 5 : if( eDT == GDT_UInt16 || eDT == GDT_Int16 )
4133 1 : eDT = GDT_UInt16;
4134 : else
4135 3 : eDT = GDT_Byte;
4136 :
4137 : #else
4138 : if( eDT != GDT_Byte )
4139 : {
4140 : CPLError( CE_Failure, CPLE_NotSupported,
4141 : "JPEG driver doesn't support data type %s. "
4142 : "Only eight bit byte bands supported.\n",
4143 : GDALGetDataTypeName(
4144 : poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
4145 :
4146 : return FALSE;
4147 : }
4148 :
4149 : eDT = GDT_Byte; // force to 8bit.
4150 : #endif
4151 :
4152 : /* -------------------------------------------------------------------- */
4153 : /* What options has the user selected? */
4154 : /* -------------------------------------------------------------------- */
4155 4 : if( CSLFetchNameValue(papszOptions,"QUALITY") != NULL )
4156 : {
4157 2 : nQuality = atoi(CSLFetchNameValue(papszOptions,"QUALITY"));
4158 2 : if( nQuality < 10 || nQuality > 100 )
4159 : {
4160 : CPLError( CE_Failure, CPLE_IllegalArg,
4161 : "QUALITY=%s is not a legal value in the range 10-100.",
4162 0 : CSLFetchNameValue(papszOptions,"QUALITY") );
4163 0 : return FALSE;
4164 : }
4165 : }
4166 :
4167 4 : bProgressive = CSLFetchBoolean( papszOptions, "PROGRESSIVE", FALSE );
4168 :
4169 : /* -------------------------------------------------------------------- */
4170 : /* Compute blocking factors */
4171 : /* -------------------------------------------------------------------- */
4172 4 : int nNPPBH = nXSize;
4173 4 : int nNPPBV = nYSize;
4174 :
4175 4 : if( CSLFetchNameValue( papszOptions, "BLOCKSIZE" ) != NULL )
4176 2 : nNPPBH = nNPPBV = atoi(CSLFetchNameValue( papszOptions, "BLOCKSIZE" ));
4177 :
4178 4 : if( CSLFetchNameValue( papszOptions, "BLOCKXSIZE" ) != NULL )
4179 0 : nNPPBH = atoi(CSLFetchNameValue( papszOptions, "BLOCKXSIZE" ));
4180 :
4181 4 : if( CSLFetchNameValue( papszOptions, "BLOCKYSIZE" ) != NULL )
4182 0 : nNPPBV = atoi(CSLFetchNameValue( papszOptions, "BLOCKYSIZE" ));
4183 :
4184 4 : if( CSLFetchNameValue( papszOptions, "NPPBH" ) != NULL )
4185 0 : nNPPBH = atoi(CSLFetchNameValue( papszOptions, "NPPBH" ));
4186 :
4187 4 : if( CSLFetchNameValue( papszOptions, "NPPBV" ) != NULL )
4188 0 : nNPPBV = atoi(CSLFetchNameValue( papszOptions, "NPPBV" ));
4189 :
4190 4 : if( nNPPBH <= 0 || nNPPBV <= 0 ||
4191 : nNPPBH > 9999 || nNPPBV > 9999 )
4192 0 : nNPPBH = nNPPBV = 256;
4193 :
4194 4 : int nNBPR = (nXSize + nNPPBH - 1) / nNPPBH;
4195 4 : int nNBPC = (nYSize + nNPPBV - 1) / nNPPBV;
4196 :
4197 4 : VSIFSeekL( fp, nStartOffset, SEEK_SET );
4198 :
4199 4 : const char* pszIC = CSLFetchNameValue( papszOptions, "IC" );
4200 : GUInt32 nIMDATOFF;
4201 4 : if (EQUAL(pszIC, "M3"))
4202 : {
4203 : GUInt32 nIMDATOFF_MSB;
4204 : GUInt16 nBMRLNTH, nTMRLNTH, nTPXCDLNTH;
4205 :
4206 : /* Prepare the block map */
4207 : #define BLOCKMAP_HEADER_SIZE (4 + 2 + 2 + 2)
4208 1 : nIMDATOFF_MSB = nIMDATOFF = BLOCKMAP_HEADER_SIZE + nNBPC * nNBPR * 4;
4209 1 : nBMRLNTH = 4;
4210 1 : nTMRLNTH = 0;
4211 1 : nTPXCDLNTH = 0;
4212 :
4213 1 : CPL_MSBPTR32( &nIMDATOFF_MSB );
4214 1 : CPL_MSBPTR16( &nBMRLNTH );
4215 1 : CPL_MSBPTR16( &nTMRLNTH );
4216 1 : CPL_MSBPTR16( &nTPXCDLNTH );
4217 :
4218 1 : VSIFWriteL( &nIMDATOFF_MSB, 1, 4, fp );
4219 1 : VSIFWriteL( &nBMRLNTH, 1, 2, fp );
4220 1 : VSIFWriteL( &nTMRLNTH, 1, 2, fp );
4221 1 : VSIFWriteL( &nTPXCDLNTH, 1, 2, fp );
4222 :
4223 : /* Reserve space for the table itself */
4224 1 : VSIFSeekL( fp, nNBPC * nNBPR * 4, SEEK_CUR );
4225 : }
4226 :
4227 : /* -------------------------------------------------------------------- */
4228 : /* Copy each block */
4229 : /* -------------------------------------------------------------------- */
4230 : int nBlockXOff, nBlockYOff;
4231 10 : for(nBlockYOff=0;nBlockYOff<nNBPC;nBlockYOff++)
4232 : {
4233 16 : for(nBlockXOff=0;nBlockXOff<nNBPR;nBlockXOff++)
4234 : {
4235 : /*CPLDebug("NITF", "nBlockXOff=%d/%d, nBlockYOff=%d/%d",
4236 : nBlockXOff, nNBPR, nBlockYOff, nNBPC);*/
4237 10 : if (EQUAL(pszIC, "M3"))
4238 : {
4239 : /* Write block offset for current block */
4240 :
4241 4 : GUIntBig nCurPos = VSIFTellL(fp);
4242 4 : VSIFSeekL( fp, nStartOffset + BLOCKMAP_HEADER_SIZE + 4 * (nBlockYOff * nNBPR + nBlockXOff), SEEK_SET );
4243 4 : GUIntBig nBlockOffset = nCurPos - nStartOffset - nIMDATOFF;
4244 4 : GUInt32 nBlockOffset32 = (GUInt32)nBlockOffset;
4245 4 : if (nBlockOffset == (GUIntBig)nBlockOffset32)
4246 : {
4247 4 : CPL_MSBPTR32( &nBlockOffset32 );
4248 4 : VSIFWriteL( &nBlockOffset32, 1, 4, fp );
4249 : }
4250 : else
4251 : {
4252 : CPLError(CE_Failure, CPLE_AppDefined,
4253 : "Offset for block (%d, %d) = " CPL_FRMT_GUIB ". Cannot fit into 32 bits...",
4254 0 : nBlockXOff, nBlockYOff, nBlockOffset);
4255 :
4256 0 : nBlockOffset32 = 0xffffffff;
4257 : int i;
4258 0 : for(i=nBlockYOff * nNBPR + nBlockXOff; i < nNBPC * nNBPR; i++)
4259 : {
4260 0 : VSIFWriteL( &nBlockOffset32, 1, 4, fp );
4261 : }
4262 0 : return FALSE;
4263 : }
4264 4 : VSIFSeekL( fp, nCurPos, SEEK_SET );
4265 : }
4266 :
4267 10 : if (!NITFWriteJPEGBlock(poSrcDS, fp,
4268 : nBlockXOff, nBlockYOff,
4269 : nNPPBH, nNPPBV,
4270 : bProgressive, nQuality,
4271 : pfnProgress, pProgressData))
4272 : {
4273 0 : return FALSE;
4274 : }
4275 : }
4276 : }
4277 4 : return TRUE;
4278 : }
4279 :
4280 : #endif /* def JPEG_SUPPORTED */
4281 :
4282 : /************************************************************************/
4283 : /* GDALRegister_NITF() */
4284 : /************************************************************************/
4285 :
4286 : typedef struct
4287 : {
4288 : int nMaxLen;
4289 : const char* pszName;
4290 : } NITFFieldDescription;
4291 :
4292 : /* Keep in sync with NITFCreate */
4293 : static const NITFFieldDescription asFieldDescription [] =
4294 : {
4295 : { 2, "CLEVEL" } ,
4296 : { 10, "OSTAID" } ,
4297 : { 14, "FDT" } ,
4298 : { 80, "FTITLE" } ,
4299 : { 1, "FSCLAS" } ,
4300 : { 2, "FSCLSY" } ,
4301 : { 11, "FSCODE" } ,
4302 : { 2, "FSCTLH" } ,
4303 : { 20, "FSREL" } ,
4304 : { 2, "FSDCTP" } ,
4305 : { 8, "FSDCDT" } ,
4306 : { 4, "FSDCXM" } ,
4307 : { 1, "FSDG" } ,
4308 : { 8, "FSDGDT" } ,
4309 : { 43, "FSCLTX" } ,
4310 : { 1, "FSCATP" } ,
4311 : { 40, "FSCAUT" } ,
4312 : { 1, "FSCRSN" } ,
4313 : { 8, "FSSRDT" } ,
4314 : { 15, "FSCTLN" } ,
4315 : { 5, "FSCOP" } ,
4316 : { 5, "FSCPYS" } ,
4317 : { 24, "ONAME" } ,
4318 : { 18, "OPHONE" } ,
4319 : { 10, "IID1" } ,
4320 : { 14, "IDATIM" } ,
4321 : { 17, "TGTID" } ,
4322 : { 80, "IID2" } ,
4323 : { 1, "ISCLAS" } ,
4324 : { 2, "ISCLSY" } ,
4325 : { 11, "ISCODE" } ,
4326 : { 2, "ISCTLH" } ,
4327 : { 20, "ISREL" } ,
4328 : { 2, "ISDCTP" } ,
4329 : { 8, "ISDCDT" } ,
4330 : { 4, "ISDCXM" } ,
4331 : { 1, "ISDG" } ,
4332 : { 8, "ISDGDT" } ,
4333 : { 43, "ISCLTX" } ,
4334 : { 1, "ISCATP" } ,
4335 : { 40, "ISCAUT" } ,
4336 : { 1, "ISCRSN" } ,
4337 : { 8, "ISSRDT" } ,
4338 : { 15, "ISCTLN" } ,
4339 : { 42, "ISORCE" } ,
4340 : { 8, "ICAT" } ,
4341 : { 2, "ABPP" } ,
4342 : { 1, "PJUST" } ,
4343 : };
4344 :
4345 : /* Keep in sync with NITFWriteBLOCKA */
4346 : static const char *apszFieldsBLOCKA[] = {
4347 : "BLOCK_INSTANCE", "0", "2",
4348 : "N_GRAY", "2", "5",
4349 : "L_LINES", "7", "5",
4350 : "LAYOVER_ANGLE", "12", "3",
4351 : "SHADOW_ANGLE", "15", "3",
4352 : "BLANKS", "18", "16",
4353 : "FRLC_LOC", "34", "21",
4354 : "LRLC_LOC", "55", "21",
4355 : "LRFC_LOC", "76", "21",
4356 : "FRFC_LOC", "97", "21",
4357 : NULL, NULL, NULL };
4358 :
4359 338 : void GDALRegister_NITF()
4360 :
4361 : {
4362 : GDALDriver *poDriver;
4363 :
4364 338 : if( GDALGetDriverByName( "NITF" ) == NULL )
4365 : {
4366 : unsigned int i;
4367 336 : CPLString osCreationOptions;
4368 :
4369 : osCreationOptions =
4370 : "<CreationOptionList>"
4371 : " <Option name='IC' type='string-select' default='NC' description='Compression mode. NC=no compression. "
4372 : #ifdef JPEG_SUPPORTED
4373 : "C3/M3=JPEG compression. "
4374 : #endif
4375 : "C8=JP2 compression through the JP2ECW driver"
4376 : "'>"
4377 : " <Value>NC</Value>"
4378 : #ifdef JPEG_SUPPORTED
4379 : " <Value>C3</Value>"
4380 : " <Value>M3</Value>"
4381 : #endif
4382 : " <Value>C8</Value>"
4383 : " </Option>"
4384 : #ifdef JPEG_SUPPORTED
4385 : " <Option name='QUALITY' type='int' description='JPEG quality 10-100' default='75'/>"
4386 : " <Option name='PROGRESSIVE' type='boolean' description='JPEG progressive mode'/>"
4387 : #endif
4388 : " <Option name='NUMI' type='int' default='1' description='Number of images to create (1-999). Only works with IC=NC'/>"
4389 : " <Option name='TARGET' type='float' description='For JP2 only. Compression Percentage'/>"
4390 : " <Option name='PROFILE' type='string-select' description='For JP2 only.'>"
4391 : " <Value>BASELINE_0</Value>"
4392 : " <Value>BASELINE_1</Value>"
4393 : " <Value>BASELINE_2</Value>"
4394 : " <Value>NPJE</Value>"
4395 : " <Value>EPJE</Value>"
4396 : " </Option>"
4397 : " <Option name='ICORDS' type='string-select' description='To ensure that space will be reserved for geographic corner coordinates in DMS (G), in decimal degrees (D), UTM North (N) or UTM South (S)'>"
4398 : " <Value>G</Value>"
4399 : " <Value>D</Value>"
4400 : " <Value>N</Value>"
4401 : " <Value>S</Value>"
4402 : " </Option>"
4403 : " <Option name='FHDR' type='string-select' description='File version' default='NITF02.10'>"
4404 : " <Value>NITF02.10</Value>"
4405 : " <Value>NSIF01.00</Value>"
4406 : " </Option>"
4407 : " <Option name='IREP' type='string' description='Set to RGB/LUT to reserve space for a color table for each output band. (Only needed for Create() method, not CreateCopy())'/>"
4408 : " <Option name='LUT_SIZE' type='integer' description='Set to control the size of pseudocolor tables for RGB/LUT bands' default='256'/>"
4409 : " <Option name='BLOCKXSIZE' type='int' description='Set the block width'/>"
4410 : " <Option name='BLOCKYSIZE' type='int' description='Set the block height'/>"
4411 336 : " <Option name='BLOCKSIZE' type='int' description='Set the block with and height. Overridden by BLOCKXSIZE and BLOCKYSIZE'/>";
4412 :
4413 16464 : for(i=0;i<sizeof(asFieldDescription) / sizeof(asFieldDescription[0]); i++)
4414 : {
4415 : char szFieldDescription[128];
4416 : sprintf(szFieldDescription, " <Option name='%s' type='string' maxsize='%d'/>",
4417 16128 : asFieldDescription[i].pszName, asFieldDescription[i].nMaxLen);
4418 16128 : osCreationOptions += szFieldDescription;
4419 : }
4420 :
4421 : osCreationOptions +=
4422 : " <Option name='TRE' type='string' description='Under the format TRE=tre-name,tre-contents'/>"
4423 336 : " <Option name='BLOCKA_BLOCK_COUNT' type='int'/>";
4424 :
4425 3696 : for(i=0; apszFieldsBLOCKA[i] != NULL; i+=3)
4426 : {
4427 : char szFieldDescription[128];
4428 : sprintf(szFieldDescription, " <Option name='BLOCKA_%s_*' type='string' maxsize='%d'/>",
4429 3360 : apszFieldsBLOCKA[i], atoi(apszFieldsBLOCKA[i+2]));
4430 3360 : osCreationOptions += szFieldDescription;
4431 : }
4432 :
4433 336 : osCreationOptions += "</CreationOptionList>";
4434 :
4435 336 : poDriver = new GDALDriver();
4436 :
4437 336 : poDriver->SetDescription( "NITF" );
4438 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
4439 336 : "National Imagery Transmission Format" );
4440 :
4441 336 : poDriver->pfnIdentify = NITFDataset::Identify;
4442 336 : poDriver->pfnOpen = NITFDataset::Open;
4443 336 : poDriver->pfnCreate = NITFDatasetCreate;
4444 336 : poDriver->pfnCreateCopy = NITFDataset::NITFCreateCopy;
4445 :
4446 336 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_nitf.html" );
4447 336 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "ntf" );
4448 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
4449 336 : "Byte UInt16 Int16 UInt32 Int32 Float32" );
4450 :
4451 336 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, osCreationOptions);
4452 336 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
4453 :
4454 336 : GetGDALDriverManager()->RegisterDriver( poDriver );
4455 : }
4456 338 : }
|