void KakaduImage::loadImageInfo( int seq, int ang )
{
  jp2_channels j2k_channels;
  jp2_palette j2k_palette;
  jp2_resolution j2k_resolution;
  jp2_colour j2k_colour;
  kdu_coords layer_size;
  jpx_layer_source jpx_layer;

  // Check for High Throughput JPEG2000 codestream
#ifdef DEBUG
  siz_params *siz = codestream.access_siz();
  int pcap_value = 0;
  siz->get( Scap, 0, 0, pcap_value );
  if( pcap_value & 0x00020000 ) logfile << "Kakadu :: HTJ2K codestream" << endl;
#endif

  // Malformed images can throw exceptions here with older versions of Kakadu
  try{
    jpx_layer = jpx_input.access_layer(0);
  }
  catch( ... ){
    throw file_error( "Kakadu :: Core Exception Caught During Metadata Extraction"); // Rethrow the exception
  }

  j2k_channels = jpx_layer.access_channels();
  j2k_resolution = jpx_layer.access_resolution();
  j2k_colour = jpx_layer.access_colour(0);
  layer_size = jpx_layer.get_layer_size();

  image_widths.push_back(layer_size.x);
  image_heights.push_back(layer_size.y);
  channels = codestream.get_num_components();
  numResolutions = codestream.get_min_dwt_levels();
  bpc = codestream.get_bit_depth(0,true);

  // Get capture resolution
  dpi_y = j2k_resolution.get_resolution( false );
  if( dpi_y > 0.0 ){
    dpi_y /= 100.0;          // JP2 are in pixels/m, so convert to cm
    float aspect = j2k_resolution.get_aspect_ratio( false );
    dpi_x = dpi_y * aspect;
    dpi_units = 2;           // cm units
  }
  else dpi_y = 0.0;

  unsigned int w = layer_size.x;
  unsigned int h = layer_size.y;

#ifdef DEBUG
  logfile << "Kakadu :: DWT Levels: " << numResolutions << endl;
  logfile << "Kakadu :: Pixel Resolution : " << w << "x" << h << endl;
  logfile << "Kakadu :: Capture Resolution : " << dpi_x << "x" << dpi_y << " pixels/cm" << endl;
#endif

  // Loop through each resolution and calculate the image dimensions - 
  // We calculate ourselves rather than relying on get_dims() to force a similar
  // behaviour to TIFF with resolutions at floor(x/2) rather than Kakadu's default ceil(x/2) 
  for( unsigned int c=1; c<numResolutions; c++ ){
    //    codestream.apply_input_restrictions(0,0,c,1,NULL,KDU_WANT_OUTPUT_COMPONENTS);
    //    kdu_dims layers;
    //    codestream.get_dims(0,layers,true);
    //    image_widths.push_back(layers.size.x);
    //    image_heights.push_back(layers.size.y);
    w = floor( w/2.0 );
    h = floor( h/2.0 );
    image_widths.push_back(w);
    image_heights.push_back(h);
#ifdef DEBUG
    logfile << "Kakadu :: Resolution : " << w << "x" << h << endl;
#endif
  }

  // If we don't have enough resolutions to fit a whole image into a single tile
  // we need to generate them ourselves virtually. Fortunately, the
  // kdu_region_decompressor function is able to handle the downsampling for us for one extra level.
  // Extra downsampling has to be done ourselves
  unsigned int n = 1;
  w = image_widths[0];
  h = image_heights[0];
  while( (w>tile_width) || (h>tile_height) ){
    n++;
    w = floor( w/2.0 );
    h = floor( h/2.0 );
    if( n > numResolutions ){
      image_widths.push_back(w);
      image_heights.push_back(h);
    }
  }

  if( n > numResolutions ){
#ifdef DEBUG
    logfile << "Kakadu :: Warning! Insufficient resolution levels in JPEG2000 stream. Will generate " << n-numResolutions << " extra levels dynamically -" << endl
	    << "Kakadu :: However, you are advised to regenerate the file with at least " << n << " levels" << endl;
#endif
  }

  if( n > numResolutions ) virtual_levels = n-numResolutions-1;
  numResolutions = n;


  // Check for a palette and LUT - only used for bilevel images for now
  int cmp, plt, stream_id,format=0;
#if defined(KDU_MAJOR_VERSION) && (KDU_MAJOR_VERSION >= 8 || ((KDU_MAJOR_VERSION >= 7) && (KDU_MINOR_VERSION >= 8)))
  // API change for get_colour_mapping in Kakadu 7.8
  j2k_channels.get_colour_mapping(0,cmp,plt,stream_id,format);
#else
  j2k_channels.get_colour_mapping(0,cmp,plt,stream_id);
#endif

  j2k_palette = jpx_stream.access_palette();

  if( j2k_palette.exists() && j2k_palette.get_num_luts()>0 ){
    int entries = j2k_palette.get_num_entries();
    float *lt = new float[entries];
    j2k_palette.get_lut(0,lt);    // Note that we extract only first LUT
    // Force to unsigned format, scale to 8 bit and load these into our LUT vector
    for( int n=0; n<entries; n++ ){
      lut.push_back((int)((lt[n]+0.5)*255));
    }
    delete[] lt;
#ifdef DEBUG
    logfile << "Kakadu :: Palette with " << j2k_palette.get_num_luts() << " LUT and " << entries
	    << " entries/LUT with values " << lut[0] << "," << lut[1] << endl;
#endif
  }


  // Extract any ICC profile and add it to our metadata map
  int icc_length = 0;
  const char* icc = (const char*) j2k_colour.get_icc_profile( &icc_length );
  if( icc_length > 0 ) metadata["icc"] = string( icc, icc_length );


  // Set our colour space - we let Kakadu automatically handle CIELAB->sRGB conversion for the time being
  if( channels == 1 ){
    colourspace = (bpc==1)? BINARY : GREYSCALE;
  }
  else{
    jp2_colour_space cs = j2k_colour.get_space();
    if( cs == JP2_sRGB_SPACE || cs == JP2_iccRGB_SPACE || cs == JP2_esRGB_SPACE || cs == JP2_CIELab_SPACE ) colourspace = sRGB;
    //else if ( cs == JP2_CIELab_SPACE ) colourspace = CIELAB;
    else {
#ifdef DEBUG
    	logfile << "WARNING : colour space not found, setting sRGB colour space value" << endl;
#endif
    	colourspace = sRGB;
    }
  }


  // Get the number of quality layers - must first open a tile, however
  kdu_tile kt = codestream.open_tile(kdu_coords(0,0),NULL);
  quality_layers = codestream.get_max_tile_layers();
#ifdef DEBUG
  string cs;
  switch( j2k_colour.get_space() ){
    case JP2_sRGB_SPACE:
      cs = "JP2_sRGB_SPACE";
      break;
    case JP2_sLUM_SPACE:
      cs =  "JP2_sLUM_SPACE";
      break;
    case JP2_CIELab_SPACE:
      cs = "JP2_CIELab_SPACE";
      break;
    default:
      cs = j2k_colour.get_space();
      break;
  }
  logfile << "Kakadu :: " << bpc << " bit data" << endl
	  << "Kakadu :: " << channels << " channels" << endl
	  << "Kakadu :: colour space: " << cs << endl
	  << "Kakadu :: " << quality_layers << " quality layers detected" << endl;
#endif
  kt.close();

  // For bilevel images, force channels to 1 as we sometimes come across such images which claim 3 channels
  if( bpc == 1 ) channels = 1;

  // Get the max and min values for our data type
  //double sminvalue[4], smaxvalue[4];
  for( unsigned int i=0; i<channels; i++ ){
    min.push_back( 0.0 );
    if( bpc > 8 && bpc <= 16 ) max.push_back( 65535.0 );
    else max.push_back( 255.0 );
  }

  isSet = true;
}
void KakaduImage::loadImageInfo( int seq, int ang )
{
  jp2_channels j2k_channels;
  jp2_palette j2k_palette;
  jp2_resolution j2k_resolution;
  jp2_colour j2k_colour;
  kdu_coords layer_size;
  jpx_layer_source jpx_layer;

   
#ifdef DEBUG
  siz_params *siz = codestream.access_siz();
  int pcap_value = 0;
  siz->get( Scap, 0, 0, pcap_value );
  if( pcap_value & 0x00020000 ) logfile << "Kakadu :: HTJ2K codestream" << endl;
#endif

   
  try{
    jpx_layer = jpx_input.access_layer(0);
  }
  catch( ... ){
    throw file_error( "Kakadu :: Core Exception Caught During Metadata Extraction");  
  }

  j2k_channels = jpx_layer.access_channels();
  j2k_resolution = jpx_layer.access_resolution();
  j2k_colour = jpx_layer.access_colour(0);
  layer_size = jpx_layer.get_layer_size();

  image_widths.push_back(layer_size.x);
  image_heights.push_back(layer_size.y);
  channels = codestream.get_num_components();
  numResolutions = codestream.get_min_dwt_levels();
  bpc = codestream.get_bit_depth(0,true);

   
  dpi_y = j2k_resolution.get_resolution( false );
  if( dpi_y > 0.0 ){
    dpi_y /= 100.0;           
    float aspect = j2k_resolution.get_aspect_ratio( false );
    dpi_x = dpi_y * aspect;
    dpi_units = 2;            
  }
  else dpi_y = 0.0;

  unsigned int w = layer_size.x;
  unsigned int h = layer_size.y;

#ifdef DEBUG
  logfile << "Kakadu :: DWT Levels: " << numResolutions << endl;
  logfile << "Kakadu :: Pixel Resolution : " << w << "x" << h << endl;
  logfile << "Kakadu :: Capture Resolution : " << dpi_x << "x" << dpi_y << " pixels/cm" << endl;
#endif

   
   
   
  for( unsigned int c=1; c<numResolutions; c++ ){
     
     
     
     
     
    w = floor( w/2.0 );
    h = floor( h/2.0 );
    image_widths.push_back(w);
    image_heights.push_back(h);
#ifdef DEBUG
    logfile << "Kakadu :: Resolution : " << w << "x" << h << endl;
#endif
  }

   
   
   
   
  unsigned int n = 1;
  w = image_widths[0];
  h = image_heights[0];
  while( (w>tile_width) || (h>tile_height) ){
    n++;
    w = floor( w/2.0 );
    h = floor( h/2.0 );
    if( n > numResolutions ){
      image_widths.push_back(w);
      image_heights.push_back(h);
    }
  }

  if( n > numResolutions ){
#ifdef DEBUG
    logfile << "Kakadu :: Warning! Insufficient resolution levels in JPEG2000 stream. Will generate " << n-numResolutions << " extra levels dynamically -" << endl
	    << "Kakadu :: However, you are advised to regenerate the file with at least " << n << " levels" << endl;
#endif
  }

  if( n > numResolutions ) virtual_levels = n-numResolutions-1;
  numResolutions = n;


   
  int cmp, plt, stream_id,format=0;
#if defined(KDU_MAJOR_VERSION) && (KDU_MAJOR_VERSION >= 8 || ((KDU_MAJOR_VERSION >= 7) && (KDU_MINOR_VERSION >= 8)))
   
  j2k_channels.get_colour_mapping(0,cmp,plt,stream_id,format);
#else
  j2k_channels.get_colour_mapping(0,cmp,plt,stream_id);
#endif

  j2k_palette = jpx_stream.access_palette();

  if( j2k_palette.exists() && j2k_palette.get_num_luts()>0 ){
    int entries = j2k_palette.get_num_entries();
    float *lt = new float[entries];
    j2k_palette.get_lut(0,lt);     
     
    for( int n=0; n<entries; n++ ){
      lut.push_back((int)((lt[n]+0.5)*255));
    }
    delete[] lt;
#ifdef DEBUG
    logfile << "Kakadu :: Palette with " << j2k_palette.get_num_luts() << " LUT and " << entries
	    << " entries/LUT with values " << lut[0] << "," << lut[1] << endl;
#endif
  }


   
  int icc_length = 0;
  const char* icc = (const char*) j2k_colour.get_icc_profile( &icc_length );
  if( icc_length > 0 ) metadata["icc"] = string( icc, icc_length );


   
  if( channels == 1 ){
    colourspace = (bpc==1)? BINARY : GREYSCALE;
  }
  else{
    jp2_colour_space cs = j2k_colour.get_space();
    if( cs == JP2_sRGB_SPACE || cs == JP2_iccRGB_SPACE || cs == JP2_esRGB_SPACE || cs == JP2_CIELab_SPACE ) colourspace = sRGB;
     
    else {
#ifdef DEBUG
    	logfile << "WARNING : colour space not found, setting sRGB colour space value" << endl;
#endif
    	colourspace = sRGB;
    }
  }


   
  kdu_tile kt = codestream.open_tile(kdu_coords(0,0),NULL);
  quality_layers = codestream.get_max_tile_layers();
#ifdef DEBUG
  string cs;
  switch( j2k_colour.get_space() ){
    case JP2_sRGB_SPACE:
      cs = "JP2_sRGB_SPACE";
      break;
    case JP2_sLUM_SPACE:
      cs =  "JP2_sLUM_SPACE";
      break;
    case JP2_CIELab_SPACE:
      cs = "JP2_CIELab_SPACE";
      break;
    default:
      cs = j2k_colour.get_space();
      break;
  }
  logfile << "Kakadu :: " << bpc << " bit data" << endl
	  << "Kakadu :: " << channels << " channels" << endl
	  << "Kakadu :: colour space: " << cs << endl
	  << "Kakadu :: " << quality_layers << " quality layers detected" << endl;
#endif
  kt.close();

   
  if( bpc == 1 ) channels = 1;

   
   
  for( unsigned int i=0; i<channels; i++ ){
    min.push_back( 0.0 );
    if( bpc > 8 && bpc <= 16 ) max.push_back( 65535.0 );
    else max.push_back( 255.0 );
  }

  isSet = true;
}