OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimOpjCompressor.cpp
Go to the documentation of this file.
1 //----------------------------------------------------------------------------
2 //
3 // License: LGPL
4 //
5 // See LICENSE.txt file in the top level directory for more details.
6 //
7 // Author: David Burken
8 //
9 // Description: Wrapper class to compress whole tiles using kdu_analysis
10 // object.
11 //
12 //----------------------------------------------------------------------------
13 // $Id: ossimOpjCompressor.cpp 22513 2013-12-11 21:45:51Z dburken $
14 
15 #include "ossimOpjCompressor.h"
16 #include "ossimOpjCommon.h"
17 #include "ossimOpjKeywords.h"
18 
21 #include <ossim/base/ossimIpt.h>
24 #include <ossim/base/ossimNotify.h>
28 #include <ossim/base/ossimTrace.h>
29 
32 
35 
36 #include <sstream>
37 
38 //---
39 // For trace debugging (to enable at runtime do:
40 // your_app -T "ossimOpjCompressor:debug" your_app_args
41 //---
42 static ossimTrace traceDebug("ossimOpjCompressor:debug");
43 
44 static const ossim_int32 DEFAULT_LEVELS = 5;
45 
46 // Callback stream function prototypes:
47 static OPJ_SIZE_T ossim_opj_ostream_write( void * p_buffer,
48  OPJ_SIZE_T p_nb_bytes,
49  void * p_user_data )
50 {
51  OPJ_SIZE_T count = 0;
52  if ( p_user_data )
53  {
54  ostream* str = (ostream*)p_user_data;
55  std::streamsize bytesToRead = (std::streamsize)p_nb_bytes;
56  str->write( (char*) p_buffer, bytesToRead );
57  count = p_nb_bytes;
58  }
59  return count;
60 }
61 
62 // Callback function prototype for skip function:
63 static OPJ_OFF_T ossim_opj_ostream_skip(OPJ_OFF_T p_nb_bytes, void * p_user_data)
64 {
65  OPJ_OFF_T pos = 0;
66  if ( p_user_data )
67  {
68  ostream* str = (ostream*)p_user_data;
69  str->seekp( p_nb_bytes, std::ios_base::cur );
70  pos = p_nb_bytes;
71  }
72  return pos;
73 }
74 
76 static OPJ_BOOL ossim_opj_ostream_seek(OPJ_OFF_T p_nb_bytes, void * p_user_data)
77 {
78  if ( p_user_data )
79  {
80  ostream* str = (ostream*)p_user_data;
81  // str->seekp( p_nb_bytes, std::ios_base::cur );
82  str->seekp( p_nb_bytes, std::ios_base::beg );
83  }
84  return OPJ_TRUE;
85 }
86 
87 static void ossim_opj_free_user_ostream_data( void * p_user_data )
88 {
89  if ( p_user_data )
90  {
91  ostream* str = (ostream*)p_user_data;
92  str->flush();
93  }
94 }
95 
96 // Matches ossimOpjCompressionQuality enumeration:
97 static const ossimString COMPRESSION_QUALITY[] = { "unknown",
98  "user_defined",
99  "numerically_lossless",
100  "visually_lossless",
101  "lossy" };
102 
103 
105  :
106  m_params(0),
107  m_codec(0),
108  m_stream(0),
109  m_image(0),
110  m_imageRect(),
111  m_reversible(true),
112  m_alpha(false),
113  m_levels(0),
114  m_threads(1),
115  m_options(),
116  m_qualityType(ossimOpjCompressor::OPJ_NUMERICALLY_LOSSLESS)
117 {
118  //---
119  // Uncomment for debug mode:
120  // traceDebug.setTraceFlag(true);
121  //---
122 }
123 
125 {
126  finish();
127 }
128 
130  ossimScalarType scalar,
131  ossim_uint32 bands,
132  const ossimIrect& imageRect,
133  const ossimIpt& tileSize,
134  bool jp2)
135 {
136  static const char MODULE[] = "ossimOpjCompressor::create";
137  if ( traceDebug() )
138  {
139  ossimNotify(ossimNotifyLevel_WARN) << MODULE << " entered...\n";
140  }
141 
142 #if 0 /* Please leave for debug. (drb) */
143  cout << "levels: " << m_levels
144  << "\nreversible: " << m_reversible
145  << "\nthreads: " << m_threads
146  << "\nscalar: " << scalar
147  << "\nbands: " << bands
148  << "\nimageRect: " << imageRect
149  << "\ntileSize: " << tileSize
150  << "\njp2: " << jp2
151  << endl;
152 #endif
153 
154  // In case we were reused.
155  finish();
156 
157  if ( !os )
158  {
159  std::string errMsg = MODULE;
160  errMsg += " ERROR: Null stream passed to method!";
161  throw ossimException(errMsg);
162  }
163 
164  if ( !os->good() )
165  {
166  std::string errMsg = MODULE;
167  errMsg += " ERROR: Stream state has error!";
168  throw ossimException(errMsg);
169  }
170 
171  if ( ossim::getActualBitsPerPixel(scalar) > 31 )
172  {
173  // Data is not reversible.
174  if ( m_reversible )
175  {
176  std::string errMsg = MODULE;
177  errMsg += " ERROR: Reversible processing not possible with 32 bit data!";
178  throw ossimException(errMsg);
179  }
180  }
181 
182  // Store for tile clip.
183  m_imageRect = imageRect;
184 
185  m_stream = createOpjStream( os );
186  if ( !m_stream )
187  {
188  std::string errMsg = MODULE;
189  errMsg += " ERROR: OPJ stream creation failed!";
190  throw ossimException(errMsg);
191  }
192 
193  // Requests the insertion of TLM (tile-part-length) marker.
194  // setTlmTileCount(tilesToWrite);
195 
196  // Set up stream:
197  initOpjCodingParams( jp2, tileSize, imageRect );
198  if ( !m_params )
199  {
200  std::string errMsg = MODULE;
201  errMsg += " ERROR: coding parameters creation failed!";
202  throw ossimException(errMsg);
203  }
204 
205  m_codec = createOpjCodec( jp2 );
206  if ( !m_codec )
207  {
208  std::string errMsg = MODULE;
209  errMsg += " ERROR: code creation failed!";
210  throw ossimException(errMsg);
211  }
212 
213  // Set rates rates/distorsion
214  // parameters->cp_disto_alloc = 1;
215 
216  // ossim::print( cout, *m_params );
217 
218  if (m_alpha)
219  {
220  if ( (bands != 1) && (bands != 3) )
221  {
222  m_alpha = false;
223  if ( traceDebug() )
224  {
226  << "Alpha channel being unset! Can only be used with "
227  << "one or three band data.\n"
228  << "Source image bands: " << bands << "\n";
229  }
230  }
231  }
232 
233  // Create an image without allocating memory(for tile based).
234  m_image = createOpjImage( scalar, bands, imageRect );
235  if ( !m_image )
236  {
237  std::string errMsg = MODULE;
238  errMsg += " ERROR: Unsupported input image type!";
239  throw ossimException(errMsg);
240  }
241 
242  if ( !opj_setup_encoder( m_codec, m_params, m_image) )
243  {
244  std::string errMsg = MODULE;
245  errMsg += " ERROR: opj_setup_encoder failed!";
246  throw ossimException(errMsg);
247  }
248 
249  // openJp2Codestream();
250 
251  if ( traceDebug() )
252  {
254 
256  << MODULE << " exiting...\n";
257  }
258 }
259 
261 {
262  //---
263  // Start compression...
264  // Matching "opj_end_compress" is in ossimOpjCompressor::finish().
265  //---
266  if ( !opj_start_compress(m_codec, m_image, m_stream) )
267  {
268  std::string errMsg = "ossimOpjCompressor::openJp2Codestream ERROR: opj_start_compress failed!";
269  throw ossimException(errMsg);
270  }
271 }
272 
274  ossimImageData* srcTile, ossim_uint32 tileIndex )
275 {
276  bool result = false;
277 
278  if ( srcTile )
279  {
280  if (srcTile->getDataObjectStatus() != OSSIM_NULL)
281  {
282  ossimIrect tileRect = srcTile->getImageRectangle();
283 
284  // Write the tile out:
285  if ( opj_write_tile( m_codec,
286  tileIndex,
287  srcTile->getUcharBuf(),
288  srcTile->getDataSizeInBytes(),
289  m_stream ) )
290  {
291  result = true;
292  }
293  else
294  {
296  << "ossimOpjCompressor::writeTile ERROR on tile index: "
297  << tileIndex << std::endl;
298  }
299  }
300  else
301  {
303  << "ossimOpjCompressor::writeTile ERROR null tile passed in!" << endl;
304  }
305  }
306 
307  return result;
308 
309 } // End: ossimOpjCompressor::writeTile
310 
312 {
313  if ( m_stream )
314  {
315  // Every opj_start_compress must have an end.
316  opj_end_compress( m_codec, m_stream );
317 
318  opj_stream_destroy( m_stream );
319  m_stream = 0;
320  }
321  if ( m_codec )
322  {
323  opj_destroy_codec( m_codec );
324  m_codec = 0;
325  }
326  if ( m_image )
327  {
328  opj_image_destroy( m_image );
329  m_image = 0;
330  }
331 }
332 
334 {
335  m_qualityType = type;
336 
337  //---
338  // Set the reversible flag for appropriate type.
339  // Not sure what to set for unknown and user defined but visually lossless
340  // and lossy need to set the reversible flag to false.
341  //---
344  {
345  setReversibleFlag(false);
346  }
347  else
348  {
349  setReversibleFlag(true);
350  }
351 }
352 
354 {
355  return m_qualityType;
356 
357 }
358 
360 {
361  m_reversible = reversible;
362 }
363 
365 {
366  return m_reversible;
367 }
368 
370 {
371  m_alpha = flag;
372 }
373 
375 {
376  return m_alpha;
377 }
378 
380 {
381  if (levels)
382  {
383  m_levels = levels;
384  }
385 }
386 
388 {
389  return m_levels;
390 }
391 
393 {
394  if (threads)
395  {
396  m_threads = threads;
397  }
398 }
399 
401 {
402  return m_threads;
403 }
404 
405 void ossimOpjCompressor::setOptions(const std::vector<ossimString>& options)
406 {
407  std::vector<ossimString>::const_iterator i = options.begin();
408  while ( i != options.end() )
409  {
410  m_options.push_back( (*i) );
411  ++i;
412  }
413 }
414 
416 {
417  bool consumed = false;
418 
419  if ( property.valid() )
420  {
421  ossimString key = property->getName();
422 
423  if ( traceDebug() )
424  {
426  << "ossimOpjCompressor::setProperty DEBUG:"
427  << "\nkey: " << key
428  << " values: " << property->valueToString() << std::endl;
429  }
430 
432  {
433  setQualityTypeString(property->valueToString());
434  consumed = true;
435  }
436  else if ( (key == LEVELS_KW) || (key == "Clevels") )
437  {
438  m_levels = property->valueToString().toInt32();
439  consumed = true;
440  }
441  else if( (key == REVERSIBLE_KW) || (key == "Creversible") )
442  {
443  setReversibleFlag(property->valueToString().toBool());
444  consumed = true;
445  }
446  else if (key == ADD_ALPHA_CHANNEL_KW)
447  {
448  m_alpha = property->valueToString().toBool();
449  consumed = true;
450  }
451  else if ( key == THREADS_KW)
452  {
453  m_threads = property->valueToString().toInt32();
454  consumed = true;
455  }
456  else if ( (key == "Clayers") ||
457  (key == "Cprecincts") )
458  {
459  // Generic options passed through kdu_params::parse_string.
460 
461  // Make in the form of "key=value" for kdu_params::parse_string.
462  ossimString option = key;
463  option += "=";
464  option += property->valueToString();
465 
466  // Add to list.
467  m_options.push_back(option);
468 
469  consumed = true;
470  }
471  }
472 
473  return consumed;
474 }
475 
477  const ossimString& name)const
478 {
480 
482  {
483  // property value
485 
486  if ( (value == COMPRESSION_QUALITY[ossimOpjCompressor::OPJ_USER_DEFINED] ) ||
487  (value == COMPRESSION_QUALITY[ossimOpjCompressor::OPJ_UNKNOWN])
488  )
489  {
490  value = COMPRESSION_QUALITY[ossimOpjCompressor::OPJ_NUMERICALLY_LOSSLESS];
491  }
492 
493  // constraint list
494  vector<ossimString> constraintList;
495  constraintList.push_back(COMPRESSION_QUALITY[ossimOpjCompressor::
497  constraintList.push_back(COMPRESSION_QUALITY[ossimOpjCompressor::
499  constraintList.push_back(COMPRESSION_QUALITY[ossimOpjCompressor::
500  OPJ_LOSSY]);
501 
502  p = new ossimStringProperty(name,
503  value,
504  false, // not editable
505  constraintList);
506  }
507  else if (name == LEVELS_KW)
508  {
510  }
511  else if (name == REVERSIBLE_KW)
512  {
513  p = new ossimBooleanProperty(name, m_reversible);
514  }
515  else if (name == ADD_ALPHA_CHANNEL_KW)
516  {
517  p = new ossimBooleanProperty(name, m_alpha);
518  }
519  else if (name == THREADS_KW)
520  {
522  }
523 
524  return p;
525 }
526 
528  std::vector<ossimString>& propertyNames)const
529 {
530  propertyNames.push_back(ossimKeywordNames::COMPRESSION_QUALITY_KW);
531  propertyNames.push_back(LEVELS_KW);
532  propertyNames.push_back(REVERSIBLE_KW);
533  propertyNames.push_back(THREADS_KW);
534 }
535 
537  const char* prefix)const
538 {
539  kwl.add( prefix,
541  getQualityTypeString().c_str(),
542  true );
543 
544  kwl.add( prefix,
545  LEVELS_KW,
547  true );
548 
549  kwl.add( prefix,
550  REVERSIBLE_KW,
552  true );
553 
554  kwl.add( prefix,
555  ADD_ALPHA_CHANNEL_KW,
557  true );
558 
559  kwl.add( prefix,
560  THREADS_KW,
562  true );
563 
564  std::vector<ossimString>::size_type size = m_options.size();
565  for (ossim_uint32 i = 0; i < size; ++i)
566  {
567  ossimString key = "option";
568  key += ossimString::toString(i);
569 
570  kwl.add( prefix,
571  key.c_str(),
572  m_options[i].c_str(),
573  true );
574  }
575 
576  return true;
577 }
578 
580  const char* prefix)
581 {
582  const char* value = 0;
583 
584  value = kwl.find(prefix, ossimKeywordNames::COMPRESSION_QUALITY_KW);
585  if(value)
586  {
588  }
589 
590  value = kwl.find(prefix, LEVELS_KW);
591  if(value)
592  {
593  m_levels = ossimString(value).toInt32();
594  }
595 
596  value = kwl.find(prefix, REVERSIBLE_KW);
597  if(value)
598  {
599  setReversibleFlag(ossimString(value).toBool());
600  }
601 
602  value = kwl.find(prefix, ADD_ALPHA_CHANNEL_KW);
603  if(value)
604  {
605  m_alpha = ossimString(value).toBool();
606  }
607 
608  value = kwl.find(prefix, THREADS_KW);
609  if(value)
610  {
611  m_threads = ossimString(value).toInt32();
612  }
613 
614  ossimString searchKey;
615  if (prefix)
616  {
617  searchKey = prefix;
618  }
619  searchKey += "option";
620  ossim_uint32 nOptions = kwl.numberOf(searchKey);
621  for (ossim_uint32 i = 0; i < nOptions; ++i)
622  {
623  ossimString key = searchKey;
624  key += ossimString::toString(i);
625 
626  const char* lookup = kwl.find(key.c_str());
627  if (lookup)
628  {
629  m_options.push_back(ossimString(lookup));
630  }
631  }
632 
633  return true;
634 }
635 
637  const ossimImageGeometry* geom,
638  const ossimIrect& rect,
639  const ossimFilename& tmpFile,
640  ossimPixelType pixelType)
641 {
642  // cout << "ossimOpjCompressor::writeGeotiffBox entered..." << endl;
643 
644 
645  bool result = false;
646 
647  if ( stream && geom )
648  {
651  if ( proj.valid() )
652  {
653  //---
654  // Make a temp file. No means currently write a tiff straight to
655  // memory.
656  //---
657 
658  // Buffer to hold the tiff box.
659  std::vector<ossim_uint8> buf;
660 
661  // Write to buffer.
663  rect,
664  proj.get(),
665  buf,
666  pixelType) )
667  {
668  //---
669  // JP2 box type uuid in ascii expressed as an int.
670  // "u(75), u(75), i(69), d(64)"
671  //---
672  const ossim_uint8 UUID[4] =
673  {
674  0x75, 0x75, 0x69, 0x64
675  };
676 
677  ossim_uint32 lbox = buf.size() + 8;
678 
679  // cout << "gbox tellp: " << stream->tellp() << endl;
680  // cout << "lbox: " << lbox << endl;
681 
683  {
684  ossimEndian endian;
685  endian.swap( lbox );
686  }
687 
688  stream->write( (char*)&lbox, 4 ); // LBox
689 
690  stream->write((const char*)UUID, 4); // TBox
691 
692  // DBox: geotiff
693  stream->write((const char*)&buf.front(), (std::streamsize)buf.size());
694 
695  result = true;
696 
697  // cout << "wrote box!!!" << endl;
698  }
699  }
700  }
701 
702  return result;
703 
704 } // End: ossimOpjCompressor::writeGeotiffBox
705 
707  const ossimImageGeometry* geom,
708  const ossimIrect& rect )
709 {
710  // cout << "ossimOpjCompressor::writeGmlBox entered..." << endl;
711 
712  bool result = false;
713 
714  if ( stream && geom )
715  {
717 
718  if ( gml->initialize( geom, rect ) )
719  {
720  const ossim_uint8 ASOC_BOX_ID[4] =
721  {
722  0x61, 0x73, 0x6F, 0x63
723  };
724 
725  const ossim_uint8 LBL_BOX_ID[4] =
726  {
727  0x6C, 0x62, 0x6C, 0x20
728  };
729 
730  const ossim_uint8 XML_BOX_ID[4] =
731  {
732  0x78, 0x6D, 0x6C, 0x20
733  };
734 
735  // Write the xml to a stream.
736  ostringstream xmlStr;
737  if ( gml->write( xmlStr ) )
738  {
739  ossim_uint32 xmlDataSize = xmlStr.str().size();
740 
741  // Set the 1st asoc box size and type
742  ossim_uint32 boxSize = xmlDataSize + 17 + 8 + 8 + 8 + 8 + 8 + 8;
744  {
745  ossimEndian endian;
746  endian.swap( boxSize );
747  }
748  stream->write((char*)&boxSize, 4); // 1st asoc size
749  stream->write((const char*)ASOC_BOX_ID, 4); // 1st asoc type
750 
751  // Set the 1st lbl box size, type, and data
752  boxSize = 8 + 8;
754  {
755  ossimEndian endian;
756  endian.swap( boxSize );
757  }
758  stream->write((char*)&boxSize, 4); // 1st lbl size
759  stream->write((const char*)LBL_BOX_ID, 4); // 1st lbl type
760  stream->write("gml.data", 8); // 1st lbl data
761 
762  // Set the 2nd asoc box size and type
763  boxSize = xmlDataSize + 17 + 8 + 8 + 8;
765  {
766  ossimEndian endian;
767  endian.swap( boxSize );
768  }
769  stream->write((char*)&boxSize, 4); // 2nd asoc size
770  stream->write((const char*)ASOC_BOX_ID, 4); // 2nd asoc type
771 
772  // Set the 2nd lbl box size, type, and data
773  boxSize = 17 + 8;
775  {
776  ossimEndian endian;
777  endian.swap( boxSize );
778  }
779  stream->write((char*)&boxSize, 4); // 2nd lbl size
780  stream->write((const char*)LBL_BOX_ID, 4); // 2nd lbl type
781  stream->write("gml.root-instance", 17); // 2nd lbl data
782 
783  // Set the xml box size, type, and data
784  boxSize = xmlDataSize + 8;
786  {
787  ossimEndian endian;
788  endian.swap( boxSize );
789  }
790  stream->write((char*)&boxSize, 4); // xml size
791  stream->write((const char*)XML_BOX_ID, 4); // xml type
792  stream->write(xmlStr.str().data(), xmlDataSize); // xml data
793 
794  result = true;
795 
796  //cout << "wrote gml box!!!" << endl;
797  }
798  }
799 
800  // cleanup:
801  delete gml;
802  gml = 0;
803  }
804 
805  return result;
806 
807 } // End: ossimOpjCompressor::writeGmlBox
808 
810  const ossimIpt& tileSize,
811  const ossimIrect& imageRect )
812 {
813  static const char MODULE[] = "ossimOpjCompressor::initOpjCodingParams";
814  if ( traceDebug() )
815  {
816  ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " entered...\n";
817  }
818 
819  if ( m_params )
820  {
821  delete m_params;
822  }
823 
824  m_params = new opj_cparameters_t();
825 
826  // Set encoding parameters to default values.
827  opj_set_default_encoder_parameters( m_params );
828 
829  // Output format: 0: J2K, 1: JP2, 2: JPT
830  m_params->cod_format = jp2 ? 1 : 0;
831 
832  // std::string outfile = "test.jp2";
833  // strncpy(m_params->outfile, outfile.data(), outfile.size());
834 
835  //---
836  // Shall we do an Multi-component Transformation(MCT) ?
837  // 0:no_mct;1:rgb->ycc;2:custom mct
838  //---
839 
840  // Set the tiles size:
841  m_params->cp_tx0 = 0;
842  m_params->cp_ty0 = 0;
843  m_params->cp_tdx = tileSize.x;
844  m_params->cp_tdy = tileSize.y;
845  m_params->tile_size_on = OPJ_TRUE;
846 
847  // No mct.
848  m_params->tcp_mct = 0;
849 
850  //---
851  // Number of resolutions:
852  // This sets m_levels if not set and
853  // m_params->numresolution.
854  //---
855  initLevels( imageRect );
856 
857  // Set the block size. Note 64x64 is the current kakadu default.
858  setCodeBlockSize( 64, 64 );
859 
860  //---
861  // Set progression order to use. Note LRCP is the current opj default.
862  // L=layer; R=resolution C=component; P=position
863  //
864  // OPJ_LRCP, OPJ_RLCP, OPJ_RPCL, PCRL, CPRL */
865  //---
866  setProgressionOrder( OPJ_LRCP );
867 
868  // total pixels
869  const ossim_float64 TP = imageRect.area();
870 
871  if ( traceDebug() )
872  {
874  << "quality type: " << getQualityTypeString() << endl;
875  }
876 
877  //---
878  // Rate is a ratio of desired bytes / total bytes. So if you
879  // want 4 bits per pixels it's total_pixels * 4 / 8 or
880  // total_pixels * 4 * 0.125.
881  //---
882 
883  // Allocation by rate/distortion.
884  m_params->cp_disto_alloc = 1;
885 
886  switch (m_qualityType)
887  {
889  {
890  // cout << "ossimOpjCompressor::OPJ_NUMERICALLY_LOSSLESS..." << endl;
891 
892  // W5X3 Kernel
893  setReversibleFlag(true);
894 
895  // Tmp drb...
896  m_params->tcp_numlayers = 1;
897  m_params->tcp_rates[0] = 1;
898 
899 #if 0
900 
901  m_params->tcp_numlayers = 20;
902 
903  m_params->tcp_rates[0] = std::ceil( TP * 0.03125 * 0.125 );
904  m_params->tcp_rates[1] = std::ceil( TP * 0.0625 * 0.125 );
905  m_params->tcp_rates[2] = std::ceil( TP * 0.125 * 0.125 );
906  m_params->tcp_rates[3] = std::ceil( TP * 0.25 * 0.125 );
907  m_params->tcp_rates[4] = std::ceil( TP * 0.5 * 0.125 );
908  m_params->tcp_rates[5] = std::ceil( TP * 0.6 * 0.125 );
909  m_params->tcp_rates[6] = std::ceil( TP * 0.7 * 0.125 );
910  m_params->tcp_rates[7] = std::ceil( TP * 0.8 * 0.125 );
911  m_params->tcp_rates[8] = std::ceil( TP * 0.9 * 0.125 );
912  m_params->tcp_rates[9] = std::ceil( TP * 1.0 * 0.125 );
913  m_params->tcp_rates[10] = std::ceil( TP * 1.1 * 0.125 );
914  m_params->tcp_rates[11] = std::ceil( TP * 1.2 * 0.125 );
915  m_params->tcp_rates[12] = std::ceil( TP * 1.3 * 0.125 );
916  m_params->tcp_rates[13] = std::ceil( TP * 1.5 * 0.125 );
917  m_params->tcp_rates[14] = std::ceil( TP * 1.7 * 0.125 );
918  m_params->tcp_rates[15] = std::ceil( TP * 2.0 * 0.125 );
919  m_params->tcp_rates[16] = std::ceil( TP * 2.3 * 0.125 );
920  m_params->tcp_rates[17] = std::ceil( TP * 2.8 * 0.125 );
921  m_params->tcp_rates[18] = std::ceil( TP * 3.5 * 0.125 );
922 
923  //---
924  // Indicate that the final quality layer should include all
925  // compressed bits.
926  //---
927  // m_params->tcp_rates[19] = OSSIM_DEFAULT_MAX_PIX_SINT32; // KDU_LONG_MAX;
928  m_params->tcp_rates[19] = std::ceil( TP * 4.0 * 0.125 );
929 
930 #endif
931 
932  break;
933  }
935  {
936  // W9X7 kernel:
937  setReversibleFlag(false);
938 
939  m_params->tcp_numlayers = 19;
940 
941  m_params->tcp_rates[0] = std::ceil( TP * 0.03125 * 0.125 );
942  m_params->tcp_rates[1] = std::ceil( TP * 0.0625 * 0.125 );
943  m_params->tcp_rates[2] = std::ceil( TP * 0.125 * 0.125 );
944  m_params->tcp_rates[3] = std::ceil( TP * 0.25 * 0.125 );
945  m_params->tcp_rates[4] = std::ceil( TP * 0.5 * 0.125 );
946  m_params->tcp_rates[5] = std::ceil( TP * 0.6 * 0.125 );
947  m_params->tcp_rates[6] = std::ceil( TP * 0.7 * 0.125 );
948  m_params->tcp_rates[7] = std::ceil( TP * 0.8 * 0.125 );
949  m_params->tcp_rates[8] = std::ceil( TP * 0.9 * 0.125 );
950  m_params->tcp_rates[9] = std::ceil( TP * 1.0 * 0.125 );
951  m_params->tcp_rates[10] = std::ceil( TP * 1.1 * 0.125 );
952  m_params->tcp_rates[11] = std::ceil( TP * 1.2 * 0.125 );
953  m_params->tcp_rates[12] = std::ceil( TP * 1.3 * 0.125 );
954  m_params->tcp_rates[13] = std::ceil( TP * 1.5 * 0.125 );
955  m_params->tcp_rates[14] = std::ceil( TP * 1.7 * 0.125 );
956  m_params->tcp_rates[15] = std::ceil( TP * 2.0 * 0.125 );
957  m_params->tcp_rates[16] = std::ceil( TP * 2.3 * 0.125 );
958  m_params->tcp_rates[17] = std::ceil( TP * 2.8 * 0.125 );
959  m_params->tcp_rates[18] = std::ceil( TP * 3.5 * 0.125 );
960  break;
961  }
963  {
964  // W9X7 kernel:
965  setReversibleFlag(false);
966 
967  m_params->tcp_numlayers = 10;
968 
969  m_params->tcp_rates[0] = std::ceil( TP * 0.03125 * 0.125 );
970  m_params->tcp_rates[1] = std::ceil( TP * 0.0625 * 0.125 );
971  m_params->tcp_rates[2] = std::ceil( TP * 0.125 * 0.125 );
972  m_params->tcp_rates[3] = std::ceil( TP * 0.25 * 0.125 );
973  m_params->tcp_rates[4] = std::ceil( TP * 0.5 * 0.125 );
974  m_params->tcp_rates[5] = std::ceil( TP * 0.6 * 0.125 );
975  m_params->tcp_rates[6] = std::ceil( TP * 0.7 * 0.125 );
976  m_params->tcp_rates[7] = std::ceil( TP * 0.8 * 0.125 );
977  m_params->tcp_rates[8] = std::ceil( TP * 0.9 * 0.125 );
978  m_params->tcp_rates[9] = std::ceil( TP * 1.0 * 0.125 );
979  break;
980  }
981 
982  default:
983  {
984  m_params->tcp_numlayers = 1;
985  m_params->tcp_rates[0] = 1.0;
986 
987  if (traceDebug())
988  {
990  << "unspecified quality type\n";
991  }
992  }
993 
994  } // matches: switch (m_qualityType)
995 
996 
997 
998  //---
999  // Set reversible flag, note, this controls the kernel.
1000  // W5X3(default) if reversible = true, W9X7 if reversible is false.
1001  //---
1002  m_params->irreversible = !m_reversible;
1003 
1004  if ( traceDebug() )
1005  {
1007  << "m_reversible: " << m_reversible
1008  << "\nm_levels: " << m_levels << "\n";
1009 
1011  }
1012 
1013  if ( traceDebug() )
1014  {
1015  ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " exited...\n";
1016  }
1017 }
1018 
1020 {
1021  return m_params->tcp_numlayers;
1022 }
1023 
1025 {
1026  return COMPRESSION_QUALITY[m_qualityType];
1027 }
1028 
1030 {
1031  ossimString type = s;
1032  type.downcase();
1033 
1034  if ( type == COMPRESSION_QUALITY[ossimOpjCompressor::OPJ_UNKNOWN] )
1035  {
1037  }
1038  else if ( type == COMPRESSION_QUALITY[ossimOpjCompressor::OPJ_USER_DEFINED] )
1039  {
1041  }
1042  else if ( type == COMPRESSION_QUALITY[ossimOpjCompressor::OPJ_NUMERICALLY_LOSSLESS] )
1043  {
1045  }
1046  else if ( type == COMPRESSION_QUALITY[ossimOpjCompressor::OPJ_VISUALLY_LOSSLESS] )
1047  {
1049  }
1050  else if (type == "lossy")
1051  {
1053  }
1054  else
1055  {
1056  if ( traceDebug() )
1057  {
1059  << "ossimOpjCompressor::setQualityTypeString DEBUG"
1060  << "\nUnhandled quality type: " << type
1061  << std::endl;
1062  }
1063  }
1064 }
1065 
1067 {
1068  //---
1069  // Number of wavelet decomposition levels, or stages. May not exceed 32.
1070  // Default is 6 (r0 - r5)
1071  //---
1072  if ( m_levels == 0 )
1073  {
1075  if (m_levels == 0)
1076  {
1077  m_levels = 1; // Must have at least one.
1078  }
1079  }
1080  if ( (m_levels < 1) || (m_levels > 32) )
1081  {
1082  m_levels = 6;
1083  }
1084 
1085  m_params->numresolution = m_levels;
1086 }
1087 
1089  ossim_int32 ySize )
1090 {
1091  if ( m_params )
1092  {
1093  //---
1094  // Nominal code-block dimensions (must be powers of 2 no less than 4 and
1095  // no greater than 1024).
1096  // Default block dimensions are {64,64}
1097  //---
1098  m_params->cblockw_init = xSize;
1099  m_params->cblockh_init = ySize;
1100  }
1101 }
1102 
1103 void ossimOpjCompressor::setProgressionOrder( OPJ_PROG_ORDER progressionOrder )
1104 {
1105  if ( m_params )
1106  {
1107  //---
1108  // Default progression order (may be overridden by Porder).
1109  // The four character identifiers have the following interpretation:
1110  // L=layer; R=resolution; C=component; P=position.
1111  // The first character in the identifier refers to the index which
1112  // progresses most slowly, while the last refers to the index which
1113  // progresses most quickly. [Default is LRCP]
1114  // Enumerations: (LRCP=0,RLCP=1,RPCL=2,PCRL=3,CPRL=4)
1115  //---
1116  m_params->prog_order = progressionOrder;
1117  }
1118 }
1119 
1121 {
1122  //---
1123  // Identifies the maximum number of tile-parts which will be written to the
1124  // code-stream for each tile.
1125  //
1126  // See Opj kdu_params.h "Macro = `ORGgen_tlm'" for more.
1127  //---
1128  // ossimString s = "ORGgen_tlm=1";
1129  // m_codestream.access_siz()->parse_string( s.c_str() );
1130 }
1131 
1132 opj_codec_t* ossimOpjCompressor::createOpjCodec( bool jp2 ) const
1133 {
1134  opj_codec_t* codec = 0;
1135  if ( jp2 )
1136  {
1137  codec = opj_create_compress(OPJ_CODEC_JP2);
1138  }
1139  else
1140  {
1141  codec = opj_create_compress(OPJ_CODEC_J2K);
1142  }
1143 
1144  if ( codec )
1145  {
1146  // Catch events using our callbacks and give a local context.
1147  opj_set_info_handler (codec, ossim::opj_info_callback, 00);
1148  opj_set_warning_handler(codec, ossim::opj_warning_callback,00);
1149  opj_set_error_handler (codec, ossim::opj_error_callback, 00);
1150  }
1151  return codec;
1152 
1153 } // End: opj_codec_t* createOpjCodec()
1154 
1156 {
1157  opj_stream_t* stream = 0;
1158  if ( os )
1159  {
1160  // stream = opj_stream_create_default_file_stream("test.jp2", OPJ_FALSE);
1161 
1162 
1163  // OPJ stream:
1164  // stream = opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE, OPJ_FALSE);
1165  // stream = opj_stream_create(512, OPJ_FALSE);
1166  // stream = opj_stream_create_default_file_stream("test.jp2", OPJ_FALSE); // false = output.
1167  stream = opj_stream_create(1048576, OPJ_FALSE);
1168  if ( stream )
1169  {
1170  // cout << "stream good..." << endl;
1171 
1172  // Set OPJ user stream:
1173  opj_stream_set_user_data(stream, os, ossim_opj_free_user_ostream_data);
1174 
1175  // Set callbacks:
1176  // opj_stream_set_read_function(m_stream, ossim_opj_stream_read);
1177  // opj_stream_set_read_function(stream, ossim_opj_imagedata_read);
1178  opj_stream_set_write_function(stream, ossim_opj_ostream_write);
1179  opj_stream_set_skip_function(stream, ossim_opj_ostream_skip);
1180  opj_stream_set_seek_function(stream, ossim_opj_ostream_seek);
1181  }
1182  }
1183  return stream;
1184 
1185 } // End: ossimOpjCompressor::createOpjStream()
1186 
1188  ossim_uint32 bands,
1189  const ossimIrect& imageRect ) const
1190 {
1191  opj_image_t* image = 0;
1192 
1193  // image component definitions:
1194  opj_image_cmptparm_t* imageParams = new opj_image_cmptparm_t[bands];
1195  opj_image_cmptparm_t* imageParam = imageParams;
1196  for (ossim_uint32 i = 0; i < bands; ++i)
1197  {
1198  imageParam->dx = 1;
1199  imageParam->dy = 1;
1200  imageParam->h = imageRect.height();
1201  imageParam->w = imageRect.width();
1202  imageParam->sgnd = (OPJ_UINT32)ossim::isSigned(scalar);
1203  imageParam->prec = ossim::getActualBitsPerPixel(scalar);
1204  imageParam->bpp = ossim::getBitsPerPixel(scalar);
1205  imageParam->x0 = 0;
1206  imageParam->y0 = 0;
1207  ++imageParam;
1208  }
1209 
1210  OPJ_COLOR_SPACE clrspc;
1211  if ( bands == 3 )
1212  {
1213  clrspc = OPJ_CLRSPC_SRGB;
1214  }
1215  else // if ( bands == 1 )
1216  {
1217  // Anything other than 3 band. Not sure if this is correct way yet?(drb)
1218  clrspc = OPJ_CLRSPC_GRAY;
1219  }
1220 
1221  if ( clrspc != OPJ_CLRSPC_UNKNOWN )
1222  {
1223  image = opj_image_tile_create( bands, imageParams, clrspc );
1224  if ( image )
1225  {
1226  image->x0 = 0;
1227  image->y0 = 0;
1228  image->x1 = imageRect.width();
1229  image->y1 = imageRect.height();
1230  image->color_space = clrspc;
1231  }
1232  }
1233 
1234  delete [] imageParams;
1235  imageParams = 0;
1236 
1237  if ( traceDebug() )
1238  {
1240  << "ossimOpjCompressor::createOpjImage DEBUG:\n";
1241  if ( image )
1242  {
1244  }
1245  else
1246  {
1248  << "ossimOpjCompressor::createOpjImage DEBUG image not created!"
1249  << std::endl;
1250  }
1251  }
1252 
1253  return image;
1254 
1255 } // End: ossimOpjCompressor::createOpjImage( ... )
~ossimOpjCompressor()
destructor
virtual void valueToString(ossimString &valueResult) const =0
bool setProperty(ossimRefPtr< ossimProperty > property)
Will set the property whose name matches the argument "property->getName()".
OSSIM_DLL ossim_uint32 computeLevels(const ossimIrect &rect)
Computes the number of decimation levels to get to the overview stop dimension.
void finish()
Finish method.
ossim_uint32 numberOf(const char *str) const
bool writeGeotiffBox(std::ostream *stream, const ossimImageGeometry *geom, const ossimIrect &rect, const ossimFilename &tmpFile, ossimPixelType pixelType)
Writes the geotiff box to the jp2.
std::basic_ostringstream< char > ostringstream
Class for char output memory streams.
Definition: ossimIosFwd.h:35
ossimOpjCompressionQuality m_qualityType
void create(std::ostream *os, ossimScalarType scalar, ossim_uint32 bands, const ossimIrect &imageRect, const ossimIpt &tileSize, bool jp2)
Create method.
virtual const ossim_uint8 * getUcharBuf() const
Represents serializable keyword/value map.
void setProgressionOrder(OPJ_PROG_ORDER progressionOrder)
Sets progression order.
void setAlphaChannelFlag(bool flag)
Set the writer to add an alpha channel to the output png image.
bool valid() const
Definition: ossimRefPtr.h:75
opj_stream_t * m_stream
const char * find(const char *key) const
ossimOpjCompressor()
default constructor
bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
saves the state of the object.
ossim_uint32 height() const
Definition: ossimIrect.h:487
ossim_int32 m_threads
Number of threads.
ossimRefPtr< ossimProperty > getProperty(const ossimString &name) const
static ossimString toString(bool aValue)
Numeric to string methods.
opj_stream_t * createOpjStream(std::ostream *os) const
virtual ossimDataObjectStatus getDataObjectStatus() const
OSSIM_DLL ossimByteOrder byteOrder()
Definition: ossimCommon.cpp:54
OSSIM_DLL ossim_uint32 getActualBitsPerPixel(ossimScalarType scalarType)
Get actual bits per pixel for a given scalar type.
void setOptions(const std::vector< ossimString > &options)
Sets the options array.
void setQualityType(ossimOpjCompressionQuality type)
Sets the quality type.
ossimOpjCompressionQuality getQualityType() const
void initOpjCodingParams(bool jp2, const ossimIpt &tileSize, const ossimIrect &imageRect)
void setThreads(ossim_int32 threads)
Sets the number of threads.
bool m_reversible
Lossless or lossy.
bool write(std::ostream &os)
Write xml doc to stream.
ossimIrect m_imageRect
Image rectangle.
ossim_int32 toInt32() const
GML support data class.
void push_back(char c)
Equivalent to insert(end(), c).
Definition: ossimString.h:905
double ossim_float64
void add(const char *prefix, const ossimKeywordlist &kwl, bool overwrite=true)
void opj_warning_callback(const char *msg, void *)
Callback method for warnings.
OSSIM_DLL bool isSigned(ossimScalarType scalarType)
yy_size_t size
void initLevels(const ossimIrect &imageRect)
Set levels, class attribute m_levels and m_parameters->numresolution.
static bool writeJp2GeotiffBox(const ossimFilename &tmpFile, const ossimIrect &rect, const ossimProjection *proj, std::vector< ossim_uint8 > &buf, ossimPixelType pixelType)
Writes a geotiff box to a buffer.
bool toBool() const
String to numeric methods.
std::ostream & print(std::ostream &out, kdu_core::kdu_codestream &cs)
Convenience print method for kdu_codestream.
unsigned int ossim_uint32
void opj_info_callback(const char *msg, void *)
Callback method for info.
virtual ossimIrect getImageRectangle() const
opj_image_t * createOpjImage(ossimScalarType scalar, ossim_uint32 bands, const ossimIrect &imageRect) const
static ossimString downcase(const ossimString &aString)
Definition: ossimString.cpp:48
void setReversibleFlag(bool reversible)
Sets the m_reversible flag.
bool initialize(const ossimImageGeometry *geom, const ossimIrect &rect)
Initializes gml block from geometry file.
ossim_uint32 width() const
Definition: ossimIrect.h:500
Container class that holds both 2D transform and 3D projection information for an image Only one inst...
ossimScalarType
OSSIM_DLL ossim_uint32 getBitsPerPixel(ossimScalarType scalarType)
Get bits per pixel for a given scalar type.
void setLevels(ossim_int32 levels)
Sets the number of levels.
std::vector< ossimString > m_options
Container for Opj options.
const ossimProjection * getProjection() const
Access methods for projection (may be NULL pointer).
ossimPixelType
ossim_int32 getThreads() const
ossim_int32 getLevels() const
bool getReversibleFlag() const
void setQualityTypeString(const ossimString &s)
bool m_alpha
If true write alpha channel.
ossim_int32 y
Definition: ossimIpt.h:142
ossimString getQualityTypeString() const
static const char * COMPRESSION_QUALITY_KW
ossim_uint32 area() const
Definition: ossimIrect.h:396
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
ossim_int32 m_levels
Reduced resolution levels.
virtual ossim_uint32 getDataSizeInBytes() const
void opj_error_callback(const char *msg, void *)
Callback method for errors.
ossim_int32 x
Definition: ossimIpt.h:141
opj_cparameters_t * m_params
opj_codec_t * createOpjCodec(bool jp2) const
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.
void swap(ossim_sint8 &)
Definition: ossimEndian.h:26
unsigned char ossim_uint8
void setTlmTileCount(ossim_uint32 tilesToWrite)
bool writeTile(ossimImageData *srcTile, ossim_uint32 tileIndex)
Write tile method.
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
std::basic_ostream< char > ostream
Base class for char output streams.
Definition: ossimIosFwd.h:23
bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
Method to the load (recreate) the state of an object from a keyword list.
void setCodeBlockSize(ossim_int32 xSize, ossim_int32 ySize)
Set code block size.
void getPropertyNames(std::vector< ossimString > &propertyNames) const
Pushes this&#39;s names onto the list of property names.
int ossim_int32