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:
10 //
11 // Contains class declaration for NitfTileSource.
12 //
13 //---
14 // $Id$
15 
16 #ifndef ossimNitfTileSource_HEADER
17 #define ossimNitfTileSource_HEADER 1
18 
19 #include <ossim/imaging/ossimImageHandler.h>
20 #include <ossim/base/ossimIoStream.h>
21 #include <ossim/imaging/ossimAppFixedTileCache.h>
22 #include <ossim/support_data/ossimNitfFile.h>
23 #include <ossim/support_data/ossimNitfFileHeader.h>
24 #include <ossim/support_data/ossimNitfImageHeader.h>
25 #include <memory>
26 
27 struct jpeg_decompress_struct;
28 
29 class OSSIM_DLL ossimNitfTileSource : public ossimImageHandler
30 {
31 public:
32 
33    enum ReadMode
34    {
35       READ_MODE_UNKNOWN = 0,
36 
37       /** IMODE = B "Band Interleaved By Block or a single band" */
38       READ_BIB_BLOCK = 1,
39 
40       /** IMODE = P "Band Interleaved By Pixel" */
41       READ_BIP_BLOCK = 2,
42 
43       /** IMODE = R "Band Interleaved By Row" */
44       READ_BIR_BLOCK = 3,
45 
46       /** IMODE = S "Band Sequential" */
47       READ_BSQ_BLOCK = 4,
48 
49       /** IMODE = B of S "single block or one block for each band" */
50       READ_BIB       = 5,
51 
52       /** IMODE = P "single block Band Interleaved By Pixel" */
53       READ_BIP       = 6,
54 
55       /** IMODE = R "single block Band Interleaved By Row" */
56       READ_BIR       = 7,
57 
58       /** IMODE = B, IC = C3 "JPEG compressed blocks" */
59       READ_JPEG_BLOCK = 8
60    };
61 
62    ossimNitfTileSource();
63 
64 
65    virtual ossimString getShortName() const;
66    virtual ossimString getLongName()  const;
67 
68    /**
69     *  Returns true if the image_file can be opened and is a valid nitf file.
70     */
71    virtual bool open();
72 
73    /**
74     *  @brief This open takes a stream and stores/captures the shared pointer
75     *  on success.
76     *  @param str Open stream to image.
77     *  @param connectionString Stored on success as the file name.
78     *  @return true on success, false on error.
79     */
80    bool open( std::shared_ptr<ossim::istream>& str,
81               const std::string& connectionString );
82 
83    /** @brief Closes file and destroys all memory allocated. */
84    virtual void close();
85 
86    /**
87     * @param tileRect Requested rectangle.
88     *
89     * @param resLevel Reduced resolution level to grab tileRect from.
90     * Default = 0 or the full resolution data set.
91     *
92     * @return Returns an image data object with requested rectangle from the
93     * image.  Depending on the overlap of tileRect with respect to the image
94     * rectangle, the returned tile could be full, partial, or an empty(blank)
95     * tile.
96     */
97    virtual ossimRefPtr<ossimImageData> getTile(const  ossimIrect& tileRect,
98                                                ossim_uint32 resLevel=0);
99 
100     /**
101      * @return Returns the number of bands in the image.
102      * Satisfies pure virtual from ImageHandler class.
103      */
104    virtual ossim_uint32 getNumberOfInputBands() const;
105 
106    /**
107     * @return Number of output bands.
108     */
109    virtual ossim_uint32 getNumberOfOutputBands() const;
110 
111    /**
112      *  Returns the number of lines in the image.
113      *  Satisfies pure virtual from ImageHandler class.
114      */
115    virtual ossim_uint32 getNumberOfLines(ossim_uint32 resLevel = 0) const;
116 
117    /**
118     *  Returns the number of samples in the image.
119     *  Satisfies pure virtual from ImageHandler class.
120     */
121    virtual ossim_uint32 getNumberOfSamples(ossim_uint32 resLevel = 0) const;
122 
123    /**
124     * Method to save the state of an object to a keyword list.
125     * Return true if ok or false on error.
126     */
127    virtual bool saveState(ossimKeywordlist& kwl,
128                           const char* prefix=0)const;
129 
130    /**
131     * Method to the load (recreate) the state of an object from a keyword
132     * list.  Return true if ok or false on error.
133     */
134    virtual bool loadState(const ossimKeywordlist& kwl,
135                           const char* prefix=0);
136 
137    /**
138     * Returns the output pixel type of the tile source.
139     */
140    virtual ossimScalarType getOutputScalarType() const;
141 
142    /**
143     * Returns the width of the output tile.
144     */
145    virtual ossim_uint32 getTileWidth() const;
146 
147    /**
148     * Returns the height of the output tile.
149     */
150    virtual ossim_uint32 getTileHeight() const;
151 
152    /**
153     * Returns the tile width of the image or 0 if the image is not tiled.
154     * Note: this is not the same as the ossimImageSource::getTileWidth which
155     * returns the output tile width which can be different than the internal
156     * image tile width on disk.
157     */
158    virtual ossim_uint32 getImageTileWidth() const;
159 
160    /**
161     * Returns the tile width of the image or 0 if the image is not tiled.
162     * Note: this is not the same as the ossimImageSource::getTileWidth which
163     * returns the output tile width which can be different than the internal
164     * image tile width on disk.
165     */
166    virtual ossim_uint32 getImageTileHeight() const;
167 
168    virtual bool isOpen()const;
169 
170    /**
171     * @return The current entry number.
172     *
173     * @note NITF's can contain multiple images in a single file.  This returns
174     * the index of the current image being read.
175     */
176    virtual ossim_uint32 getCurrentEntry() const;
177 
178    /**
179     * @param entryList This is the list to initialize with entry indexes.
180     */
181    virtual void getEntryList(std::vector<ossim_uint32>& entryList) const;
182 
183    /**
184     * @return Returns the number of entries (or images) within the nitf
185     * file.
186     */
187    ossim_uint32 getNumberOfEntries() const;
188 
189    /**
190     * @param entryIdx Zero base entry number to select.  Sets data member
191     * "theCurrentEntry".
192     *
193     * @note "theCurrentEntry" will not be set if "entryIdx" is out of range.
194     */
195    virtual bool setCurrentEntry(ossim_uint32 entryIdx);
196 
197    virtual ossimRefPtr<ossimProperty> getProperty(const ossimString& name)const;
198    virtual void setProperty(ossimRefPtr<ossimProperty> property);
199    virtual void getPropertyNames(std::vector<ossimString>& propertyNames)const;
200 
201    ossimString getSecurityClassification()const;
202 
203    /**
204     * @return Returns theCacheEnabledFlag.
205     */
206    bool getCacheEnabledFlag() const;
207 
208    /**
209     * @param flag Sets theCacheEnabledFlag and disables/enables caching
210     * accordingly.  If cache is disabled it is also flushed at the same time.
211     * If cache is enabled, blocks read from the image will be cached.
212     */
213    void setCacheEnabledFlag(bool flag);
214 
215    virtual double getMinPixelValue(ossim_uint32 band=0)const;
216    virtual double getMaxPixelValue(ossim_uint32 band=0)const;
217    virtual double getNullPixelValue(ossim_uint32 band=0)const;
218 
219    const ossimNitfFileHeader* getFileHeader()const;
220    ossimNitfFileHeader* getFileHeader();
221    ossimNitfFile *getNitfFile();
222    const ossimNitfFile *getNitfFile()const;
223 
224    /**
225     * @return The image header for the current entry.
226     */
227    const ossimNitfImageHeader* getCurrentImageHeader() const;
228    ossimNitfImageHeader* getCurrentImageHeader();
229 
230    /**
231     * @brief Convenience method to get the zero based rgb output band list.
232     *
233     * Attempts to derive RGB bands from nitf fields.
234     *
235     * @param bandList Initialized by this.
236     * @return true on success, false if number of bands is less than 3 or if
237     * rgb bands could not be derived from nitf fields.
238     */
239    virtual bool getRgbBandList(std::vector<ossim_uint32>& bandList) const;
240 
241 protected:
242    virtual ~ossimNitfTileSource();
243 
244    /**
245     * @param imageRect The full resolution image rectangle.
246     *
247     * @note Should contain offsets if there are any.
248     */
249    void setBoundingRectangle(const ossimIrect& imageRect);
250 
251    /** Copy constructor, disallow... */
252    ossimNitfTileSource(const ossimNitfTileSource& obj);
253 
254    /** Operator=, disallow... */
255    ossimNitfTileSource& operator=(const ossimNitfTileSource& rhs);
256 
257    /**
258     *  Returns true on success, false on error.
259     */
260    bool loadTile(const ossimIrect& clipRect);
261 
262    /**
263     * @return Returns the block number given an origin.
264     */
265    ossim_uint32 getBlockNumber(const ossimIpt& block_origin) const;
266 
267    /**
268     * Deletes all memory allocated by this object.
269     */
270    void destroy();
271 
272    /**
273     * @brief Parses "theImageFile" and initializes all nitf headers.
274     * @return true on success, false on error.
275     */
276    virtual bool parseFile();
277 
278    /**
279     * @brief Allocates everything for current entry.
280     *
281     * This is called on an open() or a entry change to an already open nitf
282     * file.
283     *
284     * This does not allocate buffers and tiles to keep open and
285     * setCurrentEntry times to a minimum.  Buffers are allocated on first
286     * grab of pixel data by allocatBuffers method.
287     *
288     * @return True on success, false on error.
289     */
290    virtual bool allocate();
291 
292    /**
293     * @brief Allocates buffers for current entry.
294     *
295     * This is called on first getTile().
296     *
297     * @return True on success, false on error.
298     */
299    virtual bool allocateBuffers();
300 
301    /**
302     * @param hdr Pointer to image header.
303     * @return true if reader can uncompress nitf.
304     * */
305    virtual bool canUncompress(const ossimNitfImageHeader* hdr) const;
306 
307    /**
308     * Initializes the data member "theScalarType" from the current entry.
309     */
310    virtual void initializeScalarType();
311 
312    /**
313     * Initializes the data member "theSwapBytesFlag" from the current entry.
314     */
315    virtual void initializeSwapBytesFlag();
316 
317    /**
318     * Initializes the data member "theReadMode" from the current entry.
319     */
320    virtual void initializeReadMode();
321 
322    /**
323     * Initializes the data member "theNumberOfBands" from the current entry.
324     */
325    void initializeBandCount();
326 
327    /**
328     * Initializes the data member "theBlockSize" from the current entry.
329     *
330     * @note This should be performed after setting the read mode and
331     * band count.
332     *
333     * @note This is the size of a single block read.  So if the bands are
334     * separated by block, a read of this size will get one block.
335     *
336     * @return true on success, false on error.
337     */
338    bool initializeBlockSize();
339 
340    /**
341     * Initializes the data members "theImageRect" and "theBlockRect"
342     * from the current entry.
343     *
344     * @return true on success, false on error.
345     */
346    virtual bool initializeImageRect();
347 
348    /**
349     * Initializes the data member "theCacheSize".
350     */
351    void initializeCacheSize();
352 
353    /**
354     * Initializes the data member "theCacheTileInterLeaveType".
355     */
356    virtual void initializeCacheTileInterLeaveType();
357 
358    /**
359     * Initializes the cache tile size(width and height).  For block images
360     * this will be the size of one block.  For images that are a single block,
361     * this will be the image width by the height of one tile.
362     */
363    void initializeCacheTile();
364 
365    /**
366     * Initializes the data member theCompressedBuf.
367     */
368    virtual void initializeCompressedBuf();
369 
370    /**
371     * Initializes the output tile size(width and height).
372     */
373    virtual void initializeOutputTile();
374 
375    /**
376     * @brief Initializes "theLut" if applicable.
377     */
378    void initializeLut();
379 
380    /**
381     * Loads a block of data to theCacheTile.
382     *
383     * @param x Starting x position of block to load.
384     *
385     * @param y Starting y position of block to load.
386     *
387     * @return true on success, false on error.
388     *
389     * @note x and y are zero based relative to the upper left corner so any
390     * sub image offset should be subtracted off.
391     */
392    bool loadBlockFromCache(ossim_uint32 x, ossim_uint32 y,
393                            const ossimIrect& clipRect);
394 
395    /**
396     * Loads a block of data to theCacheTile.
397     *
398     * @param x Starting x position of block to load.
399     *
400     * @param y Starting y position of block to load.
401     *
402     * @return true on success, false on error.
403     *
404     * @note x and y are zero based relative to the upper left corner so any
405     * sub image offset should be subtracted off.
406     */
407    virtual bool loadBlock(ossim_uint32 x, ossim_uint32 y);
408 
409    /**
410     * @param x Horizontal upper left pixel position of the requested block.
411     *
412     * @param y Vertical upper left pixel position of the requested block.
413     *
414     * @param band Band of block.  Only relative with IMODES that have bands
415     * in separate blocks.
416     *
417     * @return true if the stream offset was settable and false otherwise.
418     */
419    bool getPosition(std::streamoff& position,
420                     ossim_uint32 x,
421                     ossim_uint32 y,
422                     ossim_uint32 band) const;
423 
424    /**
425     * @return the total number of blocks for the current entry.
426     *
427     * @note For band separated blocks, all bands will be counted as on block.
428     */
429    ossim_uint32 getNumberOfBlocks() const;
430 
431    /**
432     * @return The number of bytes to get from one block band to the next band.
433     */
434    std::streampos getBandOffset() const;
435 
436    /**
437     * @return The number of bytes to get from one block to the next block.
438     */
439    std::streampos getBlockOffset() const;
440 
441 
442    void explodePackedBits(ossimRefPtr<ossimImageData> packedBuffer)const;
443 
444    void convertTransparentToNull(ossimRefPtr<ossimImageData> tile)const;
445 
446    ossim_uint32 getPartialReadSize(const ossimIpt& blockOrigin)const;
447    bool isVqCompressed(const ossimString& compressionCode)const;
448 
449    /**
450     * @brief Uncompresses Vector Quantization unmasked image data.
451     * IC field = C4
452     * @param destination tile to stuff.
453     * @param source Pointer to compressed data.
454     */
455    void vqUncompressC4(ossimRefPtr<ossimImageData> destination,
456                        ossim_uint8* source);
457 
458    /**
459     * @brief Uncompresses Vector Quantization masked image data.
460     * IC field = M4
461     * @param destination tile to stuff.
462     * @param source Pointer to compressed data.
463     */
464    void vqUncompressM4(ossimRefPtr<ossimImageData> destination,
465                        ossim_uint8* source);
466 
467    void lutUncompress(ossimRefPtr<ossimImageData> destination,
468                      ossim_uint8* source);
469 
470    /**
471     * @brief scans the file storing in offsets in "theNitfBlockOffset" and
472     * block sizes in "theNitfBlockSize".
473     * @return true on success, false on error.  This checks for arrays being
474     * the same size as number of blocks.
475     */
476    virtual bool scanForJpegBlockOffsets();
477 
478    /**
479     * @brief Uncompresses a jpeg block using the jpeg-6b library.
480     * This method does eight bit jpeg compressed blocks. Note there is
481     * specialized jpeg12 plugin for 12 bit.
482     * @param x sample location in image space.
483     * @param y line location in image space.
484     * @return true on success, false on error.
485     */
486    virtual bool uncompressJpegBlock(ossim_uint32 x, ossim_uint32 y);
487 
488    /**
489     * @brief Loads one of the default tables based on COMRAT value.
490     *
491     * @return true if comrat had valid table value(1-5) and table was loaded,
492     * false if COMRAT value did not contain a valid value.  Will also return
493     * false if there is already a table loaded.
494     *
495     * @note COMRAT is nitf compression rate code field:
496     * -  "00.2" == default compression table 2
497     * -  "00.5" == default compression table 5 and so on.
498     */
499    bool loadJpegQuantizationTables(jpeg_decompress_struct& cinfo) const;
500 
501    /**
502     * @brief Loads default huffman tables.
503     *
504     * @return true success, false on error.
505     */
506    bool loadJpegHuffmanTables(jpeg_decompress_struct& cinfo) const;
507 
508    /**
509    * @brief Virtual method determines the decimation factors at each resolution level.
510    * This method derives the decimations from the image metadata.
511    */
512    virtual void establishDecimationFactors();
513 
514    ossimRefPtr<ossimImageData>   theTile;
515    ossimRefPtr<ossimImageData>   theCacheTile;
516    ossimRefPtr<ossimNitfFile>    theNitfFile;
517    std::vector<ossimRefPtr<ossimNitfImageHeader> > theNitfImageHeader;
518    ReadMode                      theReadMode;
519    ossimScalarType               theScalarType;
520    bool                          theSwapBytesFlag;
521    ossim_uint32                  theNumberOfInputBands;
522    ossim_uint32                  theNumberOfOutputBands;
523    ossim_uint32                  theBlockSizeInBytes;
524    ossim_uint32                  theReadBlockSizeInBytes;
525    ossim_uint32                  theNumberOfImages;
526    ossim_uint32                  theCurrentEntry;
527    ossimIrect                    theImageRect;
528    std::shared_ptr<ossim::istream> theFileStr;
529    std::vector<ossim_uint32>     theSelectorBandList;
530    std::vector<ossim_uint32>     theOutputBandList;
531    ossimIpt                      theCacheSize;
532    ossimInterleaveType           theCacheTileInterLeaveType;
533    bool                          theCacheEnabledFlag;
534    std::vector<ossim_uint32>     theEntryList;
535    ossimAppFixedTileCache::ossimAppFixedCacheId theCacheId;
536    bool                          thePackedBitsFlag;
537    ossimIrect                    theBlockImageRect;
538    std::vector<ossim_uint8>      theCompressedBuf;
539 
540    //---
541    // Have compressed jpeg blocks of variable length so we must scan and
542    // capture the offsetts and block sizes for reading.
543    //---
544    std::vector<std::streamoff>   theNitfBlockOffset;
545    std::vector<ossim_uint32>     theNitfBlockSize;
546 
547    //---
548    // If set to true indicates scanForJpegBlockOffsets() needs to be called
549    // prior to grabbing a block.
550    //---
551    bool m_jpegOffsetsDirty;
552 
553 TYPE_DATA
554 };
555 
556 #endif /* #ifndef ossimNitfTileSource_HEADER */
557