core/vil/file_formats/vil_j2k_image.cxx
Go to the documentation of this file.
00001 #include "vil_j2k_image.h"
00002 //:
00003 // \file
00004 // vil_j2k: Written by Rob Radtke (rob@) and Harry Voorhees (hlv@) of
00005 // Stellar Science Ltd. Co. (stellarscience.com) for
00006 // Air Force Research Laboratory, 2005.
00007 // Write capability added by J. Mundy, April 2009
00008 // Do not remove the following notice
00009 // Modifications approved for public Release, distribution unlimited
00010 // DISTAR Case 14074
00011 //
00012 
00013 #include <NCSFile.h>
00014 
00015 #include <vcl_algorithm.h>
00016 #include <vcl_cassert.h>
00017 #include <vcl_cmath.h> // for ceil()
00018 #include <vcl_limits.h>
00019 #include <vcl_cstdlib.h>
00020 #include <vil/vil_memory_chunk.h>
00021 #include <vil/vil_image_view.h>
00022 #include <vil/vil_load.h>
00023 #include <vil/vil_open.h>
00024 #include <vil/vil_new.h>
00025 #include "NCSJPCVilIOStream.h"
00026 #include <NCSTypes.h>
00027 
00028 // Fix me - need to add UINT64 and INT64 - JLM
00029 // Also note, float and double are defined but not handled by SDK 3.3
00030 // they are reinterpreted as INT32 and INT64
00031 NCSFileBandInfo bandInfo( const vil_pixel_format& vilType )
00032 {
00033   NCSFileBandInfo info;
00034   switch ( vil_pixel_format_component_format( vilType ) )
00035   {
00036     case VIL_PIXEL_FORMAT_UINT_32:{
00037       info.nBits = sizeof(vxl_uint_32)*8;
00038       info.bSigned = vcl_numeric_limits<vxl_uint_32>::is_signed;
00039       info.szDesc = 0;
00040       return info;
00041     }
00042     case VIL_PIXEL_FORMAT_INT_32:{
00043       info.nBits = sizeof(vxl_int_32)*8;
00044       info.bSigned = vcl_numeric_limits<vxl_int_32>::is_signed;
00045       info.szDesc = 0;
00046       return info;
00047     }
00048     case VIL_PIXEL_FORMAT_UINT_16:{
00049       info.nBits =  sizeof(vxl_uint_16)*8;
00050       info.bSigned =  vcl_numeric_limits<vxl_uint_16>::is_signed;
00051       info.szDesc = 0;
00052       return info;
00053     }
00054     case VIL_PIXEL_FORMAT_INT_16:{
00055       info.nBits = sizeof(vxl_int_16)*8;
00056       info.bSigned = vcl_numeric_limits<vxl_int_16>::is_signed;
00057       info.szDesc = 0;
00058       return info;
00059     }
00060     case VIL_PIXEL_FORMAT_BYTE:{
00061       info.nBits = sizeof(vxl_byte)*8;
00062       info.bSigned = vcl_numeric_limits<vxl_byte>::is_signed;
00063       info.szDesc = 0;
00064       return info;
00065     }
00066     case VIL_PIXEL_FORMAT_SBYTE:{
00067       info.nBits = sizeof(vxl_sbyte)*8;
00068       info.bSigned = vcl_numeric_limits<vxl_sbyte>::is_signed;
00069       info.szDesc = 0;
00070       return info;
00071     }
00072     case VIL_PIXEL_FORMAT_FLOAT:{
00073       info.nBits = sizeof(float)*8;
00074       info.bSigned = vcl_numeric_limits<float>::is_signed;
00075       info.szDesc = 0;
00076       return info;
00077     }
00078     case VIL_PIXEL_FORMAT_DOUBLE:{
00079       info.nBits = sizeof(double)*8;
00080       info.bSigned = vcl_numeric_limits<double>::is_signed;
00081       info.szDesc = 0;
00082       return info;
00083     }
00084     case VIL_PIXEL_FORMAT_BOOL:
00085     case VIL_PIXEL_FORMAT_COMPLEX_FLOAT:
00086     case VIL_PIXEL_FORMAT_COMPLEX_DOUBLE:
00087     case VIL_PIXEL_FORMAT_UINT_64:
00088     case VIL_PIXEL_FORMAT_INT_64:
00089     case VIL_PIXEL_FORMAT_UNKNOWN:
00090     default:{
00091       assert( 0 );
00092       info.nBits = 0; info.bSigned = false; info.szDesc = 0;
00093       return info;
00094     }
00095   }
00096 }
00097 
00098 //--------------------------------------------------------------------------------
00099 // class vil_j2k_file_format
00100 
00101 static char const j2k_string[] = "j2k";
00102 
00103 char const* vil_j2k_file_format::tag() const
00104 {
00105   return j2k_string;
00106 }
00107 
00108 vil_image_resource_sptr  vil_j2k_file_format::make_input_image(vil_stream *vs)
00109 {
00110   vil_j2k_image* im = new vil_j2k_image( vs );
00111   if ( !im->is_valid() ) {
00112     delete im;
00113     im = 0;
00114   }
00115   return im;
00116 }
00117 
00118 
00119 vil_image_resource_sptr
00120 vil_j2k_file_format::make_output_image(vil_stream* vs,
00121                                        unsigned ni,
00122                                        unsigned nj,
00123                                        unsigned nplanes,
00124                                        enum vil_pixel_format format)
00125 {
00126   vil_j2k_image* j2k_img = new vil_j2k_image(vs, ni, nj, nplanes, format,
00127                                              compression_ratio_);
00128   if (j2k_img->is_valid())
00129     return static_cast<vil_image_resource*>(j2k_img);
00130   return 0;
00131 }
00132 
00133 NCSEcwCellType convertType( const vil_pixel_format& vilType )
00134 {
00135   switch ( vil_pixel_format_component_format( vilType ) ) {
00136     case VIL_PIXEL_FORMAT_UINT_64: return NCSCT_UINT64;
00137     case VIL_PIXEL_FORMAT_INT_64: return NCSCT_INT64;
00138     case VIL_PIXEL_FORMAT_UINT_32: return NCSCT_UINT32;
00139     case VIL_PIXEL_FORMAT_INT_32: return NCSCT_INT32;
00140     case VIL_PIXEL_FORMAT_UINT_16: return NCSCT_UINT16;
00141     case VIL_PIXEL_FORMAT_INT_16: return NCSCT_INT16;
00142     case VIL_PIXEL_FORMAT_BYTE: return NCSCT_UINT8;
00143     case VIL_PIXEL_FORMAT_SBYTE: return NCSCT_INT8;
00144     case VIL_PIXEL_FORMAT_FLOAT: return NCSCT_IEEE4;
00145     case VIL_PIXEL_FORMAT_DOUBLE: return NCSCT_IEEE8;
00146     case VIL_PIXEL_FORMAT_BOOL:
00147     case VIL_PIXEL_FORMAT_COMPLEX_FLOAT:
00148     case VIL_PIXEL_FORMAT_COMPLEX_DOUBLE:
00149     case VIL_PIXEL_FORMAT_UNKNOWN:
00150     default:
00151       assert(0); return NCSCT_UINT8;
00152   }
00153 }
00154 
00155 // Note the J2K SDK defines IEEE4 and IEEE8 but they are not
00156 // handled as float or double, they are reinterpreted as INT32 and INT64
00157 vil_pixel_format convertType( const NCSEcwCellType& ecwType )
00158 {
00159   switch ( ecwType ) {
00160     case NCSCT_UINT64: return VIL_PIXEL_FORMAT_UINT_64;
00161     case NCSCT_INT64: return VIL_PIXEL_FORMAT_INT_64;
00162     case NCSCT_UINT32: return VIL_PIXEL_FORMAT_UINT_32;
00163     case NCSCT_INT32: return VIL_PIXEL_FORMAT_INT_32;
00164     case NCSCT_UINT16: return VIL_PIXEL_FORMAT_UINT_16;
00165     case NCSCT_INT16: return VIL_PIXEL_FORMAT_INT_16;
00166     case NCSCT_UINT8: return VIL_PIXEL_FORMAT_BYTE;
00167     case NCSCT_INT8: return VIL_PIXEL_FORMAT_SBYTE;
00168     case NCSCT_IEEE4: return VIL_PIXEL_FORMAT_FLOAT;
00169     case NCSCT_IEEE8: return VIL_PIXEL_FORMAT_DOUBLE;
00170     default:
00171       assert(0); return VIL_PIXEL_FORMAT_UNKNOWN;
00172   }
00173 }
00174 
00175 ////////////////////////////////////////////////////
00176 //                vil_j2k_image
00177 ////////////////////////////////////////////////////
00178 
00179 vil_j2k_image::vil_j2k_image( const vcl_string& fileOrUrl )
00180   : vil_image_resource(),
00181     mFileResource( new CNCSFile() ),
00182     mStr(0),
00183     mMaxLocalDimension( 5000 ), //default value
00184     mMaxRemoteDimension( 640 ), //default value
00185     mRemoteFile( false ),
00186     mFinfo(0),
00187     mBandinfo(0),
00188     line_index_(0)
00189 {
00190   if ( mFileResource->Open( (char*)fileOrUrl.c_str(), false, false ) != NCS_SUCCESS ) {
00191     mFileResource = 0;
00192     return;
00193   }
00194   if ( fileOrUrl.substr( 0, 7 ) == "ecwp://" ||
00195        fileOrUrl.substr( 0, 7 ) == "ECWP://" )
00196     {
00197       mRemoteFile = true;
00198     }
00199 }
00200 
00201 vil_j2k_image::vil_j2k_image( vil_stream* is )
00202   : vil_image_resource(),
00203     mFileResource( new CNCSFile() ),
00204     mStr(new CNCSJPCVilIOStream()),
00205     mMaxLocalDimension( 5000 ), //default value
00206     mMaxRemoteDimension( 640 ), //default value
00207     mRemoteFile( false ),
00208     mFinfo(0),
00209     mBandinfo(0),
00210     line_index_(0)
00211 {
00212   mStr->Open( is );
00213 
00214   if ( (static_cast<CNCSJP2FileView*>(mFileResource))->Open( mStr ) != NCS_SUCCESS ) {
00215     mFileResource = 0;
00216     return;
00217   }
00218 }
00219 
00220 vil_j2k_image::vil_j2k_image( vil_stream* vs, unsigned ni, unsigned nj,
00221                               unsigned nplanes, enum vil_pixel_format format,
00222                               unsigned compression_ratio)
00223   : vil_image_resource(),
00224     mFileResource( new CNCSFile()),
00225     mStr(new CNCSJPCVilIOStream()),
00226     mMaxLocalDimension( 5000 ), //default value
00227     mMaxRemoteDimension( 640 ), //default value
00228     mRemoteFile( false ),
00229     mFinfo(new NCSFileViewFileInfoEx()),
00230     line_index_(0)
00231 {
00232   mBandinfo = new NCSFileBandInfo[nplanes];
00233   CNCSError Error;
00234   for (unsigned i = 0; i<nplanes; ++i)
00235     mBandinfo[i] = bandInfo(format);
00236 
00237   //String names for each band, should specialize according to color space
00238   mBandinfo[0].szDesc ="grey";
00239   if (nplanes==3) {
00240     mBandinfo[0].szDesc = "Red";
00241     mBandinfo[1].szDesc = "Green";
00242     mBandinfo[2].szDesc = "Blue";
00243   }
00244   NCSEcwCellType t = convertType(format);
00245   NCSFileViewFileInfoEx finfo=*mFinfo;
00246   finfo.pBands = mBandinfo;
00247   finfo.nSizeX = ni;
00248   finfo.nSizeY = nj;
00249   finfo.nBands = nplanes;
00250   finfo.eCellType = t;
00251   finfo.nCompressionRate = compression_ratio;
00252   finfo.eCellSizeUnits = ECW_CELL_UNITS_METERS;
00253   finfo.fCellIncrementX = 1.0;
00254   finfo.fCellIncrementY = 1.0;
00255   finfo.fOriginX = 0.0;
00256   finfo.fOriginY = 0.0;
00257   finfo.szDatum = "RAW";
00258   finfo.szProjection = "RAW";
00259   finfo.fCWRotationDegrees = 0.0;
00260   if (nplanes ==1)
00261     finfo.eColorSpace = NCSCS_GREYSCALE;
00262   else if (nplanes ==3)
00263     finfo.eColorSpace = NCSCS_sRGB;
00264   else {
00265     delete mFileResource;
00266     mFileResource = 0;
00267   }
00268   Error = mFileResource->SetFileInfo(finfo);
00269   if (Error != NCS_SUCCESS) {
00270     if (mFileResource)
00271       delete mFileResource;
00272     mFileResource = 0;
00273   }
00274   Error = mStr->Open(vs, true);
00275   if (Error != NCS_SUCCESS) {
00276     if (mFileResource)
00277       delete mFileResource;
00278     mFileResource = 0;
00279   }
00280   CNCSJP2FileView* fview = static_cast<CNCSJP2FileView*>(mFileResource);
00281   Error = fview->Open(static_cast<CNCSJPCIOStream*>(mStr));
00282   if (Error != NCS_SUCCESS) {
00283     if (mFileResource)
00284       delete mFileResource;
00285     mFileResource = 0;
00286     return;
00287   }
00288 }
00289 
00290 vil_j2k_image::~vil_j2k_image()
00291 {
00292   if ( mFileResource ) {
00293     mFileResource->Close( true );
00294   }
00295   if (mStr)
00296     delete mStr;
00297   if (mBandinfo)
00298     delete mBandinfo;
00299   if (mFinfo)
00300     delete mFinfo;
00301 }
00302 
00303 unsigned vil_j2k_image::nplanes() const
00304 {
00305   assert( mFileResource );
00306   return mFileResource->GetFileInfo()->nBands;
00307 }
00308 
00309 unsigned vil_j2k_image::ni() const
00310 {
00311   assert( mFileResource );
00312   return mFileResource->GetFileInfo()->nSizeX;
00313 }
00314 
00315 unsigned vil_j2k_image::nj() const
00316 {
00317   assert( mFileResource );
00318   return mFileResource->GetFileInfo()->nSizeY;
00319 }
00320 
00321 enum vil_pixel_format vil_j2k_image::pixel_format() const
00322 {
00323   assert( mFileResource );
00324   return convertType( mFileResource->GetFileInfo()->eCellType );
00325 }
00326 
00327 char const* vil_j2k_image::file_format() const
00328 {
00329   return "j2k";
00330 }
00331 
00332 vil_image_view_base_sptr
00333 vil_j2k_image::get_copy_view_decimated(unsigned sample0,
00334                                        unsigned num_samples,
00335                                        unsigned line0,
00336                                        unsigned numLines,
00337                                        double i_factor,
00338                                        double j_factor) const
00339 {
00340   return get_copy_view_decimated_by_size(sample0,
00341                                          num_samples,
00342                                          line0,
00343                                          numLines,
00344                                          (unsigned int)(((double)num_samples)/i_factor),
00345                                          (unsigned int)(((double)numLines)/j_factor));
00346 }
00347 
00348 vil_image_view_base_sptr
00349 vil_j2k_image::get_copy_view_decimated_by_size(unsigned sample0,
00350                                                unsigned num_samples,
00351                                                unsigned line0,
00352                                                unsigned numLines,
00353                                                unsigned int output_width,
00354                                                unsigned int output_height) const
00355 {
00356   if ( !( mFileResource ) ||
00357        !( ( sample0 + num_samples - 1 ) < ni() &&
00358           ( line0 + numLines - 1 ) < nj() ) )
00359   {
00360     return 0;
00361   }
00362 
00363   //we want all bands mapped in the same order as they come in the input file
00364   //eg. bandMap = {0,1,2,3...nBands}
00365   INT32 nBands = nplanes();
00366   INT32* bandMap = (INT32*) vcl_malloc(sizeof(UINT32) * nBands );
00367   for ( int i = 0 ; i < nBands ; i++ ) { bandMap[i] = i; }
00368 
00369   //this guards us from returning an image that is too big for the computer's memory
00370   //(or would take too long to download in the remote case).
00371   //We don't want infinite hangs or application crashes.
00372   unsigned int maxDim = mRemoteFile ? mMaxRemoteDimension : mMaxLocalDimension;
00373   if ( output_width > maxDim || output_height > maxDim ) {
00374     unsigned int biggestDim = vcl_max( output_width, output_height );
00375     double zoomFactor = ((double)maxDim) / ((double)biggestDim);
00376     output_width  = (unsigned int) ( ((double)output_width)  * zoomFactor );
00377     output_height = (unsigned int) ( ((double)output_height) * zoomFactor );
00378   }
00379 
00380   //set the view to be that specified by the function's input parameters
00381   //note that we don't want ECW to do any scaling for us.  That's why
00382   //the box created by (sample0,line0) and (sample0+num_samples-1,line0+numLines-1) is made to be exactly num_samplesXnumLines.
00383 
00384   NCSError setViewError = mFileResource->SetView( nBands, bandMap, output_width, output_height,
00385                                                   (INT32)sample0, (INT32)line0, (INT32)(sample0+num_samples-1), (INT32)(line0+numLines-1) );
00386   if ( setViewError != NCS_SUCCESS ) {
00387     free( bandMap );
00388     return 0;
00389   }
00390 
00391   //number of samples times the bytes per sample in each band
00392   double bitsPerSample                 = mFileResource->GetFileInfo()->pBands[0].nBits;
00393   unsigned int bytesPerSample          = (unsigned int) vcl_ceil( bitsPerSample / 8.0 );
00394   unsigned int singleBandLineSizeBytes = output_width * bytesPerSample;
00395   unsigned int allBandLineSizeBytes    = singleBandLineSizeBytes * nBands;
00396   unsigned int dataPtrSizeBytes        = allBandLineSizeBytes * output_height;
00397   //void* data_ptr = vcl_malloc( dataPtrSizeBytes );
00398   vil_memory_chunk_sptr data_ptr = new vil_memory_chunk( dataPtrSizeBytes, convertType( mFileResource->GetFileInfo()->eCellType ) );
00399   void** linePtrPtr = (void**)vcl_malloc( nBands * sizeof( int* /*all pointers have same size, so eg char* would work too*/ ) );
00400   //now read all the lines that we want
00401   for ( unsigned int currLine = 0 ; currLine < output_height ; currLine++ ) {
00402     for (int currBand = 0 ; currBand < nBands ; currBand++ ) {
00403       linePtrPtr[currBand] = (void*) ( ((char*)data_ptr->data()) + currLine * allBandLineSizeBytes + currBand * singleBandLineSizeBytes );
00404     }
00405     NCSEcwReadStatus readStatus = mFileResource->ReadLineBIL( mFileResource->GetFileInfo()->eCellType, nBands, linePtrPtr, 0);
00406     if ( readStatus != NCSECW_READ_OK ) {
00407       free( bandMap );
00408       free( linePtrPtr );
00409       return 0;
00410     }
00411   }
00412 
00413   //free our temp resources
00414   free( bandMap );
00415   free( linePtrPtr );
00416 
00417   vil_image_view_base_sptr view = 0;
00418   //now create our vil_image_view
00419   //note that float and double are defaulted since the J2K SDK doesn't
00420   //implement these types properly
00421   switch ( vil_pixel_format_component_format( data_ptr->pixel_format() ) )
00422     {
00423 #define macro( F, T ) \
00424   case F: \
00425     view = new vil_image_view< T > ( data_ptr, reinterpret_cast<T*>(data_ptr->data()), \
00426                                      output_width, output_height, nBands, 1, output_width*nBands, output_width); \
00427     break
00428       macro(VIL_PIXEL_FORMAT_BYTE , vxl_byte );
00429       macro(VIL_PIXEL_FORMAT_SBYTE , vxl_sbyte );
00430       macro(VIL_PIXEL_FORMAT_UINT_64 , vxl_uint_64 );
00431       macro(VIL_PIXEL_FORMAT_INT_64 , vxl_int_64 );
00432       macro(VIL_PIXEL_FORMAT_UINT_32 , vxl_uint_32 );
00433       macro(VIL_PIXEL_FORMAT_INT_32 , vxl_int_32 );
00434       macro(VIL_PIXEL_FORMAT_UINT_16 , vxl_uint_16 );
00435       macro(VIL_PIXEL_FORMAT_INT_16 , vxl_int_16 );
00436       macro(VIL_PIXEL_FORMAT_BOOL , bool );
00437 #undef macro
00438     default:
00439       vcl_cerr << "Pixel format not supported by ERMapper SDK\n";
00440       assert( 0 );
00441       break;
00442     }
00443 
00444   return view;
00445 }
00446 
00447 vil_image_view_base_sptr vil_j2k_image::get_copy_view(unsigned sample0,
00448                                                       unsigned num_samples,
00449                                                       unsigned line0,
00450                                                       unsigned numLines ) const
00451 {
00452   return get_copy_view_decimated( sample0, num_samples, line0, numLines, 1.0, 1.0 );
00453 }
00454 
00455 void vil_j2k_image::unsetMaxImageDimension( bool remote )
00456 {
00457 #undef max
00458   setMaxImageDimension( vcl_numeric_limits< unsigned int >::max(), remote );
00459 }
00460 
00461 void vil_j2k_image::setMaxImageDimension( unsigned int widthOrHeight, bool remote )
00462 {
00463   if ( remote ) {
00464     mMaxRemoteDimension = widthOrHeight;
00465   } else {
00466     mMaxLocalDimension = widthOrHeight;
00467   }
00468 }
00469 
00470 vil_image_view_base_sptr vil_j2k_image::s_decode_jpeg_2000( vil_stream* vs,
00471                                                             unsigned i0, unsigned ni,
00472                                                             unsigned j0, unsigned nj,
00473                                                             double i_factor, double j_factor )
00474 {
00475   vil_j2k_image* j2k_image = new vil_j2k_image(vs);
00476   //remove limit by default, since vil is not typically used remotely
00477   //but more commonly with large image files - JLM Jan 07, 2012
00478   j2k_image->unsetMaxImageDimension();
00479   vil_image_view_base_sptr view = j2k_image->get_copy_view_decimated(i0, ni, j0, nj, i_factor, j_factor);
00480   delete j2k_image;
00481   return view;
00482 }
00483 
00484 vil_image_view_base_sptr
00485 vil_j2k_image::s_decode_jpeg_2000_by_size( vil_stream* vs,
00486                                            unsigned i0, unsigned ni,
00487                                            unsigned j0, unsigned nj,
00488                                            unsigned int output_width,
00489                                            unsigned int output_height )
00490 {
00491   vil_j2k_image* j2k_image = new vil_j2k_image(vs);
00492   vil_image_view_base_sptr view = j2k_image->get_copy_view_decimated_by_size(i0, ni, j0, nj, output_width, output_height);
00493   delete j2k_image;
00494   return view;
00495 }
00496 
00497 template < class T >
00498 static bool write_line_BIL(vil_memory_chunk_sptr& chunk,
00499                            unsigned ni, unsigned nplanes, unsigned istep,
00500                            unsigned planestep, unsigned bytes_per_pixel,
00501                            CNCSFile* f_resource, NCSEcwCellType t)
00502 {
00503   T* cdata = reinterpret_cast<T*>(chunk->data());
00504   T** line_ptr = new T*[nplanes];
00505   for (unsigned p = 0; p<nplanes; ++p)
00506     line_ptr[p] = new T[ni*bytes_per_pixel];
00507 
00508   for (unsigned p = 0; p<nplanes; ++p) {
00509     T* wline = line_ptr[p];
00510     for (unsigned i = 0; i<ni; ++i) {
00511       *(wline+i) = *(cdata+ i*istep + p*planestep);
00512     }
00513   }
00514   bool good = true;
00515   void ** outbuf = reinterpret_cast<void**>(line_ptr);
00516   CNCSError writeError  = f_resource->WriteLineBIL(t, nplanes, outbuf);
00517   if ( writeError != NCS_SUCCESS ) good = false;
00518 
00519   for (unsigned p = 0; p<nplanes; ++p)
00520     delete [] line_ptr[p];
00521   delete [] line_ptr;
00522   return good;
00523 }
00524 
00525 
00526 //: JPEG2K compress by inserting an image row (line) at a time
00527 //  When the full image has been inserted, call put_line with
00528 // image_row == nj(). This call causes the resource to be closed
00529 // and is no longer valid. The lines must be inserted in strict row order.
00530 bool
00531 vil_j2k_image::put_line(const vil_image_view_base& im)
00532 {
00533   if (!mFileResource)
00534     return false;
00535   vil_pixel_format format = this->pixel_format();
00536   unsigned ni = this->ni(), nj = this->nj(), nplanes = this->nplanes();
00537   if (line_index_>=nj) {
00538     mFileResource->Close(true);
00539     if (mFileResource)
00540       delete mFileResource;
00541     mFileResource = 0;
00542     return true;
00543   }
00544   unsigned bytes_per_pixel = 0;
00545   NCSEcwCellType t = convertType(format);
00546   vil_memory_chunk_sptr chunk;
00547   //now write out the image line
00548   //note that float and double are defaulted since the J2K SDK doesn't
00549   //implement these types properly
00550   switch ( vil_pixel_format_component_format( format ) )
00551     {
00552 #define macro( F, T )\
00553   case F: {\
00554    bytes_per_pixel = sizeof(T); \
00555    const vil_image_view<T>& view = static_cast<const vil_image_view<T>&>(im); \
00556    chunk = view.memory_chunk(); \
00557    if (!write_line_BIL<T>(chunk, ni, nplanes, view.istep(), view.planestep(),\
00558                          bytes_per_pixel, mFileResource, t)) \
00559     return false; \
00560   } \
00561   break
00562       macro(VIL_PIXEL_FORMAT_BYTE , vxl_byte );
00563       macro(VIL_PIXEL_FORMAT_SBYTE , vxl_sbyte );
00564       macro(VIL_PIXEL_FORMAT_UINT_32 , vxl_uint_32 );
00565       macro(VIL_PIXEL_FORMAT_INT_32 , vxl_int_32 );
00566       macro(VIL_PIXEL_FORMAT_UINT_16 , vxl_uint_16 );
00567       macro(VIL_PIXEL_FORMAT_INT_16 , vxl_int_16 );
00568       macro(VIL_PIXEL_FORMAT_BOOL , bool );
00569 #undef macro
00570     default:
00571       vcl_cerr << "Pixel format not supported by ERMapper SDK\n";
00572       assert( 0 );
00573       break;
00574     }
00575   ++line_index_;
00576   return true;
00577 }
00578 
00579 //: JPEG2K compress the view and of the full image and insert in resource
00580 //  The file is closed after putting the view into the resource
00581 //  and becomes an invalid resource.
00582 bool vil_j2k_image::
00583 put_view(const vil_image_view_base& im)
00584 {
00585   if (!this->view_fits(im, 0, 0))
00586     return false;
00587   if (!mFileResource)
00588     return false;
00589   unsigned ni= im.ni(), nj = im.nj();
00590   vil_image_resource_sptr mem_res =
00591     vil_new_image_resource_of_view(im);
00592     vil_image_view_base_sptr view;
00593   for (unsigned j = 0; j<nj; ++j) {
00594     view = mem_res->get_copy_view(0, ni, j, 1);
00595     if (!this->put_line(*view)) return false;
00596   }
00597   return true;
00598 }
00599 
00600 //: Check that a view will fit into the data at the given offset.
00601 bool vil_j2k_image::
00602 view_fits(const vil_image_view_base& im, unsigned i0, unsigned j0)
00603 {
00604   unsigned ni_view = im.ni(), nj_view = im.nj(), nplanes_view = im.nplanes();
00605   return i0+1 < ni_view
00606       && j0+1 < nj_view
00607       && ni_view <= this->ni()
00608       && nj_view <= this->nj()
00609       && nplanes_view <= this->nplanes();
00610 }
00611 
00612 //:
00613 //  Encode an entire image by loading the input resource from stream
00614 //  and compressing the input line by line by extracting an image view
00615 //  of a block of lines at a time, thus works for arbitrarily large images.
00616 //  The num_lines_block parameter is the number of image rows in the
00617 //  block which is read into memory from the resource
00618 bool vil_j2k_image::s_encode_jpeg2000(vil_stream* vs,
00619                                       const char* out_filename,
00620                                       unsigned compression_ratio,
00621                                       unsigned num_lines_block,
00622                                       bool verbose)
00623 {
00624   vil_image_resource_sptr in_res = vil_load_image_resource_raw(vs);
00625   if (!in_res)
00626     return false;
00627   unsigned ni = in_res->ni(), nj = in_res->nj(), nplanes = in_res->nplanes();
00628   vil_pixel_format format = in_res->pixel_format();
00629   vil_stream* os = vil_open(out_filename, "w");
00630   if (!vs) return false;
00631   vil_j2k_file_format fmt;
00632   fmt.set_compression_ratio(compression_ratio);
00633   vil_image_resource_sptr res = fmt.make_output_image(os, ni, nj, nplanes,
00634                                                       format);
00635   if (!res) return false;
00636   vil_j2k_image* j2k_img = reinterpret_cast<vil_j2k_image*>(res.ptr());
00637 
00638   //number of full blocks in image height
00639   unsigned n_blocks = nj/num_lines_block;
00640   unsigned jb = 0;
00641   for (unsigned b = 0; b<n_blocks; b++, jb += num_lines_block)
00642   {
00643     // read a block from the file: width = ni, height = num_lines_block
00644     vil_image_view_base_sptr block_view = in_res->get_view(0, ni, jb, num_lines_block);
00645     if (!block_view) return false;
00646 
00647     //wrap the view in a memory resident resource
00648     vil_image_resource_sptr block_res =
00649       vil_new_image_resource_of_view(*block_view);
00650 
00651     //compress the block, line by line
00652     for (unsigned j = 0; j<num_lines_block; ++j) {
00653       vil_image_view_base_sptr line_view =
00654         block_res->get_copy_view(0, ni, j, 1);
00655       if (!j2k_img->put_line(*line_view)) return false;
00656       if (verbose)
00657         if (j%100 == 0) //output a dot every 100 lines
00658           vcl_cout << '.';
00659     }
00660   }
00661   //output the remaining lines left over after loading block-sized chunks
00662   unsigned remaining_lines = nj-jb;
00663   if (remaining_lines) {
00664     vil_image_view_base_sptr residual_view =
00665       in_res->get_view(0, ni, jb, remaining_lines);
00666     vil_image_resource_sptr residual_res =
00667       vil_new_image_resource_of_view(*residual_view);
00668     vil_image_view_base_sptr view;
00669     for (unsigned j = 0; j<remaining_lines; ++j) {
00670       view = residual_res->get_copy_view(0, ni, j, 1);
00671       if (!j2k_img->put_line(*view)) return false;
00672       if (verbose)
00673         if (j%100 == 0) //output a dot every 100 lines
00674           vcl_cout << '.';
00675     }
00676   }
00677   if (verbose) vcl_cout << '\n';
00678   return true;
00679 }
00680 
00681 bool vil_j2k_image::s_encode_jpeg2000(const char* in_filename,
00682                                       const char* out_filename,
00683                                       unsigned compression_ratio,
00684                                       unsigned num_lines_block,
00685                                       bool verbose )
00686 {
00687   vil_stream* vs = vil_open(in_filename);
00688   vs->ref();
00689   bool success =
00690     vil_j2k_image::s_encode_jpeg2000(vs, out_filename,
00691                                      compression_ratio,
00692                                      num_lines_block,
00693                                      verbose);
00694   vs->unref();
00695   return success;
00696 }
00697