/*
* This file is part of rasdaman community.
*
* Rasdaman community is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Rasdaman community is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with rasdaman community. If not, see .
*
* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
rasdaman GmbH.
*
* For more information please see
* or contact Peter Baumann via .
*/
#include "raslib/rminit.hh"
#include "raslib/rmdebug.hh"
#include "raslib/parseparams.hh"
#include "raslib/mitera.hh"
#include "raslib/minterval.hh"
#include "raslib/primitivetype.hh"
#include "ecw.hh"
#include "convertor.hh"
#include "convfactory.hh"
#ifdef ECW
#include "ecwmemfs.hh"
#include "NCSECWClient.h"
#include "NCSErrors.h"
NCSError memOpen(char *szFileName, void **ppClientData)
{
RMDBGENTER(5, RMDebug::module_conversion, "ECWMem", "memOpen(" << szFileName << ", fd)");
MemoryFileSystem* myMem = new MemoryFileSystem();
*ppClientData = (void*)myMem;
MemoryFileSystem::m_Error err = MemoryFileSystem::No_Error;
err = myMem->open(szFileName);
RMDBGEXIT(5, RMDebug::module_conversion, "ECWMem", "memOpen(" << szFileName << ", fd) " << err);
if (err == MemoryFileSystem::No_Error)
return NCS_SUCCESS;
else
return NCS_FILE_OPEN_FAILED;
}
NCSError memClose(void *pClientData)
{
RMDBGENTER(5, RMDebug::module_conversion, "ECWMem", "memClose(fd)");
MemoryFileSystem::m_Error err = MemoryFileSystem::No_Error;
err = ((MemoryFileSystem*)pClientData)->close();
if (err == MemoryFileSystem::No_Error)
{
delete pClientData;
RMDBGEXIT(5, RMDebug::module_conversion, "ECWMem", "memClose(fd) OK");
return NCS_SUCCESS;
}
else {
RMDBGEXIT(5, RMDebug::module_conversion, "ECWMem", "memClose(fd) Already closed");
return NCS_FILE_CLOSE_ERROR;
}
}
NCSError memRead(void *pClientData, void *pBuffer, UINT32 nLength)
{
RMDBGENTER(5, RMDebug::module_conversion, "ECWMem", "memRead(fd, buffer, " << nLength << ")");
MemoryFileSystem::m_Error err = ((MemoryFileSystem*)pClientData)->read(pBuffer, nLength);
if (err == MemoryFileSystem::No_Error)
{
RMDBGEXIT(5, RMDebug::module_conversion, "ECWMem", "memRead(fd, buffer, " << nLength << ") OK");
return NCS_SUCCESS;
}
else {
RMDBGEXIT(5, RMDebug::module_conversion, "ECWMem", "memRead(fd, buffer, " << nLength << ") ERROR");
return NCS_FILE_SEEK_ERROR;
}
}
NCSError memSeek(void *pClientData, UINT64 nOffset)
{
RMDBGENTER(5, RMDebug::module_conversion, "ECWMem", "memSeek(fd, " << nOffset << ")");
MemoryFileSystem::m_Error err = ((MemoryFileSystem*)pClientData)->seek(nOffset);
if (err == MemoryFileSystem::No_Error)
{
RMDBGEXIT(5, RMDebug::module_conversion, "ECWMem", "memSeek(fd, " << nOffset << ") OK");
return NCS_SUCCESS;
}
else {
RMDBGEXIT(5, RMDebug::module_conversion, "ECWMem", "memSeek(fd, " << nOffset << ") ERROR");
return NCS_FILE_SEEK_ERROR;
}
}
NCSError memTell(void *pClientData, UINT64 *pOffset)
{
RMDBGENTER(5, RMDebug::module_conversion, "ECWMem", "memTell(fd, " << *pOffset << ")");
*pOffset = ((MemoryFileSystem*)pClientData)->tell();
RMDBGEXIT(5, RMDebug::module_conversion, "ECWMem", "memTell(fd, " << *pOffset << ")");
return NCS_SUCCESS;
}
#endif
void
r_Conv_ECW::initECW()
{
RMDBGONCE(5, RMDebug::module_conversion, "r_Conv_ECW", "initECW()");
if(params ==NULL)
{
params = new r_Parse_Params(2);
}
}
r_Conv_ECW::r_Conv_ECW(const char* source, const r_Minterval& lengthordomain, const r_Type* tp) throw(r_Error)
: r_Convertor(source, lengthordomain, tp, true)
{
RMDBGONCE(5, RMDebug::module_conversion, "r_Conv_ECW", "r_Conv_ECW(source, " << lengthordomain << ", " << tp->name() << ")");
initECW();
}
r_Conv_ECW::r_Conv_ECW(const char* source, const r_Minterval& lengthordomain, int tp) throw(r_Error)
: r_Convertor(source, lengthordomain, tp)
{
RMDBGONCE(5, RMDebug::module_conversion, "r_Conv_ECW", "r_Conv_ECW(source, " << lengthordomain << ", " << tp << ")");
initECW();
}
r_convDesc&
r_Conv_ECW::convertFrom(const char* options) throw (r_Error)
{
#ifdef ECW
RMDBGENTER(5, RMDebug::module_conversion, "r_Conv_ECW", "convertFrom(" << ((options)? options : "NULL") << ")");
int windowx = 1000;
int windowy = 1000;
params->add("windowx", &windowx, r_Parse_Params::param_type_int);
params->add("windowy", &windowy, r_Parse_Params::param_type_int);
params->process(options);
RMDBGMIDDLE(5, RMDebug::module_conversion, "r_Conv_ECW", "window x " << windowx);
RMDBGMIDDLE(5, RMDebug::module_conversion, "r_Conv_ECW", "window y " << windowy);
switch (desc.baseType)
{
case ctype_bool:
case ctype_char:
case ctype_uint8:
break;
case ctype_rgb:
break;
default:
RMInit::logOut << "r_Conv_ECW unknown base type!" << std::endl;
throw r_Error(COMPRESSIONFAILED);
}
NCSFileView *pNCSFileView = NULL;
NCSFileViewFileInfo *pNCSFileInfo = NULL;
NCSError eError = NCS_SUCCESS;
eError = NCSecwSetIOCallbacks(memOpen, memClose, memRead, memSeek, memTell);
if (eError != NCS_SUCCESS)
{
RMInit::logOut << "Error = " << NCSGetErrorText(eError) << std::endl;
throw r_Error(COMPRESSIONFAILED);
}
UINT8 **p_p_output_line = NULL;
UINT8 *p_output_buffer = NULL;
UINT32 x_size = 0;
UINT32 y_size = 0;
UINT32 number_x = 0;
UINT32 number_y = 0;
UINT32 start_x = 0;
UINT32 start_y = 0;
UINT32 end_x = 0;
UINT32 end_y = 0;
UINT32 band = 0;
UINT32 nBands = 0;
MemoryFileSystem::memorySrc = desc.src;
MemoryFileSystem::memorySrcLength = desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1;
eError = NCScbmOpenFileView((char*)MemoryFileSystem::memorySrcName, &pNCSFileView, NULL);
if (eError != NCS_SUCCESS)
{
RMInit::logOut << "Error = " << NCSGetErrorText(eError) << std::endl;
throw r_Error(COMPRESSIONFAILED);
}
NCScbmGetViewFileInfo(pNCSFileView, &pNCSFileInfo);
x_size = pNCSFileInfo->nSizeX;
y_size = pNCSFileInfo->nSizeY;
nBands = pNCSFileInfo->nBands;
RMDBGMIDDLE(5, RMDebug::module_conversion, "r_Conv_ECW", "image : " << x_size << " x " << y_size << ", " << nBands << " bands");
/* Have to set up the band list. Compatible with ER Mapper's method.*/
/* In this example we always request all bands.*/
UINT32* band_list = new UINT32[nBands];
for( band = 0; band < nBands; band++ )
band_list[band] = band;
size_t typeLength = nBands;
switch (desc.baseType)
{
case ctype_bool:
case ctype_char:
case ctype_uint8:
if (nBands != 1)
{
RMInit::logOut << "r_Conv_ECW conversion of base types bot supported" << std::endl;
throw r_Error(COMPRESSIONFAILED);
}
break;
case ctype_rgb:
if (nBands != 3)
{
RMInit::logOut << "r_Conv_ECW conversion of base types bot supported" << std::endl;
throw r_Error(COMPRESSIONFAILED);
}
break;
default:
RMInit::logOut << "r_Conv_ECW there is a really bad error in your compiler" << std::endl;
throw r_Error(10000);
break;
}
start_x = 0;
start_y = 0;
end_x = x_size - 1;
end_y = y_size - 1;
number_x = x_size;
number_y = y_size;
windowx = number_x;
windowy = number_y;
r_Minterval imageDomain(2);
imageDomain << r_Sinterval((r_Range)0, (r_Range)number_x - 1);
imageDomain << r_Sinterval((r_Range)0, (r_Range)number_y - 1);
RMDBGMIDDLE(5, RMDebug::module_conversion, "r_Conv_ECW", "image domain " << imageDomain << ", type length " << typeLength << " bands");
char* image = (char*)mystore.storage_alloc(number_x * number_y * typeLength);
//char* image = new char[number_x * number_y * typeLength];
memset(image, 0, number_x * number_y * typeLength);
r_Minterval maxDom(2);
maxDom << r_Sinterval((r_Range)0, (r_Range)1000 - 1);
maxDom << r_Sinterval((r_Range)0, (r_Range)1000 - 1);
r_MiterArea dom_iter(&maxDom, &imageDomain);
r_Minterval iterArea(2);
while (!dom_iter.isDone())
{
iterArea = dom_iter.nextArea();
start_x = iterArea[0].low();
start_y = iterArea[1].low();
end_x = iterArea[0].high();
end_y = iterArea[1].high();
number_x = iterArea[0].get_extent();
number_y = iterArea[1].get_extent();
RMDBGMIDDLE(5, RMDebug::module_conversion, "r_Conv_ECW", "current " << start_x << ":" << end_x << "," << start_y << ":" << end_y << " window " << number_x << " x " << number_y);
eError = NCScbmSetFileView(pNCSFileView, nBands, band_list, start_x, start_y, end_x, end_y, number_x, number_y);
if( eError != NCS_SUCCESS)
{
RMInit::logOut << "Error while setting file view to " << nBands << " bands, [" << start_x << ":" << end_x << "," << start_y << ":" << end_y << "], window size " << number_x << " x " << number_y << " pixel" << std::endl;
RMInit::logOut << "Error = " << NCSGetErrorText(eError) << std::endl;
NCScbmCloseFileViewEx(pNCSFileView, TRUE);
delete [] band_list;
mystore.storage_free(image);
throw r_Error(COMPRESSIONFAILED);
}
p_output_buffer = new UINT8[number_x * nBands];
p_p_output_line = new UINT8*[nBands];
for(band = 0; band < nBands; band++ )
p_p_output_line[band] = p_output_buffer + (band * number_x);
/*
** Read each line of the compressed file
*/
for( UINT32 line = 0; line < number_y; line++ )
{
NCSEcwReadStatus eReadStatus = NCScbmReadViewLineBIL( pNCSFileView, p_p_output_line);
if (eReadStatus != NCSECW_READ_OK)
{
RMInit::logOut << "Read line error at line " << line << std::endl;
RMInit::logOut << "Status code " << eReadStatus << std::endl;
NCScbmCloseFileViewEx(pNCSFileView, TRUE);
delete [] band_list;
delete [] p_p_output_line;
delete [] p_output_buffer;
mystore.storage_free(image);
throw r_Error(COMPRESSIONFAILED);
}
for (int b = 0; b < nBands; b++)
{
for (int l = 0; l < number_x; l++)
{
image[(l + iterArea[0].low()) * windowy * typeLength + (line + iterArea[1].low()) * typeLength + b] = p_p_output_line[b][l];
}
}
}
delete [] p_p_output_line;
delete [] p_output_buffer;
RMDBGMIDDLE(5, RMDebug::module_conversion, "r_Conv_ECW", "read done");
}
NCScbmCloseFileViewEx(pNCSFileView, TRUE);
delete [] band_list;
desc.dest = (char*)image;
desc.destInterv = imageDomain;
desc.destType = get_external_type(desc.baseType);
return desc;
#else
RMDBGENTER(5, RMDebug::module_conversion, "r_Conv_ECW", "convertFrom(" << options << ") NOT COMPILED");
RMInit::logOut << "r_Conv_ECW::convertFrom(" << options << ") ecw support not compiled in" << std::endl;
throw r_Error(COMPRESSIONFAILED);
#endif
}
r_convDesc&
r_Conv_ECW::convertTo(const char* options) throw (r_Error)
{
RMInit::logOut << "r_Conv_ECW::convertTo(" << options << ") compression not supported" << std::endl;
throw r_Error(COMPRESSIONFAILED);
}
const char*
r_Conv_ECW::get_name() const
{
return get_name_from_data_format(r_ECW);
}
r_Data_Format
r_Conv_ECW::get_data_format() const
{
return r_ECW;
}
r_Convertor*
r_Conv_ECW::clone() const
{
return new r_Conv_ECW(desc.src, desc.srcInterv, desc.srcType);
}