OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimKakaduJpipHandler.cpp
Go to the documentation of this file.
2 #include <ossim/base/ossimUrl.h>
4 #include <sstream>
5 //#include <ossim/base/ossimByteStreamBuffer.h>
8 #include "ossimKakaduCommon.h"
10 #include <ossim/base/Thread.h>
11 #include <jpx.h>
14 #include "ossimKakaduJpipInfo.h"
16 #include <ossim/base/ossimTrace.h>
17 
18 using namespace kdu_core;
19 using namespace kdu_supp;
20 
21 static const ossimTrace traceDebug( ossimString("ossimKakaduJpipHandler:debug") );
22 
23 RTTI_DEF1(ossimKakaduJpipHandler, "ossimKakaduJpipHandler", ossimImageHandler);
26 m_headerClient(0), // let's cache the header information
27 m_client(0)
28 {
29  if(traceDebug())
30  {
31  ossimNotify(ossimNotifyLevel_DEBUG) << "ossimKakaduJpipHandler::ossimKakaduJpipHandler(): entered ..................\n";
32  }
34  m_quality = 100.0;
35 }
36 
38 {
39  if(traceDebug())
40  {
41  ossimNotify(ossimNotifyLevel_DEBUG) << "ossimKakaduJpipHandler::~ossimKakaduJpipHandler(): entered ..................\n";
42  }
43  close();
44 }
45 
47 {
49 
50  // Kakadu kdu_thread_entity::terminate throws exceptions...
51  try
52  {
53  m_jp2Family.close();
54  if(m_client)
55  {
56  if(m_client->is_alive())
57  {
58  m_client->disconnect();
59  }
60  m_client->close();
61  delete m_client;
62  m_client = 0;
63  }
64  if(m_headerClient)
65  {
66  if(m_headerClient->is_alive())
67  {
68  m_headerClient->disconnect();
69  }
70  m_headerClient->close();
71  delete m_headerClient;
72  m_headerClient = 0;
73  }
74  m_request = 0;
75  }
76  catch ( kdu_core::kdu_exception exc )
77  {
78  ostringstream e;
79  e << "ossimKakaduNitfReader::~ossimKakaduNitfReader\n"
80  << "Caught exception from kdu_region_decompressor: " << exc << "\n";
81  ossimNotify(ossimNotifyLevel_WARN) << e.str() << std::endl;
82  }
83  catch ( std::bad_alloc& )
84  {
85  std::string e =
86  "Caught exception from kdu_region_decompressor: std::bad_alloc";
87  ossimNotify(ossimNotifyLevel_WARN) << e << std::endl;
88  }
89  catch( ... )
90  {
91  std::string e =
92  "Caught unhandled exception from kdu_region_decompressor";
93  ossimNotify(ossimNotifyLevel_WARN) << e << std::endl;
94  }
95 
97 }
98 
100 {
101  return (m_client!=0);
102 }
103 
104 
106 {
107 
108  if(id >=0 &&id<=8)
109  {
110  return (id >> 1);
111  }
112 #if 0
113  switch(id)
114  {
115  case 0:
116  case 1:
117  {
118  return KDU_PRECINCT_DATABIN;
119  }
120  case 2:
121  {
122  return KDU_TILE_HEADER_DATABIN;
123  }
124  case 4:
125  case 5:
126  {
127  return KDU_TILE_DATABIN;
128  }
129  case 6:
130  {
131  return KDU_MAIN_HEADER_DATABIN;
132  }
133  case 8:
134  {
135  return KDU_META_DATABIN;
136  }
137  default:
138  {
139  break;
140  }
141  }
142 #endif
143  return -1;
144 }
145 
146 void ossimKakaduJpipHandler::showBoxes(kdu_supp::jp2_input_box* pParentBox)
147 {
148  kdu_supp::jp2_input_box box;
149 
150  if(!pParentBox)
151  {
152  //std::cout << "DEBUG: SHOWING HEADER BOXES FOR STREAM" << std::endl;
153  box.open(&m_jp2Family);
154  }
155  else
156  {
157  box.open(pParentBox);
158  }
159  while(box.exists())
160  {
161  kdu_uint32 boxType = box.get_box_type();
162  char ch[] = { (char) ( boxType >> 24 ), (char) ( boxType >> 16 ), (char) ( boxType >> 8 ) , (char) ( boxType >> 0 ), '\0' };
163 
164  //std::cout << ch << std::endl;
165  //std::cout << "Remaining bytes = " << box.get_remaining_bytes() << "\n";
166  if ( box.get_box_type() == jp2_xml_4cc )
167  {
168  //std::cout << "XML_________________________________________________\n";
169  std::vector<kdu_byte> bytes(box.get_remaining_bytes());
170  box.read(&bytes.front(), bytes.size());
171 
172  //std::cout << ossimString((char*)&bytes.front(), ((char*)&bytes.front())+bytes.size() ) << std::endl;
173  }
174  if(box.get_box_type() == jp2_uuid_4cc)
175  {
176  std::vector<kdu_byte> bytes(box.get_remaining_bytes());
177  box.read(&bytes.front(), bytes.size());
178  ossim_uint32 idx = 0;
179  //for(idx = 0; idx < 16; ++idx)
180  //{
181  //std::cout << (int)bytes[idx]<< " ";
182  //}
183  //std::cout << "\n";
184  }
185  if ( jp2_is_superbox( box.get_box_type() ) )
186  {
187  showBoxes( &box );
188  }
189  else
190  {
191  }
192  box.close();
193  box.open_next();
194  }
195 }
197 {
198  kdu_window window;
199  window.init();
200  m_headerClient->close();
201  if(loadClient(m_headerClient, window))
202  {
203  m_headerClient->set_read_scope(KDU_MAIN_HEADER_DATABIN, 0, 0);
204  kdu_codestream codestream;
205  kdu_region_decompressor decompressor;
206  codestream.create(m_headerClient);
207  codestream.set_persistent();
208 
209  kdu_channel_mapping oChannels;
210  oChannels.configure(codestream);
211 
212  kdu_coords ref_expansion(1, 1);
213  kdu_dims view_dims = decompressor.get_rendered_image_dims(codestream, &oChannels, -1, 0,
214  ref_expansion, ref_expansion,
215  KDU_WANT_OUTPUT_COMPONENTS);
216  siz_params* siz_in = codestream.access_siz();
217  kdu_params* cod_in = siz_in->access_cluster("COD");
218  m_jp2Family.close();
219  m_client->set_read_scope(KDU_META_DATABIN, 0, 0);
221 
222  extractBoxes(boxList, 0);
223  m_jp2Family.close();
224  }
225 }
226 
227 void ossimKakaduJpipHandler::extractBoxes(BoxList& boxList, jp2_input_box* pParentBox)
228 {
229  jp2_input_box box;
230 
231  if(!pParentBox)
232  {
233  //std::cout << "DEBUG: SHOWING HEADER BOXES FOR STREAM" << std::endl;
234  box.open(&m_jp2Family);
235  }
236  else
237  {
238  box.open(pParentBox);
239  }
240  while(box.exists())
241  {
242  ossim_uint32 idx = boxList.size();
243  boxList.push_back(Box());
244  boxList[idx].m_type = box.get_box_type();
245  if(box.get_remaining_bytes()>0)
246  {
247  boxList[idx].m_buffer.resize(box.get_remaining_bytes());
248  box.read(&boxList[idx].m_buffer.front(), boxList[idx].m_buffer.size());
249  }
250  if ( jp2_is_superbox( box.get_box_type() ) )
251  {
252  extractBoxes(boxList, &box );
253  }
254 
255  box.close();
256  box.open_next();
257  }
258 }
259 
261 {
262  close();
263 
264  if(!m_client)
265  {
266  m_headerClient = new kdu_client();
267  m_client = new kdu_client();
268  }
269  bool result = false;
270  ossimString protocolString = m_baseUrl.getProtocol();
271  protocolString = protocolString.downcase();
272  m_useOurGrab = false;
273 
274  if(protocolString == "jpip")
275  {
276  m_baseUrl.setProtocol("http");
277  }
278  else
279  {
280  if(protocolString == "jpips")
281  {
282  m_useOurGrab = true;
283  m_baseUrl.setProtocol("https");
284  }
285  else
286  {
287  return false;
288  }
289  }
290  //std::cout << "OUR GRAB ==== " << m_useOurGrab << std::endl;
291  // m_useOurGrab = true;
293  kdu_window window;
294  window.init();
295  //std::cout << "calling loadClient " << std::endl;
296  if(loadClient(m_client, window))
297  {
298  try
299  {
300  m_client->set_read_scope(KDU_MAIN_HEADER_DATABIN, 0, 0);
301  kdu_codestream codestream;
302  kdu_region_decompressor decompressor;
303  codestream.create(m_client);
304  codestream.set_persistent();
305 
306  kdu_channel_mapping oChannels;
307  oChannels.configure(codestream);
308 
309 
310 
311  kdu_coords ref_expansion(1, 1);
312  kdu_dims view_dims = decompressor.get_rendered_image_dims(codestream, &oChannels, -1, 0,
313  ref_expansion, ref_expansion,
314  KDU_WANT_OUTPUT_COMPONENTS);
315  siz_params* siz_in = codestream.access_siz();
316  kdu_params* cod_in = siz_in->access_cluster("COD");
317  m_jp2Family.close();
318  m_client->set_read_scope(KDU_META_DATABIN, 0, 0);
319  m_jp2Family.open(m_client);
320  //std::cout <<"SHOWING BOXES!!!!!!!!!!!" << std::endl;
321  showBoxes();
322  if(cod_in&&siz_in)
323  {
324  //std::cout << "__________________________________====\n";
325  int nResLevels = 0;
326  int nQualityLayers = 0;
327  int nTileSizeX = 0;
328  int nTileSizeY = 0;
329 
330  cod_in->get("Clevels", 0, 0, nResLevels);
331  cod_in->get("Clayers", 0, 0, nQualityLayers);
332  siz_in->get("Stiles", 0, 0, nTileSizeY);
333  siz_in->get("Stiles", 0, 1, nTileSizeX);
334  m_nQualityLayers = nQualityLayers;
335  m_nInputBands = codestream.get_num_components(false);
336  m_nOutputBands = codestream.get_num_components(true);
337  ossim_uint64 width = view_dims.size.x;
338  ossim_uint64 height = view_dims.size.y;
339  // ossim_int32 m_nQualityLayers = nQualityLayers;
340  m_bitDepth = codestream.get_bit_depth(0);
341  m_signed = codestream.get_signed(0);
342  m_resLevels = nResLevels;
343  if(nTileSizeX&&nTileSizeY)
344  {
345  m_tileSize = ossimIpt( nTileSizeX, nTileSizeY);
346  }
347  else
348  {
349  m_tileSize = ossimIpt(2048, 128);
350  }
351  m_tileSize.x = m_tileSize.x>2048?2048:m_tileSize.x;
352  m_tileSize.y = m_tileSize.y>128?128:m_tileSize.y;
353  m_bYCC=1;
354  cod_in->get("Cycc", 0, 0, m_bYCC);
355  performRlevelSetup(codestream);
356 
357  m_jp2Family.close();
358  result = true;
359 #if 0
360  std::cout << std::dec << "width = " << width << std::endl;
361  std::cout << std::dec << "height = " << height << std::endl;
362  std::cout << "m_nOutputBands = " << m_nOutputBands << std::endl;
363  std::cout << "m_nInputBands = " << m_nInputBands << std::endl;
364  std::cout << "BitDepth = " << m_bitDepth << std::endl;
365  std::cout << "Overviews = " << nResLevels<< std::endl;
366  std::cout << "nQualityLayers = " << m_nQualityLayers<< std::endl;
367  std::cout << "nTileSize = " << m_tileSize << std::endl;
368 #endif
369  }
370 
371  // walk boxes for testing
372  //
373  // showBoxes(&box);
374  // std::cout << "BOX OPENED!!!" << std::endl;
375  //do {
376  // std::cout << "type: " <<std::ios::hex << box.get_box_type() << std::endl;
377  // std::cout << "SUPER? " << jp2_is_superbox(box.get_box_type()) << std::endl;
378  // box.close();
379  // box.open_next();
380  //} while (box.exists());
381  // }
382  }
383  catch(...)
384  {
385  result = false;
386  }
387  }
388 
389  if(result)
390  {
391  completeOpen();
392  }
393  else
394  {
395  close();
396  }
397  //std::cout << "RETURNING RESULT === " << result << std::endl;
398  return result;
399 
400 }
401 
403 {
404  if(isOpen()) close();
405  bool result = false;
406  ossimFilename file = getFilename();
407  // local file and we will test for jpip extension and this
408  // will hold cached state information
409  //
410  if(file.exists())
411  {
412  if(file.ext().downcase()=="jpip")
413  {
414  ossimKeywordlist kwl;
415  if(kwl.addFile(file))
416  {
417  result = loadState(kwl);
418  }
419  }
420  }
421  else
422  {
423  m_baseUrl = ossimUrl(file);
424  result = openStream();
425  }
427  {
428  result = false;
429  close();
430  }
431  return result;
432 }
433 
435 {
437 #if 0
438  if(m_request.valid())
439  {
440  m_cid = "";
441  m_path = "";
442  m_transport ="";
443  ossimString params;
444  ossimUrl imageInfoUrl = m_baseUrl;
445  params = "type=jpp-stream&stream=0&cnew=http";
446  imageInfoUrl.setParams(params);
447  std::cout << "URL------------------------- " << imageInfoUrl.toString() << std::endl;
448  m_request->set(imageInfoUrl, ossimKeywordlist());
449  m_request->addHeaderOption("HEADERS=Accept", "jpp-stream");
451  if(response.valid()&&(response->getStatusCode()==200))
452  {
453  std::cout << "__________________________" << std::endl;
454  std::cout << response->headerKwl() << std::endl;
455  ossimString jpipCnew = response->headerKwl()["JPIP-cnew"];
456  jpipCnew = jpipCnew.trim();
457  if(!jpipCnew.empty())
458  {
459  m_cid = "";
460  m_path = "";
461  m_transport ="";
462  ossimString tempKwlString = jpipCnew.substitute(",", "\n", true);
463  std::istringstream in(tempKwlString.c_str());
464 
465  ossimKeywordlist kwl('=');
466  if(kwl.parseStream(in))
467  {
468  m_cid = kwl["cid"];
469  m_path = kwl["path"];
470  m_transport = kwl["transport"];
471  m_cid = m_cid.trim();
472  m_path = m_path.trim();
474 
475  std::cout << "PATH === " << m_path << std::endl;
476  }
477  }
478  }
479  }
480 #endif
481 }
482 bool ossimKakaduJpipHandler::loadClient(kdu_client* client, kdu_window& window)
483 {
484  bool result =false;
485 
486  if(!client) return result;
487  // we will assume that the libcurl library support ssl connections and we will use our own
488  // urlquery instead of using kakadu's persistant code
489  // if m_ourGrab is true we currently only support stateless requests. Kakadu
490  // interface we use if m_useOurGrab communicates through the channel session
491  // id.
492  if(m_useOurGrab)
493  {
494  //if(!m_request.valid())
495  allocateSession();
496 
497  client->close();
498  bool needNewChannel = false;
499 #if 0
500  if(!m_request.valid())
501  {
503  needNewChannel = true;
504  }
505 #endif
506  if(m_request.valid())
507  {
509  ossimString params;
510  ossimUrl imageInfoUrl = m_baseUrl;
511  if(window.region.size.x == 0&&
512  window.region.size.y == 0)
513  {
514 
515  params = "type=jpp-stream&stream=0";
516  }
517  else
518  {
519  params = "type=jpp-stream&stream=0";
520 
521  params += ("&roff=" + ossimString::toString((ossim_int64)window.region.pos.x)+","+ossimString::toString((ossim_int64)window.region.pos.y));
522  params += ("&rsiz=" + ossimString::toString((ossim_int64)window.region.size.x)+","+ossimString::toString((ossim_int64)window.region.size.y));
523  params += ("&fsiz=" + ossimString::toString((ossim_int64)window.resolution.x)+","+ossimString::toString((ossim_int64)window.resolution.y));
524  params += ("&layers=" + ossimString::toString(window.get_max_layers()));
525 
526  }
527  if(!m_cid.empty())
528  {
529  params += ("&cid=" + m_cid);
530  // if(!m_path.empty()) imageInfoUrl.setPath(m_path);
531  }
532  if(needNewChannel)
533  {
534  params += "&cnew=http";
535  }
536  imageInfoUrl.setParams(params);
537 
538  m_request->set(imageInfoUrl, ossimKeywordlist());
539  m_request->addHeaderOption("HEADERS=Accept", "jpp-stream");
541  //std::cout << "URL======================== " << imageInfoUrl.toString() << std::endl;
542  ossimRefPtr<ossimHttpResponse> response = dynamic_cast<ossimHttpResponse*>(webResponse.get());
543  //std::cout << "__________________________" << std::endl;
544  if(response.valid()&&(response->getStatusCode()==200))
545  {
546 // std::cout << response->headerKwl() << std::endl;
547  //std::cout << "__________________________" << std::endl;
548  //std::cout << response->headerKwl() << std::endl;
549 #if 0
550  ossimString jpipCnew = response->headerKwl()["JPIP-cnew"];
551  jpipCnew = jpipCnew.trim();
552 
553  if(!jpipCnew.empty())
554  {
555  m_cid = "";
556  m_path = "";
557  m_transport ="";
558  ossimString tempKwlString = jpipCnew.substitute(",", "\n", true);
559  std::istringstream in(tempKwlString.c_str());
560 
561  ossimKeywordlist kwl('=');
562  if(kwl.parseStream(in))
563  {
564  m_cid = kwl["cid"];
565  m_path = kwl["path"];
566  m_transport = kwl["transport"];
567  m_cid = m_cid.trim();
568  m_path = m_path.trim();
570 
571  std::cout << "PATH === " << m_path << std::endl;
572  }
573  }
574 #endif
575  if(traceDebug())
576  {
577  ossimNotify(ossimNotifyLevel_DEBUG) << ossimString(response->headerBuffer().buffer(),response->headerBuffer().buffer()+response->headerBuffer().bufferSize()) << std::endl;
578  }
580  response->copyAllDataFromInputStream(buf);
581  if(buf.size())
582  {
583  try
584  {
586  decoder->inputStreamBuffer().setBuf(reinterpret_cast<char*>(&buf.front()),
587  buf.size(),
588  true);
589  ossimRefPtr<ossimJpipMessage> message = decoder->readMessage();
590  ossimRefPtr<ossimJpipMessage> mainHeaderMessage;
591  if(message.valid())
592  {
593  ossim_uint32 dataWritten = 0;
594  while(message.valid()&&!message->header()->m_isEOR)
595  {
596  int id = convertClassIdToKdu(message->header()->m_classIdentifier);
597  if((!message->header()->m_isEOR)&&
598  (id >=0))
599  {
600  client->add_to_databin( id,
601  message->header()->m_CSn,
602  message->header()->m_inClassIdentifier,
603  (const kdu_byte*)&message->messageBody().front(),
604  message->header()->m_msgOffset,
605  message->messageBody().size(),
606  message->header()->m_isLastByte);
607 
608  dataWritten+= message->messageBody().size();
609  }
610  message = decoder->readMessage();
611  }
612  }
613  result = true;
614  }
615  catch(...)
616  {
617  //std::cout << "EXCEPTION!!!!!!!!!!!!!!!!!!!\n";
618  //std::cout << "-----------------------------------------------\n";
619  result = false;
620  }
621  }
622  }
623  else if(response.valid())
624  {
625  if(traceDebug())
626  {
627  ossimNotify(ossimNotifyLevel_DEBUG) << ossimString(response->headerBuffer().buffer(),response->headerBuffer().buffer()+response->headerBuffer().bufferSize()) << std::endl;
628  }
629  //std::cout << imageInfoUrl.toString() << std::endl;
630  //std::cout << ossimString(response->headerBuffer().buffer(),response->headerBuffer().buffer()+response->headerBuffer().bufferSize()) << std::endl;
631  }
632  }
633  }
634  else
635  {
636  //std::cout << "TRYING TO MAKE A CONNECTION" << std::endl;
637  result = makeConnectionIfNeeded(client);
638  if(result)
639  {
640  result = false;
641  if(client->post_window(&window, m_requestQueueId))
642  {
643  try
644  {
645  //
646  while( !client->is_idle() &&client->is_alive())
647  {
649  }
650 
651  result = true;
652  }
653  catch(...)
654  {
655  result = false;
656  }
657  }
658  }
659  }
660  //std::cout << "RESULT? " << result << std::endl;
661  return result;
662 }
663 
665 {
666  ossim_uint32 result = 0;
667  if (resLevel < m_overviewDimensions.size())
668  {
669  result = m_overviewDimensions[resLevel].height();
670  }
671  else if (theOverview.valid())
672  {
673  result = theOverview->getNumberOfLines(resLevel);
674  }
675  return result;
676 }
677 
679 {
680  ossim_uint32 result = 0;
681  if (resLevel < m_overviewDimensions.size())
682  {
683  result = m_overviewDimensions[resLevel].width();
684  }
685  else if (theOverview.valid())
686  {
687  result = theOverview->getNumberOfSamples(resLevel);
688  }
689  return result;
690 }
691 
693 {
694  return m_nInputBands;
695 }
696 
698 {
699  return m_nOutputBands;
700 }
701 
703 {
704  return m_tileSize.hasNans()?0:m_tileSize.x;
705 }
706 
708 {
709  return m_tileSize.hasNans()?0:m_tileSize.y;
710 }
711 
713 {
715  switch(m_bitDepth)
716  {
717  case 8:
718  {
720  break;
721  }
722  case 11:
723  {
725  break;
726  }
727  case 12:
728  {
730  break;
731  }
732  case 13:
733  {
735  break;
736  }
737  case 14:
738  {
740  break;
741  }
742  case 15:
743  {
745  break;
746  }
747  case 16:
748  {
750  break;
751  }
752  };
753  return result;
754 }
755 
757 {
758  ossim_uint32 result = m_overviewDimensions.size();
759  if (theOverview.valid())
760  {
762  }
763  return result;
764 }
765 
767 {
769 
770  if(m_tile.valid())
771  {
772  m_tile->initialize();
773  }
774 }
778 
780 {
781  ossim_uint64 test = 1<<maxLevel;
782  ossim_uint64 currentLevel = maxLevel;
783  while(currentLevel)
784  {
785  if(test&power2Value) break;
786  test >>=1;
787  --currentLevel;
788  }
789  return currentLevel;
790 }
791 
793  ossim_uint32 resLevel)
794 {
796 
797  try
798  {
800 
801  ossim_uint64 scalePower2 = 1<<nLevels;
802  ossim_int32 targetLevel = nLevels - ossim::round<ossim_uint32>(log(1.0+((scalePower2*m_quality)/100.0))/log(2.0));
803 
804  // now try log way
805  if(targetLevel > static_cast<ossim_int32>(resLevel))
806  {
807  double scale = 1.0/(1<<targetLevel);
808  ossimDrect scaledRect = rect*ossimDpt(scale, scale);
809  ossimIrect scaledRectRound = scaledRect;
810  scaledRectRound = ossimIrect(scaledRectRound.ul().x - 1,
811  scaledRectRound.ul().y - 1,
812  scaledRectRound.lr().x + 1,
813  scaledRectRound.lr().y + 1);
814  ossimRefPtr<ossimImageData> copy = getTileAtRes(scaledRectRound, targetLevel);
815  copy = (ossimImageData*)copy->dup();
816 
817  //result->setImageRectangle(rect);
818 
822  transform->scale(1<<targetLevel, 1<<targetLevel);
823  memSource->setImage(copy.get());
824  renderer->connectMyInputTo(memSource.get());
825  renderer->getResampler()->setFilterType("bilinear");
826  renderer->setImageViewTransform(transform.get());
827  result = renderer->getTile(rect);
828  renderer->disconnect();
829  memSource->disconnect();
830  renderer = 0;
831  memSource = 0;
832  }
833  else
834  {
835  // we need to apply a quality and then scale to the proper resolution.
836  // so if we want a 50% quality image and they are requesting a reslevel 0 product
837  // we need to query jpip at the next level down and not at 0 and scale the product up
838  // using a bilinear or some form of resampling
839  //
840  result = getTileAtRes(rect, resLevel);
841  }
842  }
843  catch ( kdu_exception exc )
844  {
845  ostringstream e;
846  e << "ossimKakaduNitfReader::~ossimKakaduNitfReader\n"
847  << "Caught exception from kdu_region_decompressor: " << exc << "\n";
848  ossimNotify(ossimNotifyLevel_WARN) << e.str() << std::endl;
849  }
850  catch ( std::bad_alloc& )
851  {
852  std::string e =
853  "Caught exception from kdu_region_decompressor: std::bad_alloc";
854  ossimNotify(ossimNotifyLevel_WARN) << e << std::endl;
855  }
856  catch( ... )
857  {
858  std::string e =
859  "Caught unhandled exception from kdu_region_decompressor";
860  ossimNotify(ossimNotifyLevel_WARN) << e << std::endl;
861  }
862 
863  return result.get();
864 }
865 
867  ossim_uint32 resLevel)
868 {
871 
872  if((resLevel>=nLevels)||!isOpen()||!isSourceEnabled())
873  {
874  return result;
875  }
876 
877  if(resLevel > m_overviewDimensions.size()&&theOverview.valid())
878  {
879  return theOverview->getTile(rect, resLevel);
880  }
881  if(!m_tile.valid()) allocateTile();
882  m_tile->setImageRectangle(rect);
883 
884  if(getOverviewTile(resLevel, m_tile.get()))
885  {
886  return m_tile.get();
887  }
888 
889  ossimIrect bounds = getBoundingRect(resLevel);
890  ossimIrect clipRect = bounds.clipToRect(rect);
891 
892  kdu_dims dims;
893  if(!bounds.intersects(rect))
894  {
895  return result;
896  }
897 
898  kdu_coords ref_expansion;
899  kdu_coords exp_numerator;
900  kdu_coords exp_denominator;
901  kdu_dims rr_win;
902  ref_expansion.x = 1;
903  ref_expansion.y = 1;
904 
905  kdu_dims view_dims;
906 
907  ossimString comps;
909  ossim_uint32 idx = 0;
910  for(idx=0;idx<nBands;++idx)
911  {
912  comps+=ossimString::toString(idx);
913  if(idx+1!=nBands)
914  {
915  comps+=",";
916  }
917  }
918  ossimIpt tileSize;
919  tileSize = m_rlevelTileSize[resLevel];//m_tileSize;
920  // if(static_cast<ossim_int32>(bounds.width()) < tileSize.x) tileSize.x = bounds.width();
921  // if(static_cast<ossim_int32>(bounds.height()) < tileSize.y) tileSize.y = bounds.height();
922 
923  ossimIrect tileBoundaryRect = clipRect;
924  tileBoundaryRect.stretchToTileBoundary(tileSize);
925 
926 
927  tileBoundaryRect.clipToRect(bounds);
928  ossim_int64 ulx = tileBoundaryRect.ul().x;
929  ossim_int64 uly = tileBoundaryRect.ul().y;
930  ossim_int64 maxx = tileBoundaryRect.lr().x;
931  ossim_int64 maxy = tileBoundaryRect.lr().y;
932  m_tile->makeBlank();
933  kdu_window window;
934  kdu_dims region;
935  for(;ulx < maxx; ulx += tileSize.x)
936  {
937  for(;uly < maxy; uly += tileSize.y)
938  {
939  ossim_int64 x = ulx;
940  ossim_int64 y = uly;
941  ossim_int64 w = tileSize.x;
942  ossim_int64 h = tileSize.y;
943 
944  if(x+w-1 > maxx) w = maxx-x;
945  if(y+h-1 > maxy) h = maxy-y;
946 
948  if(!cacheTile.valid())
949  {
950  // double percent = (m_quality/100.0);
951  window.init();
952  region.pos.x = x;
953  region.pos.y = y;
954  region.size.x = w;
955  region.size.y = h;
956  //std::cout << "NLAYERS ================= " << m_nQualityLayers << std::endl;
957  //ossim_int32 nQualityLayers = ((m_quality/100.0)*m_nQualityLayers);
958  ossim_int32 nQualityLayers = (m_nQualityLayers);//*percent;
959  nQualityLayers = nQualityLayers<1?1:nQualityLayers;
960  // std::cout << "nquality === " << nQualityLayers << std::endl;
961  window.set_region(region);
962 
963  window.set_max_layers(nQualityLayers);
964  window.resolution.x = bounds.width();
965  window.resolution.y = bounds.height();
966 
967  try
968  {
969  if(loadClient(m_client, window))
970  {
971  //std::cout << "WE LOADED THE CLIENT!!!!" << std::endl;
972  bool gotRegion = true;
973  // if we do not need to use ssl we use kakadu for the window loads
974  if(!m_useOurGrab)
975  {
976  kdu_window reqWindow;
977  m_client->get_window_in_progress(&reqWindow);
978  gotRegion = ((reqWindow.region.size.x>0)&&
979  (reqWindow.region.size.y>0));
980  }
981  //kdu_window reqWindow = window;
982  //m_client->get_window_in_progress(&reqWindow);
983  // now get a codestream ready for decompressing the data
984  //
985 
986  if(gotRegion)
987  {
988  jp2_family_src jp2FamilySource;
989  jp2FamilySource.open(m_client);
990 
991  jpx_source jpxSource;
992  if(jpxSource.open(&jp2FamilySource, true)==1)
993  {
994  jpx_codestream_source jpx_codestream = jpxSource.access_codestream(0);
995  kdu_codestream codestream;
996  jpx_input_box* inputBox = jpx_codestream.open_stream();
997  if(inputBox)
998  {
999  codestream.create(inputBox);
1000  codestream.set_persistent();
1001  codestream.apply_input_restrictions(
1002  0, 0,
1003  resLevel, nQualityLayers, &region,
1004  KDU_WANT_CODESTREAM_COMPONENTS);
1005  if ( ossim::clipRegionToImage(codestream,
1006  region,
1007  resLevel,
1008  region) )
1009  {
1010  kdu_channel_mapping channels;
1011  channels.configure(codestream);
1012  cacheTile = ossimImageDataFactory::instance()->create(this, this);
1013  cacheTile->setImageRectangle(ossimIrect(region.pos.x,region.pos.y,
1014  region.pos.x + region.size.x - 1,
1015  region.pos.y+region.size.y - 1));
1016  cacheTile->initialize();
1017 
1018  ossim::copyRegionToTile(&channels, codestream, resLevel, 0, 0, cacheTile.get());
1019  ossimAppFixedTileCache::instance()->addTile(m_rlevelBlockCache[resLevel], cacheTile.get(), false);
1020  }
1021  }
1022  }
1023  jpxSource.close();
1024  jp2FamilySource.close();
1025  }
1026  else
1027  {
1028  ossimNotify(ossimNotifyLevel_WARN) << "Unable to get block from server, defaulting to blank\n";
1029  }
1030  }
1031  else
1032  {
1033  ossimNotify(ossimNotifyLevel_WARN) << "Unable to establish a connection to the server\n";
1034  }
1035  }
1036  catch(...)
1037  {
1038  cacheTile = 0;
1039  }
1040  }
1041  if(cacheTile.valid())
1042  {
1043  m_tile->loadTile(cacheTile->getBuf(), cacheTile->getImageRectangle(), OSSIM_BSQ);
1044  }
1045  }
1046  }
1047  m_tile->validate();
1048 
1049  return m_tile;
1050 }
1051 
1052 
1054 {
1055  if(!client->is_alive())
1056  {
1057  ossimString server = m_baseUrl.getIp()+(m_baseUrl.getPort().empty()?"":":"+m_baseUrl.getPort());
1058  ossimString path = m_baseUrl.getPath();
1059 
1060  m_requestQueueId = client->connect(server.c_str(), "",path.c_str(), "http", "", KDU_CLIENT_MODE_INTERACTIVE, "");
1061  }
1062  return client->is_alive();
1063 
1064 }
1065 
1067 {
1068  ossim_uint32 idx = 0;
1069  for(idx = 0; idx < m_rlevelBlockCache.size();++idx)
1070  {
1072  }
1073  m_rlevelBlockCache.clear();
1074 }
1075 
1076 void ossimKakaduJpipHandler::performRlevelSetup(kdu_codestream& codestream)
1077 {
1079  m_rlevelTileSize.clear();
1080 
1081  //Get resolution level dimensions
1082  //
1083  ossim_uint32 nDiscard = 0;
1084  for(nDiscard = 0; nDiscard < m_resLevels; ++nDiscard)
1085  {
1086  kdu_dims dims;
1087  codestream.apply_input_restrictions( 0, 0, nDiscard, 0, NULL );
1088  codestream.get_dims( 0, dims );
1089  ossimIrect rect(0,0,dims.size.x-1, dims.size.y-1);
1090  m_overviewDimensions.push_back(rect);
1091  ossimIpt tileSize(m_tileSize);
1092  tileSize.x = ((tileSize.x > static_cast<ossim_int32>(rect.width()))?static_cast<ossim_int32>(rect.width()):tileSize.x);
1093  tileSize.y = ((tileSize.y > static_cast<ossim_int32>(rect.height()))?static_cast<ossim_int32>(rect.height()):tileSize.y);
1094  m_rlevelTileSize.push_back(tileSize);
1095  rect.stretchToTileBoundary(tileSize);
1096  m_rlevelBlockCache.push_back(ossimAppFixedTileCache::instance()->newTileCache(rect, tileSize));
1097  }
1098 }
1099 
1101 {
1103  m_rlevelTileSize.clear();
1104  ossim_uint32 idx = 0;
1105  if(m_rlevelTileSize.size() != m_overviewDimensions.size()) return;
1106  for(idx = 0; idx < m_rlevelTileSize.size(); ++idx)
1107  {
1108  ossimIrect rect = m_overviewDimensions[idx];
1109  ossimIpt tileSize(m_rlevelTileSize[idx]);
1110  rect.stretchToTileBoundary(tileSize);
1111  m_rlevelBlockCache.push_back(ossimAppFixedTileCache::instance()->newTileCache(rect, tileSize));
1112  }
1113 }
1114 
1116 {
1117  bool refreshCache = false;
1118  if(property.valid())
1119  {
1120  ossimString name = property->getName();
1121  if(name == "quality")
1122  {
1123  refreshCache = !ossim::almostEqual((double)m_quality,
1124  property->valueToString().toDouble());
1125  m_quality = property->valueToString().toDouble();
1126  }
1127  else
1128  {
1129  ossimImageHandler::setProperty(property.get());
1130  }
1131  }
1132 
1133  if(refreshCache)
1134  {
1135  flushCache();
1136  if(m_client) m_client->close();
1137  }
1138 }
1139 
1141 {
1143  if(name == "quality")
1144  {
1146  0, 100);
1147  result->setCacheRefreshBit();
1148  result->setFullRefreshBit();
1149  }
1150 
1151  return result.get();
1152 }
1153 
1154 void ossimKakaduJpipHandler::getPropertyNames(std::vector<ossimString>& propertyNames)const
1155 {
1156  ossimImageHandler::getPropertyNames(propertyNames);
1157  propertyNames.push_back(ossimKeywordNames::QUALITY_KW);
1158 }
1159 
1161 {
1162  if(theGeometry.valid()) return theGeometry.get();
1163 
1164  // if base is able to create a goemetry then return it
1166 
1167  if(!theGeometry->getProjection())
1168  {
1169  ossimKeywordlist kwl;
1170 
1172  info->setHandler(this);
1173  info->getKeywordlist(kwl);
1174  info = 0;
1175  ossimString prefix = "jpip.image"+ossimString::toString(getCurrentEntry()) + ".";
1176  // dump the infromation into a kwl and then pass it to the geometry resgistry
1177 
1178  //std::cout << kwl << std::endl;
1179  //
1181  if(theGeometry.valid())
1182  {
1184  }
1185  }
1186 
1187  return theGeometry.get();
1188 }
1189 
1190 bool ossimKakaduJpipHandler::loadState(const ossimKeywordlist& kwl, const char* prefix)
1191 {
1192  close();
1193  bool result = ossimImageHandler::loadState(kwl, prefix);
1194  if(result)
1195  {
1196  m_baseUrl = ossimUrl(kwl.find(prefix, "url"));
1197  ossimString qualityString = kwl.find(prefix,ossimKeywordNames::QUALITY_KW);
1198  if(!qualityString.empty())
1199  {
1200  m_quality = qualityString.toDouble();
1201  }
1202  result = openStream();
1203  }
1204 
1205 
1206  if(!result)
1207  {
1208  close();
1209  }
1210  return result;
1211 }
1212 
1213 bool ossimKakaduJpipHandler::saveState(ossimKeywordlist& kwl, const char* prefix)const
1214 {
1215  bool result = ossimImageHandler::saveState(kwl, prefix);
1216 
1217  ossimUrl url = m_baseUrl;
1218  ossimString protocol = m_baseUrl.getProtocol();
1219  if(protocol == "http") protocol = "jpip";
1220  else if(protocol == "https") protocol = "jpips";
1221  url.setProtocol(protocol);
1222 
1223  kwl.add(prefix, "url", url.toString().c_str(), true);
1224  kwl.add(prefix, ossimKeywordNames::QUALITY_KW, m_quality, true);
1225 
1226  return result;
1227 }
1228 
1229 
1231 {
1232  ossim_uint32 idx = 0;
1233  for(idx = 0; idx < m_rlevelBlockCache.size();++idx)
1234  {
1236  }
1237 }
1238 
1239 
virtual void deleteCache(ossimAppFixedCacheId cacheId)
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
Method to save the state of an object to a keyword list.
8 bit signed integer
virtual void valueToString(ossimString &valueResult) const =0
ossim_uint32 x
virtual bool isSourceEnabled() const
Definition: ossimSource.cpp:79
virtual bool getKeywordlist(ossimKeywordlist &kwl) const
Method to dump info to a keyword list.
static ossimImageGeometryRegistry * instance()
RTTI_DEF1(ossimKakaduJpipHandler, "ossimKakaduJpipHandler", ossimImageHandler)
ossimRefPtr< ossimImageGeometry > theGeometry
ossimString substitute(const ossimString &searchKey, const ossimString &replacementValue, bool replaceAll=false) const
Substitutes searchKey string with replacementValue and returns a string.
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_int64 m_msgOffset
Identifies the offset of the data in the message from the start of the data-bin.
ossimRefPtr< ossimImageData > getTileAtRes(const ossimIrect &rect, ossim_uint32 resLevel=0)
16 bit unsigned integer (12 bits used)
std::basic_ostringstream< char > ostringstream
Class for char output memory streams.
Definition: ossimIosFwd.h:35
virtual void setImageRectangle(const ossimIrect &rect)
16 bit unsigned integer
ossim_uint32 getStatusCode() const
void performRlevelSetup(kdu_core::kdu_codestream &codestream)
virtual void disconnect(ossimConnectableObject *object=0)
Will disconnect the object passed in.
virtual void getPropertyNames(std::vector< ossimString > &propertyNames) const
Represents serializable keyword/value map.
bool addFile(const char *file)
virtual bool isOpen() const
Derived classes must implement this method to be concrete.
void showBoxes(kdu_supp::jp2_input_box *pParentBox=0)
ossim_uint32 y
bool valid() const
Definition: ossimRefPtr.h:75
const char * find(const char *key) const
16 bit unsigned integer (14 bits used)
virtual void extractBoxes(BoxList &boxList)
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
Method to the load (recreate) the state of an object from a keyword list.
bool almostEqual(T x, T y, T tolerance=FLT_EPSILON)
Definition: ossimCommon.h:53
virtual ossim_uint32 getNumberOfLines(ossim_uint32 resLevel=0) const =0
Pure virtual, derived classes must implement.
virtual void setHandler(ossimKakaduJpipHandler *handler)
kdu_supp::kdu_client * m_client
ossimRefPtr< ossimHttpRequest > m_request
ossim_uint32 height() const
Definition: ossimIrect.h:487
virtual ossim_uint32 getImageTileHeight() const
Returns the tile width of the image or 0 if the image is not tiled.
static ossimString toString(bool aValue)
Numeric to string methods.
RLevelBlockSizeList m_rlevelTileSize
void setImage(ossimRefPtr< ossimImageData > image)
16 bit signed integer
ossimKeywordlist & headerKwl()
const ossimIpt & ul() const
Definition: ossimIrect.h:274
ossimJpipMessageHeader * header()
ossim_uint64 bufferSize() const
16 bit unsigned integer (13 bits used)
MessageBodyType & messageBody()
virtual ossimScalarType getOutputScalarType() const
This will be used to query the output pixel type of the tile source.
virtual ossim_uint32 getNumberOfInputBands() const
virtual ossimHttpRequest * createHttp(const ossimUrl &url)
bool intersects(const ossimIrect &rect) const
Definition: ossimIrect.cpp:183
void setProtocol(const ossimString &protocol)
Definition: ossimUrl.h:23
virtual void setProperty(ossimRefPtr< ossimProperty > property)
static void sleepInMicroSeconds(ossim_uint64 micros)
Utility method to allow one to sleep in microseconds.
Definition: Thread.cpp:83
virtual ossimRefPtr< ossimImageData > getTile(const ossimIrect &origin, ossim_uint32 resLevel=0)
the resampler will need the tile request to come from the view.
virtual void initialize()
Initialize the data buffer.
void setImageViewTransform(ossimImageViewTransform *transform)
virtual ossim_uint32 getImageTileWidth() const
Returns the tile width of the image or 0 if the image is not tiled.
static ossimAppFixedTileCache * instance(ossim_uint32 maxSize=0)
void setFilterType(ossimFilterResamplerType filterType)
void setFullRefreshBit()
char_type * buffer()
Returns a pointer to the buffer.
virtual ossim_uint32 getNumberOfDecimationLevels() const
This returns the total number of decimation levels.
virtual ossimJpipMessage * readMessage()
virtual ossimRefPtr< ossimWebResponse > getResponse()
virtual void getPropertyNames(std::vector< ossimString > &propertyNames) const
void add(const char *prefix, const ossimKeywordlist &kwl, bool overwrite=true)
virtual void loadTile(const void *src, const ossimIrect &src_rect, ossimInterleaveType il_type)
virtual void close()
Deletes the overview and clears the valid image vertices.
ossimString toString() const
Definition: ossimUrl.cpp:106
kdu_supp::jp2_family_src m_jp2Family
virtual ossimRefPtr< ossimImageGeometry > getImageGeometry()
Returns the image geometry object associated with this tile source or NULL if non defined...
virtual bool getOverviewTile(ossim_uint32 resLevel, ossimImageData *result)
Method to get an overview tile.
static ossimImageDataFactory * instance()
virtual ossimImageGeometry * createGeometry(const ossimString &typeName) const
ossimRefPtr< ossimImageData > getTile(ossimAppFixedCacheId cacheId, const ossimIpt &origin)
virtual ossimDataObjectStatus validate() const
bool exists() const
virtual ossimRefPtr< ossimImageGeometry > getImageGeometry()
Returns the image geometry object associated with this tile source or NULL if non defined...
virtual const ossimFilename & getFilename() const
Returns the filename.
static ossimWebRequestFactoryRegistry * instance()
ossim_int32 m_CSn
If present, identifies the index (stating from 0) of the codestream to which the data-bin belongs...
unsigned long long ossim_uint64
const ossimString & getProtocol() const
Definition: ossimUrl.h:17
unsigned int ossim_uint32
ossimString trim(const ossimString &valueToTrim=ossimString(" \\)) const
this will strip lead and trailing character passed in.
bool set(const ossimUrl &url, const ossimKeywordlist &headerOptions, HttpMethodType methodType=HTTP_METHOD_GET)
ossimByteStreamBuffer & inputStreamBuffer()
virtual ossimIrect getImageRectangle() const
const ossimString & getPath() const
Definition: ossimUrl.h:20
ossimRefPtr< ossimImageData > m_tile
const ossimIpt & lr() const
Definition: ossimIrect.h:276
virtual void close()
Deletes the overview and clears the valid image vertices.
virtual ossim_uint32 getCurrentEntry() const
static ossimString downcase(const ossimString &aString)
Definition: ossimString.cpp:48
virtual ossim_int32 connectMyInputTo(ossimConnectableObject *inputObject, bool makeOutputConnection=true, bool createEventFlag=true)
Will try to connect this objects input to the passed in object.
virtual ossimRefPtr< ossimImageData > create(ossimSource *owner, ossimScalarType scalar, ossim_uint32 bands=1) const
virtual ossimRefPtr< ossimProperty > getProperty(const ossimString &name) const
ossim_uint32 width() const
Definition: ossimIrect.h:500
void initImageParameters(ossimImageGeometry *geom) const
Convenience method to set things needed in the image geometry from the image handler.
ossimIrect clipToRect(const ossimIrect &rect) const
Definition: ossimIrect.cpp:501
ossim_uint64 findLevel(ossim_uint64 power2Value, ossim_uint32 maxLevel)
void addHeaderOption(const ossimString &name, const ossimString &value)
ossimFilterResampler * getResampler()
bool m_isEOR
Indicates if this JPIP Message is an End of Response Message.
ossimScalarType
ossimByteStreamBuffer & headerBuffer()
std::streambuf * setBuf(char *buf, std::streamsize bufSize, bool shared)
bool clipRegionToImage(kdu_core::kdu_codestream &codestream, kdu_core::kdu_dims &region, int discard_levels, kdu_core::kdu_dims &clipRegion)
Sets clipRegion from region, and image dimensions for level.
const ossimString & getPort() const
Definition: ossimUrl.h:19
virtual void makeBlank()
Initializes data to null pixel values.
const ossimProjection * getProjection() const
Access methods for projection (may be NULL pointer).
virtual void completeOpen()
Will complete the opening process.
16 bit unsigned integer (15 bits used)
void copyAllDataFromInputStream(ByteBuffer &buffer)
ossimRefPtr< ossimImageHandler > theOverview
virtual bool open()
Pure virtual open.
bool copyRegionToTile(kdu_supp::kdu_channel_mapping *channelMapping, kdu_core::kdu_codestream &codestream, int discard_levels, kdu_core::kdu_thread_env *threadEnv, kdu_core::kdu_thread_queue *threadQueue, ossimImageData *destTile)
Copies region from codestream to tile at a given rlevel.
This class defines an abstract Handler which all image handlers(loaders) should derive from...
bool m_isLastByte
Bin-ID = [BinIdIndicator, completeDataBin, InClassIdentifier].
ossim_int32 y
Definition: ossimIpt.h:142
void makeNan()
Definition: ossimIrect.h:329
virtual const void * getBuf() const
virtual ossim_uint32 getNumberOfSamples(ossim_uint32 resLevel=0) const
Pure virtual, derived classes must implement.
bool loadClient(kdu_supp::kdu_client *client, kdu_supp::kdu_window &window)
virtual ossim_uint32 getNumberOfOutputBands() const
Returns the number of bands in a tile returned from this TileSource.
bool makeConnectionIfNeeded(kdu_supp::kdu_client *client)
long long ossim_int64
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
bool empty() const
Definition: ossimString.h:411
void stretchToTileBoundary(const ossimIpt &tileWidthHeight)
Definition: ossimIrect.cpp:212
ossim_int32 m_classIdentifier
If present, provides a message class identifier.
std::vector< char > ByteBuffer
ossimString ext() const
virtual ossim_uint32 getNumberOfSamples(ossim_uint32 resLevel=0) const =0
Pure virtual, derived classes must implement.
virtual ossimIrect getBoundingRect(ossim_uint32 resLevel=0) const
Returns zero-based bounding rectangle of the image.
ossim_int32 x
Definition: ossimIpt.h:141
const ossimString & getIp() const
Definition: ossimUrl.h:18
8 bit unsigned integer
virtual void scale(double x, double y)
std::basic_istringstream< char > istringstream
Class for char input memory streams.
Definition: ossimIosFwd.h:32
virtual ossim_uint32 getNumberOfDecimationLevels() const
This returns the total number of decimation levels.
bool hasNans() const
Definition: ossimIpt.h:58
kdu_supp::kdu_client * m_headerClient
static const char * QUALITY_KW
virtual void setProperty(ossimRefPtr< ossimProperty > property)
16 bit unsigned integer (11 bits used)
virtual ossim_uint32 getNumberOfLines(ossim_uint32 resLevel=0) const
Pure virtual, derived classes must implement.
void setParams(const ossimString &params)
Definition: ossimUrl.h:27
ossimRefPtr< ossimImageData > addTile(ossimAppFixedCacheId cacheId, ossimRefPtr< ossimImageData > data, bool duplicateData=true)
virtual ossimRefPtr< ossimImageData > getTile(const ossimIrect &rect, ossim_uint32 resLevel=0)
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
Method to save the state of an object to a keyword list.
void setCacheRefreshBit()
int ossim_int32
virtual ossimRefPtr< ossimImageData > getTile(const ossimIpt &origin, ossim_uint32 resLevel=0)