OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimOpjJp2Writer.cpp
Go to the documentation of this file.
1 //----------------------------------------------------------------------------
2 //
3 // License: See top level LICENSE.txt file
4 //
5 // Author: David Burken
6 //
7 // Description: OSSIM Open JPEG writer.
8 //
9 //----------------------------------------------------------------------------
10 // $Id: ossimOpjJp2Writer.cpp 11652 2007-08-24 17:14:15Z dburken $
11 
12 #include "ossimOpjJp2Writer.h"
13 #include "ossimOpjCompressor.h"
14 
15 #include <ossim/base/ossimDpt.h>
16 #include <ossim/base/ossimEndian.h>
24 #include <ossim/base/ossimTrace.h>
30 
31 #include <ctime>
32 
34  "ossimOpjJp2Writer",
36 
37 //---
38 // For trace debugging (to enable at runtime do:
39 // your_app -T "ossimOpjJp2Writer:debug" your_app_args
40 //---
41 static ossimTrace traceDebug("ossimOpjJp2Writer:debug");
42 
43 static const ossimIpt DEFAULT_TILE_SIZE(1024, 1024);
44 
45 //---
46 // For the "ident" program which will find all expanded $Id$
47 // them.
48 //---
49 #if OSSIM_ID_ENABLED
50 static const char OSSIM_ID[] = "$Id$";
51 #endif
52 
55  m_outputStream(0),
56  m_ownsStreamFlag(false),
57  m_compressor(new ossimOpjCompressor()),
58  m_do_geojp2(true),
59  m_do_gmljp2(true)
60 {
61  //---
62  // Uncomment for debug mode:
63  // traceDebug.setTraceFlag(true);
64  //---
65 
66  if (traceDebug())
67  {
69  << "ossimOpjJp2Writer::ossimOpjJp2Writer entered" << std::endl;
70 #if OSSIM_ID_ENABLED
72  << "OSSIM_ID: "
73  << OSSIM_ID
74  << std::endl;
75 #endif
76  }
77 
78  // Since there is no internal geometry set the flag to write out one.
79  // setWriteExternalGeometryFlag(true);
80 
81  // Set the output image type in the base class.
82  setOutputImageType(getShortName());
83 }
84 
87  m_outputStream(0),
88  m_ownsStreamFlag(false),
89  m_compressor(new ossimOpjCompressor()),
90  m_do_geojp2(typeName.contains("ossim_opj_geojp2")),
91  m_do_gmljp2(typeName.contains("ossim_opj_gmljp2"))
92 {
93  //---
94  // Uncomment for debug mode:
95  // traceDebug.setTraceFlag(true);
96  //---
97 
98  if (traceDebug())
99  {
101  << "ossimOpjJp2Writer::ossimOpjJp2Writer entered" << std::endl;
102 #if OSSIM_ID_ENABLED
104  << "OSSIM_ID: "
105  << OSSIM_ID
106  << std::endl;
107 #endif
108  }
109 
110  // Since there is no internal geometry set the flag to write out one.
111  // setWriteExternalGeometryFlag(true);
112 
113  // Set the output image type in the base class.
114  setOutputImageType(getShortName());
115 
116  // If typeName is unrecognized, write out both geotiff and gmljp2 headers
117  if ( !m_do_geojp2 && !m_do_gmljp2 )
118  {
119  m_do_geojp2 = true;
120  m_do_gmljp2 = true;
121  }
122 }
123 
125 {
126  // This will flush stream and delete it if we own it.
127  close();
128 }
129 
131 {
132  return ossimString("ossim_opj_jp2");
133 }
134 
136 {
137  return ossimString("ossim open jpeg writer");
138 }
139 
141 {
142  return ossimString("ossimOpjJp2Writer");
143 }
144 
146 {
147  // This method is called from ossimImageFileWriter::execute().
148 
149  bool result = false;
150 
151  if( theInputConnection.valid() &&
153  {
154 
155  // Make sure Area of Interest is an even multiple of tiles
156  ossimIrect areaOfInterest = theInputConnection->getAreaOfInterest();
157  ossimIpt imageSize(areaOfInterest.size());
158  ossimIpt imageLr(areaOfInterest.lr());
159  ossim_uint32 xBoundaryAdjustFactor = DEFAULT_TILE_SIZE.x - (imageSize.x % DEFAULT_TILE_SIZE.x);
160  ossim_uint32 yBoundaryAdjustFactor = DEFAULT_TILE_SIZE.y - (imageSize.y % DEFAULT_TILE_SIZE.y);
161  imageLr.x += xBoundaryAdjustFactor;
162  imageLr.y += yBoundaryAdjustFactor;
163  areaOfInterest.set_lr(imageLr);
164  theInputConnection->setAreaOfInterest(areaOfInterest);
165 
166  // Set the tile size for all processes.
167  theInputConnection->setTileSize( DEFAULT_TILE_SIZE );
169 
170  //---
171  // Note only the master process used for writing...
172  //---
174  {
175  if (!isOpen())
176  {
177  open();
178  }
179 
180  if ( isOpen() )
181  {
182  result = writeStream();
183  }
184  }
185  else // Slave process.
186  {
187  // This will return after all tiles for this node have been processed.
189 
190  result = true;
191  }
192  }
193 
194  return result;
195 
196 } // End: ossimOpjJp2Writer::writeFile()
197 
199 {
200  static const char MODULE[] = "ossimOpjJp2Writer::write";
201 
202  if (traceDebug())
203  {
205  << MODULE << " entered..." << endl;
206  }
207 
208  bool result = false;
209 
212  {
213  result = true; // Assuming good at this point...
214 
215  ossim_uint32 outputTilesWide =
217  ossim_uint32 outputTilesHigh =
219  ossim_uint32 numberOfTiles =
222 
223  if (traceDebug())
224  {
226  << MODULE << " DEBUG:"
227  << "\noutputTilesWide: " << outputTilesWide
228  << "\noutputTilesHigh: " << outputTilesHigh
229  << "\nnumberOfTiles: " << numberOfTiles
230  << "\nimageRect: " << theInputConnection->getAreaOfInterest()
231  << std::endl;
232  }
233 
235 
237 
238  // Create the compressor. Can through an exception.
239  try
240  {
242  scalarType,
243  BANDS,
245  DEFAULT_TILE_SIZE,
246  true);
247  }
248  catch (const ossimException& e)
249  {
250  ossimNotify(ossimNotifyLevel_WARN) << e.what() << std::endl;
251  return false;
252  }
253 
255 
256  // Flush the stream since we're going to mess with it.
257  m_outputStream->flush();
258 
259  // cout << "tellp 1: " << m_outputStream->tellp();
260 
261  // Back up to start of jp2c lbox.
262  m_outputStream->seekp( -8, std::ios_base::cur );
263  std::streamoff origJp2cBoxPos = m_outputStream->tellp();
264 
265  // cout << "origJp2cBoxPos: " << origJp2cBoxPos << endl;
266 
267  // Copy the lbox and tbox for jp2c (codestream).
268  std::vector<ossim_uint8> jp2cHdr;
269  copyData( origJp2cBoxPos, 8, jp2cHdr );
270 
271  // Write the geotiff and gml boxes:
272  // Overwrite!!! Supreme hack. (drb - 20150326)
273  if ( m_do_geojp2 == true )
275  if ( m_do_gmljp2 == true )
277  m_outputStream->flush();
278 
279  std::streamoff newJp2cBoxPos = m_outputStream->tellp();
280  // cout << "newJp2cBoxPos: " << newJp2cBoxPos << endl;
281 
282  // Write the jp2c hdr after the geotiff box:
283  m_outputStream->write( (char*)&jp2cHdr, jp2cHdr.size() );
284 
285  // Copy the lbox and tbox for geotiff box
286  std::vector<ossim_uint8> geotiffHdr;
287  copyData( origJp2cBoxPos, 8, geotiffHdr );
288 
289  bool needAlpha = m_compressor->getAlphaChannelFlag();
290  ossim_uint32 tileIndex = 0;
291 
292  // Tile loop in the line direction.
293  for(ossim_uint32 y = 0; y < outputTilesHigh; ++y)
294  {
295  // Tile loop in the sample (width) direction.
296  for(ossim_uint32 x = 0; x < outputTilesWide; ++x)
297  {
298  // Grab the resampled tile.
300  if (t.valid() && ( t->getDataObjectStatus() != OSSIM_NULL ) )
301  {
302  if (needAlpha)
303  {
304  t->computeAlphaChannel();
305  }
306  if ( ! m_compressor->writeTile( t.get(), tileIndex++) )
307  {
309  << MODULE << " ERROR:"
310  << "Error returned writing tile: "
311  << tileNumber
312  << std::endl;
313  result = false;
314  }
315  }
316  else
317  {
319  << MODULE << " ERROR:"
320  << "Error returned writing tile: " << tileNumber
321  << std::endl;
322  result = false;
323  }
324  if (result == false)
325  {
326  // This will bust out of both loops.
327  x = outputTilesWide;
328  y = outputTilesHigh;
329  }
330 
331  // Increment tile number for percent complete.
332  ++tileNumber;
333 
334  } // End of tile loop in the sample (width) direction.
335 
336  if (needsAborting())
337  {
338  setPercentComplete(100.0);
339  break;
340  }
341  else
342  {
343  ossim_float64 tile = tileNumber;
344  ossim_float64 numTiles = numberOfTiles;
345  setPercentComplete(tile / numTiles * 100.0);
346  }
347 
348  } // End of tile loop in the line (height) direction.
349 
350  if (m_outputStream)
351  {
352  m_outputStream->flush();
353  }
354 
355  m_compressor->finish();
356 
357  // Grab the jp2c hdr again in case the lbox changes.
358  copyData( origJp2cBoxPos, 8, jp2cHdr );
359 
360  // Re-write the geotiff lbox and tbox:
361  m_outputStream->seekp( origJp2cBoxPos, std::ios_base::beg );
362  m_outputStream->write( (char*)&geotiffHdr.front(), geotiffHdr.size() );
363 
364  // Re-write the jp2c hdr at new position:
365  m_outputStream->seekp( newJp2cBoxPos, std::ios_base::beg );
366  m_outputStream->write( (char*)&jp2cHdr.front(), jp2cHdr.size() );
367 
368  m_outputStream->flush();
369  close();
370 
371  } // matches: if (theInputConnection.valid() ...
372 
373  if (traceDebug())
374  {
376  << MODULE << " exit status = " << (result?"true":"false\n")
377  << std::endl;
378  }
379 
380  return result;
381 }
382 
383 bool ossimOpjJp2Writer::isOpen() const
384 {
385  if (m_outputStream)
386  {
387  return true;
388  }
389  return false;
390 }
391 
393 {
394  bool result = false;
395 
396  close();
397 
398  // Check for empty filenames.
399  if ( theFilename.size() )
400  {
401  std::ofstream* os = new std::ofstream();
402  os->open(theFilename.c_str(), ios::out | ios::binary);
403  if(os->is_open())
404  {
405  // cout << "opened " << theFilename << endl;
406  m_outputStream = os;
407  m_ownsStreamFlag = true;
408  result = true;
409  }
410  else
411  {
412  delete os;
413  os = 0;
414  }
415  }
416 
417  if (traceDebug())
418  {
420  << "ossimOpjJp2Writer::open()\n"
421  << "File " << theFilename << (result ? " opened" : " not opened")
422  << std::endl;
423  }
424 
425  return result;
426 }
427 
429 {
430  if (m_outputStream)
431  {
432  m_outputStream->flush();
433 
434  if (m_ownsStreamFlag)
435  {
436  delete m_outputStream;
437  m_outputStream = 0;
438  m_ownsStreamFlag = false;
439  }
440  }
441 }
442 
444  const char* prefix)const
445 {
446  return ossimImageFileWriter::saveState(kwl, prefix);
447 }
448 
450  const char* prefix)
451 {
452  const char* value;
453 
454  value = kwl.find(prefix, ossimKeywordNames::OVERVIEW_FILE_KW);
455  if(value)
456  {
457  m_overviewFlag = ossimString(value).toBool();
458  }
459 
460  return ossimImageFileWriter::loadState(kwl, prefix);
461 }
462 
464 {
465  if (!property)
466  {
467  return;
468  }
469 }
470 
472 {
474 }
475 
476 void ossimOpjJp2Writer::getPropertyNames(std::vector<ossimString>& propertyNames)const
477 {
479 }
480 
481 void ossimOpjJp2Writer::getImageTypeList(std::vector<ossimString>& imageTypeList)const
482 {
483  imageTypeList.push_back( getShortName() );
484  imageTypeList.push_back( "ossim_opj_geojp2" );
485  imageTypeList.push_back( "ossim_opj_gmljp2" );
486 }
487 
489 {
490  return ossimString("jp2");
491 }
492 
494 {
495  return true;
496 }
497 
498 bool ossimOpjJp2Writer::hasImageType(const ossimString& imageType) const
499 {
500  bool result = false;
501  if ( (imageType == getShortName()) ||
502  (imageType == "image/jp2") ||
503  (imageType == "image/j2k") ||
504  (imageType == "ossim_opj_geojp2") ||
505  (imageType == "ossim_opj_gmljp2") )
506  {
507  result = true;
508  }
509  return result;
510 }
511 
513 {
515  {
516  delete m_outputStream;
517  }
518  m_outputStream = &stream;
519  m_ownsStreamFlag = false;
520  return true;
521 }
522 
524 {
525  bool result = false;
526 
527  if ( theInputConnection.valid() && stream && compressor )
528  {
530  if ( geom.valid() )
531  {
532  //---
533  // Make a temp file. No means currently write a tiff straight to
534  // memory.
535  //---
537  tmpFile += "-tmp.tif";
538 
539  // Output rect.
541 
542  result = compressor->writeGeotiffBox(stream, geom.get(), rect, tmpFile, getPixelType());
543  }
544  }
545 
546  return result;
547 
548 } // End: ossimKakaduJp2Writer::writeGeotffBox
549 
551 {
552  bool result = false;
553 
554  if ( theInputConnection.valid() && stream && compressor )
555  {
557  if ( geom.valid() )
558  {
559  // Output rect.
561 
562  result = compressor->writeGmlBox(stream, geom.get(), rect );
563  }
564  }
565 
566  return result;
567 
568 } // End: ossimKakaduJp2Writer::writeGmlBox
569 
571  const std::streamoff& pos , ossim_uint32 size, std::vector<ossim_uint8>& data ) const
572 {
573  std::ifstream str;
574  str.open( theFilename.c_str(), std::ios_base::in | std::ios_base::binary);
575  if ( str.is_open() )
576  {
577  data.resize(size);
578  str.seekg( pos, std::ios_base::beg );
579  str.read( (char*)&data.front(), size );
580  }
581 }
ossim_uint32 x
static const char * OVERVIEW_FILE_KW
virtual void close()
void finish()
Finish method.
bool writeGeotiffBox(std::ostream *stream, const ossimImageGeometry *geom, const ossimIrect &rect, const ossimFilename &tmpFile, ossimPixelType pixelType)
Writes the geotiff box to the jp2.
void create(std::ostream *os, ossimScalarType scalar, ossim_uint32 bands, const ossimIrect &imageRect, const ossimIpt &tileSize, bool jp2)
Create method.
virtual void computeAlphaChannel()
Computes the alpha channel.
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
Method to the load (recreate) the state of an object from a keyword list.
ossim_uint32 tileNumber
Represents serializable keyword/value map.
static const ossimErrorCode OSSIM_OK
virtual ossim_uint32 getNumberOfOutputBands() const
Returns the number of bands in a tile returned from this TileSource.
ossim_uint32 y
std::basic_ifstream< char > ifstream
Class for char input file streams.
Definition: ossimIosFwd.h:44
bool valid() const
Definition: ossimRefPtr.h:75
const char * find(const char *key) const
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
virtual bool isOpen() const
virtual ossimRefPtr< ossimImageData > getNextTile(ossim_uint32 resLevel=0)
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
virtual bool writeFile()
Writes the file to disk or a stream.
virtual ossimDataObjectStatus getDataObjectStatus() const
bool writeGmlBox(std::ostream *stream, ossimOpjCompressor *compressor)
virtual ossimString getShortName() const
Pure virtual base class for image file writers.
virtual void getPropertyNames(std::vector< ossimString > &propertyNames) const
Pushes this&#39;s names onto the list of property names.
virtual ossimString getClassName() const
virtual void getPropertyNames(std::vector< ossimString > &propertyNames) const
ossimIpt size() const
Definition: ossimIrect.h:510
virtual ossimString getExtension() const
Returns a 3-letter extension from the image type descriptor (theOutputImageType) that can be used for...
virtual ossimRefPtr< ossimProperty > getProperty(const ossimString &name) const
double ossim_float64
virtual void setAreaOfInterest(const ossimIrect &areaOfInterest)
virtual ossimScalarType getOutputScalarType() const
This will be used to query the output pixel type of the tile source.
yy_size_t size
virtual bool getOutputHasInternalOverviews(void) const
Examples of writers that always generate internal overviews are ossim_kakadu_jp2 and ossim_kakadu_nit...
virtual const char * what() const
Returns the error message.
virtual ossimString getShortName() const
std::string::size_type size() const
Definition: ossimString.h:405
ossimRefPtr< ossimImageSourceSequencer > theInputConnection
bool toBool() const
String to numeric methods.
virtual ossimIrect getBoundingRect(ossim_uint32 resLevel=0) const
This will return the bounding rect of the source.
unsigned int ossim_uint32
virtual ~ossimOpjJp2Writer()
bool hasImageType(const ossimString &imageType) const
const ossimIpt & lr() const
Definition: ossimIrect.h:276
virtual ossimPixelType getPixelType() const
virtual ossimRefPtr< ossimProperty > getProperty(const ossimString &name) const
virtual bool writeStream()
Method to write the image to a stream.
virtual ossimRefPtr< ossimImageGeometry > getImageGeometry()
Returns the image geometry object associated with this tile source or NULL if not defined...
ossimScalarType
virtual void setProperty(ossimRefPtr< ossimProperty > property)
Will set the property whose name matches the argument "property->getName()".
ossim_int64 getNumberOfTilesHorizontal() const
void set_lr(const ossimIpt &pt)
Definition: ossimIrect.h:623
virtual ossimErrorCode getErrorStatus() const
virtual ossimString getLongName() const
ossimFilename fileNoExtension() const
void copyData(const std::streamoff &pos, ossim_uint32 size, std::vector< ossim_uint8 > &data) const
Hack to copy bytes to vector so we can re-write them.
ossimOpjCompressor * m_compressor
bool writeGeotiffBox(std::ostream *stream, ossimOpjCompressor *compressor)
std::ostream * m_outputStream
const char * c_str() const
Returns a pointer to a null-terminated array of characters representing the string&#39;s contents...
Definition: ossimString.h:396
virtual bool open()
const ossimIrect & getAreaOfInterest() const
ossim_int32 x
Definition: ossimIpt.h:141
std::basic_ofstream< char > ofstream
Class for char output file streams.
Definition: ossimIosFwd.h:47
virtual bool setOutputStream(std::ostream &stream)
Sets the output stream to write to.
virtual void getImageTypeList(std::vector< ossimString > &imageTypeList) const
void getImageTypeList(std::vector<ossimString>& imageTypeList)const
#define RTTI_DEF1(cls, name, b1)
Definition: ossimRtti.h:485
virtual void setPercentComplete(double percentComplete)
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
saves the state of the object.
virtual void setTileSize(const ossimIpt &tileSize)
bool writeGmlBox(std::ostream *stream, const ossimImageGeometry *geom, const ossimIrect &rect)
Writes the gml box to the jp2.
bool getAlphaChannelFlag() const
Retrieve the writer&#39;s setting for whether or not to add an alpha channel to the output png image...
void openJp2Codestream()
Calls "open_codestream" on the m_jp2Target.
bool writeTile(ossimImageData *srcTile, ossim_uint32 tileIndex)
Write tile method.
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
ossim_int64 getNumberOfTilesVertical() const
std::basic_ostream< char > ostream
Base class for char output streams.
Definition: ossimIosFwd.h:23