1 //---
2 //
3 // License: MIT
4 //
5 // See LICENSE.txt file in the top level directory for more details.
6 //
7 // Author:  David Burken
8 //
9 // Description:  Contains class definition for ossimNitfTileSource.
10 //
11 //---
12 // $Id$
13 
14 #include <ossim/imaging/ossimNitfTileSource.h>
15 #include <ossim/base/ossimConstants.h>
16 #include <ossim/base/ossimCommon.h>
17 #include <ossim/base/ossimTrace.h>
18 #include <ossim/base/ossimNotifyContext.h>
19 #include <ossim/base/ossimIpt.h>
20 #include <ossim/base/ossimDpt.h>
21 #include <ossim/base/ossimIrect.h>
22 #include <ossim/base/ossimFilename.h>
23 #include <ossim/base/ossimKeywordlist.h>
24 #include <ossim/base/ossimInterleaveTypeLut.h>
25 #include <ossim/base/ossimPackedBits.h>
26 #include <ossim/base/ossimScalarTypeLut.h>
27 #include <ossim/base/ossimEndian.h>
28 #include <ossim/base/ossimBooleanProperty.h>
29 #include <ossim/base/ossimStreamFactoryRegistry.h>
30 #include <ossim/imaging/ossimImageDataFactory.h>
31 #include <ossim/imaging/ossimImageGeometry.h>
32 #include <ossim/imaging/ossimJpegMemSrc.h>
33 #include <ossim/imaging/ossimTiffTileSource.h>
34 #include <ossim/imaging/ossimJpegDefaultTable.h>
35 #include <ossim/base/ossim2dTo2dShiftTransform.h>
36 #include <ossim/base/ossimContainerProperty.h>
37 #include <ossim/projection/ossimProjectionFactoryRegistry.h>
38 #include <ossim/support_data/ossimNitfIchipbTag.h>
39 #include <ossim/support_data/ossimNitfImageHeaderV2_0.h>
40 #include <ossim/support_data/ossimNitfImageHeaderV2_1.h>
41 #include <ossim/support_data/ossimNitfStdidcTag.h>
42 #include <ossim/support_data/ossimNitfVqCompressionHeader.h>
43 
44 #include <cstdlib> /* free, malloc, size_t (jpeglib.h) */
45 #include <cstdio>  /* FILE* (jpeglib.h) */
46 #include <csetjmp> /** for jmp_buf (jpeglib.h) */
47 #include <jerror.h>
48 #include <jpeglib.h>
49 #include <fstream>
50 #include <algorithm> /* for std::fill */
51 
52 using namespace std;
53 
54 RTTI_DEF1_INST(ossimNitfTileSource, "ossimNitfTileSource", ossimImageHandler)
55 
56 #ifdef OSSIM_ID_ENABLED
57    static const char OSSIM_ID[] = "$Id: ossimNitfTileSource.cpp 22925 2014-10-28 22:01:09Z dburken $";
58 #endif
59 
60 //---
61 // NOTE:  This should match the enumerations for ReadMode.
62 //---
63 static const char* READ_MODE[] = { "READ_MODE_UNKNOWN",
64                                    "READ_BIB_BLOCK",
65                                    "READ_BIP_BLOCK",
66                                    "READ_BIR_BLOCK",
67                                    "READ_BSQ_BLOCK",
68                                    "READ_BIB",
69                                    "READ_BIP",
70                                    "READ_BIR",
71                                    "READ_JPEG_BLOCK" };
72 
73 //***
74 // Static trace for debugging
75 //***
76 static ossimTrace traceDebug("ossimNitfTileSource:debug");
77 
78 // 64x64*12bits
79 // divide by 8 bits to get bytes gives you 6144 bytes
80 static const ossim_uint32   OSSIM_NITF_VQ_BLOCKSIZE = 6144;
81 
82 /** @brief Extended error handler struct for jpeg code. */
83 struct ossimJpegErrorMgr
84 {
85    struct jpeg_error_mgr pub; /* "public" fields */
86    jmp_buf setjmp_buffer;  /* for return to caller */
87 };
88 
89 
ossimNitfTileSource()90 ossimNitfTileSource::ossimNitfTileSource()
91    :
92       ossimImageHandler(),
93       theTile(0),
94       theCacheTile(0),
95       theNitfFile(0),
96       theNitfImageHeader(0),
97       theReadMode(READ_MODE_UNKNOWN),
98       theScalarType(OSSIM_SCALAR_UNKNOWN),
99       theSwapBytesFlag(false),
100       theNumberOfInputBands(0),
101       theNumberOfOutputBands(0),
102       theBlockSizeInBytes(0),
103       theReadBlockSizeInBytes(0),
104       theNumberOfImages(0),
105       theCurrentEntry(0),
106       theImageRect(0,0,0,0),
107       theFileStr(0),
108       theOutputBandList(),
109       theCacheSize(0, 0),
110       theCacheTileInterLeaveType(OSSIM_INTERLEAVE_UNKNOWN),
111       theCacheEnabledFlag(false),
112       theEntryList(0),
113       theCacheId(-1),
114       thePackedBitsFlag(false),
115       theCompressedBuf(0),
116       theNitfBlockOffset(0),
117       theNitfBlockSize(0),
118       m_jpegOffsetsDirty(false)
119 {
120    if (traceDebug())
121    {
122       ossimNotify(ossimNotifyLevel_DEBUG)
123          << "ossimNitfTileSource::ossimNitfTileSource entered..." << endl;
124 #ifdef OSSIM_ID_ENABLED
125       ossimNotify(ossimNotifyLevel_DEBUG)<< "OSSIM_ID:  " << OSSIM_ID << endl;
126 #endif
127    }
128 
129 }
130 
~ossimNitfTileSource()131 ossimNitfTileSource::~ossimNitfTileSource()
132 {
133    destroy();
134 }
135 
destroy()136 void ossimNitfTileSource::destroy()
137 {
138    if (theCacheId != -1)
139    {
140       ossimAppFixedTileCache::instance()->deleteCache(theCacheId);
141       theCacheId = -1;
142    }
143 
144    // Delete the list of image headers.
145    theNitfImageHeader.clear();
146 
147    theNitfFile = 0;
148 
149    shared_ptr<ossim::ifstream> str = std::dynamic_pointer_cast<ossim::ifstream>( theFileStr );
150    if ( str )
151    {
152       if(str->is_open())
153       {
154          str->close();
155       }
156    }
157 
158    theCacheTile = 0;
159    theTile      = 0;
160    theOverview  = 0;
161  }
162 
isOpen() const163 bool ossimNitfTileSource::isOpen()const
164 {
165 
166    return (theNitfImageHeader.size() > 0);
167 }
168 
open()169 bool ossimNitfTileSource::open()
170 {
171    bool result = false;
172 
173    if(isOpen())
174    {
175       close();
176    }
177 
178    theErrorStatus = ossimErrorCodes::OSSIM_OK;
179 
180    std::shared_ptr<ossim::istream> nitfStream= ossim::StreamFactoryRegistry::instance()->createIstream(getFilename().c_str());
181 
182    result = open(nitfStream, getFilename().c_str());
183    // if ( parseFile() )
184    // {
185    //    result = allocate();
186    // }
187    // if (result)
188    // {
189    //    completeOpen();
190    // }
191 
192    return result;
193 }
194 
open(std::shared_ptr<ossim::istream> & str,const std::string & connectionString)195 bool ossimNitfTileSource::open( std::shared_ptr<ossim::istream>& str,
196                                 const std::string& connectionString )
197 {
198    static const char MODULE[] = "ossimNitfTileSource::open( stream, ...)";
199 
200    bool result = false;
201    if(!str) return result;
202    ossimFilename file = connectionString;
203 
204    if (traceDebug())
205    {
206       ossimNotify(ossimNotifyLevel_DEBUG)
207          << MODULE << " entered...\nFile =  " << file << "\n";
208    }
209 
210    if( isOpen() )
211    {
212       close();
213    }
214 
215    theErrorStatus = ossimErrorCodes::OSSIM_OK;
216 
217 
218    theNitfFile = new ossimNitfFile();
219 
220    result = theNitfFile->parseStream( file, *str);
221 
222    if ( result )
223    {
224       // Get the number of images within the file.
225       theNumberOfImages = theNitfFile->getHeader()->getNumberOfImages();
226 
227       if(traceDebug())
228       {
229          ossimNotify(ossimNotifyLevel_DEBUG)
230             << "DEBUG:\nNumber of images " << theNumberOfImages << "\n";
231       }
232 
233       theEntryList.clear();
234 
235       //---
236       // Get image header pointers.  Note there can be multiple images in one
237       // image file.
238       //---
239 
240       for (ossim_uint32 i = 0; i < theNumberOfImages; ++i)
241       {
242          ossimRefPtr<ossimNitfImageHeader> hdr = theNitfFile->getNewImageHeader(*str, i);
243          if (!hdr)
244          {
245             result = false;
246             setErrorStatus();
247             if (traceDebug())
248             {
249                ossimNotify(ossimNotifyLevel_DEBUG)
250                   << MODULE << " ERROR:\nNull image header!" << endl;
251             }
252             break;
253          }
254 
255          if (traceDebug())
256          {
257             if(hdr.valid())
258             {
259                ossimNotify(ossimNotifyLevel_DEBUG)
260                   << MODULE << "DEBUG:"
261                   << "\nImage header[" << i << "]:\n" << *(hdr.get())
262                   << "\n";
263             }
264          }
265          if(hdr->isValid())
266          {
267             if( !hdr->isCompressed() )
268                {
269                // GP:  I will remove the NODISPLY check for if there is
270                //      any kind of data OSSIM should allow it through.
271                //      filterting for this data should be at a higher level.
272                //      SICD data is labeled as NODISPLY but we need to process
273                //      it in order for it to be used in other algorithms
274 
275                // Skip entries tagged NODISPLAY, e.g. cloud mask entries.
276                // if (hdr->getRepresentation() != "NODISPLY")
277                // {
278                   theEntryList.push_back(i);
279                   theNitfImageHeader.push_back(hdr);
280                // }
281                // else
282                // {
283                //    ossimString cat = hdr->getCategory().trim().downcase();
284                //    // this is an NGA Highr Resoluion Digital Terrain Model NITF format
285                //    if(cat == "dtem")
286                //    {
287                //       theEntryList.push_back(i);
288                //       theNitfImageHeader.push_back(hdr);
289                //    }
290                // }
291 
292             }
293             else if ( canUncompress(hdr.get()) )
294             {
295                theEntryList.push_back(i);
296                theCacheEnabledFlag = true;
297                theNitfImageHeader.push_back(hdr);
298             }
299             else
300             {
301                //std::cout << "COMPRESSION CODE: "<< hdr->getCompressionCode() << "\n";
302                if(traceDebug())
303                {
304                   ossimNotify(ossimNotifyLevel_DEBUG)
305                      << "Entry " << i
306                      <<" has an unsupported compression code = "
307                      << hdr->getCompressionCode() << std::endl;
308                }
309                theNitfImageHeader.clear();
310                theEntryList.clear();
311                // break out
312                break;
313             }
314          }
315 
316       } // End: image header loop
317       // Reset the number of images in case we skipped some, e.g. tagged "NODISPLAY"
318       if ( theNitfImageHeader.size() )
319       {
320          theNumberOfImages = (ossim_uint32)theNitfImageHeader.size();
321       }
322       else
323       {
324          result = false;
325       }
326 
327 
328 
329       if ( result )
330       {
331          // Save the stream and connection/file name.
332          theFileStr = str;
333          theImageFile = file;
334 
335          // Initialize the lut to the current entry if the current entry has a lut.
336          initializeLut();
337 
338          result = allocate();
339 
340          if (result)
341          {
342             completeOpen();
343          }
344       }
345       else
346       {
347          setErrorStatus();
348          if (traceDebug())
349          {
350             ossimNotify(ossimNotifyLevel_DEBUG)
351                << MODULE << "DEBUG:\nNo images in file!" << endl;
352          }
353       }
354    }
355 
356    if (traceDebug())
357    {
358       ossimNotify(ossimNotifyLevel_DEBUG)
359          << MODULE << " exit status: " << (result?"true":"false") << "\n";
360    }
361    return result;
362 }
363 
close()364 void ossimNitfTileSource::close()
365 {
366    destroy();
367 }
368 
parseFile()369 bool ossimNitfTileSource::parseFile()
370 {
371    static const char MODULE[] = "ossimNitfTileSource::parseFile";
372 
373    ossimFilename file = getFilename();
374 
375    if (traceDebug())
376    {
377       ossimNotify(ossimNotifyLevel_DEBUG)
378          << MODULE << " DEBUG: Nitf file =  " << file << endl;
379    }
380 
381    if (file.empty())
382    {
383       setErrorStatus();
384       return false;
385    }
386 
387    if ( !theNitfFile )  // A close deletes "theNitfFile".
388    {
389       theNitfFile = new ossimNitfFile();
390    }
391 
392    if ( !theNitfFile->parseFile(file) )
393    {
394       setErrorStatus();
395       if (traceDebug())
396       {
397          ossimNotify(ossimNotifyLevel_DEBUG)
398             << MODULE << "DEBUG:" << "\nError parsing file!" << endl;
399       }
400 
401       return false;
402    }
403 
404    // Get the number of images within the file.
405    theNumberOfImages = theNitfFile->getHeader()->getNumberOfImages();
406 
407    if(traceDebug())
408    {
409       ossimNotify(ossimNotifyLevel_DEBUG)
410          << MODULE << "DEBUG:\nNumber of images "
411          <<theNumberOfImages << std::endl;
412    }
413 
414    if ( theNumberOfImages == 0 )
415    {
416       setErrorStatus();
417       if (traceDebug())
418       {
419          ossimNotify(ossimNotifyLevel_DEBUG)
420             << MODULE << "DEBUG:\nNo images in file!" << endl;
421       }
422 
423       return false;
424    }
425    theEntryList.clear();
426    //---
427    // Get image header pointers.  Note there can be multiple images in one
428    // image file.
429    //---
430    for (ossim_uint32 i = 0; i < theNumberOfImages; ++i)
431    {
432       ossimRefPtr<ossimNitfImageHeader> hdr = theNitfFile->getNewImageHeader(i);
433       if (!hdr)
434       {
435          setErrorStatus();
436          if (traceDebug())
437          {
438             ossimNotify(ossimNotifyLevel_DEBUG)
439             << MODULE << " ERROR:\nNull image header!" << endl;
440          }
441 
442          return false;
443       }
444       if (traceDebug())
445       {
446          if(hdr.valid())
447          {
448             ossimNotify(ossimNotifyLevel_DEBUG)
449                << MODULE << "DEBUG:"
450                << "\nImage header[" << i << "]:\n" << *hdr
451                << endl;
452          }
453       }
454 
455       if(hdr->isValid())
456       {
457          if( !hdr->isCompressed() )
458          {
459             // GP:  I will remove the NODISPLYU check for if there is
460             //      any kind of data OSSIM should allow it through.
461             //      filterting for this data should be at a higher level.
462             //      SICD data is labeled as NODISPLY but we need to process
463             //      it in order for it to be used in other algorithms
464             //
465             // Skip entries tagged NODISPLAY, e.g. cloud mask entries.
466             // if (hdr->getRepresentation() != "NODISPLY")
467             // {
468                theEntryList.push_back(i);
469                theNitfImageHeader.push_back(hdr);
470             // }
471             // else
472             // {
473             //    ossimString cat = hdr->getCategory().trim().downcase();
474             //    // this is an NGA Highr Resoluion Digital Terrain Model NITF format
475             //    if(cat == "dtem")
476             //    {
477             //       theEntryList.push_back(i);
478             //       theNitfImageHeader.push_back(hdr);
479             //    }
480             // }
481 
482          }
483          else if ( canUncompress(hdr.get()) )
484          {
485             theEntryList.push_back(i);
486             theCacheEnabledFlag = true;
487             theNitfImageHeader.push_back(hdr);
488          }
489          else
490          {
491             theEntryList.clear();
492             theNitfImageHeader.clear();
493             if(traceDebug())
494             {
495                ossimNotify(ossimNotifyLevel_DEBUG)
496                   << "Entry " << i
497                   <<" has an unsupported compression code = "
498                   << hdr->getCompressionCode() << std::endl;
499             }
500             break;
501          }
502       }
503       else
504       {
505          if(traceDebug())
506          {
507                ossimNotify(ossimNotifyLevel_DEBUG)
508                   << "Entry " << i
509                   <<" has an invalid image header\n";
510 
511          }
512       }
513    }
514 
515    if(theEntryList.size()<1)
516    {
517       return false;
518    }
519 
520    //### WHY IS THIS HERE? THIS CAUSED A BUG BECAUSE theCurrentEntry was previously initialized
521    //### in loadState() according to a KWL. Any entry index in the KWL was being ignored.
522    //if(theEntryList.size()>0)
523    //{
524    //   theCurrentEntry = theEntryList[0];
525    //}
526 
527    theNumberOfImages = (ossim_uint32)theNitfImageHeader.size();
528 
529    if (theNitfImageHeader.size() != theNumberOfImages)
530    {
531       setErrorStatus();
532       if (traceDebug())
533       {
534          ossimNotify(ossimNotifyLevel_DEBUG)
535             << MODULE
536             << "DEBUG:\nNumber of header not equal number of images!"
537             << endl;
538       }
539 
540       return false;
541    }
542 
543    // Check the current entry range.
544    if ( theCurrentEntry >= theNumberOfImages )
545    {
546       if(theEntryList.size())
547       {
548          theCurrentEntry = theEntryList[0];
549       }
550    }
551 
552    // Initialize the lut to the current entry if the current entry has a lut.
553    initializeLut();
554 
555    if (traceDebug())
556    {
557       ossimNotify(ossimNotifyLevel_DEBUG)
558          << MODULE << " DEBUG:"
559          << "\nCurrent entry:  " << theCurrentEntry
560          << endl;
561    }
562 
563 
564    // Open up a stream to the file.
565    theFileStr = ossim::StreamFactoryRegistry::instance()->createIstream(
566       file, ios::in | ios::binary);
567    if (!theFileStr)
568    {
569       theErrorStatus = ossimErrorCodes::OSSIM_ERROR;
570       if(traceDebug())
571       {
572          ossimNotify(ossimNotifyLevel_DEBUG)
573             << MODULE << " ERROR:"
574             << "\nCannot open:  " << file.c_str() << endl;
575       }
576       return false;
577    }
578 
579    if(traceDebug())
580    {
581       ossimNotify(ossimNotifyLevel_DEBUG)
582          << MODULE << " leaving with true..." << endl;
583 
584    }
585 
586    return true;
587 }
588 
allocate()589 bool ossimNitfTileSource::allocate()
590 {
591    // Clear out the cache if there was any.
592    if (theCacheId != -1)
593    {
594       ossimAppFixedTileCache::instance()->deleteCache(theCacheId);
595       theCacheId = -1;
596    }
597 
598    // Clear buffers:
599    theTile = 0;
600    theCacheTile = 0;
601    theCompressedBuf.clear();
602 
603    // Set the scalar type.
604    initializeScalarType();
605    if (theScalarType == OSSIM_SCALAR_UNKNOWN)
606    {
607       return false;
608    }
609 
610    // Set the swap bytes flag.
611    initializeSwapBytesFlag();
612 
613    // Set the read mode.
614    initializeReadMode();
615    if (theReadMode == READ_MODE_UNKNOWN)
616    {
617       return false;
618    }
619 
620    // Set the number of bands.
621    initializeBandCount();
622    if (theNumberOfInputBands == 0)
623    {
624       return false;
625    }
626 
627    // Initialize the image rectangle. before the cache size is done
628    if (initializeImageRect() == false)
629    {
630       return false;
631    }
632 
633    // Initialize the cache size.  Must be done before
634    // setting the blocksize.  Since bit encoded data may very
635    // and we need to know if the nitf file needs to be accessed
636    // like a general raster.
637    //
638    initializeCacheSize();
639    if ( (theCacheSize.x == 0) || (theCacheSize.y == 0) )
640    {
641       return false;
642    }
643 
644    // Initialize the block size.
645    if (initializeBlockSize() == false)
646    {
647       return false;
648    }
649 
650    // Initialize the cache tile interleave type.
651    initializeCacheTileInterLeaveType();
652    if (theCacheTileInterLeaveType == OSSIM_INTERLEAVE_UNKNOWN)
653    {
654       return false;
655    }
656 
657    return true;
658 }
659 
allocateBuffers()660 bool ossimNitfTileSource::allocateBuffers()
661 {
662    //---
663    // Initialize the cache tile.  This will be used for a block buffer even
664    // if the cache is disabled.
665    //---
666    initializeCacheTile();
667    if (!theCacheTile.valid())
668    {
669       return false;
670    }
671 
672    // Initialize the cache if enabled.
673    if (theCacheEnabledFlag)
674    {
675       theCacheId = ossimAppFixedTileCache::instance()->
676          newTileCache(theBlockImageRect, theCacheSize);
677    }
678 
679    //---
680    // Initialize the compressed buffer if needed.
681    //---
682    initializeCompressedBuf();
683 
684    //---
685    // Make the output tile.
686    //---
687    initializeOutputTile();
688 
689    return true;
690 }
691 
canUncompress(const ossimNitfImageHeader * hdr) const692 bool ossimNitfTileSource::canUncompress(const ossimNitfImageHeader* hdr) const
693 {
694 
695    bool result = false;
696    if (hdr)
697    {
698       ossimString code = hdr->getCompressionCode();
699 
700       if (code == "C3") // jpeg
701       {
702          if (hdr->getBitsPerPixelPerBand() == 8)
703          {
704             result = true;
705          }
706          else
707          {
708             if(traceDebug())
709             {
710                ossimNotify(ossimNotifyLevel_DEBUG)
711                   << "Entry with jpeg compression (C3) has an unsupported "
712                   << "JPEG data precision: " << hdr->getBitsPerPixelPerBand()
713                   << std::endl;
714             }
715          }
716       }
717       else if(isVqCompressed( code ) &&
718               (hdr->getCompressionHeader().valid()) )
719       {
720          // we will only support single band vq compressed NITFS
721          // basically CIB and CADRG products are single band code words.
722          //
723          if(hdr->getNumberOfBands() == 1)
724          {
725             result = true;
726          }
727       }
728    }
729    return result;
730 }
731 
initializeReadMode()732 void ossimNitfTileSource::initializeReadMode()
733 {
734    // Initialize the read mode.
735    theReadMode = READ_MODE_UNKNOWN;
736 
737    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
738    if (!hdr)
739    {
740       return;
741    }
742 
743    ossim_uint32 numberOfBlocks = getNumberOfBlocks();
744    ossimString imode           = hdr->getIMode();
745    ossimString compressionCode = hdr->getCompressionCode();
746 
747    if ( (compressionCode == "C3") && ((imode == "B")||(imode == "P")) )
748    {
749       theReadMode = READ_JPEG_BLOCK;
750    }
751    else if (numberOfBlocks > 1)
752    {
753       if (imode == "B")
754       {
755          theReadMode = READ_BIB_BLOCK;
756       }
757       else if (imode == "P")
758       {
759          theReadMode = READ_BIP_BLOCK;
760       }
761       else if (imode == "R")
762       {
763          theReadMode = READ_BIR_BLOCK;
764       }
765       else if (imode == "S")
766       {
767          theReadMode = READ_BSQ_BLOCK;
768       }
769    }
770    else // The entire image comprises one block.
771    {
772       if (imode == "B")
773       {
774          theReadMode = READ_BIB;
775       }
776       else if (imode == "P")
777       {
778          theReadMode = READ_BIP;
779       }
780       else if (imode == "R")
781       {
782          theReadMode = READ_BIR;
783       }
784       else if (imode == "S")
785       {
786          theReadMode = READ_BSQ_BLOCK;
787       }
788    }
789    if (traceDebug())
790    {
791       ossimNotify(ossimNotifyLevel_DEBUG)
792          << "ossimNitfTileSource::initializeReadMode DEBUG:"
793          << "\nnumberOfBlocks:  " << numberOfBlocks
794          << "\nIMODE:           " << imode
795          << "\nRead Mode:       " << READ_MODE[theReadMode]
796          << endl;
797    }
798 }
799 
initializeScalarType()800 void ossimNitfTileSource::initializeScalarType()
801 {
802    thePackedBitsFlag = false;
803    // Initialize the read mode.
804    theScalarType = OSSIM_SCALAR_UNKNOWN;
805 
806    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
807    if (!hdr)
808    {
809       return;
810    }
811 
812    ossim_int32 bitsPerPixel = hdr->getActualBitsPerPixelPerBand();
813    if (bitsPerPixel < 1)
814    {
815       bitsPerPixel = hdr->getBitsPerPixelPerBand();
816    }
817 
818    ossimString pixelValueType = hdr->getPixelValueType().upcase();
819 
820    switch (bitsPerPixel)
821    {
822       case 8:
823       {
824          theScalarType = OSSIM_UINT8;
825          break;
826       }
827       case 11:
828       {
829          if(pixelValueType == "SI")
830          {
831             theScalarType = OSSIM_SINT16;
832          }
833          else
834          {
835             theScalarType = OSSIM_USHORT11;
836          }
837          break;
838       }
839       case 12:
840       {
841          if(pixelValueType == "SI")
842          {
843             theScalarType = OSSIM_SINT16;
844          }
845          else
846          {
847             theScalarType = OSSIM_USHORT12;
848          }
849          break;
850       }
851       case 13:
852       {
853          if(pixelValueType == "SI")
854          {
855             theScalarType = OSSIM_SINT16;
856          }
857          else
858          {
859             theScalarType = OSSIM_USHORT13;
860          }
861          break;
862       }
863       case 14:
864       {
865          if(pixelValueType == "SI")
866          {
867             theScalarType = OSSIM_SINT16;
868          }
869          else
870          {
871             theScalarType = OSSIM_USHORT14;
872          }
873          break;
874       }
875       case 15:
876       {
877          if(pixelValueType == "SI")
878          {
879             theScalarType = OSSIM_SINT16;
880          }
881          else
882          {
883             theScalarType = OSSIM_USHORT15;
884          }
885          break;
886       }
887       case  9:
888       case 10:
889       case 16:
890       {
891          if(pixelValueType == "SI")
892          {
893             theScalarType = OSSIM_SINT16;
894          }
895          else
896          {
897             theScalarType = OSSIM_UINT16;
898          }
899          break;
900       }
901       case 32:
902       {
903          if(pixelValueType == "SI")
904          {
905             theScalarType = OSSIM_SINT32;
906          }
907          else if(pixelValueType == "R")
908          {
909             theScalarType = OSSIM_FLOAT32;
910          }
911          break;
912       }
913       case 64:
914       {
915          if(pixelValueType == "R")
916          {
917             theScalarType = OSSIM_FLOAT64;
918          }
919 
920          break;
921       }
922       default:
923       {
924          if(hdr->isCompressed())
925          {
926             thePackedBitsFlag = true;
927             if(bitsPerPixel < 8)
928             {
929                theScalarType = OSSIM_UINT8;
930             }
931             else if(bitsPerPixel < 16)
932             {
933                theScalarType = OSSIM_UINT16;
934             }
935             else if(bitsPerPixel < 32)
936             {
937                theScalarType = OSSIM_FLOAT32;
938             }
939          }
940          else
941          {
942             if(bitsPerPixel<8)
943             {
944                theScalarType = OSSIM_UINT8;
945             }
946          }
947          break;
948       }
949    }
950 
951    if (traceDebug())
952    {
953       ossimNotify(ossimNotifyLevel_DEBUG)
954          << "ossimNitfTileSource::initializeScalarType DEBUG:"
955          << "\nScalar type:  "
956          << (ossimScalarTypeLut::instance()->getEntryString(theScalarType))
957          << "\nPacked bits:  " << (thePackedBitsFlag?"true":"false")
958          << endl;
959    }
960 }
961 
initializeSwapBytesFlag()962 void ossimNitfTileSource::initializeSwapBytesFlag()
963 {
964    if ( (theScalarType != OSSIM_UINT8) &&
965         (ossim::byteOrder() == OSSIM_LITTLE_ENDIAN) )
966    {
967       theSwapBytesFlag = true;
968    }
969    else
970    {
971      theSwapBytesFlag = false;
972    }
973 }
974 
initializeBandCount()975 void ossimNitfTileSource::initializeBandCount()
976 {
977    // Initialize the read mode.
978    theNumberOfInputBands = 0;
979    theNumberOfOutputBands = 0;
980    //theOutputBandList.clear();
981 
982    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
983    if (!hdr)
984    {
985       return;
986    }
987 
988    if(!isVqCompressed(hdr->getCompressionCode()))
989    {
990       theNumberOfInputBands = hdr->getNumberOfBands();
991       theNumberOfOutputBands = hdr->getNumberOfBands();
992       if(hdr->getRepresentation().contains("LUT")&&(theNumberOfInputBands == 1))
993       {
994          theNumberOfOutputBands = 3;
995       }
996    }
997    else
998    {
999       ossimRefPtr<ossimNitfImageBand> bandInfo = hdr->getBandInformation(0);
1000       if ( bandInfo.valid() )
1001       {
1002          theNumberOfInputBands = 1;
1003          theNumberOfOutputBands = bandInfo->getNumberOfLuts();
1004       }
1005    }
1006 
1007    //for (ossim_uint32 i=0; i < theNumberOfOutputBands; ++i)
1008    // Need to take bands from loadState to pass to Kakadu to avoid decompressing all bands
1009    if (theOutputBandList.size() > 0) theNumberOfOutputBands = theOutputBandList.size();
1010    else
1011    {
1012       theOutputBandList.resize(theNumberOfOutputBands);
1013       for (ossim_uint32 i=0; i < theNumberOfOutputBands; ++i)
1014       {
1015         theOutputBandList[i] = i; // One to one for initial setup.
1016       }
1017    }
1018 
1019    if (traceDebug())
1020    {
1021       ossimNotify(ossimNotifyLevel_DEBUG)
1022          << "ossimNitfTileSource::initializeBandCount DEBUG:"
1023          << "\nInput Band count:  " << theNumberOfInputBands
1024          << "\nOutput Band count:  " << theNumberOfOutputBands
1025          << endl;
1026    }
1027 }
1028 
initializeBlockSize()1029 bool ossimNitfTileSource::initializeBlockSize()
1030 {
1031    theBlockSizeInBytes     = 0;
1032    theReadBlockSizeInBytes = 0;
1033 
1034    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
1035    if (!hdr)
1036    {
1037       return false;
1038    }
1039 
1040    ossim_uint32 bytesRowCol = 0;
1041    ossim_uint32 bytesRowColCacheTile = 0;
1042 
1043    if(isVqCompressed(hdr->getCompressionCode()))
1044    {
1045       bytesRowCol = OSSIM_NITF_VQ_BLOCKSIZE;
1046    }
1047    else
1048    {
1049       //---
1050       // Busting int32 limit on single block data.
1051       // Need a new read method to handle this. (drb - 09 May 2016)
1052       //---
1053       ossim_uint64 x     = hdr->getNumberOfPixelsPerBlockHoriz();
1054       ossim_uint64 y     = hdr->getNumberOfPixelsPerBlockVert();
1055       ossim_uint64 bpp   = hdr->getBitsPerPixelPerBand();
1056       ossim_uint64 bytes = x * y * bpp / 8;
1057       if ( bytes > 2147483647 )
1058       {
1059          if (traceDebug())
1060          {
1061             ossimNotify(ossimNotifyLevel_WARN)
1062                << "ossimNitfTileSource::initializeBlockSize WARNING!"
1063                << "\nBusting 2 GIG block size: " << bytes
1064                << std::endl;
1065          }
1066          return false;
1067       }
1068       bytesRowCol = (ossim_uint32)bytes;
1069    }
1070 
1071    if ( !bytesRowColCacheTile )
1072    {
1073       //---
1074       // Busting int32 limit on single block data.
1075       // Need a new read method to handle this. (drb - 09 May 2016)
1076       //---
1077       ossim_uint64 x = theCacheSize.x;
1078       ossim_uint64 y = theCacheSize.y;
1079       ossim_uint64 bpp = hdr->getBitsPerPixelPerBand();
1080       ossim_uint64 bytes = x * y * bpp / 8;
1081       if ( bytes > 2147483647 )
1082       {
1083          if (traceDebug())
1084          {
1085             ossimNotify(ossimNotifyLevel_WARN)
1086                << "ossimNitfTileSource::initializeBlockSize WARNING!"
1087                << "\nBusting 2 GIG cache bytes: " << bytes
1088                << std::endl;
1089          }
1090          return false;
1091       }
1092 
1093       bytesRowColCacheTile = bytes;
1094    }
1095 
1096 #if 0
1097    if (traceDebug())
1098    {
1099       ossimNotify(ossimNotifyLevel_DEBUG)
1100          << "DEBUG:"
1101          // << "\ncompressionHeader:  " << compressionHeader
1102          << "\ngetNumberOfPixelsPerBlockHoriz():  "
1103          << hdr->getNumberOfPixelsPerBlockHoriz()
1104          << "\ngetNumberOfPixelsPerBlockVert():  "
1105          << hdr->getNumberOfPixelsPerBlockVert()
1106          << "\ngetBitsPerPixelPerBand():  "
1107          << hdr->getBitsPerPixelPerBand()
1108          << "\nbytesRowCol:  " << bytesRowCol
1109          << "\nbytesRowColCacheTile:  " << bytesRowColCacheTile
1110          << endl;
1111    }
1112 #endif
1113 
1114    theBlockSizeInBytes = bytesRowCol;
1115    theReadBlockSizeInBytes = theBlockSizeInBytes;
1116    switch (theReadMode)
1117    {
1118       case READ_BSQ_BLOCK:
1119       case READ_BIB_BLOCK:
1120       {
1121          break;
1122       }
1123       case READ_BIB:
1124       {
1125          theReadBlockSizeInBytes = bytesRowColCacheTile;
1126          break;
1127       }
1128 
1129       case READ_BIP_BLOCK:
1130       case READ_BIR_BLOCK:
1131       {
1132          theBlockSizeInBytes     *= theNumberOfInputBands;
1133          theReadBlockSizeInBytes *= theNumberOfInputBands;
1134          break;
1135       }
1136       case READ_BIP:
1137       case READ_BIR:
1138       {
1139          theBlockSizeInBytes *= theNumberOfInputBands;
1140          theReadBlockSizeInBytes = bytesRowColCacheTile*theNumberOfInputBands;
1141          break;
1142       }
1143       case READ_JPEG_BLOCK:
1144       {
1145          theBlockSizeInBytes *= theNumberOfInputBands;
1146          ossimString code = hdr->getCompressionCode();
1147          if (code == "C3") // jpeg
1148          {
1149             m_jpegOffsetsDirty  = true;
1150          }
1151          break;
1152       }
1153       default:
1154       {
1155          return false;
1156       }
1157    }
1158 
1159 #if 0
1160    if (traceDebug())
1161    {
1162       ossimNotify(ossimNotifyLevel_DEBUG)
1163          << "ossimNitfTileSource::initializeBlockSize DEBUG:"
1164          << "\nNumber of input bands:          " << theNumberOfInputBands
1165          << "\nNumber of output bands:          " << theNumberOfOutputBands
1166          << "\nBlock size in bytes:      " << theBlockSizeInBytes
1167          << "\nRead block size in bytes: " << theReadBlockSizeInBytes
1168          << endl;
1169    }
1170 #endif
1171 
1172    return true;
1173 }
1174 
1175 //*************************************************************************************************
1176 // Virtual method determines the decimation factors at each resolution level.
1177 // This implementation derives the R0 decimation from the image metadata if available, then hands
1178 // off the computation of remaining R-levels to the base class implementation.
1179 //*************************************************************************************************
establishDecimationFactors()1180 void ossimNitfTileSource::establishDecimationFactors()
1181 {
1182    theDecimationFactors.clear();
1183    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
1184    if (hdr)
1185    {
1186       double decimation;
1187       hdr->getDecimationFactor(decimation);
1188       if ((decimation != 0.0) && !ossim::isnan(decimation))
1189       {
1190          //---
1191          // Note: Commented out as other code is picking up the resolution and then we're applying
1192          // a decimation on top of that. (drb Aug. 2011)
1193          // ossimDpt dec_2d (decimation, decimation);
1194          //---
1195          ossimDpt dec_2d (1.0, 1.0);
1196          theDecimationFactors.push_back(dec_2d);
1197       }
1198    }
1199 
1200    // Just needed to set the first R level here, the base class can do the rest:
1201    ossimImageHandler::establishDecimationFactors();
1202 }
1203 
1204 #if 0
1205 ossimImageGeometry* ossimNitfTileSource::getImageGeometry()
1206 {
1207    //---
1208    // Call base class getImageGeometry which will check for external geometry
1209    // or an already set geometry.
1210    //---
1211    ossimImageGeometry* result = ossimImageHandler::getImageGeometry();
1212 
1213    if (result)
1214    {
1215       if ( !result->getTransform() )
1216       {
1217          ossimRefPtr<ossim2dTo2dTransform> transform = 0;
1218 
1219          const ossimNitfImageHeader* hdr = getCurrentImageHeader();
1220          if (hdr)
1221          {
1222             //---
1223             // Test for the ichipb tag and set the sub image if needed.
1224             //
1225             // NOTE # 1:
1226             //
1227             // There are nitf writers that set the ichipb offsets and only have
1228             // IGEOLO field present.  For these it has been determined
1229             // (but still in question) that we should not apply the sub image
1230             // offset.
1231             //
1232             // See trac # 1578
1233             // http://trac.osgeo.org/ossim/ticket/1578
1234             //
1235             // NOTE # 2:
1236             //
1237             // Let the ICHIPB have precedence over the STDIDC tag as we could
1238             // have a chip of a segment.
1239             //---
1240             ossimRefPtr<ossimNitfRegisteredTag> tag =
1241                hdr->getTagData(ossimString("ICHIPB"));
1242             if (tag.valid())
1243             {
1244                ossimNitfIchipbTag* ichipb =
1245                   PTR_CAST(ossimNitfIchipbTag, tag.get());
1246                if (ichipb)
1247                {
1248 //                  const ossimRefPtr<ossimNitfRegisteredTag> blocka =
1249 //                     hdr->getTagData(ossimString("BLOCKA"));
1250 //                  const ossimRefPtr<ossimNitfRegisteredTag> rpc00a =
1251 //                     hdr->getTagData(ossimString("RPC00A"));
1252 //                  const ossimRefPtr<ossimNitfRegisteredTag> rpc00b =
1253 //                     hdr->getTagData(ossimString("RPC00B"));
1254 
1255                   //---
1256                   // If any of these tags are present we will use the sub
1257                   // image from the ichipb tag.
1258                   //---
1259 //                  if ( blocka.get() || rpc00a.get() || rpc00b.get() )
1260                   // ************************* THERE ARE PROBLEMS NOT SETTING THIS AT SITE.  GO AHEAD AND ALWAYS INIT THE SHIFT
1261                   {
1262                      transform = ichipb->newTransform();
1263                   }
1264                }
1265             }
1266 
1267             if ( !transform)
1268             {
1269                //---
1270                // Look for the STDIDC tag for a sub image (segment) offset.
1271                //
1272                // See: STDI-002 Table 7.3 for documentation.
1273                //---
1274                tag = hdr->getTagData(ossimString("STDIDC"));
1275                if (tag.valid() && (hdr->getIMode() == "B") )
1276                {
1277                   ossimDpt shift;
1278                   ossimNitfStdidcTag* stdidc =
1279                      PTR_CAST(ossimNitfStdidcTag, tag.get());
1280                   if (stdidc)
1281                   {
1282                      ossim_int32 startCol = stdidc->getStartColumn().toInt32();
1283                      ossim_int32 startRow = stdidc->getStartRow().toInt32();
1284                      if ( (startCol > 0) && (startRow > 0) )
1285                      {
1286 
1287                         // field are one based; hence, the - 1.
1288                         shift.x = (startCol-1) *
1289                            hdr->getNumberOfPixelsPerBlockHoriz();
1290                         shift.y = (startRow-1) *
1291                            hdr->getNumberOfPixelsPerBlockVert();
1292                      }
1293                      if(shift.x > 0 ||
1294                         shift.y > 0)
1295                      {
1296                         transform = new ossim2dTo2dShiftTransform(shift);
1297                      }
1298                   }
1299                }
1300             }
1301 
1302          } // matches: if (hdr)
1303 
1304          if ( transform.valid() )
1305          {
1306             result->setTransform( transform.get() );
1307          }
1308          //else
1309          //{
1310          //   ossimImageGeometryRegistry::instance()->createTransform(this);
1311          //}
1312 
1313 
1314       } // matches: if ( !result->getTransform() )
1315 
1316       if ( !result->getProjection() )
1317       {
1318          ossimRefPtr<ossimProjection> proj =
1319             ossimProjectionFactoryRegistry::instance()->
1320                createProjection(this);
1321          if ( proj.valid() )
1322          {
1323             result->setProjection( proj.get() );
1324          }
1325          //else
1326          //{
1327          //   ossimImageGeometryRegistry::instance()->createProjection(this);
1328          //}
1329 
1330       }
1331 
1332    } // matches: if (result)
1333 
1334    if (traceDebug())
1335    {
1336       ossimNotify(ossimNotifyLevel_DEBUG)
1337          << "ossimNitfTileSource::createImageGeometry DEBUG:\n";
1338 
1339       if (result)
1340       {
1341          result->print(ossimNotify(ossimNotifyLevel_DEBUG)) << "\n";
1342       }
1343    }
1344 
1345    return result;
1346 }
1347 #endif
1348 
initializeImageRect()1349 bool ossimNitfTileSource::initializeImageRect()
1350 {
1351    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
1352    if (!hdr)
1353    {
1354       theImageRect.makeNan();
1355       return false;
1356    }
1357 
1358    theBlockImageRect = hdr->getBlockImageRect();
1359    theImageRect      = hdr->getImageRect();
1360 
1361    if (traceDebug())
1362    {
1363       ossimIpt iloc;
1364       hdr->getImageLocation(iloc); // for temp debug (drb)
1365       ossimNotify(ossimNotifyLevel_DEBUG)
1366          << "ossimNitfTileSource::initializeImageRect DEBUG:"
1367          << "\noffset from ILOC field:  " << iloc
1368          << "\nImage Rect:              " << theImageRect
1369          << "\nBlock rect:              " << theBlockImageRect
1370          << endl;
1371    }
1372    return true;
1373 }
1374 
initializeCacheSize()1375 void ossimNitfTileSource::initializeCacheSize()
1376 {
1377    theCacheSize.x = 0;
1378    theCacheSize.y = 0;
1379 
1380    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
1381    if (!hdr)
1382    {
1383       return;
1384    }
1385    switch (theReadMode)
1386    {
1387       case READ_BIB_BLOCK:
1388       case READ_BIP_BLOCK:
1389       case READ_BIR_BLOCK:
1390       case READ_BSQ_BLOCK:
1391       case READ_JPEG_BLOCK:
1392          theCacheSize.x = hdr->getNumberOfPixelsPerBlockHoriz();
1393          theCacheSize.y = hdr->getNumberOfPixelsPerBlockVert();
1394          break;
1395 
1396       case READ_BIB:
1397       case READ_BIP:
1398       case READ_BIR:
1399          theCacheSize.x = hdr->getNumberOfPixelsPerBlockHoriz();
1400          theCacheSize.y = hdr->getNumberOfPixelsPerBlockVert();
1401          if(getNumberOfBlocks() == 1)
1402          {
1403             // is it larger than 4kx4k then we will for now error out so
1404             // we can't continue
1405             if((theCacheSize.x*theCacheSize.y) > 16777216)
1406             {
1407                if(traceDebug())
1408                {
1409                   ossimNotify(ossimNotifyLevel_WARN) << "We currently do not support single blocks with block sizes larger than 4kx4k";
1410                   ossimNotify(ossimNotifyLevel_WARN) << "Current size is: " << theCacheSize << std::endl;
1411                }
1412                theCacheSize.x = 0;
1413                theCacheSize.y = 0;
1414             }
1415          }
1416 //          theCacheSize.x = getNumberOfSamples(0);
1417 //          theCacheSize.y = getTileHeight();
1418 //          if(theCacheSize.y > hdr->getNumberOfPixelsPerBlockVert())
1419 //          {
1420 //             theCacheSize.y = hdr->getNumberOfPixelsPerBlockVert();
1421 //          }
1422          break;
1423 
1424       default:
1425          break;
1426    }
1427 
1428    if (traceDebug())
1429    {
1430       ossimNotify(ossimNotifyLevel_DEBUG)
1431          << "ossimNitfTileSource::initializeCacheSize DEBUG:"
1432          << "\nCache size:  " << theCacheSize
1433          << endl;
1434    }
1435 }
1436 
initializeCacheTileInterLeaveType()1437 void ossimNitfTileSource::initializeCacheTileInterLeaveType()
1438 {
1439    theCacheTileInterLeaveType = OSSIM_INTERLEAVE_UNKNOWN;
1440 
1441    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
1442    if (!hdr)
1443    {
1444       return;
1445    }
1446 
1447    switch (theReadMode)
1448    {
1449       case READ_BIB_BLOCK:
1450       case READ_BSQ_BLOCK:
1451       case READ_BIB:
1452       case READ_JPEG_BLOCK:
1453          theCacheTileInterLeaveType = OSSIM_BSQ;
1454          break;
1455 
1456       case READ_BIP_BLOCK:
1457       case READ_BIP:
1458          theCacheTileInterLeaveType = OSSIM_BIP;
1459          break;
1460 
1461       case READ_BIR_BLOCK:
1462       case READ_BIR:
1463          theCacheTileInterLeaveType = OSSIM_BIL;
1464          break;
1465 
1466       default:
1467          break;
1468    }
1469 
1470    if (traceDebug())
1471    {
1472       ossimInterleaveTypeLut lut;
1473 
1474       ossimNotify(ossimNotifyLevel_DEBUG)
1475          << "ossimNitfTileSource::initializeCacheTileInterLeaveType DEBUG:"
1476          << "\nCache tile interleave type:  "
1477          << lut.getEntryString(theCacheTileInterLeaveType)
1478          << endl;
1479    }
1480 }
1481 
initializeCacheTile()1482 void ossimNitfTileSource::initializeCacheTile()
1483 {
1484    theCacheTile = ossimImageDataFactory::instance()->create(
1485       this,
1486       theScalarType,
1487       theNumberOfOutputBands,
1488       theCacheSize.x,
1489       theCacheSize.y);
1490 
1491    theCacheTile->initialize();
1492 }
1493 
initializeCompressedBuf()1494 void ossimNitfTileSource::initializeCompressedBuf()
1495 {
1496    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
1497    if (!hdr)
1498    {
1499       return;
1500    }
1501 
1502    if( (hdr->getRepresentation().upcase().contains("LUT")) ||
1503        ( isVqCompressed(hdr->getCompressionCode()) ) )
1504    {
1505       theCompressedBuf.resize(theReadBlockSizeInBytes);
1506       std::fill(theCompressedBuf.begin(), theCompressedBuf.end(), '\0');
1507    }
1508 }
1509 
initializeOutputTile()1510 void ossimNitfTileSource::initializeOutputTile()
1511 {
1512    //---
1513    // Make the output tile.  This implementation will use default tile size.
1514    ossimImageDataFactory* idf = ossimImageDataFactory::instance();
1515    theTile = idf->create(this, this);
1516    theTile->initialize();
1517 }
1518 
initializeLut()1519 void ossimNitfTileSource::initializeLut()
1520 {
1521    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
1522    if (hdr)
1523    {
1524       if ( hdr->hasLut() )
1525       {
1526          //---
1527          // NOTE: Only band 0 ??? (drb)
1528          //---
1529          theLut = theNitfImageHeader[theCurrentEntry]->createLut(0);
1530       }
1531    }
1532 }
1533 
getTile(const ossimIrect & tileRect,ossim_uint32 resLevel)1534 ossimRefPtr<ossimImageData> ossimNitfTileSource::getTile(
1535    const  ossimIrect& tileRect, ossim_uint32 resLevel)
1536 {
1537    // This tile source bypassed, or invalid res level, return a blank tile.
1538    if(!isSourceEnabled() || !isOpen() || !isValidRLevel(resLevel))
1539    {
1540       return ossimRefPtr<ossimImageData>();
1541    }
1542 
1543    if ( !theTile.valid() )
1544    {
1545       // First call to getTile:
1546       allocateBuffers();
1547       if ( !theTile.valid() )
1548       {
1549          return theTile;
1550       }
1551    }
1552 
1553    // Rectangle must be set prior to getOverviewTile call.
1554    theTile->setImageRectangle(tileRect);
1555 
1556    if (resLevel)
1557    {
1558       if ( getOverviewTile(resLevel, theTile.get() ) )
1559       {
1560          return theTile;
1561       }
1562    }
1563 
1564    ossim_uint32 level = resLevel;
1565    if (theStartingResLevel)  // Used as overview.
1566    {
1567       if (theStartingResLevel <= resLevel)
1568       {
1569          //---
1570          // Adjust the level to be relative to the reader using this as
1571          // overview.
1572          //---
1573          level -= theStartingResLevel;
1574       }
1575    }
1576 
1577    //---
1578    // See if the whole tile is going to be filled, if not, start out with
1579    // a blank tile so data from a previous load gets wiped out.
1580    //---
1581    if ( !tileRect.completely_within(theImageRect) )
1582    {
1583       // Start with a blank tile.
1584       theTile->makeBlank();
1585    }
1586 
1587    //---
1588    // See if any point of the requested tile is in the image.
1589    //---
1590    if ( tileRect.intersects(theBlockImageRect) )
1591    {
1592       ossimIrect clipRect = tileRect.clipToRect(theImageRect);
1593 
1594       // See if the requested clip rect is already in the cache tile.
1595       if ( (clipRect.completely_within(theCacheTile->getImageRectangle()))&&
1596            (theCacheTile->getDataObjectStatus() != OSSIM_EMPTY)&&
1597            (theCacheTile->getBuf()))
1598       {
1599          //---
1600          // Note: Clip the cache tile(nitf block) to the image clipRect since
1601          // there are nitf blocks that go beyond the image dimensions, i.e.,
1602          // edge blocks.
1603          //---
1604          ossimIrect cr =
1605                theCacheTile->getImageRectangle().clipToRect(clipRect);
1606          theTile->loadTile(theCacheTile->getBuf(),
1607                            theCacheTile->getImageRectangle(),
1608                            cr,
1609                            theCacheTileInterLeaveType);
1610          //---
1611          // Validate the tile.  This will set the status to full, partial
1612          // or empty.  Must be performed if any type of combining is to be
1613          // performed down the chain.
1614          //---
1615          theTile->validate();
1616       }
1617       else
1618       {
1619          if ( loadTile(clipRect) == true )
1620          {
1621             //---
1622             // Validate the tile.  This will set the status to full, partial
1623             // or empty.  Must be performed if any type of combining is to be
1624             // performed down the chain.
1625             //---
1626             theTile->validate();
1627          }
1628          else
1629          {
1630             //---
1631             // Commented setting error status out for jpeg data that had several bad
1632             // blocks but the rest of the image was good.  If the error status is
1633             // set the overview builder stops! (drb) 10 May 2013
1634             // Flag an error for callers:
1635             // setErrorStatus();
1636 
1637             ossimNotify(ossimNotifyLevel_WARN)
1638                << __FILE__ << " " << __LINE__
1639                << " loadTile failed!"
1640                << std::endl;
1641 
1642             theTile->makeBlank(); // loadTile failed...
1643          }
1644       }
1645    } // End of if ( tileRect.intersects(image_rect) )
1646 
1647    return theTile;
1648 }
1649 
loadTile(const ossimIrect & clipRect)1650 bool ossimNitfTileSource::loadTile(const ossimIrect& clipRect)
1651 {
1652    ossimIrect zbClipRect  = clipRect;
1653 
1654    const ossim_uint32 BLOCK_HEIGHT = theCacheSize.y;
1655    const ossim_uint32 BLOCK_WIDTH  = theCacheSize.x;
1656 
1657    zbClipRect.stretchToTileBoundary(ossimIpt(BLOCK_WIDTH, BLOCK_HEIGHT));
1658 
1659    //---
1660    // Shift the upper left corner of the "clip_rect" to the an even nitf
1661    // block boundry.
1662    //---
1663    ossimIpt nitfBlockOrigin = zbClipRect.ul();
1664 
1665    // Vertical block loop.
1666    ossim_int32 y = nitfBlockOrigin.y;
1667    while (y < zbClipRect.lr().y)
1668    {
1669       // Horizontal block loop.
1670       ossim_int32 x = nitfBlockOrigin.x;
1671       while (x < zbClipRect.lr().x)
1672       {
1673          if ( loadBlockFromCache(x, y, clipRect) == false )
1674          {
1675             if ( loadBlock(x, y) )
1676             {
1677                //---
1678                // Note: Clip the cache tile(nitf block) to the image clipRect
1679                // since there are nitf blocks that go beyond the image
1680                // dimensions, i.e., edge blocks.
1681                //---
1682                ossimIrect cr =
1683                   theCacheTile->getImageRectangle().clipToRect(clipRect);
1684 
1685                theTile->loadTile(theCacheTile->getBuf(),
1686                                  theCacheTile->getImageRectangle(),
1687                                  cr,
1688                                  theCacheTileInterLeaveType);
1689             }
1690             else
1691             {
1692                // Error loading...
1693                return false;
1694             }
1695          }
1696 
1697          x += BLOCK_WIDTH; // Go to next block.
1698       }
1699 
1700       y += BLOCK_HEIGHT; // Go to next row of blocks.
1701    }
1702 
1703    return true;
1704 }
1705 
loadBlockFromCache(ossim_uint32 x,ossim_uint32 y,const ossimIrect & clipRect)1706 bool ossimNitfTileSource::loadBlockFromCache(ossim_uint32 x, ossim_uint32 y,
1707                                              const ossimIrect& clipRect)
1708 {
1709    bool result = false;
1710 
1711    if (theCacheEnabledFlag)
1712    {
1713       //---
1714       // The origin set in the cache tile must have the sub image offset in it
1715       // since "theTile" is relative to any sub image offset.  This is so that
1716       // "theTile->loadTile(theCacheTile)" will work.
1717       //---
1718       ossimIpt origin(x, y);
1719 
1720       ossimRefPtr<ossimImageData> tempTile =
1721          ossimAppFixedTileCache::instance()->getTile(theCacheId, origin);
1722       if (tempTile.valid())
1723       {
1724          //---
1725          // Note: Clip the cache tile(nitf block) to the image clipRect since
1726          // there are nitf blocks that go beyond the image dimensions, i.e.,
1727          // edge blocks.
1728          //---
1729          ossimIrect cr =
1730             tempTile->getImageRectangle().clipToRect(clipRect);
1731 
1732          theTile->loadTile(tempTile.get()->getBuf(),
1733                            tempTile->getImageRectangle(),
1734                            cr,
1735                            theCacheTileInterLeaveType);
1736          result = true;
1737       }
1738    }
1739 
1740    return result;
1741 }
1742 
loadBlock(ossim_uint32 x,ossim_uint32 y)1743 bool ossimNitfTileSource::loadBlock(ossim_uint32 x, ossim_uint32 y)
1744 {
1745 #if 0
1746    if (traceDebug())
1747    {
1748       ossimNotify(ossimNotifyLevel_DEBUG)
1749          << "ossimNitfTileSource::loadBlock DEBUG:"
1750          << "  x:  " << x << " y:  " << y << endl;
1751    }
1752 #endif
1753 
1754    //---
1755    // The origin set in the cache tile must have the sub image offset in it
1756    // since "theTile" is relative to any sub image offset.  This is so that
1757    // "theTile->loadTile(theCacheTile)" will work.
1758    //---
1759    ossimIpt origin(x, y);
1760 
1761    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
1762    theCacheTile->setOrigin(origin);
1763    ossim_uint32 readSize = theReadBlockSizeInBytes;
1764    if(!theCacheTile->getImageRectangle().completely_within(theBlockImageRect))
1765    {
1766       readSize = getPartialReadSize(origin);
1767    }
1768    if((hdr->hasBlockMaskRecords())||
1769       (readSize != theReadBlockSizeInBytes))
1770    {
1771       theCacheTile->makeBlank();
1772    }
1773 
1774    switch (theReadMode)
1775    {
1776       case READ_BIR:
1777       case READ_BIR_BLOCK:
1778       case READ_BIP:
1779       case READ_BIP_BLOCK:
1780       {
1781          std::streamoff p;
1782          if(getPosition(p, x, y, 0))
1783          {
1784             theFileStr->seekg(p, ios::beg);
1785             char* buf = (char*)(theCacheTile->getBuf());
1786             if (!theFileStr->read(buf, readSize))
1787             {
1788                theFileStr->clear();
1789                ossimNotify(ossimNotifyLevel_FATAL)
1790                   << "ossimNitfTileSource::loadBlock BIP Read Error!"
1791                   << "\nReturning error..." << endl;
1792                theErrorStatus = ossimErrorCodes::OSSIM_ERROR;
1793 
1794                return false;
1795             }
1796          }
1797          break;
1798       }
1799       case READ_BSQ_BLOCK:
1800       case READ_BIB_BLOCK:
1801       case READ_BIB:
1802       {
1803          //---
1804          // NOTE:
1805          // With some of these types we could do one read and get all bands.
1806          // The reads are done per for future enabling on band selection
1807          // at the image handler level.
1808          //---
1809          for (ossim_uint32 band = 0; band < theNumberOfInputBands; ++band)
1810          {
1811             ossim_uint8* buf =0;
1812             if(isVqCompressed(hdr->getCompressionCode())||
1813                hdr->getRepresentation().upcase().contains("LUT"))
1814             {
1815                buf = (ossim_uint8*)&(theCompressedBuf.front());
1816             }
1817             else
1818             {
1819                buf = (ossim_uint8*)(theCacheTile->getBuf(band));
1820             }
1821             std::streamoff p;
1822             if(getPosition(p, x, y, band))
1823             {
1824                theFileStr->seekg(p, ios::beg);
1825                if (!theFileStr->read((char*)buf, readSize))
1826                {
1827                   theFileStr->clear();
1828                   ossimNotify(ossimNotifyLevel_FATAL)
1829                      << "ossimNitfTileSource::loadBlock Read Error!"
1830                      << "\nReturning error..." << endl;
1831                   theErrorStatus = ossimErrorCodes::OSSIM_ERROR;
1832                   return false;
1833                }
1834                else if(hdr->getCompressionCode() == "C4")
1835                {
1836                   vqUncompressC4(theCacheTile,
1837                                  (ossim_uint8*)&(theCompressedBuf.front()));
1838                }
1839 
1840                else if(hdr->getCompressionCode() == "M4")
1841                {
1842                   vqUncompressM4(theCacheTile,
1843                                  (ossim_uint8*)&(theCompressedBuf.front()));
1844                }
1845                else if(hdr->getRepresentation().upcase().contains("LUT"))
1846                {
1847                   lutUncompress(theCacheTile,
1848                                 (ossim_uint8*)&(theCompressedBuf.front()));
1849                }
1850             }
1851          }
1852          break;
1853       }
1854       case READ_JPEG_BLOCK:
1855       {
1856          if (uncompressJpegBlock(x, y) == false)
1857          {
1858             theCacheTile->makeBlank();
1859             theFileStr->clear();
1860             ossimNotify(ossimNotifyLevel_FATAL)
1861                << "ossimNitfTileSource::loadBlock Read Error!"
1862                << "\nReturning error..." << endl;
1863             return false;
1864          }
1865          break;
1866       }
1867       default:
1868          break;
1869    }
1870 
1871    if(thePackedBitsFlag)
1872    {
1873       explodePackedBits(theCacheTile);
1874    }
1875    // Check for swap bytes.
1876    if (theSwapBytesFlag)
1877    {
1878       ossimEndian swapper;
1879       swapper.swap(theScalarType,
1880                    theCacheTile->getBuf(),
1881                    theCacheTile->getSize());
1882    }
1883 
1884    if ( !isVqCompressed(hdr->getCompressionCode()) )
1885    {
1886       convertTransparentToNull(theCacheTile);
1887    }
1888 
1889    // Set the origin of the cache tile.
1890    theCacheTile->validate();
1891    if (theCacheEnabledFlag)
1892    {
1893       // Add it to the cache for the next time.
1894       ossimAppFixedTileCache::instance()->addTile(theCacheId, theCacheTile);
1895    }
1896 
1897    return true;
1898 }
1899 
explodePackedBits(ossimRefPtr<ossimImageData> packedBuffer) const1900 void ossimNitfTileSource::explodePackedBits(ossimRefPtr<ossimImageData> packedBuffer)const
1901 {
1902    ossim_uint8* tempBuf = new ossim_uint8[packedBuffer->getSizePerBandInBytes()];
1903    ossim_uint32 idx      = 0;
1904    ossim_uint32 bandIdx  = 0;
1905    ossim_uint32 h = packedBuffer->getHeight();
1906    ossim_uint32 w = packedBuffer->getWidth();
1907    ossim_uint32 maxIdx = w*h;
1908    ossim_uint32 bandCount = packedBuffer->getNumberOfBands();
1909    switch(packedBuffer->getScalarType())
1910    {
1911       case OSSIM_UINT8:
1912       {
1913 
1914          ossim_uint8* outputBuf = (ossim_uint8*)tempBuf;
1915          for(bandIdx = 0; bandIdx < bandCount; ++bandIdx)
1916          {
1917             ossimPackedBits packedBits((ossim_uint8*)packedBuffer->getBuf(bandIdx),
1918                                            getCurrentImageHeader()->getBitsPerPixelPerBand());
1919             for(idx = 0; idx < maxIdx; ++idx)
1920             {
1921                *outputBuf = (ossim_uint8)packedBits.getValueAsUint32(idx);
1922                ++outputBuf;
1923             }
1924 
1925             memcpy((char*)packedBuffer->getBuf(bandIdx),
1926                    (char*)tempBuf,
1927                    theCacheTile->getSizePerBandInBytes()*bandCount);
1928          }
1929          break;
1930       }
1931       case OSSIM_UINT16:
1932       {
1933 
1934          ossim_uint16* outputBuf = (ossim_uint16*)tempBuf;
1935          for(bandIdx = 0; bandIdx < bandCount; ++bandIdx)
1936          {
1937             ossimPackedBits packedBits((ossim_uint8*)packedBuffer->getBuf(bandIdx),
1938                                            getCurrentImageHeader()->getBitsPerPixelPerBand());
1939             for(idx = 0; idx < maxIdx; ++idx)
1940             {
1941                *outputBuf = (ossim_uint16)packedBits.getValueAsUint32(idx);
1942                ++outputBuf;
1943             }
1944 
1945             memcpy((char*)packedBuffer->getBuf(bandIdx),
1946                    (char*)tempBuf,
1947                    theCacheTile->getSizePerBandInBytes()*bandCount);
1948          }
1949          break;
1950       }
1951       case OSSIM_FLOAT:
1952       {
1953          ossim_float32* outputBuf = (ossim_float32*)tempBuf;
1954          for(bandIdx = 0; bandIdx < bandCount; ++bandIdx)
1955          {
1956             ossimPackedBits packedBits((ossim_uint8*)packedBuffer->getBuf(bandIdx),
1957                                            getCurrentImageHeader()->getBitsPerPixelPerBand());
1958             for(idx = 0; idx < maxIdx; ++idx)
1959             {
1960                *outputBuf = (ossim_float32)packedBits.getValueAsUint32(idx);
1961                ++outputBuf;
1962             }
1963 
1964             memcpy((char*)packedBuffer->getBuf(bandIdx),
1965                    (char*)tempBuf,
1966                    theCacheTile->getSizePerBandInBytes()*bandCount);
1967          }
1968          break;
1969       }
1970       default:
1971       {
1972          break;
1973       }
1974    }
1975    delete [] tempBuf;
1976 }
1977 
convertTransparentToNull(ossimRefPtr<ossimImageData> tile) const1978 void ossimNitfTileSource::convertTransparentToNull(ossimRefPtr<ossimImageData> tile)const
1979 {
1980    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
1981 
1982    if(!hdr||!tile) return;
1983 
1984    if(!tile->getBuf()) return;
1985    ossimIpt tempOrigin = tile->getOrigin();
1986    ossim_uint32 blockNumber = getBlockNumber(tempOrigin);
1987    ossim_uint32 numberOfBands = tile->getNumberOfBands();
1988    ossim_uint32 band = 0;
1989 
1990    if(hdr->hasPadPixelMaskRecords())
1991    {
1992       if(hdr->hasTransparentCode())
1993       {
1994          ossim_uint32 idx = 0;
1995          ossim_uint32 maxIdx = tile->getWidth()*tile->getHeight();
1996 
1997          for (band = 0; band < numberOfBands; ++band)
1998          {
1999             if(hdr->getPadPixelMaskRecordOffset(blockNumber,
2000                                                 band)!=0xffffffff)
2001             {
2002                switch(tile->getScalarType())
2003                {
2004                   case OSSIM_UINT8:
2005                   {
2006                      ossim_uint8 transparentValue = hdr->getTransparentCode();
2007                      ossim_uint8* buf = (ossim_uint8*)tile->getBuf(band);
2008                      ossim_uint8 nullPix = (ossim_uint8)tile->getNullPix(band);
2009                      for(idx = 0; idx < maxIdx; ++idx)
2010                      {
2011                         if(*buf == transparentValue)
2012                         {
2013                            *buf = nullPix;
2014                         }
2015                         ++buf;
2016                      }
2017                      break;
2018                   }
2019                   case OSSIM_USHORT11:
2020                   case OSSIM_USHORT12:
2021                   case OSSIM_USHORT13:
2022                   case OSSIM_USHORT14:
2023                   case OSSIM_USHORT15:
2024                   case OSSIM_UINT16:
2025                   {
2026                      ossim_uint16 transparentValue = hdr->getTransparentCode();
2027                      ossim_uint16* buf = (ossim_uint16*)tile->getBuf(band);
2028                      ossim_uint16 nullPix = (ossim_uint16)tile->getNullPix(band);
2029                      for(idx = 0; idx < maxIdx; ++idx)
2030                      {
2031                         if(*buf == transparentValue)
2032                         {
2033                            *buf = nullPix;
2034                         }
2035                         ++buf;
2036                      }
2037                      break;
2038                   }
2039                   case OSSIM_SINT16:
2040                   {
2041                      ossim_sint16 transparentValue = hdr->getTransparentCode();
2042                      ossim_sint16* buf = (ossim_sint16*)tile->getBuf(band);
2043                      ossim_sint16 nullPix = (ossim_sint16)tile->getNullPix(band);
2044                      for(idx = 0; idx < maxIdx; ++idx)
2045                      {
2046                         if(*buf == transparentValue)
2047                         {
2048                            *buf = nullPix;
2049                         }
2050                         ++buf;
2051                      }
2052                      break;
2053                   }
2054                   default:
2055                   {
2056                      break;
2057                   }
2058                }
2059             }
2060          }
2061       }
2062    }
2063 }
2064 
2065 
getMinPixelValue(ossim_uint32 band) const2066 double ossimNitfTileSource::getMinPixelValue(ossim_uint32 band)const
2067 {
2068    double result = ossimImageHandler::getMinPixelValue(band);
2069 
2070    if(thePackedBitsFlag)
2071    {
2072       if(result < 1.0) result = 1.0;
2073    }
2074 
2075    return result;
2076 }
2077 
getMaxPixelValue(ossim_uint32 band) const2078 double ossimNitfTileSource::getMaxPixelValue(ossim_uint32 band)const
2079 {
2080    double result = ossimImageHandler::getMaxPixelValue(band);
2081 
2082    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
2083    if(hdr)
2084    {
2085       if(thePackedBitsFlag)
2086       {
2087          double test = 1<<(hdr->getBitsPerPixelPerBand());
2088 
2089          if(result > test) result = test;
2090       }
2091       else
2092       {
2093          ossim_int32 bitsPerPixel = hdr->getActualBitsPerPixelPerBand();
2094          switch (bitsPerPixel)
2095          {
2096             case 11:
2097             {
2098                if (result > 2047.0)
2099                {
2100                   result = 2047.0;
2101                }
2102                break;
2103             }
2104             case 12:
2105             {
2106                if (result > 4095.0)
2107                {
2108                   result = 4095.0;
2109                }
2110                break;
2111             }
2112             default:
2113                break;
2114          }
2115       }
2116    }
2117 
2118    return result;
2119 }
2120 
getNullPixelValue(ossim_uint32 band) const2121 double ossimNitfTileSource::getNullPixelValue(ossim_uint32 band)const
2122 {
2123    double result = ossimImageHandler::getNullPixelValue(band);
2124 
2125    if(thePackedBitsFlag)
2126    {
2127       if((result < 0) ||
2128          (result > getMaxPixelValue(band)))
2129          {
2130             result = 0.0;
2131          }
2132    }
2133 
2134 
2135    return result;
2136 }
2137 
2138 
getPosition(std::streamoff & streamPosition,ossim_uint32 x,ossim_uint32 y,ossim_uint32 band) const2139 bool ossimNitfTileSource::getPosition(std::streamoff& streamPosition,
2140                                       ossim_uint32 x,
2141                                       ossim_uint32 y,
2142                                       ossim_uint32 band) const
2143 {
2144    //
2145    // NOTE:  "theCacheSize is always relative to a block size except in
2146    // the case where a block is the entire image.
2147    //
2148    streamPosition = 0;
2149 
2150    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
2151    if (!hdr)
2152    {
2153       return streamPosition;
2154    }
2155 
2156    ossim_uint64 blockNumber = getBlockNumber(ossimIpt(x,y));
2157 
2158 #if 0
2159    cout << "ossimNitfTileSource::getPosition blockNumber:  "
2160         << blockNumber << endl;
2161 #endif
2162 
2163    streamPosition = (std::streamoff)hdr->getDataLocation(); // Position to first block.
2164    if(hdr->hasBlockMaskRecords())
2165    {
2166       ossim_uint64 blockOffset = hdr->getBlockMaskRecordOffset(blockNumber,
2167                                                                band);
2168       if(blockOffset == 0xffffffff)
2169       {
2170          return false;
2171       }
2172       streamPosition += blockOffset;
2173    }
2174 
2175    switch (theReadMode)
2176    {
2177       case READ_BIB_BLOCK:
2178       {
2179          if(!hdr->hasBlockMaskRecords())
2180          {
2181             streamPosition +=
2182             (std::streamoff)((ossim_uint64)blockNumber *
2183                 (ossim_uint64)getBlockOffset()) +
2184                ((ossim_uint64)getBandOffset() * band);
2185          }
2186          else
2187          {
2188             streamPosition += (std::streamoff)((ossim_uint64)getBandOffset() * (ossim_uint64)band);
2189 
2190          }
2191          break;
2192       }
2193 
2194       case READ_BIB:
2195       {
2196          streamPosition +=
2197          (std::streamoff) ((ossim_uint64)blockNumber * (ossim_uint64)theReadBlockSizeInBytes)+
2198             ((ossim_uint64)getBandOffset() * (ossim_uint64)band);
2199          break;
2200       }
2201 
2202       case READ_BSQ_BLOCK:
2203       {
2204 
2205          if(!hdr->hasBlockMaskRecords())
2206          {
2207             streamPosition += (std::streamoff)((ossim_uint64)blockNumber *
2208                                                (ossim_uint64)getBlockOffset()) +
2209                                               ((ossim_uint64)getBandOffset() *
2210                                                (ossim_uint64)band);
2211          }
2212 
2213          break;
2214       }
2215       case READ_JPEG_BLOCK:
2216       {
2217          streamPosition += (std::streamoff)((ossim_uint64)blockNumber * (ossim_uint64)theReadBlockSizeInBytes);
2218          break;
2219       }
2220       default:
2221       {
2222          if(!hdr->hasBlockMaskRecords())
2223          {
2224             streamPosition += (std::streamoff)((ossim_uint64)blockNumber*(ossim_uint64)getBlockOffset());
2225          }
2226 
2227          break;
2228       }
2229    }
2230 
2231    return true;
2232 }
2233 
getBandOffset() const2234 std::streampos ossimNitfTileSource::getBandOffset() const
2235 {
2236    std::streampos bandOffset = 0;
2237 
2238    switch (theReadMode)
2239    {
2240       case READ_BIB_BLOCK:
2241       case READ_BIP_BLOCK:
2242       case READ_BIR_BLOCK:
2243       case READ_BIB:
2244       case READ_BIP:
2245       case READ_BIR:
2246          bandOffset = theBlockSizeInBytes;
2247          break;
2248 
2249       case READ_BSQ_BLOCK:
2250          bandOffset = getNumberOfBlocks() * theBlockSizeInBytes;
2251          break;
2252 
2253       default:
2254          break;
2255    }
2256 
2257    return bandOffset;
2258 }
2259 
getBlockOffset() const2260 std::streampos ossimNitfTileSource::getBlockOffset() const
2261 {
2262    std::streampos blockOffset = 0;
2263    std::streampos blockSizeInBytes = 0;
2264    if (getNumberOfBlocks() == 1)
2265    {
2266       blockSizeInBytes = theReadBlockSizeInBytes;
2267    }
2268    else
2269    {
2270       blockSizeInBytes = theBlockSizeInBytes;
2271    }
2272 
2273    switch (theReadMode)
2274    {
2275       case READ_BIB_BLOCK:
2276       case READ_BIB:
2277          // Band interleaved by block.
2278          blockOffset = blockSizeInBytes * theNumberOfInputBands;
2279          break;
2280 
2281       case READ_BIR_BLOCK:
2282       case READ_BSQ_BLOCK:
2283       case READ_BIP_BLOCK:
2284       case READ_BIP:
2285       case READ_BIR:
2286          // Blocks side by side.
2287          blockOffset = blockSizeInBytes;
2288          break;
2289       case READ_JPEG_BLOCK:
2290         blockSizeInBytes = theReadBlockSizeInBytes;
2291         break;
2292 
2293       default:
2294          break;
2295    }
2296 
2297    return blockOffset;
2298 }
2299 
getNumberOfBlocks() const2300 ossim_uint32 ossimNitfTileSource::getNumberOfBlocks() const
2301 {
2302    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
2303    if (!hdr)
2304    {
2305       return 0;
2306    }
2307 
2308    return static_cast<ossim_uint32>( hdr->getNumberOfBlocksPerRow() *
2309                                      hdr->getNumberOfBlocksPerCol() );
2310 }
2311 
loadState(const ossimKeywordlist & kwl,const char * prefix)2312 bool ossimNitfTileSource::loadState(const ossimKeywordlist& kwl,
2313                                     const char* prefix)
2314 {
2315    if ( !ossimImageHandler::loadState(kwl, prefix) )
2316    {
2317       if(traceDebug())
2318       {
2319          ossimNotify(ossimNotifyLevel_DEBUG)
2320             << "ossimNitfTileSource::loadState(kwl, prefix) DEBUG:"
2321             << "\nUnable to load, exiting..." << std::endl;
2322       }
2323       return false;
2324    }
2325 
2326    const char* lookup = kwl.find(prefix, "entry");
2327    if (lookup)
2328    {
2329       ossimString s(lookup);
2330       theCurrentEntry = s.toUInt32();
2331    }
2332 
2333    theOutputBandList.clear();
2334    ossimString bands = kwl.find(prefix, ossimKeywordNames::BANDS_KW);
2335    if (!bands.empty())
2336    {
2337       ossim::toSimpleVector(theOutputBandList, bands);
2338    }
2339 
2340    lookup = kwl.find(prefix,ossimKeywordNames::ENABLE_CACHE_KW);
2341    if (lookup)
2342    {
2343       ossimString s(lookup);
2344       theCacheEnabledFlag = s.toBool();
2345    }
2346 
2347    if(traceDebug())
2348    {
2349       ossimNotify(ossimNotifyLevel_DEBUG)
2350          << "ossimNitfTileSource::loadState(kwl, prefix) DEBUG:"
2351          << "\nCurrent entry:      " << theCurrentEntry
2352          << "\nCache enable flag:  " << theCacheEnabledFlag
2353          << std::endl;
2354    }
2355 
2356    return open();
2357 }
2358 
saveState(ossimKeywordlist & kwl,const char * prefix) const2359 bool ossimNitfTileSource::saveState(ossimKeywordlist& kwl,
2360                                     const char* prefix) const
2361 {
2362    // Add the entry number.
2363    kwl.add(prefix, "entry", theCurrentEntry, true);
2364 
2365    // Add the cache_enable flag.
2366    kwl.add(prefix, ossimKeywordNames::ENABLE_CACHE_KW, theCacheEnabledFlag, true);
2367 
2368    // Call the base class save state.
2369    return ossimImageHandler::saveState(kwl, prefix);
2370 }
2371 
getOutputScalarType() const2372 ossimScalarType ossimNitfTileSource::getOutputScalarType() const
2373 {
2374    return theScalarType;
2375 }
2376 
getTileWidth() const2377 ossim_uint32 ossimNitfTileSource::getTileWidth() const
2378 {
2379    ossim_uint32 result = 0;
2380    bool needDefault = false;
2381    if(!theCacheSize.hasNans()&& theCacheSize.x > 0)
2382    {
2383       result = theCacheSize.x;
2384       if(result >= getBoundingRect().width())
2385       {
2386          needDefault = true;
2387       }
2388    }
2389    else
2390    {
2391       needDefault = true;
2392    }
2393    if(needDefault)
2394    {
2395       ossimIpt tileSize;
2396       ossim::defaultTileSize(tileSize);
2397       result = static_cast<ossim_uint32>(tileSize.x);
2398    }
2399    return result;
2400 }
2401 
getTileHeight() const2402 ossim_uint32 ossimNitfTileSource::getTileHeight() const
2403 {
2404    ossim_uint32 result = 0;
2405    bool needDefault = false;
2406    if(!theCacheSize.hasNans()&& theCacheSize.y > 0)
2407    {
2408       result = theCacheSize.y;
2409       if(result >= getBoundingRect().height())
2410       {
2411          needDefault = true;
2412       }
2413    }
2414    else
2415    {
2416       needDefault = true;
2417    }
2418    if(needDefault)
2419    {
2420       ossimIpt tileSize;
2421       ossim::defaultTileSize(tileSize);
2422       result = static_cast<ossim_uint32>(tileSize.y);
2423    }
2424    return result;
2425 }
2426 
getNumberOfInputBands() const2427 ossim_uint32 ossimNitfTileSource::getNumberOfInputBands() const
2428 {
2429    return theNumberOfInputBands;
2430 }
2431 
getNumberOfOutputBands() const2432 ossim_uint32 ossimNitfTileSource::getNumberOfOutputBands() const
2433 {
2434    return theNumberOfOutputBands;
2435 }
2436 
getNumberOfLines(ossim_uint32 resLevel) const2437 ossim_uint32 ossimNitfTileSource::getNumberOfLines(ossim_uint32 resLevel) const
2438 {
2439    ossim_uint32 result = 0;
2440    if (resLevel == 0)
2441    {
2442       const ossimNitfImageHeader* hdr = getCurrentImageHeader();
2443       if (hdr)
2444       {
2445          result = hdr->getNumberOfRows();
2446       }
2447    }
2448    else if (theOverview.valid())
2449    {
2450       result = theOverview->getNumberOfLines(resLevel);
2451    }
2452    return result;
2453 }
2454 
getNumberOfSamples(ossim_uint32 resLevel) const2455 ossim_uint32 ossimNitfTileSource::getNumberOfSamples(ossim_uint32 resLevel) const
2456 {
2457    ossim_uint32 result = 0;
2458    if (resLevel == 0)
2459    {
2460       const ossimNitfImageHeader* hdr = getCurrentImageHeader();
2461       if (hdr)
2462       {
2463          result = hdr->getNumberOfCols();
2464       }
2465    }
2466    else if (theOverview.valid())
2467    {
2468       result = theOverview->getNumberOfSamples(resLevel);
2469    }
2470    return result;
2471 }
2472 
getBlockNumber(const ossimIpt & block_origin) const2473 ossim_uint32 ossimNitfTileSource::getBlockNumber(const ossimIpt& block_origin) const
2474 {
2475    ossim_uint32 blockNumber = 0;
2476 
2477    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
2478    if (!hdr)
2479    {
2480       return blockNumber;
2481    }
2482 
2483    ossim_uint32 blockY;
2484    ossim_uint32 blockX;
2485    blockX  = (block_origin.x /
2486               theCacheSize.x);
2487    blockY= (block_origin.y /
2488             theCacheSize.y);
2489 
2490    switch (theReadMode)
2491    {
2492       case READ_BIB_BLOCK:
2493       case READ_BIP_BLOCK:
2494       case READ_BIR_BLOCK:
2495       case READ_BSQ_BLOCK:
2496       case READ_JPEG_BLOCK:
2497       {
2498          blockNumber = ((blockY*hdr->getNumberOfBlocksPerRow()) + blockX);
2499          break;
2500       }
2501       case READ_BIB:
2502       case READ_BIP:
2503       case READ_BIR:
2504          //---
2505          // These read modes are for a single block image.  The cache size will
2506          // be set to the width of the image (block) by the height of one tile.
2507          //
2508          // This is to avoid reading an entire large image with a single block
2509          // into memory.
2510          //---
2511          blockNumber = blockY;
2512          break;
2513 
2514       default:
2515          break;
2516    }
2517    return blockNumber;
2518 }
2519 
getPartialReadSize(const ossimIpt &) const2520 ossim_uint32 ossimNitfTileSource::getPartialReadSize(const ossimIpt& /* blockOrigin */)const
2521 {
2522    ossim_uint32 result = 0;
2523    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
2524    if (!hdr)
2525    {
2526       return result;
2527    }
2528 
2529    if(theCacheTile->getImageRectangle().completely_within(theBlockImageRect))
2530    {
2531       return theReadBlockSizeInBytes;
2532    }
2533    ossimIrect clipRect = theCacheTile->getImageRectangle().clipToRect(theBlockImageRect);
2534 
2535    result = (theCacheSize.x*
2536              clipRect.height()*
2537              hdr->getBitsPerPixelPerBand())/8;
2538 
2539    switch (theReadMode)
2540    {
2541       case READ_BSQ_BLOCK:
2542       case READ_BIB_BLOCK:
2543       case READ_BIB:
2544       {
2545          // purposely left blank.  only hear for clarity.
2546          break;
2547       }
2548 
2549       case READ_BIP_BLOCK:
2550       case READ_BIR_BLOCK:
2551       case READ_BIP:
2552       case READ_BIR:
2553       {
2554          result *= theNumberOfInputBands;
2555          break;
2556       }
2557       default:
2558       {
2559          break;
2560       }
2561    }
2562    return result;
2563 }
2564 
isVqCompressed(const ossimString & compressionCode) const2565 bool ossimNitfTileSource::isVqCompressed(const ossimString& compressionCode)const
2566 {
2567    return((compressionCode == "C4")||
2568           (compressionCode == "M4"));
2569 }
2570 
2571 
getImageTileWidth() const2572 ossim_uint32 ossimNitfTileSource::getImageTileWidth() const
2573 {
2574    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
2575    ossim_uint32 tileSize = 0;
2576    if (!hdr)
2577    {
2578       return tileSize;
2579    }
2580    tileSize = hdr->getNumberOfPixelsPerBlockHoriz();
2581 
2582    if(tileSize >= getBoundingRect().width()) tileSize = 0;
2583    return tileSize;
2584 }
2585 
getImageTileHeight() const2586 ossim_uint32 ossimNitfTileSource::getImageTileHeight() const
2587 {
2588    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
2589    ossim_uint32 tileSize = 0;
2590    if (!hdr)
2591    {
2592       return tileSize;
2593    }
2594    tileSize = hdr->getNumberOfPixelsPerBlockVert();
2595    if(tileSize >= getBoundingRect().height()) tileSize = 0;
2596    return tileSize;
2597 }
2598 
getShortName() const2599 ossimString ossimNitfTileSource::getShortName()const
2600 {
2601    return ossimString("ossim_nitf");
2602 }
2603 
getLongName() const2604 ossimString ossimNitfTileSource::getLongName()const
2605 {
2606    return ossimString("ossim nitf reader");
2607 }
2608 
getCurrentEntry() const2609 ossim_uint32 ossimNitfTileSource::getCurrentEntry() const
2610 {
2611    return theCurrentEntry;
2612 }
2613 
getNumberOfEntries() const2614 ossim_uint32 ossimNitfTileSource::getNumberOfEntries() const
2615 {
2616    return (ossim_uint32)theEntryList.size();
2617 }
2618 
getEntryList(std::vector<ossim_uint32> & entryList) const2619 void ossimNitfTileSource::getEntryList(std::vector<ossim_uint32>& entryList)const
2620 {
2621    entryList = theEntryList;
2622 //    entryList.resize(theNumberOfImages);
2623 //    for (ossim_uint32 i = 0; i < theNumberOfImages; ++i)
2624 //    {
2625 //       entryList[i] = i;
2626 //    }
2627 }
2628 
setCurrentEntry(ossim_uint32 entryIdx)2629 bool ossimNitfTileSource::setCurrentEntry(ossim_uint32 entryIdx)
2630 {
2631    bool result = true;
2632    if (theCurrentEntry != entryIdx)
2633    {
2634       if ( isOpen() )
2635       {
2636          if ( entryIdx < theNumberOfImages )
2637          {
2638             // Clear the geometry.
2639             theGeometry = 0;
2640 
2641             // Must clear or openOverview will use last entries.
2642             theOverviewFile.clear();
2643 
2644             theCurrentEntry = entryIdx;
2645             theOutputBandList.clear();
2646             //---
2647             // Since we were previously open and the the entry has changed we
2648             // need to reinitialize some things.
2649             //---
2650             result = allocate();
2651             if (result)
2652             {
2653                completeOpen();
2654             }
2655          }
2656          else
2657          {
2658             result = false; // Entry index out of range.
2659          }
2660       }
2661       else
2662       {
2663          //---
2664          // Not open.
2665          // Allow this knowing that the parseFile will check for out of range.
2666          //---
2667          theCurrentEntry = entryIdx;
2668       }
2669    }
2670 
2671    if(result)
2672    {
2673       if(theNitfImageHeader[theCurrentEntry]->getRepresentation().contains("LUT"))
2674       {
2675          theLut = theNitfImageHeader[theCurrentEntry]->createLut(0);
2676       }
2677 
2678 
2679    }
2680    return result;
2681 }
2682 
getCacheEnabledFlag() const2683 bool ossimNitfTileSource::getCacheEnabledFlag() const
2684 {
2685    return theCacheEnabledFlag;
2686 }
2687 
setCacheEnabledFlag(bool flag)2688 void ossimNitfTileSource::setCacheEnabledFlag(bool flag)
2689 {
2690    if (flag != theCacheEnabledFlag)
2691    {
2692       // State of caching has changed...
2693 
2694       theCacheEnabledFlag = flag;
2695 
2696       if ( theCacheEnabledFlag) // Cache enabled.
2697       {
2698          theCacheId = ossimAppFixedTileCache::instance()->
2699             newTileCache(theBlockImageRect, theCacheSize);
2700       }
2701       else // Cache disabled...
2702       {
2703          // Clean out the cache if there was one.
2704          if (theCacheId != -1)
2705          {
2706             ossimAppFixedTileCache::instance()->deleteCache(theCacheId);
2707             theCacheId = -1;
2708          }
2709       }
2710    }
2711 }
2712 
getFileHeader() const2713 const ossimNitfFileHeader* ossimNitfTileSource::getFileHeader()const
2714 {
2715    if(theNitfFile.valid())
2716    {
2717       return theNitfFile->getHeader();
2718    }
2719 
2720    return 0;
2721 }
2722 
getFileHeader()2723 ossimNitfFileHeader* ossimNitfTileSource::getFileHeader()
2724 {
2725    if(theNitfFile.valid())
2726    {
2727       return theNitfFile->getHeader();
2728    }
2729 
2730    return 0;
2731 }
getNitfFile()2732 ossimNitfFile* ossimNitfTileSource::getNitfFile()
2733 {
2734    return theNitfFile.get();
2735 }
2736 
getNitfFile() const2737 const ossimNitfFile *ossimNitfTileSource::getNitfFile() const
2738 {
2739    return theNitfFile.get();
2740 }
2741 
getCurrentImageHeader() const2742 const ossimNitfImageHeader* ossimNitfTileSource::getCurrentImageHeader() const
2743 {
2744    if(theNitfImageHeader.size())
2745    {
2746       return theNitfImageHeader[theCurrentEntry].get();
2747    }
2748 
2749    return 0;
2750 }
2751 
getCurrentImageHeader()2752 ossimNitfImageHeader* ossimNitfTileSource::getCurrentImageHeader()
2753 {
2754    if(theNitfImageHeader.size())
2755    {
2756       return theNitfImageHeader[theCurrentEntry].get();
2757    }
2758 
2759    return 0;
2760 }
2761 
getRgbBandList(std::vector<ossim_uint32> & bandList) const2762 bool ossimNitfTileSource::getRgbBandList(std::vector<ossim_uint32>& bandList) const
2763 {
2764    bool result = false;
2765    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
2766    const ossim_uint32 BANDS = getNumberOfOutputBands();
2767    const ossim_uint32 BOGUS = 99999;
2768    if ( hdr && (BANDS > 2) )
2769    {
2770       ossim_uint32 r = BOGUS;
2771       ossim_uint32 g = BOGUS;
2772       ossim_uint32 b = BOGUS;
2773 
2774       for ( ossim_uint32 i = 0; i < BANDS; ++i )
2775       {
2776          const ossimRefPtr<ossimNitfImageBand> imageBand = hdr->getBandInformation( i );
2777          if ( imageBand.valid() )
2778          {
2779             ossimString os = imageBand->getBandRepresentation();
2780             os.trim(); // Remove trailing spaces.
2781             os.upcase();
2782             if ( os == "R" )
2783             {
2784                r = i;
2785             }
2786             else if ( os == "G" )
2787             {
2788                g = i;
2789             }
2790             else if ( os == "B" )
2791             {
2792                b = i;
2793             }
2794 
2795             if ( ( i > 1 ) &&
2796                  ( r != BOGUS ) && ( g != BOGUS ) && ( b != BOGUS ) )
2797             {
2798                result = true;
2799                bandList.resize(3);
2800                bandList[0] = r;
2801                bandList[1] = g;
2802                bandList[2] = b;
2803                break; // done...
2804             }
2805          }
2806       }
2807       // TODO: Derive rgb from ISUBCAT wavelength or other nitf tags.
2808    }
2809 
2810    return result;
2811 
2812 } // End: ossimNitfTileSource::getRgbBandList( ... )
2813 
setBoundingRectangle(const ossimIrect & imageRect)2814 void ossimNitfTileSource::setBoundingRectangle(const ossimIrect& imageRect)
2815 {
2816    theImageRect = imageRect;
2817    // now shift the internal block rect as well
2818    theBlockImageRect = (theBlockImageRect - theBlockImageRect.ul());
2819 }
2820 
getProperty(const ossimString & name) const2821 ossimRefPtr<ossimProperty> ossimNitfTileSource::getProperty(const ossimString& name)const
2822 {
2823    if (name == ossimKeywordNames::ENABLE_CACHE_KW)
2824    {
2825       ossimProperty* p = new ossimBooleanProperty(name, theCacheEnabledFlag);
2826       return ossimRefPtr<ossimProperty>(p);
2827    }
2828    else
2829    {
2830       if(theNitfFile.valid())
2831       {
2832          if(getFileHeader())
2833          {
2834             ossimRefPtr<ossimProperty> p = theNitfFile->getHeader()->getProperty(name);
2835             if(p.valid())
2836             {
2837                p->setReadOnlyFlag(true);
2838                return p;
2839             }
2840          }
2841       }
2842       const ossimNitfImageHeader* imageHeader = getCurrentImageHeader();
2843       if(imageHeader)
2844       {
2845          ossimRefPtr<ossimProperty> p = imageHeader->getProperty(name);
2846          if(p.valid())
2847          {
2848             p->setReadOnlyFlag(true);
2849             return p;
2850          }
2851       }
2852    }
2853 
2854    return ossimImageHandler::getProperty(name);
2855 }
2856 
setProperty(ossimRefPtr<ossimProperty> property)2857 void ossimNitfTileSource::setProperty(ossimRefPtr<ossimProperty> property)
2858 {
2859    if (!property) return;
2860 
2861    ossimString name = property->getName();
2862 
2863    if (name == ossimKeywordNames::ENABLE_CACHE_KW)
2864    {
2865       ossimBooleanProperty* obj = PTR_CAST(ossimBooleanProperty,
2866                                            property.get());
2867       if (obj)
2868       {
2869          setCacheEnabledFlag(obj->getBoolean());
2870       }
2871    }
2872    else
2873    {
2874       ossimImageHandler::setProperty(property);
2875    }
2876 }
2877 
getPropertyNames(std::vector<ossimString> & propertyNames) const2878 void ossimNitfTileSource::getPropertyNames(std::vector<ossimString>& propertyNames)const
2879 {
2880    ossimImageHandler::getPropertyNames(propertyNames);
2881    propertyNames.push_back(ossimKeywordNames::ENABLE_CACHE_KW);
2882    if(getFileHeader())
2883    {
2884       getFileHeader()->getPropertyNames(propertyNames);
2885    }
2886    const ossimNitfImageHeader* imageHeader = getCurrentImageHeader();
2887    if(imageHeader)
2888    {
2889       imageHeader->getPropertyNames(propertyNames);
2890    }
2891 }
2892 
getSecurityClassification() const2893 ossimString ossimNitfTileSource::getSecurityClassification() const
2894 {
2895    if(getCurrentImageHeader())
2896    {
2897       return getCurrentImageHeader()->getSecurityClassification();
2898    }
2899 
2900    return "U";
2901 }
2902 
lutUncompress(ossimRefPtr<ossimImageData> destination,ossim_uint8 * source)2903 void ossimNitfTileSource::lutUncompress(ossimRefPtr<ossimImageData> destination, ossim_uint8* source)
2904 {
2905    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
2906    if (!hdr||!destination)
2907    {
2908       return;
2909    }
2910    if((destination->getNumberOfBands()<3)||
2911       (!destination->getBuf())||
2912       (destination->getScalarType()!=OSSIM_UINT8)||
2913       (!theLut.valid()))
2914    {
2915       return;
2916    }
2917 
2918    if(destination->getNumberOfBands()!=theLut->getNumberOfBands())
2919    {
2920       return;
2921    }
2922 
2923    ossim_uint8* tempRows[3];
2924    tempRows[0] = (ossim_uint8*)destination->getBuf(0);
2925    tempRows[1] = (ossim_uint8*)destination->getBuf(1);
2926    tempRows[2] = (ossim_uint8*)destination->getBuf(2);
2927 
2928    ossim_uint8* srcPtr = source;
2929    ossim_uint32 compressionYidx   = 0;
2930    ossim_uint32 compressionXidx   = 0;
2931    ossim_uint32 uncompressIdx     = 0;
2932    ossim_uint32 h = destination->getHeight();
2933    ossim_uint32 w = destination->getWidth();
2934 
2935    for(compressionYidx = 0; compressionYidx < h; ++compressionYidx)
2936    {
2937       for(compressionXidx = 0; compressionXidx < w; ++compressionXidx)
2938       {
2939          tempRows[0][uncompressIdx] = (*theLut)[*srcPtr][0];
2940          tempRows[1][uncompressIdx] = (*theLut)[*srcPtr][1];
2941          tempRows[2][uncompressIdx] = (*theLut)[*srcPtr][2];
2942          ++srcPtr;
2943          ++uncompressIdx;
2944       }
2945    }
2946 }
2947 
vqUncompressC4(ossimRefPtr<ossimImageData> destination,ossim_uint8 * source)2948 void ossimNitfTileSource::vqUncompressC4(
2949    ossimRefPtr<ossimImageData> destination, ossim_uint8* source)
2950 {
2951    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
2952    if (!hdr||!destination)
2953    {
2954       return;
2955    }
2956 
2957    const ossim_uint32 BANDS = destination->getNumberOfBands();
2958 
2959    if( ( (BANDS != 1) && (BANDS!=3) ) ||
2960        (!destination->getBuf()) ||
2961        (destination->getScalarType()!=OSSIM_UINT8) ||
2962        !theLut.valid() ||
2963        (theLut->getNumberOfBands() != BANDS) )
2964    {
2965       return;
2966    }
2967 
2968    ossimNitfVqCompressionHeader* compressionHeader =
2969       PTR_CAST(ossimNitfVqCompressionHeader,
2970                hdr->getCompressionHeader().get());
2971 
2972    if(!compressionHeader)
2973    {
2974       return;
2975    }
2976 
2977    const std::vector<ossimNitfVqCompressionOffsetTableData>& table =
2978       compressionHeader->getTable();
2979 
2980    ossimRefPtr<ossimNitfImageBand> bandInfo = hdr->getBandInformation(0);
2981 
2982    if(!bandInfo.valid()) return;
2983 
2984    std::vector<ossimRefPtr<ossimNitfImageLut> > luts(BANDS);
2985    std::vector<ossim_uint8*> tempRows(BANDS);
2986 
2987    ossim_uint32 band;
2988    for (band =0; band<BANDS; ++band)
2989    {
2990       luts[band] = bandInfo->getLut(band);
2991       if ( luts[band].valid() )
2992       {
2993          tempRows[band] = (ossim_uint8*)destination->getBuf(band);
2994       }
2995       else
2996       {
2997          return;
2998       }
2999    }
3000 
3001    ossimPackedBits bits(source, compressionHeader->getImageCodeBitLength());
3002 
3003 
3004    const ossim_uint32 ROWS = static_cast<ossim_uint32>(table.size());
3005    const ossim_uint32 COLS =
3006       static_cast<ossim_uint32>(table[0].
3007                                 theNumberOfValuesPerCompressionLookup);
3008    const ossim_uint32 COMPRESSION_HEIGHT =
3009       compressionHeader->getNumberOfImageRows();
3010    const ossim_uint32 COMPRESSION_WIDTH  =
3011       compressionHeader->getNumberOfImageCodesPerRow();
3012    ossim_uint32 DEST_WIDTH  = destination->getWidth();
3013 
3014    ossim_uint32 compressionIdx = 0;
3015    ossim_uint32 uncompressIdx  = 0;
3016    ossim_uint32 uncompressYidx = 0;
3017    ossim_uint8  lutValue = 0;
3018    ossim_uint8* data     = 0;
3019    ossim_uint32 codeWord = 0;
3020 
3021    for(ossim_uint32 compressionYidx = 0;
3022        compressionYidx < COMPRESSION_HEIGHT;
3023        ++compressionYidx)
3024    {
3025       uncompressYidx = compressionYidx * ROWS * DEST_WIDTH;
3026 
3027       for(ossim_uint32 compressionXidx = 0;
3028           compressionXidx < COMPRESSION_WIDTH;
3029           ++compressionXidx)
3030       {
3031          uncompressIdx = uncompressYidx + COLS * compressionXidx;
3032 
3033          codeWord = bits.getValueAsUint32(compressionIdx++);
3034          codeWord *= COLS;
3035 
3036          for(ossim_uint32 rowIdx = 0; rowIdx < ROWS; ++rowIdx)
3037          {
3038             data = &(table[rowIdx].theData[codeWord]);
3039 
3040             for(ossim_uint32 colIdx = 0; colIdx < COLS; ++colIdx)
3041             {
3042                lutValue = (*data)&0xff;
3043 
3044                for (band = 0; band < BANDS; ++band)
3045                {
3046                   ossim_uint8 p = (*theLut.get())[lutValue][band];
3047                   tempRows[band][uncompressIdx+colIdx] = p;
3048                }
3049                ++data;
3050 
3051             } // column loop
3052 
3053             uncompressIdx += DEST_WIDTH;
3054 
3055          } // row loop
3056 
3057       } // x compression loop
3058 
3059    } // y compression loop
3060 }
3061 
vqUncompressM4(ossimRefPtr<ossimImageData> destination,ossim_uint8 * source)3062 void ossimNitfTileSource::vqUncompressM4(
3063    ossimRefPtr<ossimImageData> destination, ossim_uint8* source)
3064 {
3065    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
3066    if (!hdr||!destination)
3067    {
3068       return;
3069    }
3070 
3071    const ossim_uint32 BANDS = destination->getNumberOfBands();
3072 
3073    if(( (BANDS != 1)&&(BANDS!=3) ) ||
3074       (!destination->getBuf())||
3075       (destination->getScalarType()!=OSSIM_UINT8))
3076    {
3077       return;
3078    }
3079 
3080    ossimNitfVqCompressionHeader* compressionHeader =
3081       PTR_CAST(ossimNitfVqCompressionHeader,
3082                hdr->getCompressionHeader().get());
3083 
3084    if(!compressionHeader)
3085    {
3086       return;
3087    }
3088 
3089    const std::vector<ossimNitfVqCompressionOffsetTableData>& table =
3090       compressionHeader->getTable();
3091 
3092    ossimRefPtr<ossimNitfImageBand> bandInfo = hdr->getBandInformation(0);
3093 
3094    if(!bandInfo.valid()) return;
3095 
3096    std::vector<ossimRefPtr<ossimNitfImageLut> > luts(BANDS);
3097    std::vector<ossim_uint8*> tempRows(BANDS);
3098 
3099    ossim_uint32 band;
3100    for (band =0; band<BANDS; ++band)
3101    {
3102       luts[band] = bandInfo->getLut(band);
3103       if ( luts[band].valid() )
3104       {
3105          tempRows[band] = (ossim_uint8*)destination->getBuf(band);
3106       }
3107       else
3108       {
3109          return;
3110       }
3111    }
3112 
3113    const ossim_uint8 NI = 216; // null index (transparency index).
3114    const ossim_uint8 NP = 0;   // null pixel
3115 
3116    ossim_uint32 destWidth  = destination->getWidth();
3117    ossimPackedBits bits(source, compressionHeader->getImageCodeBitLength());
3118 
3119    ossim_uint32 compressionYidx   = 0;
3120    ossim_uint32 compressionXidx   = 0;
3121    ossim_uint32 compressionIdx    = 0;
3122    ossim_uint32 uncompressIdx     = 0;
3123    ossim_uint32 uncompressYidx    = 0;
3124    ossim_uint32 rows   = (ossim_uint32)table.size();
3125    ossim_uint32 cols   = 0;
3126    ossim_uint32 rowIdx = 0;
3127    ossim_uint32 colIdx = 0;
3128    if(rows)
3129    {
3130       cols = table[0].theNumberOfValuesPerCompressionLookup;
3131    }
3132    ossim_uint32 compressionHeight = compressionHeader->getNumberOfImageRows();
3133    ossim_uint32 compressionWidth  =
3134       compressionHeader->getNumberOfImageCodesPerRow();
3135    ossim_uint8 lutValue = 0;
3136    ossim_uint8* data=0;
3137 
3138    for(compressionYidx = 0;
3139        compressionYidx < compressionHeight;
3140        ++compressionYidx)
3141    {
3142       uncompressYidx = compressionYidx*rows*destWidth;
3143 
3144       for(compressionXidx = 0;
3145           compressionXidx < compressionWidth;
3146           ++compressionXidx)
3147       {
3148          uncompressIdx = uncompressYidx + cols*compressionXidx;
3149          ossim_uint32 codeWord = bits.getValueAsUint32(compressionIdx);
3150 
3151          bool transparent = false;
3152          if (codeWord == 4095)
3153          {
3154             //---
3155             // Check to see if the whole kernel is transparent.  If no, the
3156             // null index '216' could be used for valid pixels.
3157             //
3158             // For more see docs:
3159             // MIL-PRF-89041A 3.13.1.2 Transparent pixels
3160             // MIL-STD-2411
3161             //---
3162             codeWord *= cols;
3163             transparent = true;
3164             for(rowIdx = 0; rowIdx < rows; ++rowIdx)
3165             {
3166                data = &table[rowIdx].theData[codeWord];
3167 
3168                for(colIdx = 0; colIdx < cols; ++colIdx)
3169                {
3170                   lutValue = (*data)&0xff;
3171                   if (lutValue != NI)
3172                   {
3173                      // Not a kernel full of transparent pixels.
3174                      transparent = false;
3175                      break;
3176                   }
3177                   ++data;
3178                }
3179                if (!transparent)
3180                {
3181                   break;
3182                }
3183                uncompressIdx += destWidth;
3184             }
3185          }
3186 
3187          // Reset everyone for loop to copy pixel data from lut.
3188          uncompressIdx = uncompressYidx + cols*compressionXidx;
3189          codeWord = bits.getValueAsUint32(compressionIdx);
3190          codeWord *= cols;
3191 
3192          for(rowIdx = 0; rowIdx < rows; ++rowIdx)
3193          {
3194             data = &table[rowIdx].theData[codeWord];
3195 
3196             for(colIdx = 0; colIdx < cols; ++colIdx)
3197             {
3198                lutValue = (*data)&0xff;
3199 
3200                for (band = 0; band < BANDS; ++band)
3201                {
3202                   ossim_uint8 p = luts[band]->getValue(lutValue);
3203                   tempRows[band][uncompressIdx+colIdx] = (!transparent?p:NP);
3204                }
3205                ++data;
3206             }
3207 
3208             uncompressIdx += destWidth;
3209          }
3210          ++compressionIdx;
3211 
3212       } // x loop
3213 
3214    } // y loop
3215 }
3216 
scanForJpegBlockOffsets()3217 bool ossimNitfTileSource::scanForJpegBlockOffsets()
3218 {
3219    // Find, capture all jpeg block offsets and sizes for an entry.
3220 
3221    bool allBlocksFound = false;
3222 
3223    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
3224 
3225    if ( !hdr || (theReadMode != READ_JPEG_BLOCK) || !theFileStr )
3226    {
3227       return allBlocksFound; // Get out...
3228    }
3229 
3230    theNitfBlockOffset.clear();
3231    theNitfBlockSize.clear();
3232 
3233    //---
3234    // Get the totol blocks.
3235    // Note:  There can be more than one jpeg image in the nitf.  So after blocks
3236    // found equals total_blocks get out.
3237    //---
3238    ossim_uint32 total_blocks = hdr->getNumberOfBlocksPerRow()*hdr->getNumberOfBlocksPerCol();
3239 
3240    //---
3241    // NOTE:
3242    // SOI = 0xffd8 Start of image
3243    // EOI = 0xffd9 End of image
3244    // DHT = 0xffc4 Define Huffman Table(s)
3245    // DQT = 0xffdb Define Quantization Table(s)
3246    //---
3247 
3248    // Seek to the first block.
3249    theFileStr->seekg(hdr->getDataLocation(), ios::beg);
3250 
3251    if ( theFileStr->good() )
3252    {
3253       const ossim_uint8 AP6 = 0xe6;
3254       const ossim_uint8 AP7 = 0xe7;
3255       const ossim_uint8 DHT = 0xc4;
3256       const ossim_uint8 DQT = 0xdb;
3257       const ossim_uint8 EOI = 0xd9;
3258       const ossim_uint8 FF  = 0xff;
3259       const ossim_uint8 SOI = 0xd8;
3260       const ossim_uint8 SOS = 0xda;
3261 
3262       union
3263       {
3264          char c;
3265          ossim_uint8 uc;
3266       } ct;
3267 
3268       std::streamoff soiOffset = 0;
3269       std::streamoff eoiOffset = 0;
3270       ossim_uint16   length    = 0;
3271 
3272       ossimEndian* swapper = 0;
3273       if ( ossim::byteOrder() == OSSIM_LITTLE_ENDIAN )
3274       {
3275          swapper = new ossimEndian();
3276       }
3277 
3278       // Find all the SOI markers.
3279       while ( theFileStr->get( ct.c ) && !allBlocksFound )
3280       {
3281          if ( ct.uc == FF ) // Found FF byte.
3282          {
3283             // Loop to skip multiple 0xff's in cases like FF FF D8
3284             while ( theFileStr->get( ct.c ) )
3285             {
3286                if ( ct.uc != FF)
3287                {
3288                   break;
3289                }
3290             }
3291 
3292             if ( ct.uc == SOI )
3293             {
3294                // At SOI 0xFFD8 marker... SOI marker offset is two bytes back.
3295                soiOffset = ((std::streamoff)theFileStr->tellg()) - 2;
3296 
3297                // Now look for matching EOI.
3298                while ( theFileStr->get( ct.c ) )
3299                {
3300                   if ( ct.uc == FF ) // Found FF byte.
3301                   {
3302                      // Loop to skip multiple 0xff's in cases like FF FF D8
3303                      while ( theFileStr->get( ct.c ) )
3304                      {
3305                         if ( ct.uc != FF )
3306                         {
3307                            break;
3308                         }
3309                      }
3310 
3311                      if ( ct.uc == EOI )
3312                      {
3313                         // At EOI 0xD9marker...
3314                         eoiOffset = theFileStr->tellg();
3315 
3316                         // Capture offset:
3317                         theNitfBlockOffset.push_back( soiOffset );
3318 
3319                         // Capture block size:
3320                         theNitfBlockSize.push_back( eoiOffset - soiOffset );
3321 
3322                         //---
3323                         // Since there can be more than one jpeg entry in a file, breeak out of
3324                         // loop when we hit block size.
3325                         //---
3326                         if ( theNitfBlockOffset.size() == total_blocks )
3327                         {
3328                            allBlocksFound = true;
3329                         }
3330 
3331                         break; // From "find EOI" while loop.
3332                      }
3333                      //---
3334                      // These are things to skip to avoid hitting random sequence of FFD9
3335                      // and picking up a false EOI.
3336                      // Not a complete set of markers but all test data works.
3337                      // drb - 14 May 2013.
3338                      //---
3339                      else if ( ( ct.uc == AP6 ) || ( ct.uc == AP7 ) || ( ct.uc == DHT ) ||
3340                                ( ct.uc == DQT ) || ( ct.uc == SOS ) ||
3341                                ( ( ct.uc >= 0xc0 ) && ( ct.uc <= 0xcF ) )
3342                                )
3343                      {
3344                         // Length two byte big endian.
3345                         theFileStr->read( (char*)&length, 2 );
3346                         if ( swapper )
3347                         {
3348                            swapper->swap( length );
3349                         }
3350                         // Length includes two length bytes.
3351 
3352                         // Seek to the end of the record.
3353                         theFileStr->seekg( length - 2, std::ios_base::cur );
3354                      }
3355 
3356                   } //  Matches: if ( ct.uc == FF )
3357 
3358                } // Matches: while ( theFileStr->get( ut.c ) ) "find EOI loop"
3359 
3360             } // Matches: if ( ut.uc == SOI ) "SOI marker found"
3361 
3362          } // Matches: if ( ut.uc == FF )
3363 
3364       } // Matches: while ( theFileStr->get( ut.c ) && !allBlocksFound )
3365 
3366       if ( swapper )
3367       {
3368          delete swapper;
3369          swapper = 0;
3370       }
3371 
3372    } // Matches: if ( theFileStr->good() )
3373 
3374    theFileStr->seekg(0, ios::beg);
3375    theFileStr->clear();
3376 
3377 #if 0 /* Please leave for debug. (drb) */
3378    std::streamoff startOfData = hdr->getDataLocation();
3379    ossimNotify(ossimNotifyLevel_WARN) << "current entry: " << theCurrentEntry << "\n";
3380    for (ossim_uint32 i = 0; i < total_blocks; ++i)
3381    {
3382       cout << "theNitfBlockOffset[" << i << "]: " << theNitfBlockOffset[i]
3383            << "\nrealative_offset[" << i << "]:   " << (theNitfBlockOffset[i] - startOfData)
3384            << "\ntheNitfBlockSize[" << i << "]:   " << theNitfBlockSize[i]
3385            << "\n";
3386    }
3387 #endif
3388 
3389    if ( !allBlocksFound )
3390    {
3391       if (traceDebug())
3392       {
3393          ossimNotify(ossimNotifyLevel_WARN)
3394             << "DEBUG:"
3395             << "\nBlock offset count wrong!"
3396             << "\nexpected blocks:        " << total_blocks
3397             << "\noffset array count:     " << theNitfBlockOffset.size()
3398             << "\nblock size array count: " << theNitfBlockSize.size()
3399             << std::endl;
3400       }
3401       theNitfBlockOffset.clear();
3402       theNitfBlockSize.clear();
3403    }
3404 
3405    return allBlocksFound;
3406 }
3407 
uncompressJpegBlock(ossim_uint32 x,ossim_uint32 y)3408 bool ossimNitfTileSource::uncompressJpegBlock(ossim_uint32 x, ossim_uint32 y)
3409 {
3410    ossim_uint32 blockNumber = getBlockNumber( ossimIpt(x,y) );
3411 
3412    if (traceDebug())
3413    {
3414       ossimNotify(ossimNotifyLevel_DEBUG)
3415          << "ossimNitfTileSource::uncompressJpegBlock DEBUG:"
3416          << "\nblockNumber:  " << blockNumber
3417          << std::endl;
3418    }
3419 
3420    //---
3421    // Logic to hold off on scanning for offsets until a block is actually needed
3422    // to speed up loads for things like ossim-info that don't actually read
3423    // pixel data.
3424    //---
3425    if ( m_jpegOffsetsDirty )
3426    {
3427       if ( scanForJpegBlockOffsets() )
3428       {
3429          m_jpegOffsetsDirty = false;
3430       }
3431       else
3432       {
3433          ossimNotify(ossimNotifyLevel_FATAL)
3434             << "ossimNitfTileSource::uncompressJpegBlock scan for offsets error!"
3435             << "\nReturning error..." << endl;
3436          theErrorStatus = ossimErrorCodes::OSSIM_ERROR;
3437          return false;
3438       }
3439    }
3440 
3441    if (traceDebug())
3442    {
3443       ossimNotify(ossimNotifyLevel_DEBUG)
3444          << "\noffset to block: " << theNitfBlockOffset[blockNumber]
3445          << "\nblock size: " << theNitfBlockSize[blockNumber]
3446          << std::endl;
3447    }
3448 
3449    // Seek to the block.
3450    theFileStr->seekg(theNitfBlockOffset[blockNumber], ios::beg);
3451 
3452    // Read the block into memory.
3453    std::vector<ossim_uint8> compressedBuf(theNitfBlockSize[blockNumber]);
3454    if (!theFileStr->read((char*)&(compressedBuf.front()),
3455                         theNitfBlockSize[blockNumber]))
3456    {
3457       theFileStr->clear();
3458       ossimNotify(ossimNotifyLevel_FATAL)
3459          << "ossimNitfTileSource::uncompressJpegBlock Read Error!"
3460          << "\nReturning error..." << endl;
3461       return false;
3462    }
3463 
3464    //---
3465    // Most of comments below from jpeg-6b "example.c" file.
3466    //---
3467 
3468    /* This struct contains the JPEG decompression parameters and pointers
3469     * to working space (which is allocated as needed by the JPEG library).
3470     */
3471    jpeg_decompress_struct cinfo;
3472 
3473    /* We use our private extension JPEG error handler.
3474     * Note that this struct must live as long as the main JPEG parameter
3475     * struct, to avoid dangling-pointer problems.
3476     */
3477    ossimJpegErrorMgr jerr;
3478 
3479    /* Step 1: allocate and initialize JPEG decompression object */
3480 
3481    /* We set up the normal JPEG error routines, then override error_exit. */
3482    cinfo.err = jpeg_std_error(&jerr.pub);
3483 
3484    jerr.pub.error_exit = ossimJpegErrorExit;
3485 
3486    /* Establish the setjmp return context for my_error_exit to use. */
3487    if (setjmp(jerr.setjmp_buffer))
3488    {
3489       /* If we get here, the JPEG code has signaled an error.
3490        * We need to clean up the JPEG object, close the input file, and return.
3491        */
3492      jpeg_destroy_decompress(&cinfo);
3493      return false;
3494    }
3495 
3496    /* Now we can initialize the JPEG decompression object. */
3497    jpeg_CreateDecompress(&cinfo, JPEG_LIB_VERSION, sizeof(cinfo));
3498 
3499    //---
3500    // Step 2: specify data source.  In this case we will uncompress from
3501    // memory so we will use "ossimJpegMemorySrc" in place of " jpeg_stdio_src".
3502    //---
3503    ossimJpegMemorySrc (&cinfo,
3504                        &(compressedBuf.front()),
3505                        static_cast<size_t>(theReadBlockSizeInBytes));
3506 
3507    /* Step 3: read file parameters with jpeg_read_header() */
3508    jpeg_read_header(&cinfo, TRUE);
3509 
3510    // Check for Quantization tables.
3511    if (cinfo.quant_tbl_ptrs[0] == NULL)
3512    {
3513       // This will load table specified in COMRAT field.
3514       if (loadJpegQuantizationTables(cinfo) == false)
3515       {
3516         jpeg_destroy_decompress(&cinfo);
3517         return false;
3518       }
3519    }
3520 
3521    // Check for huffman tables.
3522    if (cinfo.ac_huff_tbl_ptrs[0] == NULL)
3523    {
3524       // This will load default huffman tables into .
3525       if (loadJpegHuffmanTables(cinfo) == false)
3526       {
3527         jpeg_destroy_decompress(&cinfo);
3528         return false;
3529       }
3530    }
3531 
3532    /* Step 4: set parameters for decompression */
3533 
3534    /* In this example, we don't need to change any of the defaults set by
3535     * jpeg_read_header(), so we do nothing here.
3536     */
3537 
3538    /* Step 5: Start decompressor */
3539    jpeg_start_decompress(&cinfo);
3540 
3541 #if 0 /* Please leave for debug. (drb) */
3542    if ( traceDebug() )
3543    {
3544       ossimNotify(ossimNotifyLevel_DEBUG)
3545          << "jpeg cinfo.output_width:  " << cinfo.output_width
3546          << "\njpeg cinfo.output_height: " << cinfo.output_height
3547          << "\n";
3548    }
3549 #endif
3550 
3551    const ossim_uint32 SAMPLES = cinfo.output_width;
3552 
3553    //---
3554    // Note: Some nitf will be tagged with a given number of lines but the last
3555    // jpeg block may go beyond that to a complete block.  So it you clamp to
3556    // last line of the nitf you will get a libjpeg error:
3557    //
3558    // "Application transferred too few scanlines"
3559    //
3560    // So here we will always read the full jpeg block even if it is beyond the
3561    // last line of the nitf.
3562    //---
3563    const ossim_uint32 LINES_TO_READ =
3564       min(static_cast<ossim_uint32>(theCacheSize.y), cinfo.output_height);
3565 
3566    /* JSAMPLEs per row in output buffer */
3567    const ossim_uint32 ROW_STRIDE = SAMPLES * cinfo.output_components;
3568 
3569    if ( (SAMPLES < theCacheTile->getWidth() ) ||
3570         (LINES_TO_READ < theCacheTile->getHeight()) )
3571    {
3572       theCacheTile->makeBlank();
3573    }
3574 
3575    if ( (SAMPLES > theCacheTile->getWidth()) ||
3576         (LINES_TO_READ > theCacheTile->getHeight()) )
3577    {
3578      // Error...
3579      jpeg_finish_decompress(&cinfo);
3580      jpeg_destroy_decompress(&cinfo);
3581      return false;
3582    }
3583 
3584    // Get pointers to the cache tile buffers.
3585    std::vector<ossim_uint8*> destinationBuffer(theNumberOfInputBands);
3586    for (ossim_uint32 band = 0; band < theNumberOfInputBands; ++band)
3587    {
3588      destinationBuffer[band] = theCacheTile->getUcharBuf(band);
3589    }
3590 
3591    std::vector<ossim_uint8> lineBuffer(ROW_STRIDE);
3592    JSAMPROW jbuf[1];
3593    jbuf[0] = (JSAMPROW) &(lineBuffer.front());
3594 
3595    while (cinfo.output_scanline < LINES_TO_READ)
3596    {
3597      // Read a line from the jpeg file.
3598      jpeg_read_scanlines(&cinfo, jbuf, 1);
3599 
3600      //---
3601      // Copy the line which if band interleaved by pixel the the band
3602      // separate buffers.
3603      //
3604      // Note:
3605      // Not sure if IMODE of 'B' is interleaved the same as image with
3606      // IMODE of 'P'.
3607      //
3608      // This works with all samples with IMODE of B and P but I only have
3609      // one band 'B' and three band 'P'.  So if we ever get a three band
3610      // 'B' it could be wrong here. (drb - 20090615)
3611      //---
3612      ossim_uint32 index = 0;
3613      for (ossim_uint32 sample = 0; sample < SAMPLES; ++sample)
3614      {
3615        for (ossim_uint32 band = 0; band < theNumberOfInputBands; ++band)
3616        {
3617          destinationBuffer[band][sample] = lineBuffer[index];
3618          ++index;
3619        }
3620      }
3621 
3622      for (ossim_uint32 band = 0; band < theNumberOfInputBands; ++band)
3623      {
3624        destinationBuffer[band] += theCacheSize.x;
3625      }
3626    }
3627 
3628    // clean up...
3629 
3630    jpeg_finish_decompress(&cinfo);
3631    jpeg_destroy_decompress(&cinfo);
3632 
3633    return true;
3634 }
3635 
3636 //---
3637 // Default JPEG quantization tables
3638 // Values from: MIL-STD-188-198, APPENDIX A
3639 //---
loadJpegQuantizationTables(jpeg_decompress_struct & cinfo) const3640 bool ossimNitfTileSource::loadJpegQuantizationTables(
3641    jpeg_decompress_struct& cinfo) const
3642 {
3643    //---
3644    // Check to see if table is present.  We will only look at the first table
3645    // in the array of arrays.
3646    //
3647    // NOTE:  There are four tables in the array "cinfo.quant_tbl_ptrs".  It
3648    // looks like the standard is to use the first table. (not sure though)
3649    //---
3650    if (cinfo.quant_tbl_ptrs[0] != NULL)
3651    {
3652       return false;
3653    }
3654 
3655    // Get the COMRAT (compression rate code) from the header:
3656    const ossimNitfImageHeader* hdr = getCurrentImageHeader();
3657    if (!hdr)
3658    {
3659       return false;
3660    }
3661 
3662    ossimString comrat = hdr->getCompressionRateCode();
3663    ossim_uint32 tableIndex = 0;
3664    if (comrat.size() >= 4)
3665    {
3666       // COMRAT string like: "00.2" = use table 2. (between 1 and 5).
3667       ossimString s;
3668       s.push_back(comrat[static_cast<std::string::size_type>(3)]);
3669       ossim_int32 comTbl = s.toInt32();
3670       if ( (comTbl > 0) && (comTbl < 6) )
3671       {
3672          tableIndex = comTbl-1;
3673       }
3674       else
3675       {
3676          ossimNotify(ossimNotifyLevel_WARN)
3677             << "ossimNitfTileSource::loadJpegQuantizationTables WARNING\n"
3678             << "\nNo quantization tables specified!"
3679             << endl;
3680          return false;
3681       }
3682    }
3683 
3684    cinfo.quant_tbl_ptrs[0] = jpeg_alloc_quant_table((j_common_ptr) &cinfo);
3685 
3686    JQUANT_TBL* quant_ptr = cinfo.quant_tbl_ptrs[0]; // quant_ptr is JQUANT_TBL*
3687 
3688    for (ossim_int32 i = 0; i < 64; ++i)
3689    {
3690       /* Qtable[] is desired quantization table, in natural array order */
3691       quant_ptr->quantval[i] = QTABLE_ARRAY[tableIndex][i];
3692    }
3693    return true;
3694 }
3695 
3696 //---
3697 // Default JPEG Huffman tables
3698 // Values from: MIL-STD-188-198, APPENDIX B
3699 //---
loadJpegHuffmanTables(jpeg_decompress_struct & cinfo) const3700 bool ossimNitfTileSource::loadJpegHuffmanTables(
3701    jpeg_decompress_struct& cinfo) const
3702 {
3703    if ( (cinfo.ac_huff_tbl_ptrs[0] != NULL) &&
3704         (cinfo.dc_huff_tbl_ptrs[0] != NULL) )
3705    {
3706       return false;
3707    }
3708 
3709    cinfo.ac_huff_tbl_ptrs[0] = jpeg_alloc_huff_table((j_common_ptr)&cinfo);
3710    cinfo.dc_huff_tbl_ptrs[0] = jpeg_alloc_huff_table((j_common_ptr)&cinfo);
3711 
3712    ossim_int32 i;
3713    JHUFF_TBL* huff_ptr;
3714 
3715    // Copy the ac tables.
3716    huff_ptr = cinfo.ac_huff_tbl_ptrs[0]; /* huff_ptr is JHUFF_TBL* */
3717    for (i = 0; i < 16; ++i)
3718    {
3719       // huff_ptr->bits is array of 17 bits[0] is unused; hence, the i+1
3720       huff_ptr->bits[i+1] = AC_BITS[i];
3721    }
3722 
3723    for (i = 0; i < 256; ++i)
3724    {
3725       huff_ptr->huffval[i] = AC_HUFFVAL[i];
3726    }
3727 
3728    // Copy the dc tables.
3729    huff_ptr = cinfo.dc_huff_tbl_ptrs[0]; /* huff_ptr is JHUFF_TBL* */
3730    for (i = 0; i < 16; ++i)
3731    {
3732       // huff_ptr->bits is array of 17 bits[0] is unused; hence, the i+1
3733       huff_ptr->bits[i+1] = DC_BITS[i];
3734    }
3735 
3736    for (i = 0; i < 256; i++)
3737    {
3738       /* symbols[] is the list of Huffman symbols, in code-length order */
3739       huff_ptr->huffval[i] = DC_HUFFVAL[i];
3740    }
3741    return true;
3742 }
3743 
3744 // Protected to disallow use...
ossimNitfTileSource(const ossimNitfTileSource &)3745 ossimNitfTileSource::ossimNitfTileSource(const ossimNitfTileSource& /* obj */)
3746 {
3747 }
3748 
3749 // Protected to disallow use...
operator =(const ossimNitfTileSource &)3750 ossimNitfTileSource& ossimNitfTileSource::operator=(
3751    const ossimNitfTileSource& /* rhs */)
3752 {
3753    return *this;
3754 }
3755