diff --git a/Code/IO/otbGDALImageIO.cxx b/Code/IO/otbGDALImageIO.cxx index 5d98a800ff8e763d50adade1e31e1981e58548e8..6d2c891344302800aef2cfb021e10a2515b0cc6b 100644 --- a/Code/IO/otbGDALImageIO.cxx +++ b/Code/IO/otbGDALImageIO.cxx @@ -1004,7 +1004,6 @@ bool GDALImageIO::CanStreamWrite() itkDebugMacro(<< "Unable to instantiate driver " << gdalDriverShortName); m_CanStreamWrite = false; } - if ( GDALGetMetadataItem( driver, GDAL_DCAP_CREATE, NULL ) != NULL ) { m_CanStreamWrite = true; @@ -1013,6 +1012,7 @@ bool GDALImageIO::CanStreamWrite() { m_CanStreamWrite = false; } + return m_CanStreamWrite; } @@ -1111,27 +1111,11 @@ void GDALImageIO::Write(const void* buffer) itkExceptionMacro(<< "Unable to instantiate driver " << gdalDriverShortName << " to write " << m_FileName); } - GDALCreationOptionsType creationOptions = m_CreationOptions; - // If not initialized in m_CreationOptions, force JPEG quality to 95 - if( gdalDriverShortName.compare("JPEG") == 0 ) + GDALCreationOptionsType creationOptions = m_CreationOptions; + if( gdalDriverShortName == "JPEG" && !CreationOptionContains( "QUALITY=" ) ) { - size_t i; - for (i = 0; i < creationOptions.size(); ++i) - { - if (boost::algorithm::starts_with(creationOptions[i], "QUALITY=")) - { - // User has set the QUALITY argument - // -> Do not touch it - break; - } - } - if (i == creationOptions.size()) - { - // User did not set the QUALITY argument - // Force it to 95 by default... - creationOptions.push_back("QUALITY=95"); - } + creationOptions.push_back("QUALITY=95"); } GDALDataset* hOutputDS = driver->CreateCopy( realFileName.c_str(), m_Dataset->GetDataSet(), FALSE, @@ -1242,7 +1226,7 @@ void GDALImageIO::InternalWriteImageInformation(const void* buffer) if( m_BytePerPixel == 8 ) { itkWarningMacro(<< "Cast an unsigned long (64 bits) image into an unsigned int (32 bits) one.") - } + } m_PxType->pixType = GDT_UInt32; } else if (this->GetComponentType() == FLOAT) @@ -1274,34 +1258,53 @@ void GDALImageIO::InternalWriteImageInformation(const void* buffer) if (m_CanStreamWrite) { - - // Force tile mode for TIFF format. Tile mode is a lot more - // efficient when writing huge tiffs - if( driverShortName.compare("GTiff") == 0 ) + // Force tile mode for TIFF format if no creation option are given + GDALCreationOptionsType creationOptions = m_CreationOptions; + if( driverShortName == "GTiff" ) { - otbMsgDevMacro(<< "Enabling TIFF Tiled mode") - papszOptions = CSLAddNameValue( papszOptions, "TILED", "YES" ); + if ( CreationOptionContains( "TILED=YES" ) ) + { + // User requested tiled TIFF explicitly + // + // Let GDAL set up the BLOCKXSIZE and BLOCKYSIZE + // or suppose the user have set it also along with TILED=YES + // This allows the user to have complete + // control over the tiling scheme + } + else if ( CreationOptionContains( "BLOCKYSIZE=" ) ) + { + // User did not set "TILED=YES" but set "BLOCKYSIZE=" + // -> He requested a stripped TIFF + } + else + { + // User did not specify "TILED=YES" nor "BLOCKYSIZE=?" + // Switch to TILED mode automatically, and choose BLOCKXSIZE and BLOCKYSIZE for him - // Use a fixed tile size - // Take as reference is a 256*256 short int 4 bands tile - const unsigned int ReferenceTileSizeInBytes = 256 * 256 * 4 * 2; + otbMsgDevMacro(<< "Enabling TIFF Tiled mode") - unsigned int nbPixelPerTile = ReferenceTileSizeInBytes / m_BytePerPixel / m_NbBands; - unsigned int idealTileDimension = static_cast<unsigned int>( vcl_sqrt(static_cast<float>(nbPixelPerTile)) ); + // Use a fixed tile size + // Take as reference is a 256*256 short int 4 bands tile + const unsigned int ReferenceTileSizeInBytes = 256 * 256 * 4 * 2; + const unsigned int NbPixelPerTile = ReferenceTileSizeInBytes / m_BytePerPixel / m_NbBands; + const unsigned int IdealTileDimension = static_cast<unsigned int>( vcl_sqrt(static_cast<float>(NbPixelPerTile)) ); - // Set tileDimension to the nearest power of two and aligned to - // 16 pixels (needed by tiff spec) - unsigned int tileDimension = 16; - while(2*tileDimension < idealTileDimension) - { - tileDimension*=2; - } - otbMsgDevMacro(<< "Tile dimension : " << tileDimension << " * " << tileDimension) + // Set tileDimension to the nearest power of two and aligned to + // 16 pixels (needed by TIFF spec) + unsigned int tileDimension = 16; + while(2*tileDimension < IdealTileDimension) + { + tileDimension*=2; + } + otbMsgDevMacro(<< "Tile dimension : " << tileDimension << " * " << tileDimension) + + std::ostringstream tileDimensionStr; + tileDimensionStr << tileDimension; - std::ostringstream oss; - oss << tileDimension; - papszOptions = CSLAddNameValue( papszOptions, "BLOCKXSIZE", oss.str().c_str() ); - papszOptions = CSLAddNameValue( papszOptions, "BLOCKYSIZE", oss.str().c_str() ); + creationOptions.push_back( "TILED=YES" ); + creationOptions.push_back( std::string("BLOCKXSIZE=") + tileDimensionStr.str() ); + creationOptions.push_back( std::string("BLOCKYSIZE=") + tileDimensionStr.str() ); + } } m_Dataset = GDALDriverManagerWrapper::GetInstance().Create( @@ -1309,12 +1312,12 @@ void GDALImageIO::InternalWriteImageInformation(const void* buffer) GetGdalWriteImageFileName(driverShortName, m_FileName), m_Dimensions[0], m_Dimensions[1], m_NbBands, m_PxType->pixType, - papszOptions); + otb::ogr::StringListConverter(creationOptions).to_ogr()); } else { - // buffer casted in unsigned long cause under Win32 the adress - // don't begin with 0x, the adress in not interpreted as + // buffer casted in unsigned long cause under Win32 the address + // doesn't begin with 0x, the address in not interpreted as // hexadecimal but alpha numeric value, then the conversion to // integer make us pointing to an non allowed memory block => Crash. std::ostringstream stream; @@ -1537,5 +1540,17 @@ bool GDALImageIO::GDALInfoReportCorner(const char * /*corner_name*/, double x, d return IsTrue; } +bool GDALImageIO::CreationOptionContains(std::string partialOption) const +{ + size_t i; + for (i = 0; i < m_CreationOptions.size(); ++i) + { + if (boost::algorithm::starts_with(m_CreationOptions[i], partialOption)) + { + break; + } + } + return (i != m_CreationOptions.size()); +} } // end namespace otb diff --git a/Code/IO/otbGDALImageIO.h b/Code/IO/otbGDALImageIO.h index 49230d7059df5d56ca2b5e8fd4938ad8da20182c..3d54867511100f7213e1b2471ca8afaeedd062de 100644 --- a/Code/IO/otbGDALImageIO.h +++ b/Code/IO/otbGDALImageIO.h @@ -165,6 +165,10 @@ private: std::string FilenameToGdalDriverShortName(const std::string& name) const; + /** Test whether m_CreationOptions has an option + * \param partialOption The beginning of a creation option (for example "QUALITY=") + */ + bool CreationOptionContains(std::string partialOption) const; /** GDAL parameters. */ typedef itk::SmartPointer<GDALDatasetWrapper> GDALDatasetWrapperPointer;