/*
* 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 .
/
/**
* PURPOSE:
*
* rView data exchange interface for storing MDD to the filing system
* or loading from it. Currently supported operations are:
* - Load TIFF file.
* - Save wxPixmap as TIFF to file.
* - Load VFF file (if RVIEW_USE_VFF supported; use conversion module)
*
* COMMENTS:
* None
*/
#ifdef __GNUG__
#pragma implementation
#endif
// changed in wxWindows 2.4.2:
//#include "wx_prec.h"
#include
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include
#endif
#include
#include
#include
#include "wx_pixmap.h"
#ifdef EARLY_TEMPLATE
#define __EXECUTABLE__
#endif
#include "raslib/rmdebug.hh"
#include "raslib/basetype.hh"
#include "raslib/parseparams.hh"
#include "rviewIO.hh"
#include "rviewTypes.hh"
#include "tiffio.h"
#ifdef RVIEW_USE_VFF
/*
* The use of the conversion module might cause problems, therefore VFF is
* optional; if you have problems with it, build rView without VFF support.
*/
#include "conversion/vff.hh"
#endif
r_Parse_Params *rviewIO::dfltParams = NULL;
char *rviewIO::tiffCompStr = NULL;
int rviewIO::tiffCompression = COMPRESSION_DEFLATE;
// Base type structure formats
const char rviewIO::structure_format_mono[] = "marray ";
const char rviewIO::structure_format_grey[] = "marray ";
const char rviewIO::structure_format_rgb[] = "marray ";
const char rviewIO::structure_format_cube8[] = "marray ";
const char rviewIO::structure_format_cube16[] = "marray ";
const char rviewIO::structure_format_cube32[] = "marray ";
// parameters
const char rviewIO::param_KeyTiffComp[] = "comptype";
const char rviewIO::param_TiffCompNone[] = "none";
const char rviewIO::param_TiffCompPack[] = "packbits";
const char rviewIO::param_TiffCompLZW[] = "lzw";
const char rviewIO::param_TiffCompZLib[] = "deflate";
const char rviewIO::param_TiffCompJPEG[] = "jpeg";
rviewIO::rviewIO(void)
{
}
rviewIO::~rviewIO(void)
{
}
void rviewIO::ensureParams(void)
{
if (dfltParams == NULL)
{
tiffCompStr = NULL;
tiffCompression = COMPRESSION_DEFLATE;
dfltParams = new r_Parse_Params;
dfltParams->add(param_KeyTiffComp, &tiffCompStr, r_Parse_Params::param_type_string);
}
}
void rviewIO::processParams(const char *params)
{
ensureParams();
dfltParams->process(params);
tiffCompression = COMPRESSION_DEFLATE;
if (tiffCompStr != NULL)
{
if (strcasecmp(tiffCompStr, param_TiffCompNone) == 0)
tiffCompression = COMPRESSION_NONE;
else if (strcasecmp(tiffCompStr, param_TiffCompPack) == 0)
tiffCompression = COMPRESSION_PACKBITS;
else if (strcasecmp(tiffCompStr, param_TiffCompLZW) == 0)
tiffCompression = COMPRESSION_LZW;
else if (strcasecmp(tiffCompStr, param_TiffCompZLib) == 0)
tiffCompression = COMPRESSION_DEFLATE;
else if (strcasecmp(tiffCompStr, param_TiffCompJPEG) == 0)
tiffCompression = COMPRESSION_JPEG;
}
}
void rviewIO::terminate(void)
{
if (dfltParams != NULL)
{
delete dfltParams;
dfltParams = NULL;
}
if (tiffCompStr != NULL)
{
delete [] tiffCompStr;
tiffCompStr = NULL;
}
}
const char *rviewIO::getExtension(const char *filename)
{
const char *b, *ext;
b = filename; ext = NULL;
while (*b != '\0')
{
if (*b == '.')
ext = b+1;
b++;
}
return ext;
}
int rviewIO::isTIFF(const char *filename)
{
const char *ext = getExtension(filename);
// no extension ==> unrecognized
if (ext != NULL)
{
if ((strcasecmp(ext, "tif") == 0) || (strcasecmp(ext, "tiff") == 0))
return 1;
}
return 0;
}
int rviewIO::loadTIFF(const char *filename, r_Ref &mddObj, const char *params)
{
RMDBGONCE(3, RMDebug::module_applications, "rviewIO", "loadTIFF()");
TIFF* tif;
uint32 width, height, x, y;
uint16 bps, spp, planarc, photom;
int depth, stepx, stepy;
r_Minterval interv(2);
r_Point prun(2);
tdata_t buffer;
unsigned char *b;
char structure[STRINGSIZE]="";
if ((tif = TIFFOpen(filename, "r")) == NULL)
return RVIEW_IO_NOTFOUND;
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bps);
TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &planarc);
TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photom);
if ((width < 1) || (height < 1)) return 0;
RMDBGMIDDLE(3, RMDebug::module_applications, "rviewIO", "loadTIFF() Width " << width << ", height " << height << ", bps " << bps << ", spp " << spp << ", planarconfig " << planarc);
depth = bps * spp;
interv << r_Sinterval(r_Range(0), r_Range(width-1)) << r_Sinterval(r_Range(0), r_Range(height-1));
if ((buffer = _TIFFmalloc(TIFFScanlineSize(tif))) == NULL)
{
TIFFClose(tif); return RVIEW_IO_MEMORY;
}
switch (depth)
{
case 1:
{
r_Ref > mddPtr = new r_Marray(interv);
r_Boolean *imgLine, *imgPtr;
r_Boolean min, max;
char val=0;
int mask;
// Adjust the photometric interpretation. Later on 0 will be interpreted as black.
if (photom == PHOTOMETRIC_MINISWHITE)
{
min = 1; max = 0;
}
else
{
min = 0; max = 1;
}
stepx = &((*mddPtr)[r_Point(1,0)]) - &((*mddPtr)[r_Point(0,0)]);
stepy = &((*mddPtr)[r_Point(0,1)]) - &((*mddPtr)[r_Point(0,0)]);
imgLine = (r_Boolean*)(mddPtr->get_array());
for (y=0; y>= 1;
#else
if (mask == 0x100) {val = *b++; mask = 1;}
*imgPtr = ((val & mask) == 0) ? min : max;
mask <<= 1;
#endif
}
}
mddPtr->set_type_by_name(rviewTypeNames[rbt_bool][2-1]);
// Init base structure (hack, but better than leaving it undefined)
sprintf(structure, structure_format_mono, width-1, height-1);
mddObj = (r_Ref)mddPtr;
}
break;
case 8:
{
int paletteIsGrey = 0;
uint16 *reds, *greens, *blues;
TIFFGetField(tif, TIFFTAG_COLORMAP, &reds, &greens, &blues);
if (photom == PHOTOMETRIC_PALETTE)
{
for (x=0; x<256; x++)
{
if ((reds[x] != greens[x]) || (greens[x] != blues[x])) break;
}
if (x >= 256) paletteIsGrey = 1;
}
if ((photom == PHOTOMETRIC_PALETTE) && (paletteIsGrey == 0))
{
r_Ref > mddPtr = new r_Marray(interv);
RGBPixel *imgLine, *imgPtr;
stepx = &((*mddPtr)[r_Point(1,0)]) - &((*mddPtr)[r_Point(0,0)]);
stepy = &((*mddPtr)[r_Point(0,1)]) - &((*mddPtr)[r_Point(0,0)]);
imgLine = (RGBPixel*)(mddPtr->get_array());
for (y=0; yred = (reds[*b] >> 8);
imgPtr->green = (greens[*b] >> 8);
imgPtr->blue = (blues[*b] >> 8);
}
}
mddPtr->set_type_by_name(rviewTypeNames[rbt_rgb][2-1]);
sprintf(structure, structure_format_rgb, width-1, height-1);
mddObj = (r_Ref)mddPtr;
}
else
{
r_Ref > mddPtr = new r_Marray(interv);
r_Char *imgLine, *imgPtr;
r_Char transTab[256];
if (paletteIsGrey != 0)
{
for (x=0; x<256; x++) transTab[x] = (reds[x] >> 8);
}
else
{
// Build a translation table depending on the photometric interpretation
if (photom == PHOTOMETRIC_MINISWHITE)
{
for (x=0; x<256; x++) transTab[x] = 255-x;
}
else // default to minisblack
{
for (x=0; x<256; x++) transTab[x] = x;
}
}
stepx = &((*mddPtr)[r_Point(1,0)]) - &((*mddPtr)[r_Point(0,0)]);
stepy = &((*mddPtr)[r_Point(0,1)]) - &((*mddPtr)[r_Point(0,0)]);
imgLine = (r_Char*)(mddPtr->get_array());
for (y=0; yset_type_by_name(rviewTypeNames[rbt_char][2-1]);
sprintf(structure, structure_format_grey, width-1, height-1);
mddObj = (r_Ref)mddPtr;
}
}
break;
case 24:
{
r_Ref > mddPtr = new r_Marray(interv);
RGBPixel *imgLine, *imgPtr;
stepx = &((*mddPtr)[r_Point(1,0)]) - &((*mddPtr)[r_Point(0,0)]);
stepy = &((*mddPtr)[r_Point(0,1)]) - &((*mddPtr)[r_Point(0,0)]);
imgLine = (RGBPixel*)(mddPtr->get_array());
//cout << "stepx=" << stepx << ", stepy=" << stepy << endl;
for (y=0; yred = b[0];
imgPtr->green = b[1];
imgPtr->blue = b[2];
}
}
mddPtr->set_type_by_name(rviewTypeNames[rbt_rgb][2-1]);
sprintf(structure, structure_format_rgb, width-1, height-1);
mddObj = (r_Ref)mddPtr;
}
break;
default: return RVIEW_IO_FORMAT;
}
if (structure[0] != 0)
mddObj->set_type_structure(structure);
_TIFFfree(buffer);
TIFFClose(tif);
RMDBGEXIT(3, RMDebug::module_applications, "rviewImage", "~rviewImage() Created MDD object of domain " << mddObj->spatial_domain());
return RVIEW_IO_OK;
}
int rviewIO::saveTIFF(const char *filename, r_Ref &mddPtr, const char *params)
{
cout << "rviewIO::saveTIFF() not implemented" << endl;
return RVIEW_IO_UNSUPP;
}
/*
* Save a wxPixmap as a TIFF image
*/
int rviewIO::PixmapToTIFF(wxPixmap *pixmap, const char *filename, const char *params)
{
TIFF *tif;
int depth, pitch;
uint32 width, height;
uint8 *srcLine;
uint32 i;
depth = pixmap->getDepth(); pitch = pixmap->getPitch();
width = (uint32)(pixmap->getWidth()); height = (uint32)(pixmap->getHeight());
if ((tif = TIFFOpen(filename, "w")) == NULL)
{
char buffer[STRINGSIZE];
sprintf(buffer, "%s %s.\n", lman->lookup("errorFileOpen"), filename);
rviewErrorbox eb(buffer); eb.activate();
return -1;
}
processParams(params);
TIFFSetField(tif, TIFFTAG_ARTIST, "rView");
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
TIFFSetField(tif, TIFFTAG_COMPRESSION, tiffCompression);
TIFFSetField(tif, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
TIFFSetField(tif, TIFFTAG_XRESOLUTION, 90.0);
TIFFSetField(tif, TIFFTAG_YRESOLUTION, 90.0);
srcLine = (uint8*)(pixmap->getData());
switch (depth)
{
case 1:
{
wxColour *pal;
pal = pixmap->getPalette();
if (pal == NULL)
{
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
}
else
{
if ((int)(pal[0].Red()+pal[0].Green()+pal[0].Blue()) < (int)(pal[1].Red()+pal[1].Green()+pal[1].Blue()))
{
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
}
else
{
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
}
}
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 1);
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
for (i=0; igetPalette();
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
if (pal == NULL)
{
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
}
else
{
uint16 reds[256], greens[256], blues[256];
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
for (i=0; i<256; i++)
{
reds[i] = ((pal[i].Red() << 16) - 1) / 255;
greens[i] = ((pal[i].Green() << 16) - 1) / 255;
blues[i] = ((pal[i].Blue() << 16) -1) / 255;
}
TIFFSetField(tif, TIFFTAG_COLORMAP, reds, greens, blues);
}
for (i=0; i> 2;
destPtr[2] = (*srcPtr & 0x7c00) >> 7;
}
if (TIFFWriteScanline(tif, (tdata_t)destLine, i, 0) < 0) break;
}
delete [] destLine;
}
break;
case 24:
{
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
for (i=0; i> 8) & 0xff;
destPtr[2] = (*srcPtr >> 16) & 0xff;
}
if (TIFFWriteScanline(tif, (tdata_t)destLine, i, 0) < 0) break;
}
delete [] destLine;
}
break;
default:
cerr << "rviewIO::PixmapToTIFF(): Unsupported pixmap depth (" << depth << ')' << endl;
TIFFClose(tif);
break;
}
TIFFClose(tif);
if (i < height)
{
char buffer[STRINGSIZE];
sprintf(buffer, "%s %s.\n", lman->lookup("errorFileWrite"), filename);
rviewErrorbox eb(buffer); eb.activate();
return -1;
}
return 0;
}
int rviewIO::isVFF(const char *filename)
{
const char *ext = getExtension(filename);
if (ext != NULL)
{
if (strcasecmp(ext, "vff") == 0)
return 1;
}
return 0;
}
int rviewIO::loadVFF(const char *filename, r_Ref &mddPtr, const char *params)
{
#ifdef RVIEW_USE_VFF
FILE *fp;
if ((fp = fopen(filename, "rb")) != NULL)
{
unsigned long vffSize;
char *vffData;
fseek(fp, 0, SEEK_END);
vffSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
vffData = new char[vffSize];
fread(vffData, 1, vffSize, fp);
fclose(fp);
r_Minterval dom(1);
dom << r_Sinterval((r_Range)0, (r_Range)vffSize-1);
r_Conv_VFF vff(vffData, dom, r_Convertor::ctype_char);
r_Storage_Man_CPP sman;
vff.set_storage_handler(sman);
try
{
r_convDesc desc = vff.convertFrom(params);
delete [] vffData;
if (desc.destInterv.dimension() == 3)
{
const char *fmtString = NULL;
const char *nameString = NULL;
// Hmm... we seem to lack a set_type_schema() method...
switch (desc.destType->type_id())
{
case r_Type::BOOL:
case r_Type::CHAR:
case r_Type::OCTET:
fmtString = structure_format_cube8;
nameString = rviewTypeNames[rbt_char][2];
break;
case r_Type::SHORT:
case r_Type::USHORT:
fmtString = structure_format_cube16;
nameString = rviewTypeNames[rbt_ushort][2];
break;
case r_Type::LONG:
case r_Type::ULONG:
fmtString = structure_format_cube32;
nameString = rviewTypeNames[rbt_ulong][2];
break;
default:
break;
}
if (fmtString != NULL)
{
char fmtBuffer[STRINGSIZE];
sprintf(fmtBuffer, fmtString, desc.destInterv[0].low(), desc.destInterv[0].high(), desc.destInterv[1].low(), desc.destInterv[1].high(), desc.destInterv[2].low(), desc.destInterv[2].high());
mddPtr = new r_GMarray;
mddPtr->set_spatial_domain(desc.destInterv);
mddPtr->set_array(desc.dest);
mddPtr->set_type_structure(fmtBuffer);
mddPtr->set_type_by_name(nameString);
mddPtr->set_type_length(((const r_Base_Type*)desc.destType)->size());
mddPtr->set_current_format(r_Array);
mddPtr->set_array_size(mddPtr->spatial_domain().cell_count() * mddPtr->get_type_length());
//cout << "LOADED VFF " << mddPtr->spatial_domain() << ", " << mddPtr->get_type_structure() << ", " << mddPtr->get_type_name() << endl;
delete desc.destType;
return RVIEW_IO_OK;
}
}
delete desc.destType;
delete [] desc.dest;
return RVIEW_IO_FORMAT;
}
catch (r_Error &err)
{
cerr << "rviewIO::loadVFF(): " << err.what() << endl;
delete [] vffData;
return RVIEW_IO_FORMAT;
}
}
return RVIEW_IO_NOTFOUND;
#else
return RVIEW_IO_UNSUPP;
#endif
}
int rviewIO::saveVFF(const char *filename, r_Ref &mddPtr, const char *params)
{
cout << "rviewIO::saveVFF() not implemented" << endl;
return RVIEW_IO_UNSUPP;
}