diff options
| author | Constantin Jucovschi <cj@ubuntu.localdomain> | 2009-04-24 07:20:22 -0400 |
|---|---|---|
| committer | Constantin Jucovschi <cj@ubuntu.localdomain> | 2009-04-24 07:20:22 -0400 |
| commit | 8f27e65bddd7d4b8515ce620fb485fdd78fcdf89 (patch) | |
| tree | bd328a4dd4f92d32202241b5e3a7f36177792c5f /conversion | |
| download | rasdaman-upstream-8.0.tar.gz rasdaman-upstream-8.0.tar.xz rasdaman-upstream-8.0.zip | |
Initial commitv8.0
Diffstat (limited to 'conversion')
56 files changed, 14905 insertions, 0 deletions
diff --git a/conversion/Makefile.am b/conversion/Makefile.am new file mode 100644 index 0000000..8da362d --- /dev/null +++ b/conversion/Makefile.am @@ -0,0 +1,37 @@ +# -*-Makefile-*- (for Emacs) +# +# 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 <http://www.gnu.org/licenses/>. +# +# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +# rasdaman GmbH. +# +# For more information please see <http://www.rasdaman.org> +# or contact Peter Baumann via <baumann@rasdaman.com>. +# +# MAKEFILE FOR: +# module conversion +# +# +# COMMENTS: +# +################################################################## + +noinst_LIBRARIES=libconversion.a +libconversion_a_SOURCES= convertor.cc convfactory.cc tiff.cc hdf.cc png.cc jpeg.cc \ + csv.cc bmp.cc vff.cc tor.cc dem.cc ecw.cc memfs.cc \ + convertor.hh convfactory.hh tiff.hh hdf.hh png.hh jpeg.hh \ + csv.hh bmp.hh vff.hh tor.hh dem.hh ecw.hh memfs.hh \ + ntf.hh diff --git a/conversion/bmp.cc b/conversion/bmp.cc new file mode 100644 index 0000000..9995943 --- /dev/null +++ b/conversion/bmp.cc @@ -0,0 +1,990 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * SOURCE: bmp.cc + * + * MODULE: conversion + * + * CLASSES: r_Conv_BMP + * + * COMMENTS: + * Provides functions to convert data to BMP and back. + * +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <iostream> +#include <string.h> +#include <new> + +#include "raslib/rminit.hh" +#include "raslib/rmdebug.hh" +#include "raslib/parseparams.hh" +#include "conversion/bmp.hh" +#include "conversion/memfs.hh" + + +// Some Windows-structs, redefined for platform-independent use. +typedef struct { + unsigned short type; + r_ULong size; + unsigned short res0; + unsigned short res1; + r_ULong offset; +} bitmap_file_header_t; + +typedef struct { + r_ULong size; + r_Long width; + r_Long height; + unsigned short planes; + unsigned short bitCount; + r_ULong compression; + r_ULong sizeImage; + r_Long xpels; + r_Long ypels; + r_ULong clrUsed; + r_ULong clrImportant; +} bitmap_info_header_t; + +typedef struct { + unsigned char blue; + unsigned char green; + unsigned char red; + unsigned char null; +} rgb_quad_t; + +// Identifier of BMP data (first two bytes) +const unsigned short BMP_IDENTIFIER=0x4d42; +// Compression types (correspond to BI_RGB, BI_RLE8, BI_RLE4) +const int COMPRESS_NONE=0; +const int COMPRESS_RLE8=1; +const int COMPRESS_RLE4=2; +// Size of BITMAPFILEHEADER (the Windows struct) +const int BMPFILEHEADERSIZE=sizeof(bitmap_file_header_t) - sizeof(BMP_IDENTIFIER); +// Size of BITMAPINFOHEADER (the Windows struct) +const int BMPINFOHEADERSIZE=sizeof(bitmap_info_header_t); +// Total header size +const int BMPHEADERSIZE=(BMPFILEHEADERSIZE + BMPINFOHEADERSIZE); + +// Shortcuts for reading and writing short and long types from/to little endian bytestreams +#define READ_LE_SHORT(p,s) \ + s = p[0] | (p[1] << 8); p += 2; +#define READ_LE_LONG(p,l) \ + l = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); p += 4; +#define WRITE_LE_SHORT(p,s) \ + p[0] = s & 0xff; p[1] = (s >> 8) & 0xff; p += 2; +#define WRITE_LE_LONG(p,l) \ + p[0] = l & 0xff; p[1] = (l >> 8) & 0xff; p[2] = (l >> 16) & 0xff; p[3] = (l >> 24) & 0xff; p += 4; + + + +void r_Conv_BMP::initBMP( void ) +{ + memFS = NULL; + + compress = 1; + + if (params == NULL) + params = new r_Parse_Params; + + params->add("compress", &compress, r_Parse_Params::param_type_int); +} + + +r_Conv_BMP::r_Conv_BMP(const char *src, const r_Minterval &interv, int tp) throw(r_Error) +: r_Convertor(src, interv, tp) +{ + initBMP(); +} + + +r_Conv_BMP::r_Conv_BMP(const char *src, const r_Minterval &interv, const r_Type *tp) throw(r_Error) +: r_Convertor(src, interv, tp) +{ + initBMP(); +} + + +r_Conv_BMP::~r_Conv_BMP(void) +{ + if (memFS != NULL) + { + memfs_killfs((void*)memFS); + delete memFS; + memFS=NULL; + } +} + + +unsigned char *r_Conv_BMP::flushLiterals(int numLit, int pixelAdd, unsigned char *dest, const unsigned char *lastLit, const unsigned char *mapColours) +{ + unsigned char *destPtr = dest; + + while (numLit != 0) + { + // Must code literal runs of less than 3 bytes as runs + if (numLit < 3) + { + while (numLit > 0) + { + *destPtr++ = 1; *destPtr++ = mapColours[*lastLit]; + lastLit += pixelAdd; numLit--; + } + } + else + { + int litLength=0; + r_Ptr align=0; + + litLength = numLit; if (litLength > 255) litLength = 255; + *destPtr++ = 0x00; *destPtr++ = (unsigned char)litLength; + numLit -= litLength; + while (litLength > 0) + { + *destPtr++ = mapColours[*lastLit]; lastLit += pixelAdd; litLength--; + } + align = (r_Ptr)destPtr; if ((align & 1) != 0) *destPtr++ = 0; + } + } + return destPtr; +} + + +r_convDesc &r_Conv_BMP::convertTo( const char *options) throw(r_Error) +{ + void *handle=NULL; + bitmap_info_header_t ihead; + rgb_quad_t *palette = NULL; + int i=0, j=0; + int paletteSize=0, pixelSize=0; + int destPitch=0, pixelAdd=0, lineAdd=0; + int width=0, height=0; + r_ULong offset=0; + r_ULong fileSize=0; + unsigned char *dest=NULL, *destPtr=NULL; + const unsigned char *srcLine=NULL, *srcPtr=NULL; + unsigned char bmpHeaders[BMPHEADERSIZE]; + unsigned char mapColours[256]; + + memFS = new memFSContext; handle = (void*)memFS; + if ((memFS == NULL) || (memfs_initfs(handle) < 0)) + { + RMInit::logOut << "r_Conv_BMP::convertTo(): couldn't initialize memfs!" << endl; + throw r_Error(MEMMORYALLOCATIONERROR); + } + memfs_newfile(handle); + + width = (int)(desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1); + height = (int)(desc.srcInterv[1].high() - desc.srcInterv[1].low() + 1); + + params->process(options); + + ihead.size = BMPINFOHEADERSIZE; + ihead.width = (r_Long)width; + ihead.height = (r_Long)height; + ihead.planes = 1; + ihead.compression = COMPRESS_NONE; + ihead.xpels = 0; ihead.ypels = 0; + + switch (desc.baseType) + { + case ctype_bool: + ihead.bitCount = 1; destPitch = ((width + 31) & ~31) >> 3; paletteSize = 2; pixelSize = 1; + ihead.clrUsed = 2; ihead.clrImportant = 2; + palette = new rgb_quad_t[2]; + palette[0].red = 0x00; palette[0].green = 0x00; palette[0].blue = 0x00; palette[0].null = 0x00; + palette[1].red = 0xff; palette[1].green = 0xff; palette[1].blue = 0xff; palette[1].null = 0x00; + break; + case ctype_char: + { + ihead.bitCount = 8; destPitch = ((width + 3) & ~3); pixelSize = 1; + if (compress != 0) ihead.compression = COMPRESS_RLE8; + // Determine which colours actually appear in the image + memset(mapColours, 0, 256); + srcLine = (const unsigned char*)desc.src; + for (i=0; i<width*height; i++) mapColours[*srcLine++] = 1; + // Count distinct colours + paletteSize = 0; + for (i=0; i<256; i++) if (mapColours[i] != 0) paletteSize++; + // Create palette + RMDBGONCE(3, RMDebug::module_conversion, "r_Conv_BMP", "convertTo(): number of distinct colours: " << paletteSize ) + palette = new rgb_quad_t[paletteSize]; + paletteSize = 0; + for (i=0; i<256; i++) + { + if (mapColours[i] != 0) + { + palette[paletteSize].red = (unsigned char)i; + palette[paletteSize].green = (unsigned char)i; + palette[paletteSize].blue = (unsigned char)i; + palette[paletteSize].null = 0; + paletteSize++; + } + } + // ``compress'' colourmap + paletteSize = 0; + for (i=0; i<256; i++) + { + if (mapColours[i] != 0) mapColours[i] = paletteSize++; + } + ihead.clrUsed = paletteSize; ihead.clrImportant = 0; // for simplicity's sake + break; + } + case ctype_rgb: + ihead.bitCount = 24; destPitch = ((width * 3 + 3) & ~3); paletteSize = 0; pixelSize = 3; + ihead.clrUsed = 0; ihead.clrImportant = 0; + break; + default: + RMInit::logOut << "r_Conv_BMP::convertTo(): Unknown base type!" << endl; + throw r_Error(r_Error::r_Error_General); + } + lineAdd = pixelSize; pixelAdd = height * pixelSize; + + // Write dummy header, to be replaced later + memset(bmpHeaders, 0, BMPHEADERSIZE); + memfs_write(handle, bmpHeaders, BMPHEADERSIZE); + if (paletteSize != 0) + { + memfs_write(handle, palette, paletteSize * sizeof(rgb_quad_t)); + delete [] palette; palette = NULL; + } + + srcLine = (const unsigned char*)(desc.src + (height-1) * pixelSize); + + if (ihead.compression == COMPRESS_NONE) + { + if ((dest = new unsigned char[destPitch]) == NULL) + { + RMInit::logOut << "r_Conv_BMP::convertTo(): out of memory!" << endl; + throw r_Error(MEMMORYALLOCATIONERROR); + } + for (j=0; j<height; j++, srcLine -= lineAdd) + { + srcPtr = srcLine; destPtr = dest; + switch (desc.baseType) + { + case ctype_bool: + { + int mask=0; + unsigned char val=0; + + mask = 0x80; val = 0; + for (i=0; i<width; i++, srcPtr += pixelAdd) + { + if (*srcPtr != 0) val |= mask; + mask >>= 1; + if (mask == 0) + { + *destPtr++ = val; mask = 0x80; val = 0; + } + } + if (mask != 0x80) *destPtr++ = val; + } + break; + case ctype_char: + for (i=0; i<width; i++, srcPtr += pixelAdd) + { + *destPtr++ = mapColours[*srcPtr]; + } + break; + case ctype_rgb: + for (i=0; i<width; i++, srcPtr += pixelAdd) + { + *destPtr++ = srcPtr[2]; *destPtr++ = srcPtr[1]; *destPtr++ = srcPtr[0]; + } + break; + } + // Align to 32bit-boundary + for (i = (4 - (r_Ptr)destPtr) & 3; i>0; i--) *destPtr++ = 0; + memfs_write(handle, dest, destPitch); + } + delete [] dest; dest = NULL; + } + else // implies RLE 8 + { + if ((dest = new unsigned char[2*destPitch]) == NULL) + { + RMInit::logOut << "r_Conv_BMP::convertTo(): out of memory!" << endl; + throw r_Error(MEMMORYALLOCATIONERROR); + } + + for (j=0; j<height; j++, srcLine -= lineAdd) + { + const unsigned char *lastLit=NULL, *tryRun=NULL; + int k=0, numLit=0; + + srcPtr = srcLine; destPtr = dest; + lastLit = srcPtr; i = 0; numLit = 0; + while (i < width) + { + k = i; + tryRun = srcPtr; + while (k < width-1) + { + if (*tryRun != *(tryRun + pixelAdd)) break; + tryRun += pixelAdd; k++; + } + // If k < width-1 tryRun points to the first symbol not int the run, + // otherwise it points to the last one in the run + if (k == width-1) k = width - i; else k -= i; + // Run found ==> encode literals + run + // If a literal sequence has to be broken for the run we require a longer run. + // For the sequence <lit><run><lit> a run shorter than 5 bytes is best merged into lit. + // For the sequence <lit><run1><run2> the first run should be merged with lit if it's + // less than 3 bytes long. Therefore on average 4 bytes minimum runs are best. + if (((numLit == 0) && (k > 1)) || (k > 3)) + { + // First output the pending literals, if any + destPtr = flushLiterals(numLit, pixelAdd, destPtr, lastLit, mapColours); + numLit = 0; + i += k; + // Now output the run + while (k > 0) + { + int runLength=0; + + runLength = k; if (runLength > 255) runLength = 255; + *destPtr++ = runLength; *destPtr++ = mapColours[*srcPtr]; + k -= runLength; + } + srcPtr = tryRun; lastLit = srcPtr; + } + else + { + numLit++; srcPtr += pixelAdd; i++; + } + } + // Flush remaining literals + destPtr = flushLiterals(numLit, pixelAdd, destPtr, lastLit, mapColours); + // EOL + *destPtr++ = 0; *destPtr++ = 0; + memfs_write(handle, dest, (destPtr - dest)); + } + // EOB + dest[0] = 0; dest[1] = 1; + memfs_write(handle, dest, 2); + + delete [] dest; dest = NULL; + } + + fileSize = memfs_size(handle); + RMDBGONCE( 3, RMDebug::module_conversion, "r_Conv_BMP", "convertTo(): size: " << fileSize ); + offset = BMPHEADERSIZE + paletteSize * sizeof(rgb_quad_t); + dest = bmpHeaders; + ihead.sizeImage = fileSize - offset; + + WRITE_LE_SHORT(dest, BMP_IDENTIFIER); + WRITE_LE_LONG(dest, fileSize); + WRITE_LE_SHORT(dest, 0); + WRITE_LE_SHORT(dest, 0); + WRITE_LE_LONG(dest, offset); + + WRITE_LE_LONG(dest, ihead.size); + WRITE_LE_LONG(dest, ihead.width); + WRITE_LE_LONG(dest, ihead.height); + WRITE_LE_SHORT(dest, ihead.planes); + WRITE_LE_SHORT(dest, ihead.bitCount); + WRITE_LE_LONG(dest, ihead.compression); + WRITE_LE_LONG(dest, ihead.sizeImage); + WRITE_LE_LONG(dest, ihead.xpels); + WRITE_LE_LONG(dest, ihead.ypels); + WRITE_LE_LONG(dest, ihead.clrUsed); + WRITE_LE_LONG(dest, ihead.clrImportant); + + memfs_seek(handle, 0, SEEK_SET); + memfs_write(handle, bmpHeaders, BMPHEADERSIZE); + + if ((desc.dest = (char*)mystore.storage_alloc(fileSize)) == NULL) + { + RMInit::logOut << "r_Conv_BMP::convertTo(): out of memory!" << endl; + throw r_Error(MEMMORYALLOCATIONERROR); + } + memfs_seek(handle, 0, SEEK_SET); + memfs_read(handle, desc.dest, fileSize); + + memfs_killfs(handle); + delete memFS; memFS = NULL; + + desc.destInterv = r_Minterval(1); + desc.destInterv << r_Sinterval((r_Range)0, (r_Range)fileSize-1); + + desc.destType = r_Type::get_any_type("char"); + + return desc; +} + + +// Auxiliary makro for RLE coders +#define BMP_RLE_LINEFEED \ + destLine -= lineAdd; destPtr = destLine; j++; i = 0; + +r_convDesc &r_Conv_BMP::convertFrom(const char *options) throw(r_Error) +{ + bitmap_file_header_t fhead; + bitmap_info_header_t ihead; + const rgb_quad_t *palette=NULL; + const unsigned char *bmp=NULL; + int i=0, j=0; + int srcPitch=0; + int pixelSize=0, destType=0; + int paletteIsGrey=0, paletteSize=0; + int width=0, height=0; + unsigned char emit0=0, emit1=0; // in case of bitmap -> bool: values to emit for 0 and 1 + int lineAdd=0, pixelAdd=0; + + bmp = (const unsigned char*)desc.src; + + // Read file header + READ_LE_SHORT(bmp, fhead.type); + READ_LE_LONG(bmp, fhead.size); + READ_LE_SHORT(bmp, fhead.res0); + READ_LE_SHORT(bmp, fhead.res1); + READ_LE_LONG(bmp, fhead.offset); + + if (fhead.type != BMP_IDENTIFIER) + { + RMInit::logOut << "r_Conv_BMP::convertFrom(): not a BMP file" << endl; + throw r_Error(r_Error::r_Error_General); + } + + // Read info header + READ_LE_LONG(bmp, ihead.size); + READ_LE_LONG(bmp, ihead.width); + READ_LE_LONG(bmp, ihead.height); + READ_LE_SHORT(bmp, ihead.planes); + READ_LE_SHORT(bmp, ihead.bitCount); + READ_LE_LONG(bmp, ihead.compression); + READ_LE_LONG(bmp, ihead.sizeImage); + READ_LE_LONG(bmp, ihead.xpels); + READ_LE_LONG(bmp, ihead.ypels); + READ_LE_LONG(bmp, ihead.clrUsed); + READ_LE_LONG(bmp, ihead.clrImportant); + + width = (int)ihead.width; height = (int)ihead.height; + + RMDBGIF(4, RMDebug::module_conversion, "r_Conv_BMP", \ + RMInit::dbgOut << "File: type " << std::hex << fhead.type << ", size " << std::dec << fhead.size; \ + RMInit::dbgOut << ", rsv0 " << fhead.res0 << ", rsv1 " << fhead.res1 << ", offs " << fhead.offset << endl; \ + RMInit::dbgOut << "Info: size " << ihead.size << ", width " << ihead.width << ", height " << ihead.height; \ + RMInit::dbgOut << ", planes " << ihead.planes << ", bits " << ihead.bitCount << ", comp " << ihead.compression; \ + RMInit::dbgOut << ", sizeImg " << ihead.sizeImage << ", xpels " << ihead.xpels << ", ypels " << ihead.ypels; \ + RMInit::dbgOut << ", clrUsed " << ihead.clrUsed << ", clrImp " << ihead.clrImportant << endl; ) + + palette = (const rgb_quad_t*)(desc.src + BMPFILEHEADERSIZE + ihead.size); + paletteIsGrey = 0; + paletteSize = ihead.clrUsed; + if ((paletteSize == 0) && (ihead.bitCount != 24)) paletteSize = (1 << ihead.bitCount); + + switch (ihead.bitCount) + { + case 1: + srcPitch = ((width + 31) & ~31) >> 3; + // Grey? + if ((palette[0].red == palette[0].green) && (palette[0].green == palette[0].blue) && + (palette[1].red == palette[1].green) && (palette[1].green == palette[1].blue)) + { + paletteIsGrey = 1; pixelSize = 1; + // Yes; also black + white? + if (((palette[0].red == 0x00) && (palette[1].red == 0xff)) || + ((palette[0].red == 0xff) && (palette[1].red == 0x00))) + { + // Yes + destType = ctype_bool; + if (palette[0].red == 0) + { + emit0 = 0; emit1 = 1; + } + else + { + emit0 = 1; emit1 = 0; + } + } + else + { + // No + destType = ctype_char; + } + } + else + { + // Convert to RGB + destType = ctype_rgb; pixelSize = 3; + } + break; + case 4: + case 8: + { + if (ihead.bitCount == 4) + { + srcPitch = ((width + 7) & ~7) >> 1; + } + else + { + srcPitch = ((width + 3) & ~3); } + // Check whether the palette is greyscale + for (i=0; i<paletteSize; i++) + { + if ((palette[i].red != palette[i].green) || (palette[i].green != palette[i].blue)) break; + } + if (i < paletteSize) + { + destType = ctype_rgb; pixelSize = 3; + } + else + { + destType = ctype_char; paletteIsGrey = 1; pixelSize = 1; + } + } + break; + case 24: + destType = ctype_rgb; srcPitch = (width * 3 + 3) & ~3; + pixelSize = 3; + break; + default: + { + RMInit::logOut << "r_Conv_BMP::convertFrom(): Bad bitmap depth" << endl; + throw r_Error(r_Error::r_Error_General); + } + } + + RMDBGONCE( 4, RMDebug::module_conversion, "r_Conv_BMP", "convertFrom(): type " << destType << ", srcPitch " << srcPitch << ", pixelSize " << pixelSize << ", palsize " << paletteSize ); + + unsigned char *dest=NULL, *destPtr=NULL, *destLine=NULL; + const unsigned char *imgPtr=NULL, *imgLine=NULL; + + pixelAdd = pixelSize * height; lineAdd = pixelSize; + + imgLine = (const unsigned char *)(palette + paletteSize); + + if ((dest = (unsigned char*)mystore.storage_alloc(width * height * pixelSize)) == NULL) + { + RMInit::logOut << "r_Conv_BMP::convertFrom(): out of memory" << endl; + throw r_Error(MEMMORYALLOCATIONERROR); + } + + if (ihead.compression != COMPRESS_NONE) + { + // This is only defined for 8bpp and 4bpp data. The result can only be 8bpp or 24bpp. + // Init the entire picture to colour #0. Is this correct? Undocumented. + destPtr = dest; i = width * height; + if (paletteIsGrey == 0) + { + while (i > 0) + { + destPtr[0] = palette[0].red; destPtr[1] = palette[0].green; destPtr[2] = palette[0].blue; + destPtr += pixelSize; i--; + } + } + else + { + while (i > 0) + { + destPtr[0] = palette[0].red; + destPtr += pixelSize; i--; + } + } + } + + destLine = dest + ((height - 1) * pixelSize); + + switch (ihead.compression) + { + case COMPRESS_NONE: + for (j=0; j<height; j++, destLine -= lineAdd, imgLine += srcPitch) + { + destPtr = destLine; imgPtr = imgLine; + switch (ihead.bitCount) + { + case 1: + { + int mask=0; + unsigned char val=0; + + mask = 0x00; + switch (destType) + { + case ctype_bool: + for (i=0; i<width; i++, destPtr += pixelAdd) + { + if (mask == 0x00) + { + mask = 0x80; val = *imgPtr++; + } + *destPtr = ((val & mask) == 0) ? emit0 : emit1; + mask >>= 1; + } + break; + case ctype_char: + for (i=0; i<width; i++, destPtr += pixelAdd) + { + if (mask == 0x00) + { + mask = 0x80; val = *imgPtr++; + } + *destPtr = palette[(((val & mask) == 0) ? 0 : 1)].red; + mask >>= 1; + } + break; + case ctype_rgb: + for (i=0; i<width; i++, destPtr += pixelAdd) + { + int idx=0; + + if (mask == 0x00) + { + mask = 0x80; val = *imgPtr++; + } + idx = ((val & mask) == 0) ? 0 : 1; + destPtr[0] = palette[idx].red; + destPtr[1] = palette[idx].green; + destPtr[2] = palette[idx].blue; + mask >>= 1; + } + break; + } + } + break; + case 4: + { + switch (destType) + { + case ctype_char: + for (i=0; i<width; i+=2) + { + *destPtr = palette[(*imgPtr) >> 4].red; + destPtr += pixelAdd; + *destPtr = palette[(*imgPtr & 0x0f)].red; + destPtr += pixelAdd; imgPtr++; + } + if (i < width) + { + *destPtr = palette[(*imgPtr) >> 4].red; + } + break; + case ctype_rgb: + for (i=0; i<width; i+=2) + { + int idx; + + idx = (*imgPtr) >> 4; + destPtr[0] = palette[idx].red; + destPtr[1] = palette[idx].green; + destPtr[2] = palette[idx].blue; + destPtr += pixelAdd; + idx = (*imgPtr) & 0x0f; + destPtr[0] = palette[idx].red; + destPtr[1] = palette[idx].green; + destPtr[2] = palette[idx].blue; + destPtr += pixelAdd; imgPtr++; + } + if (i < width) + { + int idx; + + idx = (*imgPtr) >> 4; + destPtr[0] = palette[idx].red; + destPtr[1] = palette[idx].green; + destPtr[2] = palette[idx].blue; + } + break; + } + } + break; + case 8: + switch (destType) + { + case ctype_char: + for (i=0; i<width; i++, destPtr += pixelAdd) + { + *destPtr = palette[*imgPtr++].red; + } + break; + case ctype_rgb: + for (i=0; i<width; i++, destPtr += pixelAdd) + { + destPtr[0] = palette[*imgPtr].red; + destPtr[1] = palette[*imgPtr].green; + destPtr[2] = palette[*imgPtr].blue; + imgPtr++; + } + break; + } + break; + case 24: + for (i=0; i<width; i++, destPtr += pixelAdd) + { + destPtr[0] = imgPtr[2]; destPtr[1] = imgPtr[1]; destPtr[2] = imgPtr[0]; + imgPtr += 3; + } + break; + } + } + break; + case COMPRESS_RLE8: + { + i = 0; j = 0; destPtr = destLine; imgPtr = imgLine; + while (j >= 0) + { + unsigned char val=0, cmd=0; + + //cout << "(" << i << "," << j << ")" << endl; + cmd = *imgPtr++; + if (cmd == 0) // escape + { + cmd = *imgPtr++; + switch (cmd) + { + case 0: // end of line + //cout << "EOL" << endl; + BMP_RLE_LINEFEED; + break; + case 1: // end of bitmap + //cout << "EOB" << endl; + j = -1; + break; + case 2: // delta + //cout << "DELTA" << endl; + val = *imgPtr++; i += val; destPtr += val * pixelAdd; + val = *imgPtr++; j += val; destPtr -= val * lineAdd; destLine -= val * lineAdd; + break; + default: // absolute mode + //cout << "ABS" << endl; + while (cmd > 0) + { + val = *imgPtr++; + if (j < height) + { + if (i >= width) + { + BMP_RLE_LINEFEED; + } + destPtr[0] = palette[val].red; + if (paletteIsGrey == 0) + { + destPtr[1] = palette[val].green; + destPtr[2] = palette[val].blue; + } + destPtr += pixelAdd; i++; + } + cmd--; + } + // Align srcPtr to a Windows-Word position (==> aligned to short) + if ((((r_Ptr)imgPtr) & 1) != 0) imgPtr++; + break; + } + } + else // repeat sequence + { + //cout << "RUN" << endl; + val = *imgPtr++; + while (cmd > 0) + { + if (j < height) + { + if (i >= width) + { + BMP_RLE_LINEFEED; + } + destPtr[0] = palette[val].red; + if (paletteIsGrey == 0) + { + destPtr[1] = palette[val].green; + destPtr[2] = palette[val].blue; + } + destPtr += pixelAdd; i++; + } + cmd--; + } + } + } + } + break; + case COMPRESS_RLE4: + { + i = 0; j = 0; destPtr = destLine; imgPtr = imgLine; + while (j >= 0) + { + unsigned char val=0, cmd=0; + + cmd = *imgPtr++; + if (cmd == 0) // escape + { + cmd = *imgPtr++; + switch (cmd) + { + case 0: // end of line + BMP_RLE_LINEFEED; + break; + case 1: // end of bitmap + j = -1; + break; + case 2: // delta + val = *imgPtr++; i += val; destPtr += val * pixelAdd; + val = *imgPtr++; j += val; destPtr -= val * lineAdd; destLine -= val * lineAdd; + break; + default: // absolute mode + while (cmd > 1) + { + val = *imgPtr++; + if (j < height) + { + if (i >= width) + { + BMP_RLE_LINEFEED; + } + destPtr[0] = palette[val >> 4].red; + if (paletteIsGrey == 0) + { + destPtr[1] = palette[val >> 4].green; + destPtr[2] = palette[val >> 4].blue; + } + destPtr += pixelAdd; i++; + if (i >= width) + { + BMP_RLE_LINEFEED; + } + destPtr[0] = palette[val & 0x0f].red; + if (paletteIsGrey == 0) + { + destPtr[1] = palette[val & 0x0f].green; + destPtr[2] = palette[val & 0x0f].blue; + } + destPtr += pixelAdd; i++; + } + cmd-=2; + } + if (cmd != 0) + { + val = *imgPtr++; + if (j < height) + { + if (i >= width) + { + BMP_RLE_LINEFEED; + } + destPtr[0] = palette[val >> 4].red; + if (paletteIsGrey == 0) + { + destPtr[1] = palette[val >> 4].green; + destPtr[2] = palette[val >> 4].blue; + } + destPtr += pixelAdd; i++; + } + } + // Align srcPtr to a Windows-Word position (==> aligned to short) + if ((((r_Ptr)imgPtr) & 1) != 0) imgPtr++; + break; + } + } + else // repeat sequence + { + val = *imgPtr++; + while (cmd > 1) + { + if (j < height) + { + if (i >= width) + { + BMP_RLE_LINEFEED; + } + destPtr[0] = palette[val >> 4].red; + if (paletteIsGrey == 0) + { + destPtr[1] = palette[val >> 4].green; + destPtr[2] = palette[val >> 4].blue; + } + destPtr += pixelAdd; i++; + if (i >= width) + { + BMP_RLE_LINEFEED; + } + destPtr[0] = palette[val & 0x0f].red; + if (paletteIsGrey == 0) + { + destPtr[1] = palette[val & 0x0f].green; + destPtr[2] = palette[val & 0x0f].blue; + } + destPtr += pixelAdd; i++; + } + cmd -= 2; + } + if (cmd != 0) + { + if (j < height) + { + if (i >= width) + { + BMP_RLE_LINEFEED; + } + destPtr[0] = palette[val >> 4].red; + if (paletteIsGrey == 0) + { + destPtr[1] = palette[val >> 4].green; + destPtr[2] = palette[val >> 4].blue; + } + destPtr += pixelAdd; i++; + } + } + } + } + } + break; + default: + { + RMInit::logOut << "r_Conv_BMP::convertFrom(): bad compression type" << endl; + mystore.storage_free(dest); + throw r_Error(r_Error::r_Error_General); + } + } + + desc.dest = (char*)dest; desc.baseType = destType; + + desc.destInterv = r_Minterval(2); + desc.destInterv << r_Sinterval((r_Range)0, (r_Range)width-1) + << r_Sinterval((r_Range)0, (r_Range)height-1); + + desc.destType = get_external_type(desc.baseType); + + return desc; +} + + + +const char *r_Conv_BMP::get_name( void ) const +{ + return format_name_bmp; +} + + +r_Data_Format r_Conv_BMP::get_data_format( void ) const +{ + return r_BMP; +} + + +r_Convertor *r_Conv_BMP::clone( void ) const +{ + return new r_Conv_BMP(desc.src, desc.srcInterv, desc.baseType); +} diff --git a/conversion/bmp.hh b/conversion/bmp.hh new file mode 100644 index 0000000..de49ddc --- /dev/null +++ b/conversion/bmp.hh @@ -0,0 +1,91 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * INCLUDE: bmp.hh + * + * MODULE: conversion + * + * CLASSES: r_Conv_BMP + * + * COMMENTS: + * + * Provides interface to convert data to other formats. + * +*/ + +#ifndef _R_CONV_BMP_HH_ +#define _R_CONV_BMP_HH_ + +#include "conversion/convertor.hh" + + + +//@ManMemo: Module {\bf conversion} + +/*@Doc: + BMP convertor class. + Completely native implementation, doesn't use external libs. + memfs is used differently here, therefore the class is derived + directly from r_Convertor rather than r_Convert_Memory. + + Supported parameters are + + \begin{tabular}{lcl} + compress && int && Use compression (8bpp only) + \end{tabular} +*/ + +class r_Conv_BMP : public r_Convertor +{ + public: + /// constructor using an r_Type object + r_Conv_BMP( const char *src, const r_Minterval &interv, const r_Type *tp ) throw(r_Error); + /// constructor using convert_type_e shortcut + r_Conv_BMP( const char *src, const r_Minterval &interv, int tp ) throw(r_Error); + /// destructor + ~r_Conv_BMP( void ); + + /// convert to BMP + virtual r_convDesc &convertTo( const char *options=NULL ) throw(r_Error); + /// convert from BMP + virtual r_convDesc &convertFrom( const char *options=NULL ) throw(r_Error); + /// cloning + virtual r_Convertor *clone( void ) const; + /// identification + virtual const char *get_name( void ) const; + virtual r_Data_Format get_data_format( void ) const; + + + private: + /// initalize BMP class + void initBMP( void ); + /// Needed by the encoder in RLE mode + unsigned char *flushLiterals(int numLit, int pixelAdd, unsigned char *dest, const unsigned char *lastLit, const unsigned char *mapColours); + + memFSContext *memFS; + + /// parameters + int compress; +}; + +#endif diff --git a/conversion/convertor.cc b/conversion/convertor.cc new file mode 100644 index 0000000..9c6f353 --- /dev/null +++ b/conversion/convertor.cc @@ -0,0 +1,405 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * SOURCE: convertor.cc + * + * MODULE: conversion + * + * CLASSES: r_Convertor, r_Convert_Memory + * + * PURPOPSE: + * Provides interface to convert data to other formats. + * + * COMMENTS: + * - FIXME: r_Convertor::get_internal_type(): every structType is recognised as RGB! + * +*/ + +#include "conversion/convertor.hh" +#include "conversion/memfs.hh" +#include "raslib/error.hh" +#include "raslib/parseparams.hh" +#include "raslib/rminit.hh" +#include "raslib/primitivetype.hh" + + +/* + * r_Convertor class + */ + +void r_Convertor::initShare( const char *src, const r_Minterval &interv ) +{ + desc.src = src; + desc.srcInterv = interv; + desc.srcType = NULL; + desc.destType = NULL; + desc.dest = NULL; + params = NULL; + destroySrc = false; +} + + +r_Convertor::r_Convertor( void ) +{ + desc.srcType = NULL; + desc.destType = NULL; + desc.dest = NULL; + desc.src = NULL; + desc.baseType = ctype_void; + params = NULL; +} + + +r_Convertor::r_Convertor( const char *src, const r_Minterval &interv, const r_Type *tp, bool fullTypes ) throw(r_Error) +{ + initShare(src, interv); + + desc.srcType = tp; + + if (tp == NULL) + { + RMInit::logOut << "Error: in conversion: type is null." << endl; + throw r_Error(); + } + + // Initialise desc.baseType from desc.srcType + desc.baseType=get_internal_type(tp, fullTypes); + + if (!fullTypes) { + switch (tp->type_id()) { + case r_Type::FLOAT: + this->applyColorScheme<float>(); + break; + case r_Type::DOUBLE: + applyColorScheme<double>(); + break; + case r_Type::USHORT: + applyColorScheme<unsigned short>(); + break; + case r_Type::SHORT: + applyColorScheme<short>(); + break; + } + } +} + + +r_Convertor::r_Convertor(const char *src, const r_Minterval &interv, int type) throw(r_Error) +{ + initShare(src, interv); + + desc.baseType = type; +} + + +r_Convertor::~r_Convertor(void) +{ + // Don't delete the resulting object pointer (desc->dest) ! + // This is the job of the external application. + if (params!=NULL) + { + delete params; + params=NULL; + } + if (destroySrc) + { + delete desc.src; + destroySrc=false; + } +} + + +void r_Convertor::set_storage_handler( const r_Storage_Man &newStore ) +{ + mystore = newStore; +} + + +const r_Storage_Man& +r_Convertor::get_storage_handler( ) const +{ + return mystore; +} + + + +r_Type *r_Convertor::get_external_type( int ctype ) throw(r_Error) +{ + r_Type* retval=NULL; + switch (ctype) + { + case ctype_bool: + retval=r_Type::get_any_type("boolean"); + break; + case ctype_char: + case ctype_uint8: + retval=r_Type::get_any_type("char"); + break; + case ctype_int8: + retval=r_Type::get_any_type("octet"); + break; + case ctype_int16: + retval=r_Type::get_any_type("short"); + break; + case ctype_uint16: + retval=r_Type::get_any_type("ushort"); + break; + case ctype_int32: + retval=r_Type::get_any_type("long"); + break; + case ctype_uint32: + retval=r_Type::get_any_type("ulong"); + break; + case ctype_int64: + retval=r_Type::get_any_type("double"); // currently unsupported + break; + case ctype_uint64: + retval=r_Type::get_any_type("double"); // currently unsupported + break; + case ctype_float32: + retval=r_Type::get_any_type("float"); + break; + case ctype_float64: + retval=r_Type::get_any_type("double"); + break; + case ctype_rgb: + retval=r_Type::get_any_type("struct {char, char, char}"); + break; + default: + RMInit::logOut << "Error: in conversion: unsupported type " << ctype << endl; + r_Error err(r_Error::r_Error_General); + throw(err); + } + return retval; +} + + +template <class baseType> +void r_Convertor::applyColorScheme() { + baseType *data = (baseType*)desc.src; + baseType min=data[0], max=data[0]; + int i, size = desc.srcInterv.cell_count(); + unsigned char *t, *img = new unsigned char[size*3]; + for (i=1; i<size; ++i) { + if (min > data[i]) + min=data[i]; + if (max < data[i]) + max=data[i]; + } + for (i=0, t=img; i<size; ++i) { + float n = (data[i]-min)/(max-min); + if (n<0.5) { + *t=(unsigned char)((0.5-n)*500); t++; + *t=(unsigned char)(n*500); t++; + *t=0; t++; + } else + { + *t=0;t++; + *t=(unsigned char)((1-n)*500); t++; + *t=(unsigned char)((n-0.5)*500); t++; + } + } + destroySrc = true; + desc.src = (char*)img; +} + +r_Convertor::convert_type_e +r_Convertor::get_internal_type(const r_Type* tp, bool fullTypes) throw(r_Error) { + r_Convertor::convert_type_e retval=ctype_void; + + if (tp == NULL) + return retval; + + //check if tp is structure type + if (tp->isStructType()) + { + // make life easy and always interpret as RGB + retval = ctype_rgb; + } + else + { + //is primitive type + if (fullTypes == false) + { + // restricted types for ``classic'' image formats + switch (tp->type_id()) + { + case r_Type::BOOL: + retval = ctype_bool; break; + case r_Type::CHAR: + case r_Type::OCTET: + retval = ctype_char; break; + // added (U)LONG -- PB 2005-apr-27 + case r_Type::LONG: + retval = ctype_int32; break; + case r_Type::ULONG: + retval = ctype_uint32; break; + // set to defined value (FIXME: still not good) -- PB 2005-apr-27 + default: + RMInit::logOut << "Error: in conversion: unknown type " << tp->type_id() << ", setting to void." << endl; + retval = ctype_rgb; + //retval = ctype_char; + + break; + } + } + else + { + // full types for more generic convertors + switch (tp->type_id()) + { + case r_Type::BOOL: + //FIXME that was in hdf.cc retval = ctype_uint8; break; + retval = ctype_bool; break; + case r_Type::CHAR: + retval = ctype_uint8; break; + case r_Type::OCTET: + retval = ctype_int8; break; + case r_Type::SHORT: + retval = ctype_int16; break; + case r_Type::USHORT: + retval = ctype_uint16; break; + case r_Type::LONG: + retval = ctype_int32; break; + case r_Type::ULONG: + retval = ctype_uint32; break; + case r_Type::FLOAT: + retval = ctype_float32; break; + case r_Type::DOUBLE: + retval = ctype_float64; break; + default: + break; + } + }//endif fullTypes + if (retval == ctype_void) + { + RMInit::logOut << "Warning: in conversion: this type overrides base type: " << tp->type_id() << "; using char." << endl; + retval = ctype_char; + } + }//endif structuretype + + return retval; +} + +std::ostream& operator<<(std::ostream& os, r_Convertor::convert_type_e& cte) +{ + switch(cte) + { + case r_Convertor::ctype_bool: + os << "bool"; + break; + case r_Convertor::ctype_char: + os << "char"; + break; + case r_Convertor::ctype_uint8: + os << "uint8"; + break; + case r_Convertor::ctype_int8: + os << "int8"; + break; + case r_Convertor::ctype_int16: + os << "int16"; + break; + case r_Convertor::ctype_uint16: + os << "uint16"; + break; + case r_Convertor::ctype_int32: + os << "int32"; + break; + case r_Convertor::ctype_uint32: + os << "uint32"; + break; + case r_Convertor::ctype_int64: + os << "int64"; // currently unsupported + break; + case r_Convertor::ctype_uint64: + os << "uint64"; // currently unsupported + break; + case r_Convertor::ctype_float32: + os << "float32"; + break; + case r_Convertor::ctype_float64: + os << "float64"; + break; + case r_Convertor::ctype_rgb: + os << "rgb"; + break; + default: + os << "r_Convertor::convert_type_e unknown type: " << cte << endl; + break; + } + + return os; +} + +/* + * r_Convert_Memory class + */ + +void r_Convert_Memory::initMemory( void ) throw(r_Error) +{ + int status = -1; + + memFS=NULL; + handle=NULL; + + memFS = new memFSContext; + if ( memFS != NULL) + { + handle = (void*)memFS; + if (memfs_initfs(handle) >= 0) + status = 0; + } + if (status < 0) + { + RMInit::logOut << "Error: cannot allocate memory for conversion." << endl; + r_Error err(MEMMORYALLOCATIONERROR); + throw(err); + } +} + + +r_Convert_Memory::r_Convert_Memory( const char *src, const r_Minterval &interv, const r_Type *tp, int fullTypes ) throw(r_Error) +: r_Convertor(src, interv, tp, fullTypes) +{ + initMemory(); +} + + +r_Convert_Memory::r_Convert_Memory( const char *src, const r_Minterval &interv, int type ) throw(r_Error) +: r_Convertor(src, interv, type) +{ + initMemory(); +} + + +r_Convert_Memory::~r_Convert_Memory( void ) +{ + memfs_killfs(handle); + if(memFS!=NULL) + { + delete memFS; + memFS=NULL; + } + handle=NULL; +} diff --git a/conversion/convertor.hh b/conversion/convertor.hh new file mode 100644 index 0000000..01931f4 --- /dev/null +++ b/conversion/convertor.hh @@ -0,0 +1,252 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * INCLUDE: convertor.hh + * + * MODULE: conversion + * + * CLASSES: r_Convertor, r_Convert_Memory + * + * COMMENTS: + * + * Provides interface to convert data to other formats. + * +*/ + +#ifndef _R_CONVERTOR_ +#define _R_CONVERTOR_ + +#include <stdlib.h> + +#include "raslib/error.hh" +#include "raslib/minterval.hh" +#include "raslib/type.hh" +#include "raslib/mddtypes.hh" +#include "raslib/storageman.hh" +//#include "conversion/memfs.h" + + + +// Declare to avoid including memfs.h (and with that tiffio.h) +struct memFSContext; + +class r_Parse_Params; + + +typedef struct r_convDesc { + const char *src; // pointer to source data + char *dest; // pointer to destination data + r_Minterval srcInterv; // dimensions of source data + r_Minterval destInterv; // dimensions of destination data + int baseType; // shortcut to src basetype + const r_Type *srcType; // basetypes of src data + r_Type *destType; // basetypes of dest data +} r_convDesc; + + + +//@ManMemo: Module {\bf conversion} + + +/*@Doc: + Conversion classes from and to data exchange formats. Can also be used for + tile compression of special MDD types (= images) + + \begin{itemize} + \item + the member function convertTo() performs the conversion MDD -> DEF + \item + the member function convertFrom() performs the conversion DEF -> MDD + \item + the r_convDesc reference returned from this call is only valid while + the convertor object is. + \item + after successful execution the returned r_convDesc structure contains + the following information: + \begin{itemize} + \item + dest: pointer to converted data, allocated by the configured heap + storage object which will use malloc() by default (see + set_storage_handler()); must be deallocated by the caller. + \item + destInterv: r_Minterval describing the converted object's domain. + \item + destType: pointer to an r_Type object describing the converted + object's type; must be deallocated by the caller. + \end{itemize} + \item + on failure an exception is thrown. + \end{itemize} + + The member function convertTo() receives a parameter string as argument + which is NULL for default parameters. The format of the string is such + that it can be parsed by r_Parse_Params. The params member variable is + initialized to NULL in this class. Derived classes that wish to add + parameters must first check whether params is NULL and create a new + object if so, then add their parameters. This makes it possible to + accumulate parameters over all class hierarchies. +*/ + +class r_Convertor +{ + public: + /// default constructor (should not be used) + r_Convertor( void ); + /// constructor using an r_Type object + r_Convertor( const char *src, const r_Minterval &interv, const r_Type *tp, + bool fullTypes=false) throw(r_Error); + /// constructor using convert_type_e shortcut + r_Convertor( const char *src, const r_Minterval &interv, int type ) throw(r_Error); + /** + convert_type_e is an enumerator that acts as a shortcut to base types + relevant for DEFs. The values and what they correspond to are listed + below (the types below the line are for HDF): + + \begin{tabular}{ll} + ctype_void && No type, used for errors\\ + ctype_bool && bool\\ + ctype_char && char\\ + ctype_rgb && struct {char, char, char}\\ + \hline + ctype_int8 && signed char\\ + ctype_uint8 && unsigned char\\ + ctype_int16 && short\\ + ctype_uint16 && unsigned short\\ + ctype_int32 && int\\ + ctype_uint32 && unsigned int\\ + ctype_int64 && (unsupported)\\ + ctype_uint64 && (unsupported)\\ + ctype_float32 && float\\ + ctype_float64 && double\\ + \end{tabular} + */ + + /// destructor + virtual ~r_Convertor( void ); + + //@Man: Interface + /// convert array to DEF + virtual r_convDesc &convertTo( const char *options=NULL ) throw(r_Error) = 0; + + /// convert DEF to array + virtual r_convDesc &convertFrom( const char *options=NULL ) throw(r_Error) = 0; + + /// cloning + virtual r_Convertor *clone( void ) const = 0; + + /// identification + virtual const char *get_name( void ) const = 0; + virtual r_Data_Format get_data_format( void ) const = 0; + + /// set storage handler, default is malloc/free + void set_storage_handler( const r_Storage_Man &newStore ); + + /// get storage handler, default is malloc/free + const r_Storage_Man& get_storage_handler( ) const; + + + /// base type shortcuts + enum convert_type_e { + // undefined type + ctype_void, + // Shortcut for the three important base types r_Boolean, r_Char and RGBPixel + ctype_bool, + ctype_char, + ctype_rgb, + // More generic types for HDF + ctype_int8, + ctype_uint8, + ctype_int16, + ctype_uint16, + ctype_int32, + ctype_uint32, + ctype_int64, + ctype_uint64, + ctype_float32, + ctype_float64 + }; + + //@{ helper structure for encoding string-to-int parameters + typedef struct convert_string_s { + const char *key; + int id; + } convert_string_t; + //@} + + /// get a r_Type from an internal type + static r_Type *get_external_type( int ctype ) throw(r_Error); + + /// get a internal type from a r_Type + static convert_type_e get_internal_type( const r_Type* type, bool fullTypes=false ) throw(r_Error); + + protected: + /// initialize internal structures + void initShare( const char *src, const r_Minterval &interv ); + + /// true if we should free the src area (in case the input was converted to rgb) + bool destroySrc; + + /// convert unsupported type to rgb by applying the default color scheme + template <class baseType> + void applyColorScheme(); + + /// conversion context + r_convDesc desc; + + /// parameter parser + r_Parse_Params *params; + + /// storage manager + r_Storage_Man mystore; +}; + +///ostream operator for convert_type_e +std::ostream& operator<<(std::ostream& os, r_Convertor::convert_type_e& cte); + +/*@Doc: + Abstract base class for all memory-to-memory conversion classes, + uses memfs for of data with unknown size at the time of creation. +*/ + +class r_Convert_Memory : public r_Convertor +{ + public: + /// constructor using an r_Type object + r_Convert_Memory( const char *src, const r_Minterval &interv, const r_Type *tp, + int fullTypes=0) throw(r_Error); + /// constructur using convert_type_e shortcut + r_Convert_Memory( const char *src, const r_Minterval &interv, int type ) throw(r_Error); + /// destructor + virtual ~r_Convert_Memory( void ); + + + protected: + /// init memfs + void initMemory( void ) throw(r_Error); + + /// variables + memFSContext *memFS; + void *handle; +}; + +#endif diff --git a/conversion/convfactory.cc b/conversion/convfactory.cc new file mode 100644 index 0000000..31f27ae --- /dev/null +++ b/conversion/convfactory.cc @@ -0,0 +1,189 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * SOURCE: convertor.cc + * + * MODULE: conversion + * + * CLASSES: r_Convertor_Factory + * Create convertors out of data formats + * + * COMMENTS: + * - temporary, for debugging +*/ + +#include "raslib/rminit.hh" +#include "debug.hh" + +#include "conversion/convfactory.hh" + +// all the conversion types, for easy creation +#include "tiff.hh" +#include "hdf.hh" +#include "png.hh" +#include "jpeg.hh" +#include "bmp.hh" +#include "vff.hh" +#include "tor.hh" +#include "dem.hh" +#include "ecw.hh" +#include "ntf.hh" +#include "csv.hh" + + + +bool r_Convertor_Factory::is_supported( r_Data_Format fmt ) +{ + ENTER( "r_Convertor_Factory::is_supported( " << fmt << " )" ); + + bool retval=false; + switch (fmt) + { + case r_TIFF: + case r_PNG: + case r_JPEG: + case r_BMP: + case r_VFF: + case r_TOR: + case r_DEM: + case r_ECW: +#ifndef DISABLE_HDF + case r_HDF: +#endif + // case r_NTF: + retval=true; + break; + default: + retval=false; + break; + } + + LEAVE( "r_Convertor_Factory::is_supported() -> " << retval ); + return retval; +} + +r_Convertor *r_Convertor_Factory::create( r_Data_Format fmt, const char *src, const r_Minterval &interv, const r_Type *tp) throw(r_Error) +{ + ENTER( "r_Convertor_Factory::create( fmt=" << fmt << ", &src=" << ((r_Ptr) src) << ", interval=" << interv << ", &type=" << ((r_Ptr) tp) << " )" ); + r_Convertor *result = NULL; + + switch (fmt) + { + case r_TIFF: + result = new r_Conv_TIFF(src, interv, tp); + break; + case r_PNG: + result = new r_Conv_PNG(src, interv, tp); + break; + case r_CSV: + result = new r_Conv_CSV(src, interv, tp); + break; + case r_JPEG: + result = new r_Conv_JPEG(src, interv, tp); + break; + case r_BMP: + result = new r_Conv_BMP(src, interv, tp); + break; + case r_VFF: + result = new r_Conv_VFF(src, interv, tp); + break; + case r_TOR: + result = new r_Conv_TOR(src, interv, tp); + break; + case r_DEM: + result = new r_Conv_DEM(src, interv, tp); + break; + case r_ECW: + result = new r_Conv_ECW(src, interv, tp); + break; +#ifndef DISABLE_HDF + case r_HDF: + result = new r_Conv_HDF(src, interv, tp); + break; +#endif + // case r_NTF: + // TALK( "creating NTF converter..." ); + // result = new r_Conv_NTF(src, interv, tp); + // break; + default: + RMInit::logOut << "Error: in conversion factory during create: unsupported format: " << fmt << endl; + r_Error err(CONVERSIONFORMATNOTSUPPORTED); + throw(err); + } + + LEAVE( "r_Convertor_Factory::create() -> " << result ); + return result; +} + + +r_Convertor *r_Convertor_Factory::create( r_Data_Format fmt, const char *src, const r_Minterval &interv, int type ) throw(r_Error) +{ + ENTER( "r_Convertor_Factory::create( fmt=" << fmt << ", &src=" << ((r_Ptr) src) << ", interval=" << interv << ", type=" << type << " )" ); + + r_Convertor *result = NULL; + + switch (fmt) + { + case r_TIFF: + result = new r_Conv_TIFF(src, interv, type); + break; + case r_PNG: + result = new r_Conv_PNG(src, interv, type); + break; + case r_JPEG: + result = new r_Conv_JPEG(src, interv, type); + break; + case r_BMP: + result = new r_Conv_BMP(src, interv, type); + break; + case r_VFF: + result = new r_Conv_VFF(src, interv, type); + break; + case r_TOR: + result = new r_Conv_TOR(src, interv, type); + break; + case r_DEM: + result = new r_Conv_DEM(src, interv, type); + break; + case r_ECW: + result = new r_Conv_ECW(src, interv, type); + break; +#ifndef DISABLE_HDF + case r_HDF: + result = new r_Conv_HDF(src, interv, type); + break; +#endif + // case r_NTF: + // TALK( "creating NTF converter..." ); + // result = new r_Conv_NTF(src, interv, type); + // break; + default: + RMInit::logOut << "Error: in conversion factory during create: unsupported format: " << fmt << endl; + r_Error err(CONVERSIONFORMATNOTSUPPORTED); + throw(err); + } + + LEAVE( "r_Convertor_Factory::create() -> " << result ); + return result; +} + diff --git a/conversion/convfactory.hh b/conversion/convfactory.hh new file mode 100644 index 0000000..e299dca --- /dev/null +++ b/conversion/convfactory.hh @@ -0,0 +1,64 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * SOURCE: convertor.cc + * + * MODULE: conversion + * + * CLASSES: r_Convertor_Factory + * + * COMMENTS: + * Create convertors out of data formats +*/ + +#include "raslib/mddtypes.hh" +#include "raslib/error.hh" + + +class r_Convertor; +class r_Minterval; +class r_Type; + + +//@ManMemo: Module {\bf conversion} + +/*@Doc: + r_Convertor_Factory is a class encapsulating static functions to + create convertors out of data formats. The alternative of making + this functionality static members of r_Converstor would have meant + that all code using just one convertor would have to link the libs + of all convertors, rendering it unusable. +*/ + +class r_Convertor_Factory +{ + public: + /// check for support + static bool is_supported( r_Data_Format fmt ); + /// creating from r_Type + static r_Convertor *create( r_Data_Format fmt, const char *src, const r_Minterval &interv, + const r_Type *tp ) throw(r_Error); + /// creating from internal type + static r_Convertor *create( r_Data_Format fmt, const char *src, const r_Minterval &interv, + int type ) throw(r_Error); +}; diff --git a/conversion/csv.cc b/conversion/csv.cc new file mode 100644 index 0000000..7babcbe --- /dev/null +++ b/conversion/csv.cc @@ -0,0 +1,222 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * SOURCE: csv.cc + * + * MODULE: conversion + * + * CLASSES: r_Conv_CSV + * + * COMMENTS: + * + * Provides functions to convert data to CSV SD and back. + * +*/ + +/* Added by Sorin Stancu-Mara. Definition clashed for type int8, define in both +* /usr/include/csv.h and in /usr/include/tiff.h +* This will supress the tiff.h definition. +* Both definitions are similar +*/ +#define HAVE_INT8 + +#include "conversion/csv.hh" +#include "raslib/error.hh" +#include "raslib/rminit.hh" +#include "raslib/parseparams.hh" +#include "raslib/primitivetype.hh" +#include <iostream> +#include <fstream> +#include <cstring> + +#include "csv.hh" + +#include <stdio.h> +#include <iostream> + + +r_Conv_CSV::r_Conv_CSV(const char *src, const r_Minterval &interv, const r_Type *tp) throw(r_Error) +: r_Convertor(src, interv, tp, true) +{ + if (tp->isStructType()) + { + RMInit::logOut << "r_Conv_CSV::r_Conv_CSV(): structured types not supported." << endl; + throw r_Error(r_Error::r_Error_General); + } +} + + + +r_Conv_CSV::r_Conv_CSV(const char *src, const r_Minterval &interv, int tp) throw(r_Error) +: r_Convertor(src, interv, tp) +{ +} + + +/* +int r_Conv_HDF::getTypeSize(int intType, char *format) +{ + + switch (intType) + { + case ctype_int8: strcpy(format, "%c"); return 1; break; + case ctype_uint8: + case ctype_char: + case ctype_bool: return 1; break; + case ctype_int16: return 2; break; + case ctype_uint16: return 2; break; + case ctype_int32: return 4; break; + case ctype_uint32: return 4; break; + case ctype_int64: return 8; break; + case ctype_uint64: return 8; break; + case ctype_float32: return 4; break; + case ctype_float64: return 8; break; + default: return 1; break; + } + return 1; +} +*/ + +r_Conv_CSV::~r_Conv_CSV(void) +{ +} + +template <class baseType, class castType> +void r_Conv_CSV::print(std::ofstream &f, baseType* val, int *dims, int dim) { + if (dim==1) { + for (int i=0; i<dims[0]-1; ++i, val++) + f << (castType)val[0] << ","; + f << (castType) val[dims[0]-1]; val++; + } else { + for (int i=0; i<dims[0]-1; ++i, val++) { + f << "{"; + print<baseType, castType>(f, val, dims+1, dim-1); + f << "},"; + } + f << "{"; + print<baseType, castType>(f, val, dims+1, dim-1); + f << "}"; + } +} + + +r_convDesc &r_Conv_CSV::convertTo( const char *options ) throw(r_Error) +{ + char name[256]; + strncpy(name, tmpnam(NULL), 256); + std::ofstream ftemp(name); + //int size = getTypeSize(desc.baseType); + int rank, i; + int *dimsizes; + rank = desc.srcInterv.dimension(); + const char *src = desc.src; + + char *t; + + dimsizes = new int[rank]; + + for (i=0; i<rank; i++) + { + dimsizes[i] = desc.srcInterv[i].high() - desc.srcInterv[i].low() + 1; + } + + switch (desc.baseType) + { + case ctype_int8: print<const r_Octet, int>(ftemp, (const r_Octet* &)src, dimsizes, rank); break; + case ctype_uint8: + case ctype_char: + case ctype_bool: print<r_Char, int>(ftemp, (r_Char* &)src, dimsizes, rank); break; + case ctype_int16: print<r_Short, int>(ftemp, (r_Short* &)src, dimsizes, rank); break; + case ctype_uint16: print<r_UShort, int>(ftemp, (r_UShort* &) src, dimsizes, rank); break; + case ctype_int32: print<r_Long, int>(ftemp, (r_Long* &) src, dimsizes, rank); break; + case ctype_uint32: print<r_ULong, int>(ftemp, (r_ULong* &) src, dimsizes, rank); break; + case ctype_int64: print<long long, long long>(ftemp, (long long* &) src, dimsizes, rank); break; + case ctype_uint64: print<unsigned long long, unsigned long long>(ftemp, (unsigned long long* &) src, dimsizes, rank); break; + case ctype_float32: print<r_Float, float>(ftemp, (r_Float* &) src, dimsizes, rank); break; + case ctype_float64: print<r_Double, float>(ftemp, (r_Double* &) src, dimsizes, rank); break; + default: print<r_Char, int>(ftemp, (r_Char* &)src, dimsizes, rank); + } + + delete [] dimsizes; dimsizes=NULL; + ftemp.close(); + + FILE *fp; + int filesize; + + if ((fp = fopen(name, "rb")) == NULL) + { + RMInit::logOut << "r_Conv_CSV::convertTo(): unable to read back file." << endl; + throw r_Error(r_Error::r_Error_General); + } + fseek(fp, 0, SEEK_END); + filesize = ftell(fp); + + desc.destInterv = r_Minterval(1); + desc.destInterv << r_Sinterval((r_Range)0, (r_Range)filesize - 1); + + if ((desc.dest = (char*)mystore.storage_alloc(filesize)) == NULL) + { + RMInit::logOut << "r_Conv_CSV::convertTo(): out of memory error" << endl; + fclose(fp); + throw r_Error(MEMMORYALLOCATIONERROR); + } + fseek(fp, 0, SEEK_SET); + fread(desc.dest, 1, filesize, fp); + + fclose(fp); + + remove(name); + + // Result is just a bytestream + desc.destType = r_Type::get_any_type("char"); + + return desc; +} + + + +r_convDesc &r_Conv_CSV::convertFrom(const char *options) throw(r_Error) +{ + RMInit::logOut << "importing CSV data not yet implemented" << endl; + throw new r_Error(CONVERSIONFORMATNOTSUPPORTED); + return desc; +} + + + +const char *r_Conv_CSV::get_name( void ) const +{ + return "csv"; +} + + +r_Data_Format r_Conv_CSV::get_data_format( void ) const +{ + return r_CSV; +} + + +r_Convertor *r_Conv_CSV::clone( void ) const +{ + return new r_Conv_CSV(desc.src, desc.srcInterv, desc.baseType); +} diff --git a/conversion/csv.hh b/conversion/csv.hh new file mode 100644 index 0000000..c4eed18 --- /dev/null +++ b/conversion/csv.hh @@ -0,0 +1,93 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * INCLUDE: csv.hh + * + * MODULE: conversion + * + * CLASSES: r_Conv_CSV + * + * COMMENTS: + * + * Provides interface to convert data to other formats. + * +*/ + +#ifndef _R_CONV_CSV_HH_ +#define _R_CONV_CSV_HH_ + +#include "conversion/convertor.hh" +#include <ostream> + +//@ManMemo: Module {\bf conversion} + +/*@Doc: + CSV convertor class. + + Supported parameters are + + \begin{tabular}{lcl} + comptype && string && the compression type to use (see below)\\ + quality && int && quality parameter for JPEG compression\\ + skiphuff && int && skipping parameter for Huffman coding\\ + \end{tabular} + + The compression type defaults to deflate but may be one of the + following + + \begin{tabular}{ll} + none && no compression\\ + rle && Run Length Coding\\ + huffman && Huffman coding\\ + deflate && ZIP deflate\\ + \end{tabular} + +*/ +class r_Conv_CSV : public r_Convertor +{ + public: + /// constructor using an r_Type object. Exception if the type isn't atomic. + r_Conv_CSV( const char *src, const r_Minterval &interv, const r_Type *tp) throw(r_Error); + /// constructor using convert_type_e shortcut + r_Conv_CSV( const char *src, const r_Minterval &interv, int tp ) throw(r_Error); + /// destructor + ~r_Conv_CSV( void ); + + /// convert to CSV + virtual r_convDesc &convertTo( const char *options=NULL ) throw(r_Error); + /// convert from CSV + virtual r_convDesc &convertFrom( const char *options=NULL ) throw(r_Error); + /// cloning + virtual r_Convertor *clone( void ) const; + /// identification + virtual const char *get_name( void ) const; + virtual r_Data_Format get_data_format( void ) const; + + + private: + template <class baseType, class castType> + void print(std::ofstream &f, baseType* val, int *dims, int dim); + +}; + +#endif diff --git a/conversion/dem.cc b/conversion/dem.cc new file mode 100644 index 0000000..09e801e --- /dev/null +++ b/conversion/dem.cc @@ -0,0 +1,894 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * SOURCE: dem.hh + * + * MODULE: conversion + * + * CLASSES: r_Conv_DEM + * + * PURPOSE: + * Provides interface to convert data from/to Array format to/from DEM format. + * + * COMMENTS: + * For further support send a mail to comanl@yahoo.com + * - convertTo() writes a temp file; this should be omitted for performance reasons +*/ + +static const char rcsid[] = "@(#)conversion,r_Conv_DEM: $Id: dem.cc,v 1.10 2005/09/08 12:59:26 rasdev Exp $"; + +#include "conversion/dem.hh" + +#include <float.h> +#include <string> +#include <cstring> +#include <strstream> +#include <sstream> +#include <algorithm> + +using std::istringstream; +using std::istrstream; +using std::string; +using namespace std; + +#include "raslib/rminit.hh" +#include "raslib/parseparams.hh" +#include "raslib/primitivetype.hh" + + +const r_Dimension r_Conv_DEM::srcIntervDim=1; +const r_Dimension r_Conv_DEM::destIntervDim=2; +const r_ULong r_Conv_DEM::paramMin=6; +const char* r_Conv_DEM::paramSep=","; +const char* r_Conv_DEM::paramEq="="; +const char* r_Conv_DEM::paramFlipX="flipx"; +const char* r_Conv_DEM::paramFlipY="flipy"; +const char* r_Conv_DEM::paramStartX="startx"; +const char* r_Conv_DEM::paramEndX="endx"; +const char* r_Conv_DEM::paramResX="resx"; +const char* r_Conv_DEM::paramStartY="starty"; +const char* r_Conv_DEM::paramEndY="endy"; +const char* r_Conv_DEM::paramResY="resy"; + +const r_Double r_Conv_DEM::NULL_DB = 0.; +const r_Double r_Conv_DEM::ZERO_DB = FLT_MIN; +const r_Double r_Conv_DEM::ZERO_DEM = 0.; + +r_Conv_DEM::~r_Conv_DEM( void ) +{ + //nothing to care for +} + +void r_Conv_DEM::initGeoBBox( r_GeoBBox& cBBox ) +{ + //flipy is selected by default + cBBox.flipy = 1; + + //flipx is not selected by default + cBBox.flipx = 0; + + //geo information are initialized by default to DBL_MAX + // FIXME: better defaults res=1, min=-MAX? + cBBox.startx = DBL_MAX; + cBBox.endx = DBL_MAX; + cBBox.resx = DBL_MAX; + cBBox.starty = DBL_MAX; + cBBox.endy = DBL_MAX; + cBBox.resy = DBL_MAX; +} + +r_Conv_DEM::r_Conv_DEM(const char* source, const r_Minterval& lengthordomain, const r_Type* tp) throw(r_Error) + : r_Convertor(source, lengthordomain, tp, true) +{ + initGeoBBox(collBBox); +} + +r_Conv_DEM::r_Conv_DEM(const char* source, const r_Minterval& lengthordomain, int tp) throw(r_Error) + : r_Convertor(source, lengthordomain, tp) +{ + initGeoBBox(collBBox); +} + +bool +r_Conv_DEM::decodeOptions(const char* options, + r_GeoBBox& cBBox) throw() +{ + RMInit::logOut << "r_Conv_DEM::decodeOptions(" << (options?options:"NULL") << ")" << endl; + + r_Parse_Params parseParams; + + initGeoBBox(cBBox); + + parseParams.add(paramFlipX, &cBBox.flipx, r_Parse_Params::param_type_int); + parseParams.add(paramFlipY, &cBBox.flipy, r_Parse_Params::param_type_int); + parseParams.add(paramStartX, &cBBox.startx, r_Parse_Params::param_type_double); + parseParams.add(paramEndX, &cBBox.endx, r_Parse_Params::param_type_double); + parseParams.add(paramResX, &cBBox.resx, r_Parse_Params::param_type_double); + parseParams.add(paramStartY, &cBBox.starty, r_Parse_Params::param_type_double); + parseParams.add(paramEndY, &cBBox.endy, r_Parse_Params::param_type_double); + parseParams.add(paramResY, &cBBox.resy, r_Parse_Params::param_type_double); + + //process options + r_Long processRet=parseParams.process(options); + if(processRet < paramMin) + { + RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Error: Some required options are missing!" << endl; + return false; + } + + //check if start,res,end are present + if(cBBox.startx == DBL_MAX) + { + RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Error: startx is not present!" << endl; + return false; + } + + if(cBBox.starty == DBL_MAX) + { + RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Error: starty is not present!" << endl; + return false; + } + + if(cBBox.endx == DBL_MAX) + { + RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Error: endx is not present!" << endl; + return false; + } + + if(cBBox.endy == DBL_MAX) + { + RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Error: endy is not present!" << endl; + return false; + } + + if(cBBox.resx == DBL_MAX) + { + RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Error: resx is not present!" << endl; + return false; + } + + if(cBBox.resy == DBL_MAX) + { + RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Error: resy is not present!" << endl; + return false; + } + + + //check res + if(!cBBox.resx) + { + RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Error: resx is zero!" << endl; + return false; + } + + if(!cBBox.resy) + { + RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Error: resy is zero!" << endl; + return false; + } + + //check start >= end + if(cBBox.startx >= cBBox.endx ) + { + RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Error: startx >= endx!" << endl; + return false; + } + + if(cBBox.starty >= cBBox.endy) + { + RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Erorr: starty >= endy!" << endl; + return false; + } + + //show parsed options + RMInit::logOut.setf(std::ios::fixed); + RMInit::logOut << "r_Conv_DEM::decodeOptions(...) parsed options:" << endl + << " " << paramFlipX << paramEq << cBBox.flipx + << " " << paramFlipY << paramEq << cBBox.flipy << endl + << " " << paramStartX << paramEq << cBBox.startx + << " " << paramEndX << paramEq << cBBox.endx + << " " << paramResX << paramEq << cBBox.resx << endl + << " " << paramStartY << paramEq << cBBox.starty + << " " << paramEndY << paramEq << cBBox.endy + << " " << paramResY << paramEq << cBBox.resy << endl; + return true; +} + +string +r_Conv_DEM::encodeOptions(const r_GeoBBox& cBBox) throw() +{ + std::ostringstream os; + + os.str(""); + os.setf(std::ios::fixed); + os << paramFlipX << paramEq << cBBox.flipx + << paramSep << paramFlipY << paramEq << cBBox.flipy + << paramSep << paramStartX << paramEq << cBBox.startx + << paramSep << paramEndX << paramEq << cBBox.endx + << paramSep << paramResX << paramEq << cBBox.resx + << paramSep << paramStartY << paramEq << cBBox.starty + << paramSep << paramEndY << paramEq << cBBox.endy + << paramSep << paramResY << paramEq << cBBox.resy; + + RMInit::logOut << "r_Conv_DEM::encodeOptions(" << os.str() << ")" << endl; + + return os.str(); +} + +void +r_Conv_DEM::checkLimits() throw(r_Error) +{ + //show processed data + RMInit::logOut << "r_Conv_DEM::checkLimits() processed data:" << endl + << " minx=" << min.x << " miny=" << min.y << " minh=" << min.h << endl + << " maxx=" << max.x << " maxy=" << max.y << " maxh=" << max.h << endl; + // printf( "r_Conv_DEM::checkLimits() processed data: minx=%8G, miny=%8G, minh=%8G, maxx=%8G, maxy=%8G, maxh=%8G\n", min.x, min.y, min.h, max.x, max.y, max.h ); + + if(collBBox.startx > min.x) + { + RMInit::logOut << "r_Conv_DEM::checkLimits() startx( " << collBBox.startx << ") > min.x (" << min.x << " )!" << endl; + throw r_Error(); + } + if(collBBox.endx < max.x) + { + RMInit::logOut << "r_Conv_DEM::checkLimits() endx( " << collBBox.endx << ") < max.x (" << max.x << " )!" << endl; + throw r_Error(); + } + + if(collBBox.starty > min.y) + { + RMInit::logOut << "r_Conv_DEM::checkLimits() starty( " << collBBox.starty << ") > min.y (" << min.y << " )!" << endl; + throw r_Error(); + } + + if(collBBox.endy < max.y) + { + RMInit::logOut << "r_Conv_DEM::checkLimits() endy( " << collBBox.endy << ") < max.y (" << max.y << " )!" << endl; + throw r_Error(); + } +} + +void +r_Conv_DEM::readFromSrcStream() throw(r_Error) +{ + istrstream iFile(desc.src, desc.srcInterv[0].get_extent()); + string currStrRow; + r_Long rowNo=0; + r_Double noResx, noResy; + DEMRow currRow, prevRow; + + min.x=min.y=min.h=DBL_MAX; + max.x=max.y=max.h=-DBL_MAX; + demRows.clear(); + + //process the lines + while(!iFile.eof()) + { + getline(iFile, currStrRow); + rowNo++; + if(currStrRow.empty()) + { + // TALK( "r_Conv_DEM::readFromSrcStream() skipping empty line " << rowNo ); + continue; + } + else + { + // have an input stream for analysing the current line + // (declaring this variable here allows to have a fresh one; + // had a reentrance problem with followup lines -- PB 2005-sep-08) + istringstream icurrRow; + icurrRow.str(currStrRow); + + //decode x + icurrRow >> currRow.x; + if(!icurrRow) + { + RMInit::logOut << "Error in r_Conv_DEM::readFromSrcStream():: unable to decode x in line " << rowNo << ", skipping line: " << currStrRow << endl; + continue; + } + + //decode y + icurrRow >> currRow.y; + if(!icurrRow) + { + RMInit::logOut << "Error in r_Conv_DEM::readFromSrcStream():: unable to decode y in line " << rowNo << ", skipping line: " << currStrRow << endl; + continue; + } + + //decode h + icurrRow >> currRow.h; + if(!icurrRow) + { + RMInit::logOut << "Error in r_Conv_DEM::readFromSrcStream():: unable to decode h in line " << rowNo << ", skipping line: " << currStrRow << endl; + continue; + } + + //update to support NULL value: 0. (real value) goes in FLT_MIN(db value) + //because 0.(db value) represent NULL(real value). When we do export we skip NULL values. + if(currRow.h == ZERO_DEM) + currRow.h=ZERO_DB; + + //FIXME we ignore this check, because it may happen to have a incomplet dem + /* + //check if we have resx, resy + noResx=currRow.x/collBBox.resx; + if((currRow.x - noResx*collBBox.resx) > 0.) + { + RMInit::logOut << "r_Conv_DEM::readFromSrcStream() resolution for x on line " << + rowNo << " is not " << collBBox.resx << " !" << endl; + throw r_Error(); + } + noResy=currRow.y/collBBox.resy; + if((currRow.y - noResy*collBBox.resy) > 0.) + { + RMInit::logOut << "r_Conv_DEM::readFromSrcStream() resolution for y on line " << + rowNo << " is not " << collBBox.resy << " !" << endl; + throw r_Error(); + } + */ + + //compute min, max for x,y,z + min.x=std::min<r_Double>(min.x, currRow.x); + min.y=std::min<r_Double>(min.y, currRow.y); + min.h=std::min<r_Double>(min.h, currRow.h); + max.x=std::max<r_Double>(max.x, currRow.x); + max.y=std::max<r_Double>(max.y, currRow.y); + max.h=std::max<r_Double>(max.h, currRow.h); + + //store currRow + demRows.push_back(currRow); + }//end if(currStrRow.empty()) + + }//end reading src stream + + if(demRows.empty()) + { + // TALK( "r_Conv_DEM::readFromSrcStream() desc.src stream empty." ); + throw r_Error(); + } + + // std::cout << "r_Conv_DEM::readFromSrcStream(): x=" << min.x << ":" << max.x << ", y=" << min.y << ":" << max.y << endl; + + //check limits + checkLimits(); +} + + +void +r_Conv_DEM::readToSrcStream() throw(r_Error) +{ + r_Long x=0, y=0; + r_Long xlow=0, ylow=0; + r_Long xhigh=0, yhigh=0; + DEMRow currRow; + r_Bytes typeSize=0; + r_Long offset=0; + char* buffer=NULL; + + //initialize + xlow=desc.srcInterv[0].low(); + ylow=desc.srcInterv[1].low(); + + xhigh=desc.srcInterv[0].high(); + yhigh=desc.srcInterv[1].high(); + + //compute min & max + if (collBBox.flipx) + { + min.x=collBBox.endx - xhigh*collBBox.resx; + max.x=collBBox.endx - xlow*collBBox.resx; + } + else + { + min.x=collBBox.startx + xlow*collBBox.resx; + max.x=collBBox.startx + xhigh*collBBox.resx; + } + + if(collBBox.flipy) + { + min.y=collBBox.endy - yhigh*collBBox.resy; + max.y=collBBox.endy - ylow*collBBox.resy; + } + else + { + min.y=collBBox.starty + ylow*collBBox.resy; + max.y=collBBox.starty + yhigh*collBBox.resy; + } + + min.h=DBL_MAX; + max.h=-DBL_MAX; + + //check limits + checkLimits(); + + //prepare container + demRows.clear(); + typeSize=((r_Primitive_Type*)desc.srcType)->size(); + buffer=new char[typeSize]; + if(!buffer) + { + RMInit::logOut << "r_Conv_DEM::readToSrcStream() unable to claim memory !" << endl; + throw r_Ememory_allocation(); + } + for(y=ylow; y<=yhigh; y++) + { + if(collBBox.flipy) + currRow.y=collBBox.endy - y*collBBox.resy; + else + currRow.y=collBBox.starty + y*collBBox.resy; + + for(x=xlow; x<=xhigh; x++) + { + if(collBBox.flipx) + currRow.x=collBBox.endx - x*collBBox.resx; + else + currRow.x=collBBox.startx + x*collBBox.resx; + offset=desc.srcInterv.cell_offset(r_Point(x,y))*typeSize; + memcpy(buffer, &desc.src[offset], typeSize); + + switch(desc.srcType->type_id()) + { + case r_Type::BOOL: + currRow.h=((r_Primitive_Type*)desc.srcType)->get_boolean(buffer); + break; + case r_Type::CHAR: + currRow.h=((r_Primitive_Type*)desc.srcType)->get_char(buffer); + break; + case r_Type::OCTET: + currRow.h=((r_Primitive_Type*)desc.srcType)->get_octet(buffer); + break; + case r_Type::SHORT: + currRow.h=((r_Primitive_Type*)desc.srcType)->get_short(buffer); + break; + case r_Type::USHORT: + currRow.h=((r_Primitive_Type*)desc.srcType)->get_ushort(buffer); + break; + case r_Type::LONG: + currRow.h=((r_Primitive_Type*)desc.srcType)->get_long(buffer); + break; + case r_Type::ULONG: + currRow.h=((r_Primitive_Type*)desc.srcType)->get_ulong(buffer); + break; + case r_Type::FLOAT: + currRow.h=((r_Primitive_Type*)desc.srcType)->get_float(buffer); + break; + case r_Type::DOUBLE: + currRow.h=((r_Primitive_Type*)desc.srcType)->get_double(buffer); + break; + default: + //write message to log + RMInit::logOut << "r_Conv_DEM::readToSrcStream() srcType (" << desc.srcType->type_id() << ") unsupported !" << endl; + //clean up + if(buffer) + { + delete[] buffer; + buffer=NULL; + } + //report error + throw r_Error(); + break; + } + min.h=std::min<r_Double>(min.h, currRow.h); + max.h=std::max<r_Double>(max.h, currRow.h); + demRows.push_back(currRow); + } + } + + //clean up + if(buffer) + { + delete[] buffer; + buffer=NULL; + } + + if(demRows.empty()) + { + RMInit::logOut << "r_Conv_DEM::readToSrcStream() src stream is empty !" << endl; + throw r_Error(); + } + + RMInit::logOut << "r_Conv_DEM::readToSrcStream() processed interval [" << xlow << ":" << xhigh << "," << ylow << ":" << yhigh << "]" << endl; +} + + +void +r_Conv_DEM::writeFromDestStream() throw(r_Error) +{ + DEMRowVec::const_iterator iter, iterEnd; + r_Long xdim, ydim, offset; + r_Point currPt(destIntervDim); + r_Bytes typeSize=0; + + + //FIXME here we should modify for other type support + if(desc.destType->type_id() != r_Type::DOUBLE) + { + RMInit::logOut << "r_Conv_DEM::writeFromDestStream() destType (" << desc.destType->type_id() + << ") is not " << r_Type::DOUBLE << " !" << endl; + throw r_Error(); + } + + xdim=desc.destInterv[0].get_extent(); + ydim=desc.destInterv[1].get_extent(); + iter=demRows.begin(); + iterEnd=demRows.end(); + typeSize=((r_Primitive_Type*)desc.destType)->size(); + + //FIXME correction for strange effect of r_Long cast with 1e-6 + while(iter != iterEnd) + { + if(collBBox.flipx) + currPt[0]=(collBBox.endx - iter->x)/collBBox.resx + 1e-6; + else + currPt[0]=(iter->x - collBBox.startx)/collBBox.resx + 1e-6; + if(collBBox.flipy) + currPt[1]=(collBBox.endy - iter->y)/collBBox.resy + 1e-6; + else + currPt[1]=(iter->y - collBBox.starty)/collBBox.resy + 1e-6; + ((r_Primitive_Type*)desc.destType)->set_double(&desc.dest[desc.destInterv.cell_offset(currPt)*typeSize], iter->h); + ++iter; + } + + RMInit::logOut << "r_Conv_DEM::writeFromDestStream() processed " << xdim << " x " << ydim << " elements." << endl; +} + +void +r_Conv_DEM::writeToDestStream(ofstream& oFile) throw(r_Error) +{ + DEMRowVec::const_iterator iter, iterEnd; + r_Double currH; + + if(!oFile.is_open()) + { + RMInit::logOut << "r_Conv_DEM::writeToDestStream() oFile is not opened !" << endl; + throw r_Error(); + } + oFile.setf(std::ios::fixed); + + iter=demRows.begin(); + iterEnd=demRows.end(); + while(iter != iterEnd) + { + //update to support NULL value: 0. (real value) goes in FLT_MIN(db value) + //because 0.(db value) represent NULL(real value). When we do export we skip NULL values. + currH = iter->h; + if(currH != NULL_DB) + { + //FIXME we have to implement different here when we change server scale algorithm + if(currH == ZERO_DB) + currH = ZERO_DEM; + oFile << iter->x << "\t" << iter->y << "\t" << currH << endl; + } + ++iter; + } +} + +r_convDesc& +r_Conv_DEM::convertFrom(const char* options) throw (r_Error) +{ + bool hasSrcType=true; + + RMInit::logOut << "r_Conv_DEM::convertFrom(" << (options?options:"NULL") << ")" << endl; + + if(!desc.srcType) + { + desc.srcType=get_external_type(desc.baseType); + hasSrcType=false; + } + + try + { + RMInit::logOut << "r_Conv_DEM::convertFrom(...) src interval=" << desc.srcInterv << endl; + RMInit::logOut << "r_Conv_DEM::convertFrom(...) src type=" << desc.srcType->type_id() << endl; + + //check options + if(!decodeOptions(options, collBBox)) + { + RMInit::logOut << "Error in r_Conv_DEM::convertFrom(): illegal option string: " << (options?options:"(null)") << endl; + throw r_Error(); + } + + //check desc.srcInterv.dimension + if(desc.srcInterv.dimension() != srcIntervDim) + { + RMInit::logOut << "r_Conv_DEM::convertFrom(" << (options?options:"NULL") + << ") desc.srcInterv dimension (" << desc.srcInterv.dimension() + << " != " << srcIntervDim << " !" << endl; + throw r_Error(); + } + + //check srcType + if(!desc.srcType->isPrimitiveType()) + { + RMInit::logOut << "r_Conv_DEM::convertFrom(" << (options?options:"NULL") + << ") desc.srcType (" << desc.srcType->type_id() + << ") not supported, only primitive types !" << endl; + throw r_Error(); + } + + if(desc.srcType->isComplexType()) + { + RMInit::logOut << "r_Conv_DEM::convertFrom(" << (options?options:"NULL") + << ") desc.srcType (" << desc.srcType->type_id() + << ") not supported !" << endl; + throw r_Error(); + } + + //read src stream + readFromSrcStream(); + + //convert from DEM to marray + //--computing the marray domain + desc.destInterv = r_Minterval(destIntervDim); + + //FIXME correction for strange efect of r_Long cast with 1e-6 + if(collBBox.flipx) + desc.destInterv << r_Sinterval((r_Long)((collBBox.endx - max.x)/collBBox.resx + 1e-6), + (r_Long)((collBBox.endx - min.x)/collBBox.resx + 1e-6)); + else + desc.destInterv << r_Sinterval((r_Long)((min.x - collBBox.startx)/collBBox.resx + 1e-6), + (r_Long)((max.x - collBBox.startx)/collBBox.resx + 1e-6)); + if(collBBox.flipy) + desc.destInterv << r_Sinterval((r_Long)((collBBox.endy - max.y)/collBBox.resy + 1e-6), + (r_Long)((collBBox.endy - min.y)/collBBox.resy + 1e-6)); + else + desc.destInterv << r_Sinterval((r_Long)((min.y - collBBox.starty)/collBBox.resy + 1e-6), + (r_Long)((max.y - collBBox.starty)/collBBox.resy + 1e-6)); + + RMInit::logOut << "r_Conv_DEM::convertFrom(...) dest interval=" << desc.destInterv << endl; + + //--creating the resulting type + desc.destType = new r_Primitive_Type("Double", r_Type::DOUBLE); + RMInit::logOut << "r_Conv_DEM::convertFrom(...) dest type=" << desc.destType->type_id() << endl; + + //--claim memory for result + desc.dest = (char*)mystore.storage_alloc(desc.destInterv.cell_count() * ((r_Primitive_Type*)desc.destType)->size()); + if(desc.dest==NULL) + { + RMInit::logOut << "r_Conv_DEM::convertFrom(" << (options?options:"NULL") + << ") unable to claim memory !" << endl; + throw r_Ememory_allocation(); + } + memset(desc.dest, 0, desc.destInterv.cell_count() * ((r_Primitive_Type*)desc.destType)->size()); + + //--write parsed data in desc.dest + writeFromDestStream(); + } + catch(r_Error& err) + { + //cleanup + if(!hasSrcType) + { + delete desc.srcType; + desc.srcType=NULL; + } + + //desc.destType + if(desc.destType) + { + delete desc.destType; + desc.destType=NULL; + } + + //desc.dest + if(desc.dest) + { + mystore.storage_free(desc.dest); + desc.dest=NULL; + } + + //report error + throw; + } + + //cleanup + if(!hasSrcType) + { + delete desc.srcType; + desc.srcType=NULL; + } + + //return result + return desc; +} + + +r_convDesc& +r_Conv_DEM::convertTo(const char* options) throw (r_Error) +{ + bool hasSrcType=true; + + char* pTempFileName=NULL; // name of temp file + string tempFileName; // duplicate of temp file name -- heaven knows why + ofstream oFile; // for writing out file + FILE* pFile=NULL; // for reading back file + size_t lenFile=0; // size of file as read + + RMInit::logOut << "r_Conv_DEM::convertTo(" << (options?options:"NULL") << ")" << endl; + + try + { + if(!desc.srcType) + { + desc.srcType=get_external_type(desc.baseType); + hasSrcType=false; + } + + RMInit::logOut << "r_Conv_DEM::convertTo(...) src interval=" << desc.srcInterv << endl; + RMInit::logOut << "r_Conv_DEM::convertTo(...) src type=" << desc.srcType->type_id() << endl; + + //check options + if(!decodeOptions(options, collBBox)) + throw r_Error(); + + if(!desc.srcType->isPrimitiveType()) + { + RMInit::logOut << "r_Conv_DEM::convertTo(" << (options?options:"NULL") + << ") desc.srcType (" << desc.srcType->type_id() + << ") not supported, only primitive types !" << endl; + throw r_Error(); + } + if(desc.srcType->isComplexType()) + { + RMInit::logOut << "r_Conv_DEM::convertTo(" << (options?options:"NULL") + << ") desc.srcType (" << desc.srcType->type_id() + << ") not supported !" << endl; + throw r_Error(); + } + + //read src data + readToSrcStream(); + + //convert from marray to DEM; + //--create the temp file + //FIXME for multithread application + pTempFileName=tmpnam(NULL); + if(pTempFileName==NULL) + { + RMInit::logOut << "r_Conv_DEM::convertTo(" << (options?options:"NULL") + << ") desc.srcType (" << desc.srcType->type_id() + << ") unable to generate a tempory file !" << endl; + throw r_Error(); + } + + tempFileName=pTempFileName; + oFile.open(tempFileName.c_str()); + if(!oFile.is_open()) + { + RMInit::logOut << "r_Conv_DEM::convertTo(" << (options?options:"NULL") + << ") desc.srcType (" << desc.srcType->type_id() + << ") unable to open the tempory file !" << endl; + throw r_Error(); + } + + RMInit::logOut << "r_Conv_DEM::convertTo(...) temp file=" << tempFileName << endl; + + //--get DEM format + writeToDestStream(oFile); + oFile.close(); + + //--accessing the temp file + if ((pFile = fopen(tempFileName.c_str(), "rb")) == NULL) + { + RMInit::logOut << "r_Conv_DEM::convertTo(): unable to read back file." << endl; + throw r_Error(r_Error::r_Error_General); + } + fseek(pFile, 0, SEEK_END); + lenFile = ftell(pFile); + RMInit::logOut << "r_Conv_DEM::convertTo(...) dest len=" << lenFile << endl; + + if (!lenFile) + { + RMInit::logOut << "r_Conv_DEM::convertTo(): source contains only NULL values." << endl; + throw r_Error( E_DEM_EMPTY ); + } + + //--creating the resulting type + desc.destType = new r_Primitive_Type("Char", r_Type::CHAR); + + //--computing the marray domain + desc.destInterv = r_Minterval(srcIntervDim); + desc.destInterv << r_Sinterval((r_Long)0, (r_Long)lenFile - 1); + + RMInit::logOut << "r_Conv_DEM::convertTo(...) dest interval=" << desc.destInterv << endl; + RMInit::logOut << "r_Conv_DEM::convertTo(...) dest type=" << desc.destType->type_id() << endl; + + //--claim memory for desc.dest + desc.dest = (char*)mystore.storage_alloc(lenFile); + if(desc.dest==NULL) + { + RMInit::logOut << "r_Conv_DEM::convertTo(" << (options?options:"NULL") + << ") unable to claim memory !" << endl; + throw r_Ememory_allocation(); + } + memset(desc.dest, 0, lenFile); + + //--store data in desc.dest + fseek(pFile, 0, SEEK_SET); + fread(desc.dest, 1, lenFile, pFile); + + //clean up + fclose(pFile); + pFile=NULL; + remove(pTempFileName); + } + catch(r_Error& err) + { + //cleanup + if(!hasSrcType) + { + delete desc.srcType; + desc.srcType=NULL; + } + + //desc.destType + if(desc.destType) + { + delete desc.destType; + desc.destType=NULL; + } + + //desc.dest + if(desc.dest) + { + mystore.storage_free(desc.dest); + desc.dest=NULL; + } + + // close & remove file, if not done previously + fclose(pFile); + pFile=NULL; + remove(pTempFileName); + + //rethrow error + throw; + } + + //clean up + if(!hasSrcType) + { + delete desc.srcType; + desc.srcType=NULL; + } + + //return result + return desc; +} + +const char* +r_Conv_DEM::get_name() const throw() +{ + return get_name_from_data_format(r_DEM); +} + +r_Data_Format +r_Conv_DEM::get_data_format() const throw() +{ + return r_DEM; +} + +r_Convertor* +r_Conv_DEM::clone() const throw(r_Error) +{ + return new r_Conv_DEM(desc.src, desc.srcInterv, desc.srcType); +} diff --git a/conversion/dem.hh b/conversion/dem.hh new file mode 100644 index 0000000..ccfdbef --- /dev/null +++ b/conversion/dem.hh @@ -0,0 +1,187 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * INCLUDE: dem.hh + * + * MODULE: conversion + * + * CLASSES: r_Conv_DEM + * + * PURPOSE: + * Provides interface to convert data to other formats. + * + * COMMENTS: + * None +*/ + +#ifndef _R_CONV_DEM_HH_ +#define _R_CONV_DEM_HH_ + +#include <sstream> +#include <vector> +#include <string> +#include <cstdio> +using std::vector; +using std::ofstream; +using std::string; + +#include "conversion/convertor.hh" +#include "raslib/odmgtypes.hh" + +//@ManMemo: Module {\bf conversion} + +/*@Doc: + DEM convertor class. + + Supported parameters are + + \begin{tabular}{lcl} + {\tt flipx} && int && flip image flag on x axis, default 0\\ + {\tt flipy} && int && flip image flag on y axis, default 1\\ + {\tt startx} && double && start value on x axis \\ + {\tt endx} && double && end value on x axis \\ + {\tt resx} && double && resolution on x axis \\ + {\tt starty} && double && start value on y axis \\ + {\tt endy} && double && end value on y axis \\ + {\tt resy} && double && resolution on y axis \\ + \end{tabular} + + The "flipx" parameter is a flag for mirroring the image on x axis. + The "flipy" parameter is a flag for mirroring the image on y axis. + [startx:endx, starty:endy] represents the geographical bounding box + of the whole image. The corresponding pixel bounding box is calculated + as follows: + if flipy is disabled: + [(minx-startx)/resx:(maxx-startx)/resx, (miny-starty)/resy:(maxy-starty)/resy] + else + [(minx-startx)/resx:(maxx-startx)/resx, (endy-maxy)/resy:(endy-miny)/resy] + + if flipx is disabled: + [(minx-startx)/resx:(maxx-startx)/resx, (miny-starty)/resy:(maxy-starty)/resy] + else + [(endx-maxx)/resx:(endx-minx)/resx, (miny-starty)/resy:(maxy-starty)/resy] + + The pairs (startx, endx, resx), (starty, endy, resy) are for the whole image(e.g image bounding) + and the pairs (minx,maxx, resx), (miny, maxy, resy) are for the current part of image. + They are used to compute the position of current image in RasDaMan coordinates. +*/ + +// r_Error code for "empty DEM result generated"; this def should go into a central list +// -- PB 2003-dec-03 +#define E_DEM_EMPTY 3000 + +class r_Conv_DEM : public r_Convertor +{ + public: + // constants to handle NULL + static const r_Double NULL_DB; + static const r_Double ZERO_DB; + static const r_Double ZERO_DEM; + + //inner class for convertor parameters + class r_GeoBBox + { + public: + r_Double startx, endx, resx; + r_Double starty, endy, resy; + r_ULong flipy, flipx; + }; + + r_Conv_DEM(const char* source, const r_Minterval& lengthordomain, const r_Type* tp) throw(r_Error); + + r_Conv_DEM(const char* source, const r_Minterval& lengthordomain, int tp) throw(r_Error); + + r_convDesc& convertFrom(const char* options = NULL) throw (r_Error); + + r_convDesc& convertTo(const char* options = NULL) throw (r_Error); + + const char* get_name() const throw(); + + r_Data_Format get_data_format() const throw(); + + r_Convertor* clone() const throw(r_Error); + + /// dimension of src domain accepted as input in convertFrom + static const r_Dimension srcIntervDim; + + /// dimension of dest domain accepted as input in convertTo + static const r_Dimension destIntervDim; + + /// decode convertor options + static bool decodeOptions( const char* options, + r_GeoBBox& collBBox) throw(); + + /// encode convertor options + static string encodeOptions(const r_GeoBBox& collBBox) throw(); + + /// destructor + virtual ~r_Conv_DEM( void ); + + /// init convertor parameters to default value + static void initGeoBBox( r_GeoBBox& cBBox ); + + private: + + + /// check limits before converting + void checkLimits() throw(r_Error); + + ///i/o src/dest stream + void readFromSrcStream() throw(r_Error); + void readToSrcStream() throw(r_Error); + void writeFromDestStream() throw(r_Error); + void writeToDestStream(ofstream& oFile) throw(r_Error); + + /// parameters + r_GeoBBox collBBox; + + /// class constants + static const r_ULong paramMin; + static const char* paramSep; + static const char* paramEq; + static const char* paramFlipX; + static const char* paramFlipY; + static const char* paramStartX; + static const char* paramEndX; + static const char* paramResX; + static const char* paramStartY; + static const char* paramEndY; + static const char* paramResY; + + + /// internal data + class DEMRow + { + public: + r_Double x,y,h; + }; + + typedef vector<DEMRow> DEMRowVec; + + DEMRow min, max; + DEMRowVec demRows; + + }; + +#endif + diff --git a/conversion/des.cc b/conversion/des.cc new file mode 100644 index 0000000..a6d9843 --- /dev/null +++ b/conversion/des.cc @@ -0,0 +1,118 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +*/ + +#include <iostream> +#include <fstream> + +#include "des.h" +#include "nitf.h" +#include "utilities.h" + +using namespace std; +using namespace RasNITF; + +des::des(){ + + m_desshf = NULL; + m_desdata = NULL; + data_length = 0; + header_length = 0; +} + +des::~des(){ + + if(m_desshf != NULL){ + delete m_desshf; + m_desshf = NULL; + } + + if(m_desdata != NULL){ + delete m_desdata; + m_desdata = NULL; + } + +} + +int des::read_file(istream &hNITF, long desh_length, long des_length){ + + int charsread = 0; + + header_length=desh_length; + + charsread += read_verify2(hNITF, m_de, 2 + 25 + 2 + 167); + + //if TRE_OF read teh next two + if(strncmp(m_destag,"TRE_OVERFLOW",12)==0) { + charsread += read_verify2(hNITF, m_desoflw, 6+3); + } + + charsread += read_verify2(hNITF, m_desshl, 4); + n_desshl = charptrtolong(m_desshl,4); + + if (n_desshl > 0) { + m_desshf = new char[n_desshl]; + if(m_desshf == NULL) cerr<<"ERROR: could not allocate memory"; + charsread += read_verify2(hNITF, m_desshf, n_desshl); + } + + m_desdata = new char[des_length]; + charsread += read_verify2(hNITF, m_desdata, des_length); + data_length = des_length; + + return charsread; +} + +int des::write_file(ofstream &fNITF){ + + fNITF.write(m_de, 2); + fNITF.write(m_destag, 25); + fNITF.write(m_desver, 2); + fNITF.write(m_dessg, 167); + + if(strncmp(m_destag,"TRE_OVERFLOW",12)==0) { + fNITF.write(m_desoflw, 6); + fNITF.write(m_desitem, 3); + } + + fNITF.write( m_desshl, 4); + + if (n_desshl > 0) { + fNITF.write(m_desshf, n_desshl); + } + + if( m_desdata != NULL) { + fNITF.write( m_desdata, data_length); + } + + //TODO + return 0; + +} + +string des::get_ld() const { + return des_dl; +} + +string des::get_ldsh() const { + return des_hl; +} diff --git a/conversion/des.h b/conversion/des.h new file mode 100644 index 0000000..358ad5e --- /dev/null +++ b/conversion/des.h @@ -0,0 +1,67 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +*/ + + +#ifndef __RASNITF_DES_H +#define __RASNITF_DES_H + +#include <vector> +#include <iostream> +#include <fstream> + +namespace RasNITF +{ + +class des { + + char m_de[2]; + char m_destag[25]; + char m_desver[2]; + char m_dessg[167]; + char m_desoflw[6]; + char m_desitem[3]; + char m_desshl[4]; + char *m_desshf; + char *m_desdata; + + int header_length; + long n_desshl; + int data_length; + int des_header_length; + + std::string des_hl ; + std::string des_dl ; + + public: + + des(); + ~des(); + int read_file(std::istream &,long,long); + int write_file(std::ofstream &); + std::string get_ld() const; + std::string get_ldsh() const; + +}; + +} +#endif diff --git a/conversion/ecw.cc b/conversion/ecw.cc new file mode 100644 index 0000000..3035e28 --- /dev/null +++ b/conversion/ecw.cc @@ -0,0 +1,339 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +*/ + +#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); + } + diff --git a/conversion/ecw.hh b/conversion/ecw.hh new file mode 100644 index 0000000..d418809 --- /dev/null +++ b/conversion/ecw.hh @@ -0,0 +1,78 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * INCLUDE: ecw.hh + * + * MODULE: conversion + * + * CLASSES: r_Conv_ECW + * + * COMMENTS: + * Provides interface to convert data from ECW to r_Array + * +*/ + +#ifndef _R_CONV_ECW_HH_ +#define _R_CONV_ECW_HH_ +#include "conversion/convertor.hh" + +//@ManMemo: Module {\bf conversion} + +/*@Doc: + ECW convertor class. + + Supported parameters are + + \begin{tabular}{lcl} + {\tt windowx} && uint && maximum number of colums to convert in one ecw call, default 1000\\ + {\tt windowy} && uint && maximum number of lines to convert in one ecw call, default 1000\\ + \end{tabular} +*/ + + +class r_Conv_ECW : public r_Convertor + { + public: + r_Conv_ECW(const char* source, const r_Minterval& lengthordomain, const r_Type* tp) throw(r_Error); + + r_Conv_ECW(const char* source, const r_Minterval& lengthordomain, int tp) throw(r_Error); + + r_convDesc& convertFrom(const char* options = NULL) throw (r_Error); + + r_convDesc& convertTo(const char* options = NULL) throw (r_Error); + + const char* get_name() const; + + r_Data_Format get_data_format() const; + + r_Convertor* clone() const; + + + private: + void initECW(); + + }; + +#endif + + diff --git a/conversion/ecwmemfs.cc b/conversion/ecwmemfs.cc new file mode 100644 index 0000000..07357d6 --- /dev/null +++ b/conversion/ecwmemfs.cc @@ -0,0 +1,157 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +*/ + +#include "ecwmemfs.hh" +#include <fstream> +#include <algorithm> +#include "raslib/rminit.hh" +#include "raslib/rmdebug.hh" + +const char* +MemoryFileSystem::memorySrc = NULL; + +r_Bytes +MemoryFileSystem::memorySrcLength = 0; + +const char* +MemoryFileSystem::memorySrcName = "memory.src"; + +MemoryFileSystem::MemoryFileSystem() + : current(NULL), + source(NULL), + length(0), + closed(false), + owner(true) + { + RMDBGONCE(5, RMDebug::module_conversion, "MemoryFileSystem", "MemoryFileSystem()"); + } + +MemoryFileSystem::m_Error +MemoryFileSystem::open(const char* memorySource, r_Bytes mSize) + { + RMDBGONCE(5, RMDebug::module_conversion, "MemoryFileSystem", "open(source, " << mSize << ")"); + owner = false; + length = mSize; + source = (char*)memorySource; + current = source; + return No_Error; + } + +MemoryFileSystem::m_Error +MemoryFileSystem::open(const char* fileName) + { + owner = true; + RMDBGENTER(5, RMDebug::module_conversion, "MemoryFileSystem", "open(" << fileName << ")"); + if (fileName == memorySrcName) + { + MemoryFileSystem::m_Error err = open(memorySrc, memorySrcLength); + RMDBGEXIT(5, RMDebug::module_conversion, "MemoryFileSystem", "open(" << fileName << ") " << err); + return err; + } + else { + std::ifstream f; + f.open(fileName); + if (!f.is_open()) + { + RMInit::logOut << "MemoryFileSystem::open(" << fileName << ") could not open file" << std::endl; + RMDBGEXIT(5, RMDebug::module_conversion, "MemoryFileSystem", "open(" << fileName << ") " << Error); + return Error; + } + f.seekg(0, std::ios::end); + std::ios::pos_type end = f.tellg(); + RMDBGMIDDLE(5, RMDebug::module_conversion, "MemoryFileSystem", "size " << end); + length = end; + source = new char[end]; + current = source; + memset(source, 0, end); + f.seekg(0, std::ios::beg); + f.read(source, end); + f.close(); + RMDBGEXIT(5, RMDebug::module_conversion, "MemoryFileSystem", "open(" << fileName << ") " << No_Error); + return No_Error; + } + } + +MemoryFileSystem::m_Error +MemoryFileSystem::close() + { + RMDBGENTER(5, RMDebug::module_conversion, "MemoryFileSystem", "close()"); + if (!closed) + { + if (owner) + { + delete [] source; + } + source = NULL; + current = NULL; + length = 0; + RMDBGEXIT(5, RMDebug::module_conversion, "MemoryFileSystem", "close() " << No_Error); + return No_Error; + } + else { + RMDBGEXIT(5, RMDebug::module_conversion, "MemoryFileSystem", "close() " << Error); + return Error; + } + } + +MemoryFileSystem::~MemoryFileSystem() + { + RMDBGONCE(5, RMDebug::module_conversion, "MemoryFileSystem", "~MemoryFileSystem()"); + close(); + } + +MemoryFileSystem::m_Error +MemoryFileSystem::read(void* buffer, r_Bytes bSize) + { + RMDBGENTER(5, RMDebug::module_conversion, "MemoryFileSystem", "read(buffer, " << bSize << ")"); + bSize = std::min(bSize, length - (current - source)); + RMDBGMIDDLE(5, RMDebug::module_conversion, "MemoryFileSystem", "reading " << bSize); + memcpy(buffer, current, bSize); + current += bSize; + RMDBGEXIT(5, RMDebug::module_conversion, "MemoryFileSystem", "read(buffer, " << bSize << ") " << No_Error); + return No_Error; + } + +unsigned long long +MemoryFileSystem::tell() + { + RMDBGONCE(5, RMDebug::module_conversion, "MemoryFileSystem", "tell() " << (current - source)); + return current - source; + } + +MemoryFileSystem::m_Error +MemoryFileSystem::seek(unsigned long long offset) + { + RMDBGENTER(5, RMDebug::module_conversion, "MemoryFileSystem", "seek(" << offset << ")"); + if (offset > length) + { + RMDBGEXIT(5, RMDebug::module_conversion, "MemoryFileSystem", "seek(" << offset << ") (length " << length << ") " << Error); + return Error; + } + else { + current = offset + source; + RMDBGEXIT(5, RMDebug::module_conversion, "MemoryFileSystem", "seek(" << offset << ") " << No_Error); + return No_Error; + } + } + diff --git a/conversion/ecwmemfs.hh b/conversion/ecwmemfs.hh new file mode 100644 index 0000000..f61ed10 --- /dev/null +++ b/conversion/ecwmemfs.hh @@ -0,0 +1,84 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +*/ + +#ifndef _ECWMEMFS_HH_ +#define _ECWMEMFS_HH_ + +#include "raslib/mddtypes.hh" + +class MemoryFileSystem + { + public: + enum m_Error + { + No_Error = 0, + Error = 1 + }; + + MemoryFileSystem(); + + ///open file an read into memory - completely + m_Error open(const char* fileName); + + ///use this memory chunk with mSize bytes length + m_Error open(const char* memorySource, r_Bytes mSize); + + ///close and deinitialise (delete only my own data) + m_Error close(); + + ///call close + ~MemoryFileSystem(); + + ///read bSize bytes into buffer, only if bSize bytes are available + m_Error read(void* buffer, r_Bytes bSize); + + ///get current position + unsigned long long tell(); + + ///go to offset bytes from begining of memory + m_Error seek(unsigned long long offset); + + ///if you use open(const* char) and the pointer is memorySrcName then no file will be read but this pointer + static const char* memorySrc; + + ///file names which point to this will not read from file system but from memorySrc + static const char* memorySrcName; + + ///the length of the memorySrc chunk must be specified in memoryLength + static r_Bytes memorySrcLength; + + private: + + ///my memory block + char* source; + ///my current position + char* current; + ///am i closed + bool closed; + ///do i own my memory data + bool owner; + ///how long is my memory data + r_Bytes length; + }; + +#endif diff --git a/conversion/graphic.cc b/conversion/graphic.cc new file mode 100644 index 0000000..1ba5bda --- /dev/null +++ b/conversion/graphic.cc @@ -0,0 +1,148 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +*/ + +#include <iostream> +#include <fstream> +#include <cstring> + +#include "graphic.h" +#include "nitf.h" +#include "utilities.h" + +using namespace std; +using namespace RasNITF; + +graphic::graphic() +{ + m_graphic_data = NULL; + m_sxshd = NULL; +} + +graphic::~graphic() +{ + if(m_graphic_data != NULL) + delete m_graphic_data; + m_graphic_data = NULL; + + if(m_sxshd != NULL) + delete m_sxshd; + m_sxshd = NULL; + +} + +int graphic::read_file(istream &hNITF, long gh_length, long graph_length) +{ + int charsread = 0; + long start_position = 0; + + header_length = gh_length; + + // here find where are we relative to the begining + start_position = hNITF.tellg(); + + // here read the header data + charsread += read_verify2(hNITF,m_sy, 2+10+20+1+2+11+2+20+2+8+4+1+8+43+1+40+1+8+15+1+1+13+3+3+10+10+1+10+2); + + charsread += read_verify2(hNITF, m_sxshdl, 5); + + n_sxshdl = charptrtolong(m_sxshdl, 5); + + if (n_sxshdl > 0) { + n_sxshdl -= 3; + read_verify2(hNITF, m_sxsofl, 3); + m_sxshd = new char[n_sxshdl - 3]; + if(m_sxshd == NULL) cerr<<"ERROR: could not allocate memory"; + read_verify2(hNITF, m_sxshd, n_sxshdl); + n_sxshdl += 3; + + } + + // check if we are where we should be + + if( ((long)hNITF.tellg()) != (start_position + gh_length)) { + cerr << "Error in graph.cpp"; + exit(2); + } + + // store the text data + + m_graphic_data = new char[graph_length]; + if(m_graphic_data == NULL) cerr<<"ERROR: could not allocate memory"; + data_length = read_verify2(hNITF, m_graphic_data, graph_length); + return charsread; +} + +int graphic::write_file(ofstream &fNITF){ + + fNITF.write( m_sy, 2); + fNITF.write( m_sid, 10); + fNITF.write( m_sname, 20); + fNITF.write( m_ssclas, 1); + fNITF.write( m_ssclsy, 2); + fNITF.write( m_sscode, 11); + fNITF.write( m_ssctlh, 2); + fNITF.write( m_ssrel, 20); + fNITF.write( m_ssdctp, 2); + fNITF.write( m_ssdcdt, 8); + fNITF.write( m_ssdcxm, 4); + fNITF.write( m_ssdg, 1); + fNITF.write( m_ssdgdt, 8); + fNITF.write( m_sscltx, 43); + fNITF.write( m_sscatp, 1); + fNITF.write( m_sscaut, 40); + fNITF.write( m_sscrsn, 1); + fNITF.write( m_sssrdt, 8); + fNITF.write( m_ssctln, 15); + fNITF.write( m_encryp, 1); + fNITF.write( m_stype, 1); + fNITF.write( m_sres1, 13); + fNITF.write( m_sdlvl, 3); + fNITF.write( m_salvl, 3); + fNITF.write( m_sloc, 10); + fNITF.write( m_sbnd1, 10); + fNITF.write( m_scolor, 1); + fNITF.write( m_sbnd2, 10); + fNITF.write( m_sres2, 2); + fNITF.write(m_sxshdl, 5); + + if (n_sxshdl > 0) { + fNITF.write(m_sxsofl, 3); + fNITF.write(m_sxshd, n_sxshdl - 3); + } + + if( m_graphic_data != NULL) { + fNITF.write( m_graphic_data, data_length); + } + + //TODO change to charswritten + return 0; + +} + +string graphic::get_ls() { + return graphic_dl; +} + +string graphic::get_lssh() { + return graphic_hl; +} diff --git a/conversion/graphic.h b/conversion/graphic.h new file mode 100644 index 0000000..e1662e2 --- /dev/null +++ b/conversion/graphic.h @@ -0,0 +1,90 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +*/ + + +#ifndef __GRAPHIC_H_INCLUDED +#define __GRAPHIC_H_INCLUDED + +#include<vector> +#include<iostream> +#include<fstream> + +namespace RasNITF +{ + +class graphic{ + private: + char m_sy[2]; + char m_sid[10]; + char m_sname[20]; + char m_ssclas[1]; + char m_ssclsy[2]; + char m_sscode[11]; + char m_ssctlh[2]; + char m_ssrel[20]; + char m_ssdctp[2]; + char m_ssdcdt[8]; + char m_ssdcxm[4]; + char m_ssdg[1]; + char m_ssdgdt[8]; + char m_sscltx[43]; + char m_sscatp[1]; + char m_sscaut[40]; + char m_sscrsn[1]; + char m_sssrdt[8]; + char m_ssctln[15]; + char m_encryp[1]; + char m_stype[1]; + char m_sres1[13]; + char m_sdlvl[3]; + char m_salvl[3]; + char m_sloc[10]; + char m_sbnd1[10]; + char m_scolor[1]; + char m_sbnd2[10]; + char m_sres2[2]; + char m_sxshdl[5]; + char m_sxsofl[3]; + char* m_sxshd; + char *m_graphic_data; + + int header_length; + int data_length; + int n_sxshdl; + int n_sxsofl; + + std::string graphic_hl ; + std::string graphic_dl ; + + public: + graphic(); + ~graphic(); + int read_file(std::istream&, long, long); + int write_file(std::ofstream &); + std::string get_ls(); + std::string get_lssh(); +}; + +} + +#endif diff --git a/conversion/hdf.cc b/conversion/hdf.cc new file mode 100644 index 0000000..5effb10 --- /dev/null +++ b/conversion/hdf.cc @@ -0,0 +1,386 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * SOURCE: hdf.cc + * + * MODULE: conversion + * + * CLASSES: r_Conv_HDF + * + * COMMENTS: + * + * Provides functions to convert data to HDF SD and back. + * +*/ + +/* Added by Sorin Stancu-Mara. Definition clashed for type int8, define in both +* /usr/include/hdf.h and in /usr/include/tiff.h +* This will supress the tiff.h definition. +* Both definitions are similar +*/ +#define HAVE_INT8 + +#include "conversion/hdf.hh" +#include "raslib/error.hh" +#include "raslib/rminit.hh" +#include "raslib/parseparams.hh" +#include "raslib/primitivetype.hh" + + +#ifdef HAVE_HDF_H + #include "hdf.h" +#elif HAVE_HDF_HDF_H + #include "hdf/hdf.h" +#else + #error "No hdf.h header available." +#endif + +#ifdef HAVE_MFHDF_H + #include "mfhdf.h" +#elif HAVE_HDF_MFHDF_H + #include "hdf/mfhdf.h" +#else + #error "No mfhdf.h header available." +#endif + +#include <stdio.h> +#include <iostream> + + + +const r_Convertor::convert_string_t r_Conv_HDF::compNames[] = { + {"none", COMP_CODE_NONE}, + {"rle", COMP_CODE_RLE}, + {"huffman", COMP_CODE_SKPHUFF}, + {"deflate", COMP_CODE_DEFLATE}, + {NULL, COMP_CODE_NONE} +}; + +// Buffer used for switching the majorness (column <--> row) of the array data +const int r_Conv_HDF::MaxSwapBufferSize = 0x10000; + + + + +void r_Conv_HDF::initHDF( void ) +{ + compType = NULL; + quality = 80; + skiphuff = 0; + + if (params == NULL) + params = new r_Parse_Params; + + params->add("comptype", &compType, r_Parse_Params::param_type_string); + params->add("quality", &quality, r_Parse_Params::param_type_int); + params->add("skiphuff", &skiphuff, r_Parse_Params::param_type_int); +} + + +int r_Conv_HDF::getHDFtype(int intType, int &size) +{ + int result=0; + + switch (intType) + { + case ctype_int8: result = DFNT_CHAR8; size = 1; break; + case ctype_uint8: + case ctype_char: + case ctype_bool: result = DFNT_UCHAR8; size = 1; break; + case ctype_int16: result = DFNT_INT16; size = 2; break; + case ctype_uint16: result = DFNT_UINT16; size = 2; break; + case ctype_int32: result = DFNT_INT32; size = 4; break; + case ctype_uint32: result = DFNT_UINT32; size = 4; break; + case ctype_int64: result = DFNT_INT64; size = 8; break; + case ctype_uint64: result = DFNT_UINT64; size = 8; break; + case ctype_float32: result = DFNT_FLOAT32; size = 4; break; + case ctype_float64: result = DFNT_FLOAT64; size = 8; break; + default: result = 0; size = 1; break; + } + return result; +} + + +int r_Conv_HDF::getIntType( int hdfType, int &size ) +{ + int result=0; + + switch (hdfType) + { + case DFNT_CHAR8: result = ctype_int8; size = 1; break; + case DFNT_UCHAR8: result = ctype_uint8; size = 1; break; + case DFNT_INT16: result = ctype_int16; size = 2; break; + case DFNT_UINT16: result = ctype_uint16; size = 2; break; + case DFNT_INT32: result = ctype_int32; size = 4; break; + case DFNT_UINT32: result = ctype_uint32; size = 4; break; + case DFNT_INT64: result = ctype_int64; size = 8; break; + case DFNT_UINT64: result = ctype_uint64; size = 8; break; + case DFNT_FLOAT32: result = ctype_float32; size = 4; break; + case DFNT_FLOAT64: result = ctype_float64; size = 8; break; + default: result = ctype_void; size = 1; break; + } + return result; +} + + + +r_Conv_HDF::r_Conv_HDF(const char *src, const r_Minterval &interv, const r_Type *tp) throw(r_Error) +: r_Convertor(src, interv, tp, true) +{ + initHDF(); + + if (tp->isStructType()) + { + RMInit::logOut << "r_Conv_HDF::r_Conv_HDF(): structured types not supported." << endl; + throw r_Error(r_Error::r_Error_General); + } +} + + + +r_Conv_HDF::r_Conv_HDF(const char *src, const r_Minterval &interv, int tp) throw(r_Error) +: r_Convertor(src, interv, tp) +{ + initHDF(); +} + + + +r_Conv_HDF::~r_Conv_HDF(void) +{ + if (compType != NULL) + { + delete [] compType; + compType = NULL; + } +} + + + +r_convDesc &r_Conv_HDF::convertTo( const char *options ) throw(r_Error) +{ + char name[256]; + int32 handle=0, sds_id=0, rank=0; + comp_coder_t comp_type=COMP_CODE_NONE; + int32 *dimsizes=NULL, *start=NULL; + size_t filesize=0; + int i=0, j=0; + FILE *fp=NULL; + comp_info c_info; + + strncpy(name, tmpnam(NULL), 256); + //name = "testfile.hdf"; + + if ((handle = SDstart(name, DFACC_CREATE)) == FAIL) + { + RMInit::logOut << "r_Conv_HDF::convertTo(): unable to open output file." << endl; + throw r_Error(r_Error::r_Error_General); + } + rank = desc.srcInterv.dimension(); + + dimsizes = new int32[rank]; start = new int32[rank]; + datatype = getHDFtype(desc.baseType, datasize); + + for (i=0; i<rank; i++) + { + dimsizes[i] = desc.srcInterv[i].high() - desc.srcInterv[i].low() + 1; + start[i] = 0; + } + + if ((sds_id = SDcreate(handle, "RasDaMan object", datatype, rank, dimsizes)) == FAIL) + { + RMInit::logOut << "r_Conv_HDF::convertTo(): unable to create object." << endl; + SDend(handle); remove(name); + throw r_Error(r_Error::r_Error_General); + } + SDsetfillmode(sds_id, SD_NOFILL); + + params->process(options); + + comp_type = COMP_CODE_DEFLATE; + if (compType != NULL) + { + for (i=0; compNames[i].key != NULL; i++) + { + if (strcasecmp(compNames[i].key, compType) == 0) + { + comp_type = (comp_coder_t)compNames[i].id; + break; + } + } + if (compNames[i].key == NULL) + { + RMInit::logOut << "r_Conv_HDF::convertTo(): unsupported compression type " << compType << endl; + } + } + c_info.skphuff.skp_size = skiphuff; + c_info.deflate.level = quality; + + SDsetcompress(sds_id, comp_type, &c_info); + + SDwritedata(sds_id, start, NULL, dimsizes, (VOIDP)(desc.src)); + + delete [] dimsizes; dimsizes=NULL; + delete [] start; start=NULL; + + SDendaccess(sds_id); + + SDend(handle); + + if ((fp = fopen(name, "rb")) == NULL) + { + RMInit::logOut << "r_Conv_HDF::convertTo(): unable to read back file." << endl; + throw r_Error(r_Error::r_Error_General); + } + fseek(fp, 0, SEEK_END); + filesize = ftell(fp); + + desc.destInterv = r_Minterval(1); + desc.destInterv << r_Sinterval((r_Range)0, (r_Range)filesize - 1); + + if ((desc.dest = (char*)mystore.storage_alloc(filesize)) == NULL) + { + RMInit::logOut << "r_Conv_HDF::convertTo(): out of memory error" << endl; + fclose(fp); + throw r_Error(MEMMORYALLOCATIONERROR); + } + fseek(fp, 0, SEEK_SET); + fread(desc.dest, 1, filesize, fp); + + fclose(fp); + + remove(name); + + // Result is just a bytestream + desc.destType = r_Type::get_any_type("char"); + + return desc; +} + + + +r_convDesc &r_Conv_HDF::convertFrom(const char *options) throw(r_Error) +{ + char name[256]; + int32 handle=0, sds_id=0, rank=0, dtype=0, numattr=0, array_size=0; + int32 dimsizes[MAX_VAR_DIMS]; + int32 *start=NULL; + int dsize=0; + size_t filesize=0; + FILE *fp=NULL; + int i=0; + + if (desc.srcInterv.dimension() != 1) + { + RMInit::logOut << "r_Conv_HDF::convertFrom(): source data must be a bytestream!" << endl; + throw r_Error(r_Error::r_Error_General); + } + + strncpy(name, tmpnam(NULL), 256); + if ((fp = fopen(name, "wb")) == NULL) + { + RMInit::logOut << "r_Conv_HDF::convertFrom(): unable to write temporary file!" << endl; + throw r_Error(r_Error::r_Error_General); + } + filesize = desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1; + if ((i = fwrite(desc.src, 1, filesize, fp)) != filesize) + { + RMInit::logOut << "r_Conv_HDF::convertFrom(): error writing to temporary file (" + << i << " / " << filesize << ')' << endl; + throw r_Error(r_Error::r_Error_General); + } + fclose(fp); + + if ((handle = SDstart(name, DFACC_READ)) == FAIL) + { + RMInit::logOut << "r_Conv_HDF::convertFrom(): can't read temporary file!" << endl; + throw r_Error(r_Error::r_Error_General); + } + // Only read the first object in the file + if ((sds_id = SDselect(handle, 0)) == FAIL) + { + RMInit::logOut << "r_Conv_HDF::convertFrom(): unable to open first object" << endl; + SDend(handle); remove(name); + throw r_Error(r_Error::r_Error_General); + } + + SDgetinfo(sds_id, NULL, &rank, dimsizes, &dtype, &numattr); + + // Ignore native datatype flag + dtype &= ~DFNT_NATIVE; + + desc.destType = get_external_type(getIntType(dtype, dsize)); + + start = new int32[rank]; + desc.destInterv = r_Minterval(rank); + array_size = (int32)dsize; + for (i=0; i<rank; i++) + { + desc.destInterv << r_Sinterval(r_Range(0), r_Range(dimsizes[i]-1)); + array_size *= dimsizes[i]; + start[i] = 0; + } + + if ((desc.dest = (char*)mystore.storage_alloc(array_size)) == NULL) + { + RMInit::logOut << "r_Conv_HDF::convertFrom(): out of memory error!" << endl; + SDend(handle); remove(name); + throw r_Error(MEMMORYALLOCATIONERROR); + } + + if (SDreaddata(sds_id, start, NULL, dimsizes, (VOIDP)desc.dest) == FAIL) + { + RMInit::logOut << "r_Conv_HDF::convertFrom(): error reading data" << endl; + SDend(handle); remove(name); + throw r_Error(r_Error::r_Error_General); + } + + delete [] start; start=NULL; + + SDendaccess(sds_id); + + SDend(handle); + + remove(name); + + return desc; +} + + + +const char *r_Conv_HDF::get_name( void ) const +{ + return format_name_hdf; +} + + +r_Data_Format r_Conv_HDF::get_data_format( void ) const +{ + return r_HDF; +} + + +r_Convertor *r_Conv_HDF::clone( void ) const +{ + return new r_Conv_HDF(desc.src, desc.srcInterv, desc.baseType); +} diff --git a/conversion/hdf.hh b/conversion/hdf.hh new file mode 100644 index 0000000..0546811 --- /dev/null +++ b/conversion/hdf.hh @@ -0,0 +1,104 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * INCLUDE: hdf.hh + * + * MODULE: conversion + * + * CLASSES: r_Conv_HDF + * + * COMMENTS: + * + * Provides interface to convert data to other formats. + * +*/ + +#ifndef _R_CONV_HDF_HH_ +#define _R_CONV_HDF_HH_ + +#include "conversion/convertor.hh" + + +//@ManMemo: Module {\bf conversion} + +/*@Doc: + HDF convertor class. + + Supported parameters are + + \begin{tabular}{lcl} + comptype && string && the compression type to use (see below)\\ + quality && int && quality parameter for JPEG compression\\ + skiphuff && int && skipping parameter for Huffman coding\\ + \end{tabular} + + The compression type defaults to deflate but may be one of the + following + + \begin{tabular}{ll} + none && no compression\\ + rle && Run Length Coding\\ + huffman && Huffman coding\\ + deflate && ZIP deflate\\ + \end{tabular} + +*/ +class r_Conv_HDF : public r_Convertor +{ + public: + /// constructor using an r_Type object. Exception if the type isn't atomic. + r_Conv_HDF( const char *src, const r_Minterval &interv, const r_Type *tp) throw(r_Error); + /// constructor using convert_type_e shortcut + r_Conv_HDF( const char *src, const r_Minterval &interv, int tp ) throw(r_Error); + /// destructor + ~r_Conv_HDF( void ); + + /// convert to HDF + virtual r_convDesc &convertTo( const char *options=NULL ) throw(r_Error); + /// convert from HDF + virtual r_convDesc &convertFrom( const char *options=NULL ) throw(r_Error); + /// cloning + virtual r_Convertor *clone( void ) const; + /// identification + virtual const char *get_name( void ) const; + virtual r_Data_Format get_data_format( void ) const; + + + private: + /// init HDF module + void initHDF( void ); + /// translate an internal type into an HDF type and return the size. + static int getHDFtype(int intType, int &size); + /// translate an HDF type into an internal type and return the size + static int getIntType(int hdfType, int &size); + /// variables + int datatype, datasize; + /// parameters + int skiphuff; + int quality; + char *compType; + static const convert_string_t compNames[]; + static const int MaxSwapBufferSize; +}; + +#endif diff --git a/conversion/image.cc b/conversion/image.cc new file mode 100644 index 0000000..95018d6 --- /dev/null +++ b/conversion/image.cc @@ -0,0 +1,1040 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +*/ + +#ifdef EARLY_TEMPLATE +#define __EXECUTABLE__ +#ifdef __GNUG__ +#include "raslib/template_inst.hh" +#endif +#endif + +#include <iostream> +#include <fstream> +#include <iomanip> +/* +#include <strstream> + +#include "raslib/rminit.hh" +#include "rasodmg/marray.hh" +#include "rasodmg/ref.hh" +#include "rasodmg/set.hh" +#include "rasodmg/database.hh" +#include "rasodmg/partinsert.hh" +#include "raslib/type.hh" +#include "raslib/odmgtypes.hh" +*/ +#include <cstring> +#include <cstdlib> +#include <sys/types.h> +#include <unistd.h> +#include <cstdio> +#include <iostream> +#include <fstream> + +#include "image.h" +#include "utilities.h" + +using namespace std; +using namespace RasNITF; + + +typedef struct { + unsigned char red, green, blue; +} RGBPixel; + +image_band::image_band(){ + lutdnnm = NULL; +} + +image_band::~image_band(){ + + if (lutdnnm != NULL){ + delete lutdnnm; + lutdnnm = NULL; + } +} + +image::image(){ + + m_icom = NULL; + m_bands = NULL; + m_udid = NULL; + m_ixshd = NULL; + m_data = NULL; + +} + +image::~image(){ + + if (m_icom != NULL) { + delete m_icom; + m_icom = NULL; + } + + if (m_bands != NULL){ + delete[] m_bands; + m_bands = NULL; + } + + if (m_udid != NULL) { + delete m_udid; + m_udid = NULL; + } + + if (m_ixshd != NULL) { + delete m_ixshd; + m_ixshd = NULL; + } + + if (m_data != NULL) { + delete m_data; + m_data = NULL; + } +} + + +/********************************************************************** + * NAME: image::read_file + * PURPOSE: read an image from an ntf file into an image object + *********************************************************************/ + +int image::read_file(istream &hNITF, long lish, long li, bool read_image_data){ + + int charsread=0; + + // read IM through ICORDS + + charsread += read_verify2(hNITF, m_im, (2+10+14+17+80+1+2+11+2+20+2+8+4+1+8+43+1+40+1+8+15+1+42+8+8+3+8+8+2+1+1)); + + // read IGEOLO field if used + + if (m_icords[0] != ' ') { + charsread += read_verify2(hNITF, m_igeolo, 60); + } else { + memset(m_igeolo, ' ', 60); + charsread += 60; + } + + // read NICOM and ICOM + + charsread += read_verify2(hNITF, m_nicom, 1); + n_nicom = charptrtoint(m_nicom, 1); + + if (n_nicom > 0) { + m_icom = new char[n_nicom * 80]; + charsread += read_verify2(hNITF, m_icom, n_nicom * 80); + } else { + m_icom = NULL; + } + + // read IC + + charsread += read_verify2(hNITF, m_ic, 2); + + // read COMRAT if necessary + + if ((strncmp(m_ic, "NC", 2) != 0) && (strncmp(m_ic, "NM", 2) != 0)) { + charsread += read_verify2(hNITF, m_comrat, 4); + } + + charsread += read_verify2(hNITF, m_nbands, 1); + n_nbands = charptrtoint(m_nbands, 1); + + if (n_nbands == 0) { + charsread += read_verify2(hNITF, m_xbands, 5); + n_xbands = charptrtoint(m_xbands, 5); + numbands = n_xbands; + } else { + n_xbands = 0; + numbands = n_nbands; + } + + if (numbands > 0){ + + m_bands = new image_band[numbands]; + + for (int i = 0; i < numbands; i++) { + + // read IREPBANDnn..NLUTSnn + charsread += read_verify2(hNITF, m_bands[i].irepbandnn, (2+6+1+3+1)); + + // get # of LUTS for this band + m_bands[i].numluts = charptrtoint( m_bands[i].nlutsnn, 1); + + // read LUTs entries per LUT + if (m_bands[i].numluts > 0) { + + // read # of LUT entries + charsread += read_verify2(hNITF, m_bands[i].nelutnn, 5); + m_bands[i].numlutentries = charptrtoint(m_bands[i].nelutnn, 5); + + // allocate space for the LUT entries + m_bands[i].lutdnnm = new char[m_bands[i].numluts * m_bands[i].numlutentries]; + + // read LUT entries + charsread += read_verify2(hNITF, m_bands[i].lutdnnm, m_bands[i].numluts * m_bands[i].numlutentries); + + } else { + + m_bands[i].lutdnnm = NULL; + } + + } /* end for (band_num = 0... */ + + } else { + + m_bands = NULL; + + } + + // read m_isync..udidl + + charsread += read_verify2(hNITF, m_isync, (1+1+4+4+4+4+2+3+3+10+4+5)); + n_udidl = charptrtolong(m_udidl, 5); + + if (n_udidl > 0) { + charsread += read_verify2(hNITF, m_udofl, 3); + m_udid = new char[n_udidl]; + charsread += read_verify2(hNITF, m_udid, n_udidl - 3); + } + + // read ixshdl + + charsread += read_verify2(hNITF, m_ixshdl, 5); + n_ixshdl = charptrtolong(m_ixshdl, 5); + + if (n_ixshdl > 0) { + charsread += read_verify2(hNITF, m_ixsofl, 3); + m_ixshd = new char[n_ixshdl]; + charsread += read_verify2(hNITF, m_ixshd, n_ixshdl - 3); + } + + /*********************************************************************** + * MASKED IMAGES ARE IGNORED FOR NOW !!! + *********************************************************************** + + strncpy(temp_buffer, m_ic, 2); + temp_buffer[2] = '\0'; + + if (strcmp(temp_buffer, "NM") == 0 || strcmp(temp_buffer, "M1") == 0 + || strcmp(temp_buffer, "M3") == 0 + || strcmp(temp_buffer, "M4") == 0 + || strcmp(temp_buffer, "M5") == 0) { + + // ERROR not implemented yet masked images + } + + ************************************************************************/ + + // copy image data + + header_length = lish; + data_length = li; + + if(read_image_data == true) { + m_data = new char[li]; + charsread += read_verify2(hNITF, m_data, li); + } else { + charsread += li; + } + n_nbpr = 0; // number of blocks per row + n_nbpc = 0; // number of blocks per column + n_nppbh = 0; // number of of pixels per block horizontally + n_nppbv = 0; // number of of pixels per block vertically + + n_nppbh = charptrtoint( m_nppbh, 4); + n_nppbv = charptrtoint( m_nppbv, 4); + n_nbpr = charptrtoint( m_nbpr, 4); + n_nbpc = charptrtoint( m_nbpc, 4); + + cout<<"IC: "; + cout.write(m_ic, 2); + + cout<<"\nNBANDS: "; + cout.write(m_nbands, 1); + + cout<<"\nnumber of blocks per row: "; + cout.write(m_nbpr, 4); + + cout<<"\nNumber of blocks per column: "; + cout.write(m_nbpc, 4); + + cout<<"\nImode: "; + cout.write(m_imode, 1); + + return charsread; + +} + +/********************************************************************** + * NAME: image::write_file + * PURPOSE: write an image object into an ntf file on hard drive + *********************************************************************/ + +int image::write_file(ofstream &fs){ + + int charswritten=0; + + fs.write(m_im, 2); + fs.write(m_iid1, 10); + fs.write(m_idatim, 14); + fs.write(m_tgtid, 17); + fs.write(m_iid2, 80); + fs.write(m_isclas, 1); + fs.write(m_isclsy, 2); + fs.write(m_iscode, 11); + fs.write(m_isctlh, 2); + fs.write(m_isrel, 20); + fs.write(m_isdctp, 2); + fs.write(m_isdcdt, 8); + fs.write(m_isdcxm, 4); + fs.write(m_isdg, 1); + fs.write(m_isdgdt, 8); + fs.write(m_iscltx, 43); + fs.write(m_iscatp, 1); + fs.write(m_iscaut, 40); + fs.write(m_iscrsn, 1); + fs.write(m_issrdt, 8); + fs.write(m_isctln, 15); + fs.write(m_encryp, 1); + fs.write(m_isorce, 42); + fs.write(m_nrows, 8); + fs.write(m_ncols, 8); + fs.write(m_pvtype, 3); + fs.write(m_irep, 8); + fs.write(m_icat, 8); + fs.write(m_abpp, 2); + fs.write(m_pjust, 1); + fs.write(m_icords, 1); + + if (m_icords[0] != ' '){ + fs.write(m_igeolo, 60); + charswritten += 60; + } + fs.write(m_nicom, 1); + + charswritten += 2 + 10 + 14 + 17 + 80 + 1 + 2 + 11 + 2 + 20 + 2 + 8 + 4 +1 + 8 + 43 + 1 + 40 + 1 + 8 + 15 + 1 + 42 + 8 + 8 + 3 + 8 + 8 + 2 + 1 + 1 + 1; + + if (m_icom!=NULL) { + fs.write(m_icom, n_nicom * 80); + charswritten += n_nicom * 80; + } + + fs.write(m_ic, 2); + charswritten += 2; + + if ((strncmp(m_ic, "NC", 2) != 0) && (strncmp(m_ic, "NM", 2) != 0)) { + fs.write(m_comrat, 4); + charswritten += 4; + } + fs.write(m_nbands, 1); + charswritten += 1; + + if (n_nbands == 0) { + fs.write(m_xbands, 5); + charswritten += 5; + } + + if (m_bands != NULL){ + for (int i=0; i<numbands; i++){ + fs.write(m_bands[i].irepbandnn, 2); + fs.write(m_bands[i].isubcatnn, 6); + fs.write(m_bands[i].ifcnn, 1); + fs.write(m_bands[i].imfltnn, 3); + fs.write(m_bands[i].nlutsnn, 1); + + charswritten += 2 + 6 + 1 + 3 + 1; + + if (m_bands[i].numluts > 0){ + fs.write(m_bands[i].nelutnn, 5); + fs.write(m_bands[i].lutdnnm, m_bands[i].numluts * m_bands[i].numlutentries); + + charswritten += 5 + m_bands[i].numluts * m_bands[i].numlutentries; + } + } + } + + fs.write(m_isync, 1); + fs.write(m_imode, 1); + fs.write(m_nbpr, 4); + fs.write(m_nbpc, 4); + fs.write(m_nppbh, 4); + fs.write(m_nppbv, 4); + fs.write(m_nbpp, 2); + fs.write(m_idlvl, 3); + fs.write(m_ialvl, 3); + fs.write(m_iloc, 10); + fs.write(m_imag, 4); + fs.write(m_udidl, 5); + + charswritten += 1 + 1 + 4 + 4 + 4 +4 + 2 + 3 + 3 + 10 + 4 + 5; + + if (n_udidl > 0) { + fs.write(m_udofl, 3); + fs.write(m_udid, n_udidl - 3); + charswritten += n_udidl; + } + + fs.write(m_ixshdl, 5); + charswritten += 5; + + if (n_ixshdl > 0) { + fs.write(m_ixsofl, 3); + fs.write(m_ixshd, n_ixshdl - 3); + charswritten += n_ixshdl; + } + + +cout<<" wrote image header length: " << charswritten <<endl; +if(m_data){ +fs.write(m_data, data_length); +cout<< "image data length is : "<<data_length<<endl ; +charswritten += data_length; +} +cout<<"IMAGE WRITE_FILE wrote "<< charswritten<<endl; + + return charswritten; +} + + +/********************************************************************** + * NAME:image::get_li + * ------------------------------------------------------------------- + * PURPOSE: image size + *********************************************************************/ + +string image::get_li() const { + string temp(textdl); + return temp; +} + +/********************************************************************** + * NAME:image::get_lish + * ------------------------------------------------------------------- + * PURPOSE: returns the image header size + *********************************************************************/ + +string image::get_lish() const { + string temp(texthl); + return temp; +} + + +/********************************************************************** + * NAME: image::compute_data_reordering_variables + *--------------------------------------------------------------------- + * PURPOSE: computes some variable necessary for converting data from + * the ntf internal data storage to pixel sequential storage and vice + * versa + *********************************************************************/ + +void image::compute_data_reordering_variables(){ + + int px_comp_size_bits = charptrtoint(m_nbpp, 2); + + if ((px_comp_size_bits % 8) == 0) { + px_comp_size = px_comp_size_bits / 8; + } else { + cout << "unsupported pixel component size "<<endl; + exit(101); + } + + px_size = px_comp_size * numbands; + numblocks = n_nbpc * n_nbpr; + block_size_bytes = data_length / numblocks; + block_size_pixels = n_nppbv * n_nppbh; + block_row_size = block_size_bytes / n_nppbv; + block_band_size = block_size_bytes /numbands; + block_band_size_px = block_size_pixels / numbands; + image_band_size = data_length / numbands; + + n_nrows = charptrtolong(m_nrows, 8); + n_ncols = charptrtolong(m_ncols, 8); + +} + +/********************************************************************** + * NAME: image::blpxseq2pxseq + * ------------------------------------------------------------------- + * PURPOSE: coverts memory data from block pixel sequential to pixel + * sequential storage + *********************************************************************/ + +int image::blpxseq2pxseq(char* src, char* dest){ + + char *rowblockstart = NULL; + char *writefrom = NULL; + + + cout<< "n_nbpc: "<<n_nbpc <<endl; + cout<< "n_nbpr: " <<n_nbpr<<endl; + cout<< "block_size_bytes: " << block_size_bytes <<endl; + cout<< "block_row_size: " << block_row_size <<endl; + + for (int vbindex=0; vbindex < n_nbpc; vbindex++){ + + rowblockstart = (char*)(src + vbindex * n_nbpr * block_size_bytes); + + for (int hbindex = 0; hbindex < n_nbpr; hbindex++){ + + for(int i = 0; i < n_nppbv; i++){ + + writefrom = (char*) (rowblockstart + i * n_nbpr * block_row_size + hbindex * block_row_size ); + strncpy(dest, writefrom , block_row_size); + dest += block_row_size; + + cout<< "writing row: "<< i <<" of BLOCK: " << hbindex << "IN BLOCK ROW "<< vbindex<<endl; + + cout << "writefrom "<< int(writefrom) <<"dest" << int(dest) <<" block row size " << block_row_size <<endl; + } + } + } + + return 0; + +} + +/********************************************************************** + * NAME: image::pxseq2blpxseq + * ------------------------------------------------------------------- + * PURPOSE: coverts memory data from pixel sequential to block pixel + * sequential storage + *********************************************************************/ + +int image::pxseq2blpxseq(char* src, char* dest){ + + char *rowblockstart = NULL; + char *copyfrom = NULL; + + for (int vbindex=0; vbindex < n_nbpc; vbindex++){ + + rowblockstart = (char*)(src + vbindex * n_nbpr * block_size_bytes); + + for (int hbindex = 0; hbindex < n_nbpr; hbindex++){ + for(int i = 0; i < n_nppbv; i++){ + copyfrom = (char*) (rowblockstart + i * n_nbpr * block_row_size + hbindex * block_row_size ); + strncpy(dest, copyfrom, block_row_size); + dest += block_row_size; + } + } + } + + return 0; +} + +/********************************************************************** + * NAME: image::to_pixel_sequential + * -------------------------------------------------------------------- + * PURPOSE: determines internal ntf image storage and chooses which + * convertion function to call in oreder to make the data pixel + * sequential + *********************************************************************/ + +int image::to_pixel_sequential(){ + + string ic(m_ic,2); + + if(ic=="NC"){ + + compute_data_reordering_variables(); + + if (numbands == 1) { + + imode_1band2ps(); + + } else if (numbands == 3) { + + switch(*m_imode) { + case 'B': + return imode_b2ps(); + case 'P': + return imode_p2ps(); + case 'S': + return imode_s2ps(); + case 'R': + return imode_r2ps(); + default: + exit(102); + } + } + + return 0; + + } else { + exit(103); + } + +} + +/********************************************************************** + * NAME: image::to_block_pixel_sequential + * -------------------------------------------------------------------- + * PURPOSE: determines internal ntf image storage and chooses which + * convertion function to call in oreder to make the data block pixel + * sequential + *********************************************************************/ + +int image::to_block_pixel_sequential(char* src){ + + string ic(m_ic,2); + + if(ic=="NC"){ + + compute_data_reordering_variables(); + + if (numbands == 1) { + + imode_ps21band(src); + + } else if (numbands == 3) { + + switch(*m_imode) { + case 'B': + return imode_ps2b(src); + case 'P': + return imode_ps2p(src); + case 'S': + return imode_ps2s(src); + case 'R': + return imode_ps2r(src); + default: + exit(104); + } + } + + return 0; + + } else { + exit(105); + } + +} + +/********************************************************************** + * NAME: image::imode_1band2ps + * -------------------------------------------------------------------- + * PURPOSE: data convertion fucntion for the data of an image with 1 + * band only (for details see NITF spec imode field) + *********************************************************************/ + +int image::imode_1band2ps() { + + char* temp_data = new char [data_length]; + strncpy(temp_data, m_data, data_length); + blpxseq2pxseq(temp_data, m_data); + delete temp_data; + + return 0; +} + +/********************************************************************** + * NAME: image::imode_ps21band + * -------------------------------------------------------------------- + * PURPOSE: data convertion fucntion for the data of an image with 1 + * band only (for details see NITF spec imode field) + *********************************************************************/ + +int image::imode_ps21band(char* src) { + + pxseq2blpxseq(src, m_data); + + return 0; +} + + +/********************************************************************** + * NAME: image::imode_b2ps + * ------------------------------------------------------------------- + * PURPOSE: data convertion fucntion for the data of an image stored + * in band interleaved by block internal storage (for details see NITF + * spec imode field) + *********************************************************************/ + +int image::imode_b2ps() { +/* + char* kurets = new char[24]; + strncpy(kurets, "ADMPBENQCFORGJSVHKTXILUY", 24); + char* temp_data = new char[24]; + char* beginning = temp_data; + char* read_sofar = kurets; + char* RED_offset = NULL; + char* GREEN_offset = NULL; + char* BLUE_offset = NULL; + + for(int block_index = 0; block_index < 2; block_index++) { + + RED_offset = read_sofar; + GREEN_offset = (char*)(read_sofar + 4); + BLUE_offset = (char*)(read_sofar + 8); + + for (int i=0; i < 4; i++) { + for (int j = 0; j < 1; j++){ + cout<<RED_offset[0]<<endl; + *temp_data++ = *RED_offset++; + read_sofar++; + } + for (int j = 0; j < 1; j++){ + cout<<GREEN_offset[0]<<endl; + *temp_data++ = *GREEN_offset++; + read_sofar++; + } + for (int j = 0; j < 1; j++){ + cout<<BLUE_offset[0]<<endl; + *temp_data++ = *BLUE_offset++; + read_sofar++; + } + } + } + temp_data=beginning; + cout.write(temp_data, 24); + cout<<endl; + blpxseq2pxseq(temp_data, kurets); + cout.write(kurets, 24); + exit(1234); + delete temp_data; + return 0; +*/ + + char* temp_data = new char[data_length]; + char* read_sofar = m_data; + char* RED_offset = NULL; + char* GREEN_offset = NULL; + char* BLUE_offset = NULL; + + for(int block_index = 0; block_index < numblocks; block_index++) { + + RED_offset = read_sofar; + GREEN_offset = (char*)(read_sofar + block_band_size); + BLUE_offset = (char*)(read_sofar + 2 * block_band_size); + + for (int i=0; i < block_band_size_px; i++) { + for (int j = 0; j < px_comp_size; j++){ + *temp_data++ = *RED_offset++; + read_sofar++; + } + for (int j = 0; j < px_comp_size; j++){ + *temp_data++ = *GREEN_offset++; + read_sofar++; + } + for (int j = 0; j < px_comp_size; j++){ + *temp_data++ = *BLUE_offset++; + read_sofar++; + } + } + } + + blpxseq2pxseq(temp_data, m_data); + + delete temp_data; + return 0; + +} + +/********************************************************************** + * NAME: image::imode_ps2b + * ------------------------------------------------------------------- + * PURPOSE: data convertion fucntion for the data of an image stored + * in band interleaved by block internal storage (for details see NITF + * spec imode field) + *********************************************************************/ + +int image::imode_ps2b(char* src) { + + char* temp_data = new char[data_length]; + pxseq2blpxseq(src, temp_data); + + char* written_sofar = m_data; + char* RED_offset = NULL; + char* GREEN_offset = NULL; + char* BLUE_offset = NULL; + + for(int block_index = 0; block_index < numblocks; block_index++) { + + RED_offset = m_data; + GREEN_offset = (char*)(written_sofar + block_band_size); + BLUE_offset = (char*)(written_sofar + 2 * block_band_size); + + for (int i=0; i < block_band_size_px; i++) { + for (int j = 0; j < px_comp_size; j++){ + *RED_offset++ = *temp_data++; + written_sofar++; + } + for (int j = 0; j < px_comp_size; j++){ + *GREEN_offset++ = *temp_data++; + written_sofar++; + } + for (int j = 0; j < px_comp_size; j++){ + *BLUE_offset++ = *temp_data++; + written_sofar++; + } + } + } + + delete temp_data; + + return 0; +} + +/********************************************************************** + * NAME:image::imode_p2ps + * -------------------------------------------------------------------- + * PURPOSE: data convertion fucntion for the data of an image stored + * in band interleaved by pixel by block internal storage (for details + * see NITF spec imode field) + *********************************************************************/ + +int image::imode_p2ps() { + + char* temp_data = new char [data_length]; + strncpy(temp_data, m_data, data_length); + blpxseq2pxseq(temp_data, m_data); + delete temp_data; + + return 0; +} + +/********************************************************************** + * NAME:image::imode_ps2p + * -------------------------------------------------------------------- + * PURPOSE: data convertion fucntion for the data of an image stored + * in band interleaved by pixel by block internal storage (for details + * see NITF spec imode field) + *********************************************************************/ + +int image::imode_ps2p(char* src){ + + pxseq2blpxseq(src, m_data); + return 0; +} + + +/********************************************************************** + * NAME:image::imode_r2ps + * -------------------------------------------------------------------- + * PURPOSE: data convertion fucntion for the data of an image stored + * in band interleaved by row by block internal storage ( for details + * see NITF spec imode field) + *********************************************************************/ + +int image::imode_r2ps() { + + char* temp_data = new char [data_length]; + + char* read_sofar = m_data; + char* RED_offset = NULL; + char* GREEN_offset = NULL; + char* BLUE_offset = NULL; + + int block_row_band_size = block_row_size/numbands; + + for(int block_index = 0; block_index < numblocks ; block_index++) { + for (int rowinblock = 0; rowinblock < n_nppbv; rowinblock++){ + + RED_offset = read_sofar; + GREEN_offset =(char*) (read_sofar + block_row_band_size); + BLUE_offset = (char*) (read_sofar+ 2 * block_row_band_size); + + for (int i = 0; i < n_nppbh; i++){ + + for (int j = 0; j < px_comp_size; j++){ + *temp_data++ = *RED_offset++; + read_sofar++; + } + + for (int j = 0; j < px_comp_size; j++){ + *temp_data++ = *GREEN_offset++; + read_sofar++; + } + + for (int j = 0; j < px_comp_size; j++){ + + *temp_data++ = *BLUE_offset++; + read_sofar++; + } + } + } + } + + blpxseq2pxseq(temp_data, m_data); + delete temp_data; + return 0; +} + +/********************************************************************** + * NAME:image::imode_ps2r + * -------------------------------------------------------------------- + * PURPOSE: data convertion fucntion for the data of an image stored + * in band interleaved by row by block internal storage ( for details + * see NITF spec imode field) + *********************************************************************/ + +int image::imode_ps2r(char* src) { + + char* temp_data = new char [data_length]; + pxseq2blpxseq(src, temp_data); + + char* written_sofar = m_data; + char* RED_offset = NULL; + char* GREEN_offset = NULL; + char* BLUE_offset = NULL; + + int block_row_band_size = block_row_size/numbands; + + for(int block_index = 0; block_index < numblocks ; block_index++) { + for (int rowinblock = 0; rowinblock < n_nppbv; rowinblock++){ + + RED_offset = written_sofar; + GREEN_offset =(char*) (written_sofar + block_row_band_size); + BLUE_offset = (char*) (written_sofar+ 2 * block_row_band_size); + + for (int i = 0; i < n_nppbh; i++){ + + for (int j = 0; j < px_comp_size; j++){ + *RED_offset++ = *temp_data++; + written_sofar++; + } + + for (int j = 0; j < px_comp_size; j++){ + *GREEN_offset++ = *temp_data++; + written_sofar++; + } + + for (int j = 0; j < px_comp_size; j++){ + *BLUE_offset++ = *temp_data++; + written_sofar++; + } + } + } + } + + delete temp_data; + return 0; +} + + +/********************************************************************** + * NAME:image::imode_s2ps + * ------------------------------------------------------------------- + * PURPOSE: data convertion fucntion for the data of an image stored + * in band sequential internal storage (for details see NITF spec + * imode field) + *********************************************************************/ + +int image::imode_s2ps() { + + int numpix = n_nrows * n_ncols; + + char* temp_data = new char [data_length]; + + char* RED_offset = m_data; + char* GREEN_offset = (char*)(m_data + image_band_size); + char* BLUE_offset = (char*)(m_data + 2 * image_band_size); + + for (int i=0; i < numpix; i++) { + + for (int j = 0; j < px_comp_size; j++){ + *temp_data++ = *RED_offset++; + } + + for (int j = 0; j < px_comp_size; j++){ + *temp_data++ = *GREEN_offset++; + } + + for (int j = 0; j < px_comp_size; j++){ + + *temp_data++ = *BLUE_offset++; + } + } + + blpxseq2pxseq(temp_data, m_data); + delete temp_data; + + return 0; +} + +/********************************************************************** + * NAME:image::imode_ps2s + * ------------------------------------------------------------------- + * PURPOSE: data convertion fucntion for the data of an image stored + * in band sequential internal storage (for details see NITF spec + * imode field) + *********************************************************************/ + +int image::imode_ps2s(char* src) { + + char* temp_data = new char[data_length]; + pxseq2blpxseq(src, temp_data); + + int numpix = n_nrows * n_ncols; + + char* RED_offset = m_data; + char* GREEN_offset = (char*)(m_data + image_band_size); + char* BLUE_offset = (char*)(m_data + 2 * image_band_size); + + for (int i=0; i < numpix; i++) { + + for (int j = 0; j < px_comp_size; j++){ + *RED_offset++ = *temp_data++; + } + + for (int j = 0; j < px_comp_size; j++){ + *GREEN_offset++ = *temp_data++; + } + + for (int j = 0; j < px_comp_size; j++){ + *BLUE_offset++ = *temp_data++; + } + } + + delete temp_data; + + return 0; +} + +long image::get_size() const +{ + return data_length; +} + +int image::get_width() const +{ + return n_nrows; +} + +int image::get_height() const +{ + return n_ncols; +} + +string image::get_irep() const { + return string(m_irep, 8); +} + +string image::get_pvtype() const { + return string(m_pvtype, 3); +} + +int image::get_nbpp_bytes() const { + + return charptrtoint(m_nbpp, 2); +} diff --git a/conversion/image.h b/conversion/image.h new file mode 100644 index 0000000..91213ed --- /dev/null +++ b/conversion/image.h @@ -0,0 +1,226 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +*/ + +#ifndef __RASNITF_IMAGE_H +#define __RASNITF_IMAGE_H + +#include <fstream> +#include <iostream> + +namespace RasNITF{ + +class image_band{ + + public: + + char irepbandnn[2]; + char isubcatnn[6]; + char ifcnn[1]; + char imfltnn[3]; + char nlutsnn[1]; + char nelutnn[5]; + int numluts; + int numlutentries; + char* lutdnnm; + + image_band(); + ~image_band(); + +}; + +class image { + + /********************************* + * image header fields + ********************************/ + + char m_im[2]; + char m_iid1[10]; + char m_idatim[14]; + char m_tgtid[17]; + char m_iid2[80]; + char m_isclas[1]; + char m_isclsy[2]; + char m_iscode[11]; + char m_isctlh[2]; + char m_isrel[20]; + char m_isdctp[2]; + char m_isdcdt[8]; + char m_isdcxm[4]; + char m_isdg[1]; + char m_isdgdt[8]; + char m_iscltx[43]; + char m_iscatp[1]; + char m_iscaut[40]; + char m_iscrsn[1]; + char m_issrdt[8]; + char m_isctln[15]; + char m_encryp[1]; + char m_isorce[42]; + char m_nrows[8]; + char m_ncols[8]; + char m_pvtype[3]; + char m_irep[8]; + char m_icat[8]; + char m_abpp[2]; + char m_pjust[1]; + char m_icords[1]; + char m_igeolo[60]; + char m_nicom[1]; + char* m_icom; + char m_ic[2]; + char m_comrat[4]; + char m_nbands[1]; + char m_xbands[5]; + image_band* m_bands; + char m_isync[1]; + char m_imode[1]; + char m_nbpr[4]; + char m_nbpc[4]; + char m_nppbh[4]; + char m_nppbv[4]; + char m_nbpp[2]; + char m_idlvl[3]; + char m_ialvl[3]; + char m_iloc[10]; + char m_imag[4]; + char m_udidl[5]; + char m_udofl[3]; + char* m_udid; + char m_ixshdl[5]; + char m_ixsofl[3]; + char* m_ixshd; + + /***************************** + * image data mask table + ****************************/ + + /* + long imdataoff; + unsigned short bmrlnth; + unsigned short tmrlnth; + unsigned short tpxcdlnth; + long tpxcd; + char* BMRnBNDm; + char* TMRnBNDm; + */ + + /***************************** + * raw image data + *****************************/ + + char* m_data; + + /***************************** + * additional variables + *****************************/ + +// bool compressed; + int n_nicom; + int n_nbands; + int n_xbands; + int numbands; + int n_udidl; + int n_ixshdl; + long header_length; + long data_length; + char texthl[6]; + char textdl[10]; + int n_nbpr; + int n_nbpc; + int n_nppbh; + int n_nppbv; + + /***************************** + * variables for data reordering + * populated by compute_data_reordering_variables() + *****************************/ + + int n_nrows; + int n_ncols; + int px_comp_size; + int px_size; + int numblocks; + + long block_size_bytes; + long block_size_pixels; + long block_row_size; //bytes + long block_band_size; //bytes + long block_band_size_px; + long image_band_size; + + + int copy_block_data(char* writeto, int hor_block_index, int ver_block_index ); + + // functions for data reordering + + void compute_data_reordering_variables(); + + int blpxseq2pxseq(char* src, char* dest); + int pxseq2blpxseq(char*, char*); + + int imode_1band2ps(); + int imode_b2ps(); + int imode_r2ps(); + int imode_p2ps(); + int imode_s2ps(); + + int imode_ps21band(char*); + int imode_ps2b(char*); + int imode_ps2r(char*); + int imode_ps2p(char*); + int imode_ps2s(char*); + + + public: + + image(); + ~image(); + + int read_file(std::istream&, long, long, bool read_image_data); + int write_file(std::ofstream& fs); + + std::string get_li() const; + std::string get_lish() const; + long get_size() const; + int get_width() const; + int get_height() const; + + int to_pixel_sequential(); + int to_block_pixel_sequential(char* src); + + std::string get_irep() const; + std::string get_pvtype() const; + + int get_nbpp_bytes() const; + +// char* get_data_ptr(); + + +}; + +} + +#endif + + diff --git a/conversion/int16.cc b/conversion/int16.cc new file mode 100644 index 0000000..abd8a2f --- /dev/null +++ b/conversion/int16.cc @@ -0,0 +1,874 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * SOURCE: int16.hh + * + * MODULE: conversion + * + * CLASSES: r_Conv_int16 + * + * COMMENTS: + * Provides interface to convert data from/to Array format to/from int16 format. + * +*/ + +static const char rcsid[] = "@(#)conversion,r_Conv_int16: $Id: int16.cc,v 1.8 2002/10/01 09:16:38 coman Exp $"; + +#include "conversion/int16.hh" + +#include <float.h> +#include <string> +#include <cstring> +#include <strstream> +#include <sstream> +#include <algorithm> + +using std::istringstream; +using std::istrstream; +using std::string; + +#include "raslib/rminit.hh" +#include "raslib/parseparams.hh" +#include "raslib/primitivetype.hh" + + +const r_Dimension r_Conv_int16::srcIntervDim=1; +const r_Dimension r_Conv_int16::destIntervDim=2; +const r_ULong r_Conv_int16::paramMin=6; +const char* r_Conv_int16::paramSep=","; +const char* r_Conv_int16::paramEq="="; +const char* r_Conv_int16::paramFlipX="flipx"; +const char* r_Conv_int16::paramFlipY="flipy"; +const char* r_Conv_int16::paramStartX="startx"; +const char* r_Conv_int16::paramEndX="endx"; +const char* r_Conv_int16::paramResX="resx"; +const char* r_Conv_int16::paramStartY="starty"; +const char* r_Conv_int16::paramEndY="endy"; +const char* r_Conv_int16::paramResY="resy"; + +const r_Double r_Conv_int16::NULL_DB = 0.; +const r_Double r_Conv_int16::ZERO_DB = FLT_MIN; +const r_Double r_Conv_int16::ZERO_int16 = 0.; + +r_Conv_int16::~r_Conv_int16( void ) +{ + //nothing to care for +} + +void r_Conv_int16::initGeoBBox( r_GeoBBox& cBBox ) +{ + //flipy is selected by default + cBBox.flipy = 1; + + //flipx is not selected by default + cBBox.flipx = 0; + + //geo information are initialized by default to DBL_MAX + // FIXME: better defaults res=1, min=-MAX? + cBBox.startx = DBL_MAX; + cBBox.endx = DBL_MAX; + cBBox.resx = DBL_MAX; + cBBox.starty = DBL_MAX; + cBBox.endy = DBL_MAX; + cBBox.resy = DBL_MAX; +} + +r_Conv_int16::r_Conv_int16(const char* source, const r_Minterval& lengthordomain, const r_Type* tp) throw(r_Error) + : r_Convertor(source, lengthordomain, tp, true) +{ + initGeoBBox(collBBox); +} + +r_Conv_int16::r_Conv_int16(const char* source, const r_Minterval& lengthordomain, int tp) throw(r_Error) + : r_Convertor(source, lengthordomain, tp) +{ + initGeoBBox(collBBox); +} + +bool +r_Conv_int16::decodeOptions(const char* options, + r_GeoBBox& cBBox) throw() +{ + RMInit::logOut << "r_Conv_int16::decodeOptions(" << (options?options:"NULL") << ")" << endl; + + r_Parse_Params parseParams; + + initGeoBBox(cBBox); + + parseParams.add(paramFlipX, &cBBox.flipx, r_Parse_Params::param_type_int); + parseParams.add(paramFlipY, &cBBox.flipy, r_Parse_Params::param_type_int); + parseParams.add(paramStartX, &cBBox.startx, r_Parse_Params::param_type_double); + parseParams.add(paramEndX, &cBBox.endx, r_Parse_Params::param_type_double); + parseParams.add(paramResX, &cBBox.resx, r_Parse_Params::param_type_double); + parseParams.add(paramStartY, &cBBox.starty, r_Parse_Params::param_type_double); + parseParams.add(paramEndY, &cBBox.endy, r_Parse_Params::param_type_double); + parseParams.add(paramResY, &cBBox.resy, r_Parse_Params::param_type_double); + + //process options + r_Long processRet=parseParams.process(options); + if(processRet < paramMin) + { + RMInit::logOut << "r_Conv_int16::decodeOptions(...) Error: Some required options are missing!" << endl; + return false; + } + + //check if start,res,end are present + if(cBBox.startx == DBL_MAX) + { + RMInit::logOut << "r_Conv_int16::decodeOptions(...) Error: startx is not present!" << endl; + return false; + } + + if(cBBox.starty == DBL_MAX) + { + RMInit::logOut << "r_Conv_int16::decodeOptions(...) Error: starty is not present!" << endl; + return false; + } + + if(cBBox.endx == DBL_MAX) + { + RMInit::logOut << "r_Conv_int16::decodeOptions(...) Error: endx is not present!" << endl; + return false; + } + + if(cBBox.endy == DBL_MAX) + { + RMInit::logOut << "r_Conv_int16::decodeOptions(...) Error: endy is not present!" << endl; + return false; + } + + if(cBBox.resx == DBL_MAX) + { + RMInit::logOut << "r_Conv_int16::decodeOptions(...) Error: resx is not present!" << endl; + return false; + } + + if(cBBox.resy == DBL_MAX) + { + RMInit::logOut << "r_Conv_int16::decodeOptions(...) Error: resy is not present!" << endl; + return false; + } + + + //check res + if(!cBBox.resx) + { + RMInit::logOut << "r_Conv_int16::decodeOptions(...) Error: resx is zero!" << endl; + return false; + } + + if(!cBBox.resy) + { + RMInit::logOut << "r_Conv_int16::decodeOptions(...) Error: resy is zero!" << endl; + return false; + } + + //check start >= end + if(cBBox.startx >= cBBox.endx ) + { + RMInit::logOut << "r_Conv_int16::decodeOptions(...) Error: startx >= endx!" << endl; + return false; + } + + if(cBBox.starty >= cBBox.endy) + { + RMInit::logOut << "r_Conv_int16::decodeOptions(...) Erorr: starty >= endy!" << endl; + return false; + } + + //show parsed options + RMInit::logOut.setf(std::ios::fixed); + RMInit::logOut << "r_Conv_int16::decodeOptions(...) parsed options:" << endl + << " " << paramFlipX << paramEq << cBBox.flipx + << " " << paramFlipY << paramEq << cBBox.flipy << endl + << " " << paramStartX << paramEq << cBBox.startx + << " " << paramEndX << paramEq << cBBox.endx + << " " << paramResX << paramEq << cBBox.resx << endl + << " " << paramStartY << paramEq << cBBox.starty + << " " << paramEndY << paramEq << cBBox.endy + << " " << paramResY << paramEq << cBBox.resy << endl; + return true; +} + +string +r_Conv_int16::encodeOptions(const r_GeoBBox& cBBox) throw() +{ + std::ostringstream os; + + os.str(""); + os.setf(std::ios::fixed); + os << paramFlipX << paramEq << cBBox.flipx + << paramSep << paramFlipY << paramEq << cBBox.flipy + << paramSep << paramStartX << paramEq << cBBox.startx + << paramSep << paramEndX << paramEq << cBBox.endx + << paramSep << paramResX << paramEq << cBBox.resx + << paramSep << paramStartY << paramEq << cBBox.starty + << paramSep << paramEndY << paramEq << cBBox.endy + << paramSep << paramResY << paramEq << cBBox.resy; + + RMInit::logOut << "r_Conv_int16::encodeOptions(" << os.str() << ")" << endl; + + return os.str(); +} + +void +r_Conv_int16::checkLimits() throw(r_Error) +{ + //show processed data + RMInit::logOut << "r_Conv_int16::checkLimits() processed data:" << endl + << " minx=" << min.x << " miny=" << min.y << " minh=" << min.h << endl + << " maxx=" << max.x << " maxy=" << max.y << " maxh=" << max.h << endl; + // printf( "r_Conv_int16::checkLimits() processed data: minx=%8G, miny=%8G, minh=%8G, maxx=%8G, maxy=%8G, maxh=%8G\n", min.x, min.y, min.h, max.x, max.y, max.h ); + + if(collBBox.startx > min.x) + { + RMInit::logOut << "r_Conv_int16::checkLimits() startx( " << collBBox.startx << ") > min.x (" << min.x << " )!" << endl; + throw r_Error(); + } + if(collBBox.endx < max.x) + { + RMInit::logOut << "r_Conv_int16::checkLimits() endx( " << collBBox.endx << ") < max.x (" << max.x << " )!" << endl; + throw r_Error(); + } + + if(collBBox.starty > min.y) + { + RMInit::logOut << "r_Conv_int16::checkLimits() starty( " << collBBox.starty << ") > min.y (" << min.y << " )!" << endl; + throw r_Error(); + } + + if(collBBox.endy < max.y) + { + RMInit::logOut << "r_Conv_int16::checkLimits() endy( " << collBBox.endy << ") < max.y (" << max.y << " )!" << endl; + throw r_Error(); + } +} + +void +r_Conv_int16::readFromSrcStream() throw(r_Error) +{ + istrstream iFile(desc.src, desc.srcInterv[0].get_extent()); + string currStrRow; + istringstream icurrRow; + r_Long rowNo=0; + r_Double noResx, noResy; + int16Row currRow, prevRow; + + min.x=min.y=min.h=DBL_MAX; + max.x=max.y=max.h=-DBL_MAX; + demRows.clear(); + + //process the lines + while(!iFile.eof()) + { + getline(iFile, currStrRow); + rowNo++; + if(currStrRow.empty()) + { + RMInit::logOut << "r_Conv_int16::readFromSrcStream() skipping empty line " << rowNo << endl; + continue; + } + else + { + icurrRow.str(currStrRow); + + //decode x + icurrRow >> currRow.x; + if(!icurrRow) + { + RMInit::logOut << "r_Conv_int16::readFromSrcStream() skiping line " << rowNo + << "(unable to decode x) !" << endl; + continue; + } + + //decode y + icurrRow >> currRow.y; + if(!icurrRow) + { + RMInit::logOut << "r_Conv_int16::readFromSrcStream() skiping line " << rowNo + << "(unable to decode y) !" << endl; + continue; + } + + //decode h + icurrRow >> currRow.h; + if(!icurrRow) + { + RMInit::logOut << "r_Conv_int16::readFromSrcStream() skiping line " << rowNo + << "(unable to decode h) !" << endl; + continue; + } + + //update to support NULL value: 0. (real value) goes in FLT_MIN(db value) + //because 0.(db value) represent NULL(real value). When we do export we skip NULL values. + if(currRow.h == ZERO_int16) currRow.h=ZERO_DB; + + //FIXME we ignore this check, because it may happen to have a incomplet dem + /* + //check if we have resx, resy + noResx=currRow.x/collBBox.resx; + if((currRow.x - noResx*collBBox.resx) > 0.) + { + RMInit::logOut << "r_Conv_int16::readFromSrcStream() resolution for x on line " << + rowNo << " is not " << collBBox.resx << " !" << endl; + throw r_Error(); + } + noResy=currRow.y/collBBox.resy; + if((currRow.y - noResy*collBBox.resy) > 0.) + { + RMInit::logOut << "r_Conv_int16::readFromSrcStream() resolution for y on line " << + rowNo << " is not " << collBBox.resy << " !" << endl; + throw r_Error(); + } + */ + + //compute min, max for x,y,z + min.x=std::min<r_Double>(min.x, currRow.x); + min.y=std::min<r_Double>(min.y, currRow.y); + min.h=std::min<r_Double>(min.h, currRow.h); + max.x=std::max<r_Double>(max.x, currRow.x); + max.y=std::max<r_Double>(max.y, currRow.y); + max.h=std::max<r_Double>(max.h, currRow.h); + + //store currRow + demRows.push_back(currRow); + }//end if(currStrRow.empty()) + }//end reading src stream + + if(demRows.empty()) + { + RMInit::logOut << "r_Conv_int16::readFromSrcStream() desc.src stream is empty !" << endl; + throw r_Error(); + } + + //check limits + checkLimits(); +} + + +void +r_Conv_int16::readToSrcStream() throw(r_Error) +{ + r_Long x=0, y=0; + r_Long xlow=0, ylow=0; + r_Long xhigh=0, yhigh=0; + int16Row currRow; + r_Bytes typeSize=0; + r_Long offset=0; + char* buffer=NULL; + + //initialize + xlow=desc.srcInterv[0].low(); + ylow=desc.srcInterv[1].low(); + + xhigh=desc.srcInterv[0].high(); + yhigh=desc.srcInterv[1].high(); + + //compute min & max + if (collBBox.flipx) + { + min.x=collBBox.endx - xhigh*collBBox.resx; + max.x=collBBox.endx - xlow*collBBox.resx; + } + else + { + min.x=collBBox.startx + xlow*collBBox.resx; + max.x=collBBox.startx + xhigh*collBBox.resx; + } + + if(collBBox.flipy) + { + min.y=collBBox.endy - yhigh*collBBox.resy; + max.y=collBBox.endy - ylow*collBBox.resy; + } + else + { + min.y=collBBox.starty + ylow*collBBox.resy; + max.y=collBBox.starty + yhigh*collBBox.resy; + } + + min.h=DBL_MAX; + max.h=-DBL_MAX; + + //check limits + checkLimits(); + + //prepare container + demRows.clear(); + typeSize=((r_Primitive_Type*)desc.srcType)->size(); + buffer=new char[typeSize]; + if(!buffer) + { + RMInit::logOut << "r_Conv_int16::readToSrcStream() unable to claim memory !" << endl; + throw r_Ememory_allocation(); + } + + for(y=ylow; y<=yhigh; y++) + { + if(collBBox.flipy) + currRow.y=collBBox.endy - y*collBBox.resy; + else + currRow.y=collBBox.starty + y*collBBox.resy; + + for(x=xlow; x<=xhigh; x++) + { + if(collBBox.flipx) + currRow.x=collBBox.endx - x*collBBox.resx; + else + currRow.x=collBBox.startx + x*collBBox.resx; + offset=desc.srcInterv.cell_offset(r_Point(x,y))*typeSize; + memcpy(buffer, &desc.src[offset], typeSize); + switch(desc.srcType->type_id()) + { + case r_Type::BOOL: + currRow.h=((r_Primitive_Type*)desc.srcType)->get_boolean(buffer); + break; + case r_Type::CHAR: + currRow.h=((r_Primitive_Type*)desc.srcType)->get_char(buffer); + break; + case r_Type::OCTET: + currRow.h=((r_Primitive_Type*)desc.srcType)->get_octet(buffer); + break; + case r_Type::SHORT: + currRow.h=((r_Primitive_Type*)desc.srcType)->get_short(buffer); + break; + case r_Type::USHORT: + currRow.h=((r_Primitive_Type*)desc.srcType)->get_ushort(buffer); + break; + case r_Type::LONG: + currRow.h=((r_Primitive_Type*)desc.srcType)->get_long(buffer); + break; + case r_Type::ULONG: + currRow.h=((r_Primitive_Type*)desc.srcType)->get_ulong(buffer); + break; + case r_Type::FLOAT: + currRow.h=((r_Primitive_Type*)desc.srcType)->get_float(buffer); + break; + case r_Type::DOUBLE: + currRow.h=((r_Primitive_Type*)desc.srcType)->get_double(buffer); + break; + default: + //write message to log + RMInit::logOut << "r_Conv_int16::readToSrcStream() srcType (" << desc.srcType->type_id() << ") unsupported !" << endl; + //clean up + if(buffer) + { + delete[] buffer; + buffer=NULL; + } + //report error + throw r_Error(); + break; + } + min.h=std::min<r_Double>(min.h, currRow.h); + max.h=std::max<r_Double>(max.h, currRow.h); + demRows.push_back(currRow); + } + } + + //clean up + if(buffer) + { + delete[] buffer; + buffer=NULL; + } + + if(demRows.empty()) + { + RMInit::logOut << "r_Conv_int16::readToSrcStream() src stream is empty !" << endl; + throw r_Error(); + } +} + + +void +r_Conv_int16::writeFromDestStream() throw(r_Error) +{ + int16RowVec::const_iterator iter, iterEnd; + r_Long xdim, ydim, offset; + r_Point currPt(destIntervDim); + r_Bytes typeSize=0; + + + //FIXME here we should modify for other type support + if(desc.destType->type_id() != r_Type::DOUBLE) + { + RMInit::logOut << "r_Conv_int16::writeFromDestStream() destType (" << desc.destType->type_id() + << ") is not " << r_Type::DOUBLE << " !" << endl; + throw r_Error(); + } + + xdim=desc.destInterv[0].get_extent(); + ydim=desc.destInterv[1].get_extent(); + iter=demRows.begin(); + iterEnd=demRows.end(); + typeSize=((r_Primitive_Type*)desc.destType)->size(); + + //FIXME correction for strange efect of r_Long cast with 1e-6 + while(iter != iterEnd) + { + if(collBBox.flipx) + currPt[0]=(collBBox.endx - iter->x)/collBBox.resx + 1e-6; + else + currPt[0]=(iter->x - collBBox.startx)/collBBox.resx + 1e-6; + if(collBBox.flipy) + currPt[1]=(collBBox.endy - iter->y)/collBBox.resy + 1e-6; + else + currPt[1]=(iter->y - collBBox.starty)/collBBox.resy + 1e-6; + ((r_Primitive_Type*)desc.destType)->set_double(&desc.dest[desc.destInterv.cell_offset(currPt)*typeSize], iter->h); + ++iter; + } +} + +void +r_Conv_int16::writeToDestStream(ofstream& oFile) throw(r_Error) +{ + int16RowVec::const_iterator iter, iterEnd; + r_Double currH; + + if(!oFile.is_open()) + { + RMInit::logOut << "r_Conv_int16::writeToDestStream() oFile is not opened !" << endl; + throw r_Error(); + } + oFile.setf(std::ios::fixed); + + iter=demRows.begin(); + iterEnd=demRows.end(); + while(iter != iterEnd) + { + //update to support NULL value: 0. (real value) goes in FLT_MIN(db value) + //because 0.(db value) represent NULL(real value). When we do export we skip NULL values. + currH = iter->h; + if(currH != NULL_DB) + { + //FIXME we have to implement different here when we change server scale algorithm + if(currH == ZERO_DB) + currH = ZERO_int16; + oFile << iter->x << "\t" << iter->y << "\t" << currH << endl; + } + ++iter; + } +} + +r_convDesc& +r_Conv_int16::convertFrom(const char* options) throw (r_Error) +{ + bool hasSrcType=true; + + RMInit::logOut << "r_Conv_int16::convertFrom(" << (options?options:"NULL") << ")" << endl; + + if(!desc.srcType) + { + desc.srcType=get_external_type(desc.baseType); + hasSrcType=false; + } + + try + { + RMInit::logOut << "r_Conv_int16::convertFrom(...) src interval=" << desc.srcInterv << endl; + RMInit::logOut << "r_Conv_int16::convertFrom(...) src type=" << desc.srcType->type_id() << endl; + + //check options + if(!decodeOptions(options, collBBox)) + throw r_Error(); + + //check desc.srcInterv.dimension + if(desc.srcInterv.dimension() != srcIntervDim) + { + RMInit::logOut << "r_Conv_int16::convertFrom(" << (options?options:"NULL") + << ") desc.srcInterv dimension (" << desc.srcInterv.dimension() + << " != " << srcIntervDim << " !" << endl; + throw r_Error(); + } + + //check srcType + if(!desc.srcType->isPrimitiveType()) + { + RMInit::logOut << "r_Conv_int16::convertFrom(" << (options?options:"NULL") + << ") desc.srcType (" << desc.srcType->type_id() + << ") not supported, only primitive types !" << endl; + throw r_Error(); + } + + if(desc.srcType->isComplexType()) + { + RMInit::logOut << "r_Conv_int16::convertFrom(" << (options?options:"NULL") + << ") desc.srcType (" << desc.srcType->type_id() + << ") not supported !" << endl; + throw r_Error(); + } + + //read src stream + readFromSrcStream(); + + //convert from int16 to marray + //--computing the marray domain + desc.destInterv = r_Minterval(destIntervDim); + + //FIXME correction for strange efect of r_Long cast with 1e-6 + if(collBBox.flipx) + desc.destInterv << r_Sinterval((r_Long)((collBBox.endx - max.x)/collBBox.resx + 1e-6), + (r_Long)((collBBox.endx - min.x)/collBBox.resx + 1e-6)); + else + desc.destInterv << r_Sinterval((r_Long)((min.x - collBBox.startx)/collBBox.resx + 1e-6), + (r_Long)((max.x - collBBox.startx)/collBBox.resx + 1e-6)); + if(collBBox.flipy) + desc.destInterv << r_Sinterval((r_Long)((collBBox.endy - max.y)/collBBox.resy + 1e-6), + (r_Long)((collBBox.endy - min.y)/collBBox.resy + 1e-6)); + else + desc.destInterv << r_Sinterval((r_Long)((min.y - collBBox.starty)/collBBox.resy + 1e-6), + (r_Long)((max.y - collBBox.starty)/collBBox.resy + 1e-6)); + + RMInit::logOut << "r_Conv_int16::convertFrom(...) dest interval=" << desc.destInterv << endl; + + //--creating the resulting type + desc.destType = new r_Primitive_Type("Double", r_Type::DOUBLE); + RMInit::logOut << "r_Conv_int16::convertFrom(...) dest type=" << desc.destType->type_id() << endl; + + //--claim memory for result + desc.dest = (char*)mystore.storage_alloc(desc.destInterv.cell_count() * ((r_Primitive_Type*)desc.destType)->size()); + if(desc.dest==NULL) + { + RMInit::logOut << "r_Conv_int16::convertFrom(" << (options?options:"NULL") + << ") unable to claim memory !" << endl; + throw r_Ememory_allocation(); + } + memset(desc.dest, 0, desc.destInterv.cell_count() * ((r_Primitive_Type*)desc.destType)->size()); + + //--write parsed data in desc.dest + writeFromDestStream(); + } + catch(r_Error& err) + { + //cleanup + if(!hasSrcType) + { + delete desc.srcType; + desc.srcType=NULL; + } + + //desc.destType + if(desc.destType) + { + delete desc.destType; + desc.destType=NULL; + } + + //desc.dest + if(desc.dest) + { + mystore.storage_free(desc.dest); + desc.dest=NULL; + } + + //report error + throw; + } + + //cleanup + if(!hasSrcType) + { + delete desc.srcType; + desc.srcType=NULL; + } + + //return result + return desc; +} + + +r_convDesc& +r_Conv_int16::convertTo(const char* options) throw (r_Error) +{ + bool hasSrcType=true; + + RMInit::logOut << "r_Conv_int16::convertTo(" << (options?options:"NULL") << ")" << endl; + + try + { + if(!desc.srcType) + { + desc.srcType=get_external_type(desc.baseType); + hasSrcType=false; + } + + RMInit::logOut << "r_Conv_int16::convertTo(...) src interval=" << desc.srcInterv << endl; + RMInit::logOut << "r_Conv_int16::convertTo(...) src type=" << desc.srcType->type_id() << endl; + + //check options + if(!decodeOptions(options, collBBox)) + throw r_Error(); + + if(!desc.srcType->isPrimitiveType()) + { + RMInit::logOut << "r_Conv_int16::convertTo(" << (options?options:"NULL") + << ") desc.srcType (" << desc.srcType->type_id() + << ") not supported, only primitive types !" << endl; + throw r_Error(); + } + if(desc.srcType->isComplexType()) + { + RMInit::logOut << "r_Conv_int16::convertTo(" << (options?options:"NULL") + << ") desc.srcType (" << desc.srcType->type_id() + << ") not supported !" << endl; + throw r_Error(); + } + + //read src data + readToSrcStream(); + + //convert from marray to int16; + char* pTempFileName=NULL; + string tempFileName; + ofstream oFile; + FILE* pFile=NULL; + size_t lenFile=0; + + //--create the temp file + //FIXME for multithread application + pTempFileName=tmpnam(NULL); + if(pTempFileName==NULL) + { + RMInit::logOut << "r_Conv_int16::convertTo(" << (options?options:"NULL") + << ") desc.srcType (" << desc.srcType->type_id() + << ") unable to generate a tempory file !" << endl; + throw r_Error(); + } + + tempFileName=pTempFileName; + oFile.open(tempFileName.c_str()); + if(!oFile.is_open()) + { + RMInit::logOut << "r_Conv_int16::convertTo(" << (options?options:"NULL") + << ") desc.srcType (" << desc.srcType->type_id() + << ") unable to open the tempory file !" << endl; + throw r_Error(); + } + + RMInit::logOut << "r_Conv_int16::convertTo(...) temp file=" << tempFileName << endl; + + //--get int16 format + writeToDestStream(oFile); + oFile.close(); + + //--accessing the temp file + if ((pFile = fopen(tempFileName.c_str(), "rb")) == NULL) + { + RMInit::logOut << "r_Conv_int16::convertTo(): unable to read back file." << endl; + throw r_Error(r_Error::r_Error_General); + } + fseek(pFile, 0, SEEK_END); + lenFile = ftell(pFile); + RMInit::logOut << "r_Conv_int16::convertTo(...) dest len=" << lenFile << endl; + + if (!lenFile) + { + RMInit::logOut << "r_Conv_int16::convertTo(): source contains only NULL values." << endl; + throw r_Error(); + } + + //--creating the resulting type + desc.destType = new r_Primitive_Type("Char", r_Type::CHAR); + + //--computing the marray domain + desc.destInterv = r_Minterval(srcIntervDim); + desc.destInterv << r_Sinterval((r_Long)0, (r_Long)lenFile - 1); + + RMInit::logOut << "r_Conv_int16::convertTo(...) dest interval=" << desc.destInterv << endl; + RMInit::logOut << "r_Conv_int16::convertTo(...) dest type=" << desc.destType->type_id() << endl; + + //--claim memory for desc.dest + desc.dest = (char*)mystore.storage_alloc(lenFile); + if(desc.dest==NULL) + { + RMInit::logOut << "r_Conv_int16::convertTo(" << (options?options:"NULL") + << ") unable to claim memory !" << endl; + throw r_Ememory_allocation(); + } + memset(desc.dest, 0, lenFile); + + //--story the data in desc.dest + fseek(pFile, 0, SEEK_SET); + fread(desc.dest, 1, lenFile, pFile); + + //clean up + fclose(pFile); + pFile=NULL; + remove(pTempFileName); + } + catch(r_Error& err) + { + //cleanup + if(!hasSrcType) + { + delete desc.srcType; + desc.srcType=NULL; + } + + //desc.destType + if(desc.destType) + { + delete desc.destType; + desc.destType=NULL; + } + + //desc.dest + if(desc.dest) + { + mystore.storage_free(desc.dest); + desc.dest=NULL; + } + + //rethrow error + throw; + } + + //clean up + if(!hasSrcType) + { + delete desc.srcType; + desc.srcType=NULL; + } + + //return result + return desc; +} + +const char* +r_Conv_int16::get_name() const throw() +{ + return get_name_from_data_format(r_int16); +} + +r_Data_Format +r_Conv_int16::get_data_format() const throw() +{ + return r_int16; +} + +r_Convertor* +r_Conv_int16::clone() const throw(r_Error) +{ + return new r_Conv_int16(desc.src, desc.srcInterv, desc.srcType); +} diff --git a/conversion/int16.hh b/conversion/int16.hh new file mode 100644 index 0000000..c8d9f98 --- /dev/null +++ b/conversion/int16.hh @@ -0,0 +1,205 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * INCLUDE: int16.hh + * + * MODULE: conversion + * + * CLASSES: r_Conv_int16 + * + * COMMENTS: + * Provides interface to convert data to other formats. +*/ + +#ifndef _R_CONV_int16_HH_ +#define _R_CONV_int16_HH_ + +#include <sstream> +#include <vector> +#include <string> +#include <cstdio> +using std::vector; +using std::ofstream; +using std::string; + +#include "conversion/convertor.hh" +#include "raslib/odmgtypes.hh" + +//@ManMemo: Module {\bf conversion} + +/*@Doc: + int16 convertor class. + + Supported parameters are + + \begin{tabular}{lcl} + {\tt flipx} && int && flip image flag on x axis, default 0\\ + {\tt flipy} && int && flip image flag on y axis, default 1\\ + {\tt startx} && double && start value on x axis \\ + {\tt endx} && double && end value on x axis \\ + {\tt sizex} && int && number of pixels in horizontal direction (int >0) + {\tt sizey} && int && number of pixels in vertical direction (int >0) + {\tt resx} && double && resolution on x axis \\ + {\tt starty} && double && start value on y axis \\ + {\tt endy} && double && end value on y axis \\ + {\tt resy} && double && resolution on y axis \\ + {\tt hstep} && double && resolution on h axis \\ + \end{tabular} + + The "flipx" parameter is a flag for mirroring the image on x axis. + The "flipy" parameter is a flag for mirroring the image on y axis. + [startx:endx, starty:endy] represents the geographical bounding box + of the whole image. The corresponding pixel bounding box is calculated + as follows: + if flipy is disabled: + [(minx-startx)/resx:(maxx-startx)/resx, (miny-starty)/resy:(maxy-starty)/resy] + else + [(minx-startx)/resx:(maxx-startx)/resx, (endy-maxy)/resy:(endy-miny)/resy] + + if flipx is disabled: + [(minx-startx)/resx:(maxx-startx)/resx, (miny-starty)/resy:(maxy-starty)/resy] + else + [(endx-maxx)/resx:(endx-minx)/resx, (miny-starty)/resy:(maxy-starty)/resy] + + The pairs (startx, endx, resx), (starty, endy, resy) apply to the whole MDD object in the database + whereas the pairs (minx,maxx, resx), (miny, maxy, resy) describe the part of image under consideration. + They are used to compute the update part's position in RasDaMan coordinates. + Value hstep is vertical resolution (multiplied into the value read during conversion into internal format). +*/ + + +Format specification: int16 + +input parameters: + geox geo reference x of upper left point (float >0) + geoy geo reference y of upper left point (float >0) + resx horizontal resolution (pixel distance) in meters (float >0) + resy vertical resolution (pixel distance) in meters (float >0) + hstep factor by which pixel values have to be multiplied to obtain real height in meters (float >0) + + +An int16 file contains a sequence of sizex*sizey height values, advancing from west to east and from north to south. Each pixel consists of a 16 bit integer where the lower byte comes first in sequence (i.e., pixel value is byte[i]+byte[i+1]*256). +There is no file header, pixels start immediately at the beginning. + +Points are defined as follows for pixel position (i,j) in file (starting with (0/0): + geo position x = geox + i*resx + geo position y = geoy + j*resy + height = ( byte[ 2*i + 2*j*sizex] + byte[ 2*i + 2*j*sizex + 1] * 256 ) * hstep + +where / denotes integer division + +class r_Conv_int16 : public r_Convertor +{ + public: + // constants to handle NULL + static const r_Double NULL_DB; + static const r_Double ZERO_DB; + static const r_Double ZERO_int16; + + //inner class for convertor parameters + class r_GeoBBox + { + public: + r_Double startx, endx, resx; + r_Double starty, endy, resy; + r_ULong flipy, flipx; + }; + + r_Conv_int16(const char* source, const r_Minterval& lengthordomain, const r_Type* tp) throw(r_Error); + + r_Conv_int16(const char* source, const r_Minterval& lengthordomain, int tp) throw(r_Error); + + r_convDesc& convertFrom(const char* options = NULL) throw (r_Error); + + r_convDesc& convertTo(const char* options = NULL) throw (r_Error); + + const char* get_name() const throw(); + + r_Data_Format get_data_format() const throw(); + + r_Convertor* clone() const throw(r_Error); + + /// dimension of src domain accepted as input in convertFrom + static const r_Dimension srcIntervDim; + + /// dimension of dest domain accepted as input in convertTo + static const r_Dimension destIntervDim; + + /// decode convertor options + static bool decodeOptions( const char* options, + r_GeoBBox& collBBox) throw(); + + /// encode convertor options + static string encodeOptions(const r_GeoBBox& collBBox) throw(); + + /// destructor + virtual ~r_Conv_int16( void ); + + /// init convertor parameters to default value + static void initGeoBBox( r_GeoBBox& cBBox ); + + private: + + + /// check limits before converting + void checkLimits() throw(r_Error); + + ///i/o src/dest stream + void readFromSrcStream() throw(r_Error); + void readToSrcStream() throw(r_Error); + void writeFromDestStream() throw(r_Error); + void writeToDestStream(ofstream& oFile) throw(r_Error); + + /// parameters + r_GeoBBox collBBox; + + /// class constants + static const r_ULong paramMin; + static const char* paramSep; + static const char* paramEq; + static const char* paramFlipX; + static const char* paramFlipY; + static const char* paramStartX; + static const char* paramEndX; + static const char* paramResX; + static const char* paramStartY; + static const char* paramEndY; + static const char* paramResY; + + + /// internal data + class int16Row + { + public: + r_Double x,y,h; + }; + + typedef vector<int16Row> int16RowVec; + + int16Row min, max; + int16RowVec demRows; + + }; + +#endif + diff --git a/conversion/jpeg.cc b/conversion/jpeg.cc new file mode 100644 index 0000000..7638d82 --- /dev/null +++ b/conversion/jpeg.cc @@ -0,0 +1,530 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * SOURCE: jpeg.cc + * + * MODULE: conversion + * + * CLASSES: r_Conv_JPEG + * + * COMMENTS: + * + * Provides functions to convert data to JPEG and back + * +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <iostream> +#include <string.h> +#include <setjmp.h> + +extern "C" { +#include "jpeglib.h" +} + +#include "raslib/rminit.hh" +#include "raslib/parseparams.hh" +#include "conversion/jpeg.hh" +#include "conversion/memfs.hh" + + + +#define JPEG_IO_BUFFER_SIZE 4096 + + +// JPEG-interface in C-namespace (like JPEG lib) +extern "C" { + + +typedef struct my_compress_struct { + jpeg_compress_struct pub; + thandle_t handle; + JOCTET *buffer; + int bufferSize; +} my_compress_struct; + +typedef struct my_decompress_struct { + jpeg_decompress_struct pub; + thandle_t handle; + JOCTET *buffer; + int bufferSize; +} my_decompress_struct; + +typedef struct my_error_mgr { + jpeg_error_mgr pub; + jmp_buf setjmp_buffer; +} my_error_mgr; + + +// See jpeg library example +static void my_error_exit(jpeg_common_struct *cptr) +{ + my_error_mgr *myerr = (my_error_mgr*)(cptr->err); + (*cptr->err->output_message)(cptr); + longjmp(myerr->setjmp_buffer, 1); +} + + + +/* + * Memory IO wrapper functions, rely on memFS. + */ + +// Destination manager methods +// cptr is actually a pointer to my_compress_struct +static void dm_init_destination(jpeg_compress_struct *cptr) +{ + my_compress_struct *mptr = (my_compress_struct*)cptr; + + if ((mptr->buffer = new JOCTET[JPEG_IO_BUFFER_SIZE]) == NULL) + { + RMInit::logOut << "r_Conv_JPEG@dm_init_destination(): out of memory" << endl; + throw r_Error(MEMMORYALLOCATIONERROR); + } + mptr->bufferSize = JPEG_IO_BUFFER_SIZE; + cptr->dest->next_output_byte = mptr->buffer; cptr->dest->free_in_buffer = mptr->bufferSize; +} + + +static boolean dm_empty_output_buffer(jpeg_compress_struct *cptr) +{ + my_compress_struct *mptr = (my_compress_struct*)cptr; + boolean retval=FALSE; + + if (memfs_write(mptr->handle, mptr->buffer, mptr->bufferSize) == mptr->bufferSize) + { + cptr->dest->next_output_byte = mptr->buffer; cptr->dest->free_in_buffer = mptr->bufferSize; + retval=TRUE; + } + return retval; +} + + +static void dm_term_destination(jpeg_compress_struct *cptr) +{ + my_compress_struct *mptr = (my_compress_struct*)cptr; + + if (cptr->dest->next_output_byte != mptr->buffer) + { + memfs_write(mptr->handle, mptr->buffer, (cptr->dest->next_output_byte - mptr->buffer)); + } + delete [] mptr->buffer; mptr->buffer = NULL; +} + + +// Source manager methods +// dptr is actually a pointer to my_decompress_struct +static void sm_init_source(jpeg_decompress_struct *dptr) +{ + my_decompress_struct *mptr = (my_decompress_struct*)dptr; + + if ((mptr->buffer = new JOCTET[JPEG_IO_BUFFER_SIZE]) == NULL) + { + RMInit::logOut << "r_Conv_JPEG@sm_init_source(): out of memory" << endl; + throw r_Error(MEMMORYALLOCATIONERROR); + } + mptr->bufferSize = JPEG_IO_BUFFER_SIZE; + dptr->src->next_input_byte = mptr->buffer; dptr->src->bytes_in_buffer = 0; +} + + +// See jdatasrc.c +static boolean sm_fill_input_buffer(jpeg_decompress_struct *dptr) +{ + my_decompress_struct *mptr = (my_decompress_struct*)dptr; + int read_bytes=0; + + if ((read_bytes = memfs_chunk_read(mptr->handle, mptr->buffer, mptr->bufferSize)) != 0) + { + dptr->src->bytes_in_buffer = read_bytes; + } + else + { + mptr->buffer[0] = (JOCTET)0xff; + mptr->buffer[1] = (JOCTET)JPEG_EOI; + dptr->src->bytes_in_buffer = 2; + } + dptr->src->next_input_byte = mptr->buffer; + + return TRUE; +} + + +// See jdatasrc.c +static void sm_skip_input_data(jpeg_decompress_struct *dptr, long num_bytes) +{ + my_decompress_struct *mptr = (my_decompress_struct*)dptr; + + if (num_bytes < dptr->src->bytes_in_buffer) + { + dptr->src->next_input_byte += num_bytes; dptr->src->bytes_in_buffer -= num_bytes; + } + else + { + int read_bytes=0; + + num_bytes -= dptr->src->bytes_in_buffer; + dptr->src->next_input_byte = mptr->buffer; + while (num_bytes >= mptr->bufferSize) + { + memfs_chunk_seek(mptr->handle, mptr->bufferSize, SEEK_CUR); + num_bytes -= mptr->bufferSize; + } + read_bytes = memfs_chunk_read(mptr->handle, mptr->buffer, mptr->bufferSize); + if (read_bytes <= num_bytes) + { + mptr->buffer[0] = (JOCTET)0xff; + mptr->buffer[1] = (JOCTET)JPEG_EOI; + dptr->src->bytes_in_buffer = 2; + } + else + { + dptr->src->next_input_byte = mptr->buffer + num_bytes; + dptr->src->bytes_in_buffer = read_bytes - num_bytes; + } + } +} + + +/*static boolean sm_resync_to_restart(jpeg_decompress_struct *dptr, int desired) +{ + return FALSE; +}*/ + + +static void sm_term_source(jpeg_decompress_struct *dptr) +{ + my_decompress_struct *mptr = (my_decompress_struct*)dptr; + + delete [] mptr->buffer; mptr->buffer = NULL; +} + + +} // end of C namespace + + + + +/* + * r_Conv_JPEG class for converting MDD to JPEG and back + */ + +void r_Conv_JPEG::initJPEG( void ) +{ + quality = 80; + + if (params == NULL) + params = new r_Parse_Params; + + params->add("quality", &quality, r_Parse_Params::param_type_int); +} + + +r_Conv_JPEG::r_Conv_JPEG(const char *src, const r_Minterval &interv, int tp) throw(r_Error) +: r_Convert_Memory(src, interv, tp) +{ + initJPEG(); +} + + +r_Conv_JPEG::r_Conv_JPEG(const char *src, const r_Minterval &interv, const r_Type *tp) throw(r_Error) +: r_Convert_Memory(src, interv, tp) +{ + initJPEG(); +} + + +r_Conv_JPEG::~r_Conv_JPEG(void) +{ +} + + +r_convDesc &r_Conv_JPEG::convertTo( const char *options) throw(r_Error) +{ + struct jpeg_destination_mgr destMgr; + struct jpeg_compress_struct *cptr=NULL; + struct jpeg_error_mgr *jptr=NULL; + my_error_mgr jerr; + my_compress_struct cinfo; + int width=0, height=0, lineAdd=0, pixelAdd=0; + int i=0, j=0, spp=0; + J_COLOR_SPACE jcs; + JSAMPROW row_pointers[1]; + JSAMPLE *row=NULL, *rowPtr=NULL; + r_Long jpegSize=0; + + row = NULL; + memset(&cinfo, 0, sizeof(my_compress_struct)); + cinfo.handle = (thandle_t)handle; + cptr = (struct jpeg_compress_struct*)&cinfo.pub; + jptr = (struct jpeg_error_mgr*)&jerr.pub; + + cptr->err = jpeg_std_error(jptr); + jptr->error_exit = my_error_exit; + + params->process(options); + + if (setjmp(jerr.setjmp_buffer)) + { + if (row != NULL) {delete [] row; row = NULL;} + jpeg_abort_compress(cptr); + jpeg_destroy_compress(cptr); + // destination manager destructor might not be called on an abort + if (cinfo.buffer != NULL){delete [] cinfo.buffer; cinfo.buffer=NULL;} + RMInit::logOut << "r_Conv_JPEG::convertTo(" << options << "): unable to save the stack" << endl; + throw r_Error(r_Error::r_Error_General); + } + + jpeg_create_compress(cptr); + jpeg_set_quality(cptr, quality, 0); + + memfs_newfile(handle); + + destMgr.init_destination = dm_init_destination; + destMgr.empty_output_buffer = dm_empty_output_buffer; + destMgr.term_destination = dm_term_destination; + + cptr->dest = &destMgr; + + width = (int)(desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1); + height = (int)(desc.srcInterv[1].high() - desc.srcInterv[1].low() + 1); + + cptr->image_width = (JDIMENSION)width; cptr->image_height = (JDIMENSION)height; + + switch (desc.baseType) + { + case ctype_bool: + case ctype_char: + jcs = JCS_GRAYSCALE; spp = 1; lineAdd = 1; pixelAdd = height; break; + case ctype_rgb: + jcs = JCS_RGB; spp = 3; lineAdd = 3; pixelAdd = 3*height; break; + default: + RMInit::logOut << "r_Conv_JPEG::convertTo(" << options << "): unsupported base type" << endl; + throw r_Error(r_Error::r_Error_General); + } + + cptr->input_components = spp; cptr->in_color_space = jcs; + + jpeg_set_defaults(cptr); + + jpeg_set_quality(cptr, quality, TRUE); + + jpeg_start_compress(cptr, TRUE); + + if ((row = new JSAMPLE[width * spp]) == NULL) + { + RMInit::logOut << "r_Conv_JPEG::convertTo(" << options << "): out of memory" << endl; + throw r_Error(MEMMORYALLOCATIONERROR); + } + + row_pointers[0] = row; + + const unsigned char *src=NULL, *srcPtr=NULL; + + src = (const unsigned char*)desc.src; + + for (j=0; j<height; j++, src += lineAdd) + { + srcPtr = src; rowPtr = row; + + switch (desc.baseType) + { + case ctype_bool: + for (i=0; i<width; i++, srcPtr += pixelAdd) + { + *rowPtr++ = (*srcPtr == 0) ? 0 : 0xff; + } + break; + case ctype_char: + for (i=0; i<width; i++, srcPtr += pixelAdd) + { + *rowPtr++ = *srcPtr; + } + break; + case ctype_rgb: + for (i=0; i<width; i++, srcPtr += pixelAdd) + { + *rowPtr++ = srcPtr[0]; *rowPtr++ = srcPtr[1]; *rowPtr++ = srcPtr[2]; + } + break; + } + jpeg_write_scanlines(cptr, row_pointers, 1); + } + + delete [] row; row = NULL; + + jpeg_finish_compress(cptr); + + jpeg_destroy_compress(cptr); + + jpegSize = memfs_size(handle); + + if ((desc.dest = (char*)mystore.storage_alloc(jpegSize)) == NULL) + { + RMInit::logOut << "r_Conv_JPEG::convertTo(" << options << "): out of memory" << endl; + throw r_Error(MEMMORYALLOCATIONERROR); + } + memfs_seek(handle, 0, SEEK_SET); + memfs_read(handle, desc.dest, jpegSize); + + desc.destInterv = r_Minterval(1); + desc.destInterv << r_Sinterval((r_Range)0, (r_Range)jpegSize - 1); + + desc.destType = r_Type::get_any_type("char"); + + return desc; +} + + +r_convDesc &r_Conv_JPEG::convertFrom(const char *options) throw(r_Error) +{ + struct jpeg_source_mgr srcMgr; + struct jpeg_decompress_struct *dptr=NULL; + struct jpeg_error_mgr *jptr=NULL; + my_error_mgr jerr; + my_decompress_struct cinfo; + int width=0, height=0, lineAdd=0, pixelAdd=0; + int i=0, j=0, spp=0; + J_COLOR_SPACE jcs; + JSAMPROW row_pointers[1]; + JSAMPLE *row=NULL, *rowPtr=NULL; + char *dest=NULL, *destPtr=NULL; + + row = NULL; desc.dest = NULL; + memset(&cinfo, 0, sizeof(my_decompress_struct)); + cinfo.handle = (thandle_t)handle; + dptr = (struct jpeg_decompress_struct*)&cinfo.pub; + jptr = (struct jpeg_error_mgr*)&jerr.pub; + + dptr->err = jpeg_std_error(jptr); + jptr->error_exit = my_error_exit; + + if (setjmp(jerr.setjmp_buffer)) + { + if (row != NULL) {delete [] row; row = NULL;} + if (desc.dest != NULL) {mystore.storage_free(desc.dest); desc.dest = NULL;} + jpeg_abort_decompress(dptr); + jpeg_destroy_decompress(dptr); + // Source manager destructor might not be called on an abort + if (cinfo.buffer != NULL) {delete [] cinfo.buffer; cinfo.buffer=NULL;} + RMInit::logOut << "r_Conv_JPEG::convertFrom(" << options << "): unable to save the stack" << endl; + throw r_Error(r_Error::r_Error_General); + } + + jpeg_create_decompress(dptr); + + memfs_chunk_initfs(handle, (char*)desc.src, (r_Long)(desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1)); + + srcMgr.init_source = sm_init_source; + srcMgr.fill_input_buffer = sm_fill_input_buffer; + srcMgr.skip_input_data = sm_skip_input_data; + srcMgr.resync_to_restart = NULL; //sm_resync_to_restart; + srcMgr.term_source = sm_term_source; + + dptr->src = &srcMgr; + + jpeg_read_header(dptr, TRUE); + width = (int)(dptr->image_width); height = (int)(dptr->image_height); + + if (dptr->num_components == 1) + { + desc.baseType = ctype_char; + lineAdd = 1; pixelAdd = height; + } + else + { + desc.baseType = ctype_rgb; + lineAdd = 3; pixelAdd = 3*height; + dptr->out_color_space = JCS_RGB; + } + + jpeg_start_decompress(dptr); + + spp = (int)(dptr->output_components); + + row = new JSAMPLE[width * spp]; + desc.dest = (char*)mystore.storage_alloc(width * height * spp); + + if ((row == NULL) || (desc.dest == NULL)) + { + if (row != NULL) {delete [] row; row = NULL;} + RMInit::logOut << "r_Conv_JPEG::convertFrom(): out of memory" << endl; + throw r_Error(MEMMORYALLOCATIONERROR); + } + + row_pointers[0] = row; dest = desc.dest; + for (j=0; j<height; j++, dest += lineAdd) + { + jpeg_read_scanlines(dptr, row_pointers, 1); + destPtr = dest; rowPtr = row; + switch (spp) + { + case 1: + for (i=0; i<width; i++, destPtr += pixelAdd) + { + *destPtr = *rowPtr++; + } + break; + case 3: + for (i=0; i<width; i++, destPtr += pixelAdd) + { + destPtr[0] = *rowPtr++; destPtr[1] = *rowPtr++; destPtr[2] = *rowPtr++; + } + break; + } + } + + delete [] row; row = NULL; + + jpeg_finish_decompress(dptr); + + jpeg_destroy_decompress(dptr); + + desc.destInterv = r_Minterval(2); + desc.destInterv << r_Sinterval((r_Range)0, (r_Range)width-1) + << r_Sinterval((r_Range)0, (r_Range)height-1); + + desc.destType = get_external_type(desc.baseType); + + return desc; +} + + + +const char *r_Conv_JPEG::get_name( void ) const +{ + return format_name_jpeg; +} + + +r_Data_Format r_Conv_JPEG::get_data_format( void ) const +{ + return r_JPEG; +} + + +r_Convertor *r_Conv_JPEG::clone( void ) const +{ + return new r_Conv_JPEG(desc.src, desc.srcInterv, desc.baseType); +} diff --git a/conversion/jpeg.hh b/conversion/jpeg.hh new file mode 100644 index 0000000..2c2bb6b --- /dev/null +++ b/conversion/jpeg.hh @@ -0,0 +1,84 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * INCLUDE: jpeg.hh + * + * MODULE: conversion + * + * CLASSES: r_Conv_JPEG + * + * COMMENTS: + * + * Provides interface to convert data to JPEG and back. + * +*/ + +#ifndef _R_CONV_JPEG_HH_ +#define _R_CONV_JPEG_HH_ + +#include "conversion/convertor.hh" + + +//@ManMemo: Module {\bf conversion} + +/*@Doc: + JPEG convertor class. + + Supported parameters are + + \begin{tabular}{lcl} + quality && int && quality ratio between 0 and 100 + \end{tabular} + + */ + +class r_Conv_JPEG : public r_Convert_Memory +{ + public: + /// constructor using an r_Type object + r_Conv_JPEG( const char *src, const r_Minterval &interv, const r_Type *tp ) throw(r_Error); + /// constructor using convert_type_e shortcut + r_Conv_JPEG( const char *src, const r_Minterval &interv, int tp ) throw(r_Error); + /// destructor + ~r_Conv_JPEG( void ); + + /// convert to JPEG + virtual r_convDesc &convertTo( const char *options=NULL ) throw(r_Error); + /// convert from JPEG + virtual r_convDesc &convertFrom( const char *options=NULL ) throw(r_Error); + /// cloning + virtual r_Convertor *clone( void ) const; + /// identification + virtual const char *get_name( void ) const; + virtual r_Data_Format get_data_format( void ) const; + + + private: + /// init JPEG class + void initJPEG( void ); + + /// parameters + int quality; +}; + +#endif diff --git a/conversion/memfs.c b/conversion/memfs.c new file mode 100644 index 0000000..c346880 --- /dev/null +++ b/conversion/memfs.c @@ -0,0 +1,421 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * SOURCE: memfs.c + * + * MODULE: conversion + * + * PURPOSE: + * Memory Filing System used by some of the convertor modules + * + * COMMENTS + * None +*/ + +#include "mymalloc/mymalloc.h" + +#include <stdio.h> +#include <malloc.h> +#include <string.h> +#include "conversion/memfs.hh" + + +/* can't use RMDBGOUT because this is C, not C++ */ +const int MEMFSDBGLEVEL = 4; + +extern int RManDebug; + + + +/* This function for internal use only */ +int memfs_ensure(thandle_t handle, toff_t off) +{ + memFSContext *memFS = (memFSContext *)handle; + char **mam2=NULL; + int mamSize2=0, i=0; + +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_ensure: %d\n", off); fflush(stdout); + } +#endif + /* Do we have to allocate a bigger mam? */ + mamSize2 = (off >> MEMFS_LD_BLOCKSIZE); + if (mamSize2 >= memFS->mamSize) + { + /* Always allocate mam in powers of 2. That ensures that if we run out + of space the new mam will be twice as big as the old one. */ + i = 0; while (mamSize2 != 0) {mamSize2 >>= 1; i++;} + mamSize2 = (1 << i); +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_ensure: growing mam from %d to %d\n", memFS->mamSize, mamSize2); + fflush(stdout); + } +#endif + if ((mam2 = (char **)mymalloc(mamSize2 * sizeof(char*))) == NULL) + return -1; + /* Copy existing mam entries */ + memcpy ((void*)mam2, (void*) memFS->mam, memFS->mamSize * sizeof(char*)); + /* Init new mam entries */ + for (i=memFS->mamSize; i < mamSize2; i++) + { + mam2[i] = NULL; + } + /* free old mam */ + free(memFS->mam); + memFS->mam = mam2; memFS->mamSize = mamSize2; + } + /* Calculate again because its value might have been changed by the + above block */ + mamSize2 = (off >> MEMFS_LD_BLOCKSIZE); + if ((memFS->mam)[mamSize2] == NULL) + { + /* We don't just have to allocate this one new block but all the + ones with lower addresses that aren't defined yet as well */ + for (i=memFS->mamHighest+1; i <= mamSize2; i++) + { + if (((memFS->mam)[i] = (char*)mymalloc((1 << MEMFS_LD_BLOCKSIZE) * sizeof(char))) == NULL) + return -1; + } + memFS->mamHighest = mamSize2; + } + /* All done, the memFS can now hold an object of size off */ + return 0; +} + + +/* Initialise the memory filing system */ +int memfs_initfs(thandle_t handle) +{ + memFSContext *memFS = (memFSContext *)handle; + int i=0; + +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_initfs\n"); fflush(stdout); + } +#endif + memFS->pos = 0; memFS->high = 0; + memFS->mamSize = MEMFS_MAM_ENTRIES; + if ((memFS->mam = (char **)mymalloc(MEMFS_MAM_ENTRIES * sizeof(char *))) == NULL) + return -1; + if (((memFS->mam)[0] = (char*)mymalloc((1 << MEMFS_LD_BLOCKSIZE) * sizeof(char))) == NULL) + return -1; + memFS->mamHighest = 0; + for (i=1; i<MEMFS_MAM_ENTRIES; i++) + { + (memFS->mam)[i] = NULL; + } + return 0; +} + + +/* Kill the memory filing system, freeing all its resources */ +void memfs_killfs(thandle_t handle) +{ + memFSContext *memFS = (memFSContext *)handle; + int i=0; + +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_killfs\n"); fflush(stdout); + } +#endif + for (i=0; i < memFS->mamSize; i++) + { + if ((memFS->mam)[i] == NULL) break; + free((memFS->mam)[i]); + } + free(memFS->mam); +} + + +/* Reset file pointers, leave memory setup */ +void memfs_newfile(thandle_t handle) +{ + memFSContext *memFS = (memFSContext *)handle; + +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_newfile\n"); fflush(stdout); + } +#endif + memFS->pos = 0; memFS->high = 0; +} + + +tsize_t memfs_read(thandle_t handle, tdata_t mem, tsize_t size) +{ + tsize_t todo=0, transfered = 0; + int block=0, offset=0, x=0; + memFSContext *memFS = (memFSContext *)handle; + + /* Don't read over the end of the "file" */ + todo = memFS->high - memFS->pos; +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_read: (%d, left: %d)\n", todo, memFS->high); fflush(stdout); + } +#endif + if (todo > size) todo = size; + while (todo > 0) + { + block = (memFS->pos >> MEMFS_LD_BLOCKSIZE); + offset = memFS->pos - (block << MEMFS_LD_BLOCKSIZE); + /* Space left in this buffer */ + x = (1 << MEMFS_LD_BLOCKSIZE) - offset; + if (x > todo) x = todo; + memcpy((void*)mem, (void*)(((memFS->mam)[block]) + offset), x); + /* tdata_t is some kind of void *, so we have to do this cast */ + mem = (tdata_t)(((char*)mem) + x); + memFS->pos += x; transfered += x; todo -= x; + } + return transfered; +} + + +tsize_t memfs_write(thandle_t handle, tdata_t mem, tsize_t size) +{ + tsize_t transfered = 0; + memFSContext *memFS = (memFSContext *)handle; + int block=0, offset=0, x=0; + + /* Make sure there's enough room for this write */ + if (memfs_ensure(handle, memFS->pos + size) < 0) return 0; +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_write (%d)\n",size); fflush(stdout); + } +#endif + while (size > 0) + { + /* See memfs_read */ + block = (memFS->pos >> MEMFS_LD_BLOCKSIZE); + offset = memFS->pos - (block << MEMFS_LD_BLOCKSIZE); + x = (1 << MEMFS_LD_BLOCKSIZE) - offset; + if (x > size) x = size; + memcpy((void*)(((memFS->mam)[block]) + offset), (void*)mem, x); + mem = (tdata_t)(((char *)mem) + x); + memFS->pos += x; transfered += x; size -= x; + } + if (memFS->pos > memFS->high) {memFS->high = memFS->pos;} + return transfered; +} + + +toff_t memfs_seek(thandle_t handle, toff_t offset, int mode) +{ + memFSContext *memFS = (memFSContext *)handle; + + switch (mode) + { + case SEEK_SET: memFS->pos = offset; break; + case SEEK_CUR: memFS->pos += offset; break; + case SEEK_END: memFS->pos = memFS->high + offset; break; + default: break; + } + if (memFS->pos < 0) memFS->pos = 0; + /* Don't limit to end of file (this actually caused problems!) */ + memfs_ensure(handle, memFS->pos); + if (memFS->pos > memFS->high) memFS->high = memFS->pos; +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_seek: Set pos to %d\n", memFS->pos); fflush(stdout); + } +#endif + return memFS->pos; +} + + +int memfs_close(thandle_t handle) +{ +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_close:\n"); fflush(stdout); + } +#endif + return 1; /* = success? */ +} + + +toff_t memfs_size(thandle_t handle) +{ +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_size:\n"); fflush(stdout); + } +#endif + return (((memFSContext *)handle)->high); +} + + +int memfs_map(thandle_t handle, tdata_t *memp, toff_t *top) +{ +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_map: %p, %d\n", *memp, *top); fflush(stdout); + } +#endif + return 0; +} + + +void memfs_unmap(thandle_t handle, tdata_t mem, toff_t to) +{ +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_unmap: %p, %d\n", mem, to); fflush(stdout); + } +#endif +} + + + + + + +/* Read-only from memory (simple chunky model, not block-oriented) */ +void memfs_chunk_initfs(thandle_t handle, char *src, r_Long size) +{ + memFSContext *memFS = (memFSContext *)handle; + +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_chunk_initfs: %p, %d\n", src, size); fflush(stdout); + } +#endif + memFS->pos = 0; + memFS->chunk = src; + memFS->high = size; +} + + +tsize_t memfs_chunk_read(thandle_t handle, tdata_t mem, tsize_t size) +{ + tsize_t todo=0; + memFSContext *memFS = (memFSContext *)handle; + + todo = memFS->high - memFS->pos; +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_chunk_read: %d (left %d)\n", size, todo); fflush(stdout); + } +#endif + if (todo > size) todo = size; + if (todo > 0) + { + memcpy((void*)mem, (void*)(memFS->chunk + memFS->pos), todo); + memFS->pos += todo; + } + return todo; +} + + +toff_t memfs_chunk_seek(thandle_t handle, toff_t offset, int mode) +{ + memFSContext *memFS = (memFSContext *)handle; + + switch (mode) + { + case SEEK_SET: memFS->pos = offset; break; + case SEEK_CUR: memFS->pos += offset; break; + case SEEK_END: memFS->pos = memFS->high + offset; break; + default: break; + } + if (memFS->pos < 0) memFS = 0; + /* Since file can't be extended this is OK here */ + if (memFS->pos > memFS->high) memFS->pos = memFS->high; +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_chunk_seek: Position to %d\n", memFS->pos); fflush(stdout); + } +#endif + return memFS->pos; +} + + +int memfs_chunk_close(thandle_t handle) +{ +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_chunk_close:\n"); fflush(stdout); + } +#endif + return 1; +} + + +toff_t memfs_chunk_size(thandle_t handle) +{ +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_chunk_size:\n"); fflush(stdout); + } +#endif + return (((memFSContext *)handle)->high); +} + + +/* Map file to memory -- since we already have it in memory in the + first place this is very simple. */ +int memfs_chunk_map(thandle_t handle, tdata_t *memp, toff_t *top) +{ + memFSContext *memFS = (memFSContext *)handle; + +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_chunk_map:\n"); fflush(stdout); + } +#endif + *memp = (tdata_t)(memFS->chunk); *top = (toff_t)(memFS->high); + return 1; /* Success? */ +} + +void memfs_chunk_unmap(thandle_t handle, tdata_t mem, toff_t to) +{ +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_chunk_unmap: %p, %d\n", mem, to); fflush(stdout); + } +#endif +} diff --git a/conversion/memfs.cc b/conversion/memfs.cc new file mode 100644 index 0000000..8dca196 --- /dev/null +++ b/conversion/memfs.cc @@ -0,0 +1,421 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * SOURCE: memfs.c + * + * MODULE: conversion + * + * PURPOSE: + * Memory Filing System used by some of the convertor modules + * + * COMMENTS: + * None +*/ + +#include "mymalloc/mymalloc.h" + +#include <stdio.h> +#include <malloc.h> +#include <string.h> +#include "conversion/memfs.hh" + + +/* can't use RMDBGOUT because this is C, not C++ */ +const int MEMFSDBGLEVEL = 4; + +extern int RManDebug; + + + +/* This function for internal use only */ +int memfs_ensure(thandle_t handle, toff_t off) +{ + memFSContext *memFS = (memFSContext *)handle; + char **mam2=NULL; + int mamSize2=0, i=0; + +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_ensure: %d\n", off); fflush(stdout); + } +#endif + /* Do we have to allocate a bigger mam? */ + mamSize2 = (off >> MEMFS_LD_BLOCKSIZE); + if (mamSize2 >= memFS->mamSize) + { + /* Always allocate mam in powers of 2. That ensures that if we run out + of space the new mam will be twice as big as the old one. */ + i = 0; while (mamSize2 != 0) {mamSize2 >>= 1; i++;} + mamSize2 = (1 << i); +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_ensure: growing mam from %d to %d\n", memFS->mamSize, mamSize2); + fflush(stdout); + } +#endif + if ((mam2 = (char **)mymalloc(mamSize2 * sizeof(char*))) == NULL) + return -1; + /* Copy existing mam entries */ + memcpy ((void*)mam2, (void*) memFS->mam, memFS->mamSize * sizeof(char*)); + /* Init new mam entries */ + for (i=memFS->mamSize; i < mamSize2; i++) + { + mam2[i] = NULL; + } + /* free old mam */ + free(memFS->mam); + memFS->mam = mam2; memFS->mamSize = mamSize2; + } + /* Calculate again because its value might have been changed by the + above block */ + mamSize2 = (off >> MEMFS_LD_BLOCKSIZE); + if ((memFS->mam)[mamSize2] == NULL) + { + /* We don't just have to allocate this one new block but all the + ones with lower addresses that aren't defined yet as well */ + for (i=memFS->mamHighest+1; i <= mamSize2; i++) + { + if (((memFS->mam)[i] = (char*)mymalloc((1 << MEMFS_LD_BLOCKSIZE) * sizeof(char))) == NULL) + return -1; + } + memFS->mamHighest = mamSize2; + } + /* All done, the memFS can now hold an object of size off */ + return 0; +} + + +/* Initialise the memory filing system */ +int memfs_initfs(thandle_t handle) +{ + memFSContext *memFS = (memFSContext *)handle; + int i=0; + +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_initfs\n"); fflush(stdout); + } +#endif + memFS->pos = 0; memFS->high = 0; + memFS->mamSize = MEMFS_MAM_ENTRIES; + if ((memFS->mam = (char **)mymalloc(MEMFS_MAM_ENTRIES * sizeof(char *))) == NULL) + return -1; + if (((memFS->mam)[0] = (char*)mymalloc((1 << MEMFS_LD_BLOCKSIZE) * sizeof(char))) == NULL) + return -1; + memFS->mamHighest = 0; + for (i=1; i<MEMFS_MAM_ENTRIES; i++) + { + (memFS->mam)[i] = NULL; + } + return 0; +} + + +/* Kill the memory filing system, freeing all its resources */ +void memfs_killfs(thandle_t handle) +{ + memFSContext *memFS = (memFSContext *)handle; + int i=0; + +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_killfs\n"); fflush(stdout); + } +#endif + for (i=0; i < memFS->mamSize; i++) + { + if ((memFS->mam)[i] == NULL) break; + free((memFS->mam)[i]); + } + free(memFS->mam); +} + + +/* Reset file pointers, leave memory setup */ +void memfs_newfile(thandle_t handle) +{ + memFSContext *memFS = (memFSContext *)handle; + +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_newfile\n"); fflush(stdout); + } +#endif + memFS->pos = 0; memFS->high = 0; +} + + +tsize_t memfs_read(thandle_t handle, tdata_t mem, tsize_t size) +{ + tsize_t todo=0, transfered = 0; + int block=0, offset=0, x=0; + memFSContext *memFS = (memFSContext *)handle; + + /* Don't read over the end of the "file" */ + todo = memFS->high - memFS->pos; +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_read: (%d, left: %d)\n", todo, memFS->high); fflush(stdout); + } +#endif + if (todo > size) todo = size; + while (todo > 0) + { + block = (memFS->pos >> MEMFS_LD_BLOCKSIZE); + offset = memFS->pos - (block << MEMFS_LD_BLOCKSIZE); + /* Space left in this buffer */ + x = (1 << MEMFS_LD_BLOCKSIZE) - offset; + if (x > todo) x = todo; + memcpy((void*)mem, (void*)(((memFS->mam)[block]) + offset), x); + /* tdata_t is some kind of void *, so we have to do this cast */ + mem = (tdata_t)(((char*)mem) + x); + memFS->pos += x; transfered += x; todo -= x; + } + return transfered; +} + + +tsize_t memfs_write(thandle_t handle, tdata_t mem, tsize_t size) +{ + tsize_t transfered = 0; + memFSContext *memFS = (memFSContext *)handle; + int block=0, offset=0, x=0; + + /* Make sure there's enough room for this write */ + if (memfs_ensure(handle, memFS->pos + size) < 0) return 0; +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_write (%d)\n",size); fflush(stdout); + } +#endif + while (size > 0) + { + /* See memfs_read */ + block = (memFS->pos >> MEMFS_LD_BLOCKSIZE); + offset = memFS->pos - (block << MEMFS_LD_BLOCKSIZE); + x = (1 << MEMFS_LD_BLOCKSIZE) - offset; + if (x > size) x = size; + memcpy((void*)(((memFS->mam)[block]) + offset), (void*)mem, x); + mem = (tdata_t)(((char *)mem) + x); + memFS->pos += x; transfered += x; size -= x; + } + if (memFS->pos > memFS->high) {memFS->high = memFS->pos;} + return transfered; +} + + +toff_t memfs_seek(thandle_t handle, toff_t offset, int mode) +{ + memFSContext *memFS = (memFSContext *)handle; + + switch (mode) + { + case SEEK_SET: memFS->pos = offset; break; + case SEEK_CUR: memFS->pos += offset; break; + case SEEK_END: memFS->pos = memFS->high + offset; break; + default: break; + } + if (memFS->pos < 0) memFS->pos = 0; + /* Don't limit to end of file (this actually caused problems!) */ + memfs_ensure(handle, memFS->pos); + if (memFS->pos > memFS->high) memFS->high = memFS->pos; +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_seek: Set pos to %d\n", memFS->pos); fflush(stdout); + } +#endif + return memFS->pos; +} + + +int memfs_close(thandle_t handle) +{ +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_close:\n"); fflush(stdout); + } +#endif + return 1; /* = success? */ +} + + +toff_t memfs_size(thandle_t handle) +{ +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_size:\n"); fflush(stdout); + } +#endif + return (((memFSContext *)handle)->high); +} + + +int memfs_map(thandle_t handle, tdata_t *memp, toff_t *top) +{ +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_map: %p, %d\n", *memp, *top); fflush(stdout); + } +#endif + return 0; +} + + +void memfs_unmap(thandle_t handle, tdata_t mem, toff_t to) +{ +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_unmap: %p, %d\n", mem, to); fflush(stdout); + } +#endif +} + + + + + + +/* Read-only from memory (simple chunky model, not block-oriented) */ +void memfs_chunk_initfs(thandle_t handle, char *src, r_Long size) +{ + memFSContext *memFS = (memFSContext *)handle; + +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_chunk_initfs: %p, %d\n", src, size); fflush(stdout); + } +#endif + memFS->pos = 0; + memFS->chunk = src; + memFS->high = size; +} + + +tsize_t memfs_chunk_read(thandle_t handle, tdata_t mem, tsize_t size) +{ + tsize_t todo=0; + memFSContext *memFS = (memFSContext *)handle; + + todo = memFS->high - memFS->pos; +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_chunk_read: %d (left %d)\n", size, todo); fflush(stdout); + } +#endif + if (todo > size) todo = size; + if (todo > 0) + { + memcpy((void*)mem, (void*)(memFS->chunk + memFS->pos), todo); + memFS->pos += todo; + } + return todo; +} + + +toff_t memfs_chunk_seek(thandle_t handle, toff_t offset, int mode) +{ + memFSContext *memFS = (memFSContext *)handle; + + switch (mode) + { + case SEEK_SET: memFS->pos = offset; break; + case SEEK_CUR: memFS->pos += offset; break; + case SEEK_END: memFS->pos = memFS->high + offset; break; + default: break; + } + if (memFS->pos < 0) memFS = 0; + /* Since file can't be extended this is OK here */ + if (memFS->pos > memFS->high) memFS->pos = memFS->high; +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_chunk_seek: Position to %d\n", memFS->pos); fflush(stdout); + } +#endif + return memFS->pos; +} + + +int memfs_chunk_close(thandle_t handle) +{ +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_chunk_close:\n"); fflush(stdout); + } +#endif + return 1; +} + + +toff_t memfs_chunk_size(thandle_t handle) +{ +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_chunk_size:\n"); fflush(stdout); + } +#endif + return (((memFSContext *)handle)->high); +} + + +/* Map file to memory -- since we already have it in memory in the + first place this is very simple. */ +int memfs_chunk_map(thandle_t handle, tdata_t *memp, toff_t *top) +{ + memFSContext *memFS = (memFSContext *)handle; + +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_chunk_map:\n"); fflush(stdout); + } +#endif + *memp = (tdata_t)(memFS->chunk); *top = (toff_t)(memFS->high); + return 1; /* Success? */ +} + +void memfs_chunk_unmap(thandle_t handle, tdata_t mem, toff_t to) +{ +#ifdef RMANDEBUG + if (RManDebug >= MEMFSDBGLEVEL) + { + printf("memfs_chunk_unmap: %p, %d\n", mem, to); fflush(stdout); + } +#endif +} diff --git a/conversion/memfs.h b/conversion/memfs.h new file mode 100644 index 0000000..42958ad --- /dev/null +++ b/conversion/memfs.h @@ -0,0 +1,85 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * INCLUDE: memfs.hh + * + * MODULE: conversion + * + * PURPOSE: + * Memory Filing System used by some of the convertor modules. + * + * COMMENTS: + * None +*/ + +#ifndef _MEMFS_HH_ +#define _MEMFS_HH_ + +/* For data types used by the memfs */ +#include "tiffio.h" +#include "raslib/odmgtypes.hh" + + +/* Claim blocks in 4k chunks */ +const int MEMFS_LD_BLOCKSIZE = 12; +/* Initially preserve enough room for 16 blocks */ +const int MEMFS_MAM_ENTRIES = 16; + +typedef struct memFSContext { + r_Long pos, high; + int mamSize, mamHighest; + char **mam; + char *chunk; +} memFSContext; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Flexible, read-write memFS */ +int memfs_initfs(thandle_t handle); +void memfs_killfs(thandle_t handle); +void memfs_newfile(thandle_t handle); +tsize_t memfs_read(thandle_t handle, tdata_t mem, tsize_t size); +tsize_t memfs_write(thandle_t handle, tdata_t mem, tsize_t size); +toff_t memfs_seek(thandle_t handle, toff_t offset, int mode); +int memfs_close(thandle_t handle); +toff_t memfs_size(thandle_t handle); +int memfs_map(thandle_t handle, tdata_t *memp, toff_t *top); +void memfs_unmap(thandle_t handle, tdata_t mem, toff_t top); + +/* Simple, read-only memFS */ +void memfs_chunk_initfs(thandle_t handle, char *src, r_Long size); +tsize_t memfs_chunk_read(thandle_t handle, tdata_t mem, tsize_t size); +toff_t memfs_chunk_seek(thandle_t handle, toff_t offset, int mode); +int memfs_chunk_close(thandle_t handle); +toff_t memfs_chunk_size(thandle_t handle); +int memfs_chunk_map(thandle_t handle, tdata_t *memp, toff_t *top); +void memfs_chunk_unmap(thandle_t handle, tdata_t mem, toff_t to); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/conversion/memfs.hh b/conversion/memfs.hh new file mode 100644 index 0000000..1b88b37 --- /dev/null +++ b/conversion/memfs.hh @@ -0,0 +1,85 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * INCLUDE: memfs.hh + * + * MODULE: conversion + * + * PURPOSE: + * Memory Filing System used by some of the convertor modules. + * + * COMMENTS: + * None +*/ + +#ifndef _MEMFS_HH_ +#define _MEMFS_HH_ + +/* For data types used by the memfs */ +#include "tiffio.h" +#include "raslib/odmgtypes.hh" + + +/* Claim blocks in 4k chunks */ +const int MEMFS_LD_BLOCKSIZE = 12; +/* Initially preserve enough room for 16 blocks */ +const int MEMFS_MAM_ENTRIES = 16; + +typedef struct memFSContext { + r_Long pos, high; + int mamSize, mamHighest; + char **mam; + char *chunk; +} memFSContext; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Flexible, read-write memFS */ +int memfs_initfs(thandle_t handle); +void memfs_killfs(thandle_t handle); +void memfs_newfile(thandle_t handle); +tsize_t memfs_read(thandle_t handle, tdata_t mem, tsize_t size); +tsize_t memfs_write(thandle_t handle, tdata_t mem, tsize_t size); +toff_t memfs_seek(thandle_t handle, toff_t offset, int mode); +int memfs_close(thandle_t handle); +toff_t memfs_size(thandle_t handle); +int memfs_map(thandle_t handle, tdata_t *memp, toff_t *top); +void memfs_unmap(thandle_t handle, tdata_t mem, toff_t top); + +/* Simple, read-only memFS */ +void memfs_chunk_initfs(thandle_t handle, char *src, r_Long size); +tsize_t memfs_chunk_read(thandle_t handle, tdata_t mem, tsize_t size); +toff_t memfs_chunk_seek(thandle_t handle, toff_t offset, int mode); +int memfs_chunk_close(thandle_t handle); +toff_t memfs_chunk_size(thandle_t handle); +int memfs_chunk_map(thandle_t handle, tdata_t *memp, toff_t *top); +void memfs_chunk_unmap(thandle_t handle, tdata_t mem, toff_t to); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/conversion/nitf.cc b/conversion/nitf.cc new file mode 100644 index 0000000..dbdfee0 --- /dev/null +++ b/conversion/nitf.cc @@ -0,0 +1,702 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +*/ + +#include <string> +#include <stdio.h> +#include <cstdlib> +#include <sys/types.h> +#include <unistd.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <iostream> +#include <fstream> +#include <strstream> +#include <exception> + + +#include "nitf.h" +#include "image.h" +#include "graphic.h" +#include "text.h" +#include "des.h" +#include "res.h" +#include "utilities.h" + +using namespace std; +using namespace RasNITF; + +nitf::nitf(){ + + isEmpty = true; + + m_li = NULL; + m_ls = NULL; + m_lt = NULL; + m_ld = NULL; + m_lr = NULL; + m_udhd = NULL; + m_xhd = NULL; + + m_images = NULL; + m_graphics = NULL; + m_texts = NULL; + m_des = NULL; + m_res = NULL; + + n_numi=0; +} +/* +nitf::nitf(char* data){ + +} +*/ +nitf::~nitf(){ + + if (m_li != NULL) { + delete m_li; + m_li = NULL; + } + + if (m_ls != NULL) { + delete m_ls; + m_ls = NULL; + } + + if (m_lt != NULL) { + delete m_lt; + m_lt = NULL; + } + + if (m_ld != NULL) { + delete m_ld; + m_ld = NULL; + } + + if (m_lr != NULL) { + delete m_lr; + m_lr = NULL; + } + + if (m_udhd != NULL) { + delete m_udhd; + m_udhd = NULL; + } + + if (m_xhd != NULL) { + delete m_xhd; + m_xhd = NULL; + } + + if (m_images != NULL) { + delete[] m_images; + m_images = NULL; + } + + if (m_graphics != NULL) { + delete[] m_graphics; + m_graphics = NULL; + } + + if (m_texts != NULL) { + delete[] m_texts; + m_texts = NULL; + } + + if (m_des != NULL) { + delete[] m_des; + m_des = NULL; + } + + if (m_res != NULL) { + delete[] m_res; + m_res = NULL; + } + +} + +bool nitf::checkempty(){ + return isEmpty; +} + +void nitf::empty(){ + + if (!this->isEmpty){ + + if (m_li != NULL) { + delete m_li; + m_li = NULL; + } + + if (m_ls != NULL) { + delete m_ls; + m_ls = NULL; + } + + if (m_lt != NULL) { + delete m_lt; + m_lt = NULL; + } + + if (m_ld != NULL) { + delete m_ld; + m_ld = NULL; + } + + if (m_lr != NULL) { + delete m_lr; + m_lr = NULL; + } + + if (m_udhd != NULL) { + delete m_udhd; + m_udhd = NULL; + } + + if (m_xhd != NULL) { + delete m_xhd; + m_xhd = NULL; + } + + if (m_images != NULL) { + delete[] m_images; + m_images = NULL; + } + + if (m_graphics != NULL) { + delete[] m_graphics; + m_graphics = NULL; + } + + if (m_texts != NULL) { + delete[] m_texts; + m_texts = NULL; + } + + if (m_des != NULL) { + delete[] m_des; + m_des = NULL; + } + + if (m_res != NULL) { + delete[] m_res; + m_res = NULL; + } + } + + this->isEmpty = true; +} + +void nitf::stats() const { + int adress=n_hl; + cout<<"Printing statistics for the NITF file in memmory\n"; + cout<<"================================================\n"; + cout<<"Filename:\t\t"<<endl; + cout<<"File title:\n"; + cout.write(m_ftitle,80); + cout<<"\nFile Length\t\t"<<n_fl; + cout<<"\nFile Header Length\t"<<n_hl; + cout<<"\nNumber of Images:\t"<<n_numi; + cout<<"\n====================IMAGES======================\n"; + for(int i=0; i<n_numi; i++) { + cout<<"Length of Image Header "<<i<<"\t"<<n_lish[i]<<" Starting at "<<adress<<endl; + adress+=n_lish[i]; + cout<<"Length of Image "<<i<<"\t"<<n_li[i]<<" Starting at "<<adress<<endl; + adress+=n_li[i]; + } + cout<<"\nNumber of Graphics:\t"<<n_nums; + cout<<"\n===================GRAPHICS======================\n"; + for(int i=0; i<n_nums; i++) { + cout<<"Length of Graphic Header "<<i<<"\t"<<n_lssh[i]<<" Starting at "<<adress<<endl; + adress+=n_lssh[i]; + cout<<"Length of Graphic "<<i<<"\t"<<n_ls[i]<<" Starting at "<<adress<<endl; + adress+=n_ls[i]; + + } + cout<<"\nNumber of Texts:\t"<<n_numt; + cout<<"\n====================TEXTS========================\n"; + for(int i=0; i<n_numt; i++) { + + cout<<"Length of Text Header "<<i<<"\t"<<n_ltsh[i]<<" Starting at "<<adress<<endl; + adress+=n_ltsh[i]; + cout<<"Length of Text "<<i<<"\t"<<n_lt[i]<<" Starting at "<<adress<<endl; + adress+=n_lt[i]; + } + cout<<"\nNumber of Deses:\t"<<n_numdes; + cout<<"\n====================DESES======================\n"; + for(int i=0; i<n_numdes; i++) { + cout<<"Length of Des Header "<<i<<"\t"<<n_ldsh[i]<<" Starting at "<<adress<<endl; + adress+=n_ldsh[i]; + cout<<"Length of Des "<<i<<"\t"<<n_ld[i]<<" Starting at "<<adress<<endl; + adress+=n_ld[i]; + + } + cout<<"\nNumber of Reses:\t"<<n_numres; + cout<<"\n====================RESES======================\n"; + for(int i=0; i<n_numres; i++) { + + cout<<"Length of Res Header "<<i<<"\t"<<n_lrsh[i]<<" Starting at "<<adress<<endl; + adress+=n_lrsh[i]; + cout<<"Length of Res "<<i<<"\t"<<n_lr[i]<<" Starting at "<<adress<<endl; + adress+=n_lr[i]; + } + cout<<"\n\nThank you for using statistics, have a nice day\n"; + cout<<"---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<---\n"; +} + + +int nitf::read_file(string filename){ + + ifstream hNITF; + hNITF.open(filename.c_str(), ios::in); + if (!hNITF.good()) exit(-1); + bool read_image_data = true; + + return read(hNITF, read_image_data); + +} + +int nitf::read_headers_from(char* file_data, long file_length){ + + istrstream hNITF(file_data, file_length); + if (!hNITF.good()) exit(-1); + bool read_image_data = false; + + return read(hNITF, read_image_data);; + +} + + +int nitf::read(istream &hNITF, bool read_image_data){ + + char temp_buffer[100]; + int charsread = 0; + + // CHECK IF EMPTY EXCEPTION + if (!hNITF.good()) exit(-1); + + // read file name and version and check for consistency + + charsread += read_verify2(hNITF, m_fhdr, 9); + + if (strncmp(m_fhdr, "NITF02.10", 9) != 0) + exit(2); + + // copy all security fields as character data + charsread += read_verify2(hNITF, m_clevel, (2 + 4 + 10 + 14 + 80 + 1 + 2 + 11 + 2 + 20 + 2 + 8 + 4 + 1 + 8 + 43 + + 1 + 40 + 1 + 8 + 15 + 5 + 5 + 1 + 3 + 24 + 18)); + + // read file length + charsread += read_verify2(hNITF, m_fl, 12); + n_fl = charptrtolong(m_fl, 12); + + // read header length + charsread += read_verify2(hNITF, m_hl, 6); + n_hl = charptrtolong(m_hl, 6); + + // read number of images + charsread += read_verify2(hNITF, m_numi, 3); + n_numi = charptrtoint(m_numi, 3); + m_li = new char[n_numi*(6+10)]; + + for (int i = 0; i < n_numi; i++ ){ + + charsread += read_verify2(hNITF, temp_buffer, 6); + n_lish.push_back(charptrtolong(temp_buffer, 6)); + strncpy((char*)(m_li + i*16), temp_buffer, 6); + + charsread += read_verify2(hNITF, temp_buffer, 10); + n_li.push_back(charptrtolong(temp_buffer, 10)); + strncpy((char*)(m_li + i*16 + 6), temp_buffer, 10); + } + + // read number of graphics + + charsread += read_verify2(hNITF, m_nums, 3); + n_nums = charptrtoint(m_nums, 3); + m_ls = new char[n_nums*(4 + 6)]; + + for (int i = 0; i < n_nums; i++ ){ + + charsread += read_verify2(hNITF, temp_buffer, 4); + n_lssh.push_back(charptrtolong(temp_buffer, 4)); + strncpy((char*)(m_ls + i*10), temp_buffer, 4); + + charsread += read_verify2(hNITF, temp_buffer, 6); + n_ls.push_back(charptrtolong(temp_buffer, 6)); + strncpy((char*)(m_ls + i*10 + 4), temp_buffer, 6); + } + + // read NUMX field + + charsread += read_verify2(hNITF, m_numx, 3); + + // read number of texts + + charsread += read_verify2(hNITF, m_numt, 3); + n_numt = charptrtoint(m_numt, 3); + m_lt = new char[n_numt*(4+5)]; + + for (int i = 0; i < n_numt; i++ ){ + + charsread += read_verify2(hNITF, temp_buffer, 4); + n_ltsh.push_back(charptrtolong(temp_buffer, 4)); + strncpy((char*)(m_lt+i*9), temp_buffer, 4); + + charsread += read_verify2(hNITF, temp_buffer, 5); + n_lt.push_back(charptrtolong(temp_buffer, 5)); + strncpy((char*)(m_lt + i*9 + 4), temp_buffer, 5); + } + + // read DES sizes data + + charsread += read_verify2(hNITF, m_numdes, 3); + n_numdes = charptrtoint(m_numdes, 3); + m_ld = new char[n_numdes * (4 + 9)]; + + for (int i = 0; i < n_numdes; i++ ){ + + charsread += read_verify2(hNITF, temp_buffer, 4); + n_ldsh.push_back(charptrtolong(temp_buffer, 4)); + strncpy((char*)(m_ld+i*13), temp_buffer, 4); + + charsread += read_verify2(hNITF, temp_buffer, 9); + n_ld.push_back(charptrtolong(temp_buffer, 9)); + strncpy((char*)(m_ld + i*13 + 4), temp_buffer, 9); + } + + // read RES sizes data + + charsread += read_verify2(hNITF, m_numres, 3); + n_numres = charptrtoint(m_numres, 3); + m_lr = new char[n_numres * (4 + 7)]; + + for (int i = 0; i < n_numres; i++){ + + charsread += read_verify2(hNITF, temp_buffer, 4); + n_lrsh.push_back(charptrtolong(temp_buffer, 4)); + strncpy((char*)(m_lr + i*11), temp_buffer, 4); + + charsread += read_verify2(hNITF, temp_buffer, 7); + n_lr.push_back(charptrtolong(temp_buffer, 7)); + strncpy((char*)(m_lr + i*11 + 4), temp_buffer, 7); + } + + // read UDHDL + + charsread += read_verify2(hNITF, m_udhdl, 5); + n_udhdl = charptrtoint(m_udhdl, 5); + + // read UDHOFL and UDHD if necessary + + if (n_udhdl > 0) { + + charsread += read_verify2(hNITF, m_udhofl, 3); + m_udhd = new char[n_udhdl-3]; + charsread += read_verify2(hNITF, m_udhd, n_udhdl-3); + } + + // read XHDL + + charsread += read_verify2(hNITF, m_xhdl, 5); + n_xhdl = charptrtoint(m_xhdl, 5); + + // read XHOFL and XHD if necessary + + if (n_xhdl > 0) { + charsread += read_verify2(hNITF, m_xhdlofl, 3); + m_xhd = new char[n_xhdl-3]; + charsread += read_verify2(hNITF, m_xhd, n_xhdl-3); + } + + if (((long)(hNITF.tellg()))!= n_hl){ + cout<< "header length read not as specified" << endl; + cout<<endl<<"read: tellg: "<< hNITF.tellg() << " nhl " << n_hl<<endl; + cout<< "chars read: " << charsread << endl; + exit(3); + } + + // read images + + if (n_numi > 0) { + m_images = new image[n_numi]; + for(int i=0; i<n_numi; i++) { + m_images[i].read_file(hNITF, n_lish[i], n_li[i], read_image_data); + } + } else { + m_images = NULL; + } + + // read graphics + + if (n_nums > 0) { + m_graphics = new graphic[n_nums]; + for(int i=0; i<n_nums; i++) { + m_graphics[i].read_file(hNITF, n_lssh[i], n_ls[i]); + } + } else { + m_graphics = NULL; + } + + // read texts + + if (n_numt > 0) { + m_texts = new text[n_numt]; + for(int i=0; i<n_numt; i++) { + m_texts[i].read_file(hNITF, n_ltsh[i], n_lt[i]); + } + } else { + m_texts = NULL; + } + + + if (n_numdes > 0) { + m_des = new des[n_numdes]; + for(int i=0; i<n_numdes; i++) { + m_des[i].read_file(hNITF, n_ldsh[i], n_ld[i]); + } + } else { + m_des = NULL; + } + + if (n_numres > 0) { + m_res = new res[n_numres]; + for(int i=0; i<n_numres; i++) { + m_res[i].read_file(hNITF, n_lrsh[i], n_lr[i]); + } + } else { + m_res = NULL; + } + + + this->isEmpty = false; + + return charsread; + +} + + + + +int nitf::write_file(std::string filename){ + + int charswritten = 0; + ofstream fNITF(filename.c_str()); + + fNITF.write(m_fhdr, 9); + fNITF.write(m_clevel, 2); + fNITF.write(m_stype, 4); + fNITF.write(m_ostaid, 10); + fNITF.write(m_fdt, 14); + fNITF.write(m_ftitle, 80); + fNITF.write(m_fsclas, 1); + fNITF.write(m_fsclsy, 2); + fNITF.write(m_fscode, 11); + fNITF.write(m_fsctlh, 2); + fNITF.write(m_fsrel, 20); + fNITF.write(m_fsdctp, 2); + fNITF.write(m_fsdcdt, 8); + fNITF.write(m_fsdcxm, 4); + fNITF.write(m_fsdg, 1); + fNITF.write(m_fsdgdt, 8); + fNITF.write(m_fscltx, 43); + fNITF.write(m_fscatp, 1); + fNITF.write(m_fscaut, 40); + fNITF.write(m_fscrsn, 1); + fNITF.write(m_fssrdt, 8); + fNITF.write(m_fsctln, 15); + fNITF.write(m_fscop, 5); + fNITF.write(m_fscpys, 5); + fNITF.write(m_encryp, 1); + fNITF.write(m_fbkgc, 3); + fNITF.write(m_oname, 24); + fNITF.write(m_ophone, 18); + fNITF.write(m_fl, 12); + fNITF.write(m_hl, 6); + + charswritten += 9 + 2 + 4 + 10 + 14 + 80 + 1+ 2 + 11 + 2 + 20 + 2 + 8 + 4 + 1 + 8 + 43 + 1 + 40 + 1 +8 + 15 + 5 + 5 + 1 + 3 + 24 + 18 + 12 + 6; + + fNITF.write(m_numi, 3); + charswritten += 3; + if(n_numi > 0){ + fNITF.write(m_li, n_numi * (6 + 10)); + charswritten += n_numi * (6 + 10); + } + + fNITF.write(m_nums, 3); + charswritten += 3; + if(n_nums > 0){ + fNITF.write(m_ls, n_nums * (4 + 6)); + charswritten += n_nums * (4 + 6); + } + + fNITF.write(m_numx, 3); + + fNITF.write(m_numt, 3); + charswritten += 6; + if(n_numt > 0) { + fNITF.write(m_lt, n_numt * (4 + 5)); + charswritten += n_numt * (4 + 5); + } + + fNITF.write(m_numdes, 3); + charswritten += 3; + if(n_numdes > 0) { + fNITF.write(m_ld, n_numdes * (4 + 9)); + charswritten += n_numdes * (4 + 9); + } + + fNITF.write(m_numres, 3); + charswritten += 3; + if(n_numres > 0) { + fNITF.write(m_lr, n_numdes * (4 + 7)); + charswritten += n_numdes* (4 + 7); + } + + fNITF.write(m_udhdl, 5); + if (n_udhdl > 0){ + fNITF.write(m_udhofl, 3); + fNITF.write(m_udhd, n_udhdl - 3); + charswritten += n_udhdl; + } + + + fNITF.write(m_xhdl, 5); + if (n_xhdl > 0){ + fNITF.write(m_xhdlofl, 3); + fNITF.write(m_xhd, n_xhdl - 3); + charswritten += n_xhdl; + } + + for(int i=0; i< n_numi; i++){ + m_images[i].write_file(fNITF); + } + + for(int i=0; i< n_nums; i++){ + m_graphics[i].write_file(fNITF); + } + + for(int i=0; i< n_numt; i++){ + m_texts[i].write_file(fNITF); + } + + for(int i=0; i< n_numdes; i++){ + m_des[i].write_file(fNITF); + } + + for(int i=0; i< n_numres; i++){ + m_res[i].write_file(fNITF); + } + + return charswritten; +} + +void nitf::image_to_pixel_sequential(int index) { + + if( !isEmpty ) { + if( (index < 0) || (index > n_numi)) { + throw(74); + exit(3); + } else { + m_images[index].to_pixel_sequential(); + } + } +} + +long nitf::get_image_size(int image_index) const +{ + return m_images[image_index].get_size(); +} + +int nitf::get_image_width(int image_index) const +{ + return m_images[image_index].get_width(); +} + +int nitf::get_image_height(int image_index) const +{ + return m_images[image_index].get_height(); +} + +long nitf::get_image_offset(int image_index) const +{ + long offset = 0; + + offset += n_hl; + + for(int ctr = 0; ctr < image_index; ctr++ ) { + offset+= n_li[ctr] + n_lish[ctr]; + } + + offset += n_lish[image_index]; + + return offset; +} + +bool nitf::isRGB(int image_index){ + + bool RGB = false; + + if (m_images[image_index].get_irep() == " RGB") { + if (m_images[image_index].get_nbpp_bytes() == 1 ){ + RGB = true; + } else { + // throw(74); + exit(1704); + } + } + + return RGB; + +} + +bool nitf::isGRAY(int image_index){ + + bool GRAY = false; + + if ((m_images[image_index].get_irep() == " MONO") && (m_images[image_index].get_pvtype() == "INT")) { + if (m_images[image_index].get_nbpp_bytes() == 1 ){ + GRAY = true; + } else { + // throw(74); + exit(1704); + } + } + + return GRAY; +} + +bool nitf::isBOOL(int image_index){ + + bool isBOOL = false; + + if ((m_images[image_index].get_irep() == " MONO") && (m_images[image_index].get_pvtype() == " B")) { + if (m_images[image_index].get_nbpp_bytes() == 1 ){ + isBOOL = true; + } else { + // throw(74); + exit(1704); + } + } + + return isBOOL; +} diff --git a/conversion/nitf.h b/conversion/nitf.h new file mode 100644 index 0000000..892eb14 --- /dev/null +++ b/conversion/nitf.h @@ -0,0 +1,165 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +*/ + +/** + * This is the definition of the NITF class, an agregation of the Classes Header, + * Image, Graphic and Text + */ + +#ifndef __RASNITF_NITF_H +#define __RASNITF_NITF_H + +#include<string> +#include<vector> +#include<iostream> +#include<fstream> + + +namespace RasNITF{ + +class image; +class graphic; +class text; +class des; +class res; + +class nitf { + + char m_fhdr[9]; + char m_clevel[2]; + char m_stype[4]; + char m_ostaid[10]; + char m_fdt[14]; + char m_ftitle[80]; + char m_fsclas[1]; + char m_fsclsy[2]; + char m_fscode[11]; + char m_fsctlh[2]; + char m_fsrel[20]; + char m_fsdctp[2]; + char m_fsdcdt[8]; + char m_fsdcxm[4]; + char m_fsdg[1]; + char m_fsdgdt[8]; + char m_fscltx[43]; + char m_fscatp[1]; + char m_fscaut[40]; + char m_fscrsn[1]; + char m_fssrdt[8]; + char m_fsctln[15]; + char m_fscop[5]; + char m_fscpys[5]; + char m_encryp[1]; + char m_fbkgc[3]; + char m_oname[24]; + char m_ophone[18]; + + char m_fl[12]; + char m_hl[6]; + char m_numi[3]; + char* m_li; // image sizes data + char m_nums[3]; + char* m_ls; // graphic sizes data + char m_numx[3]; + char m_numt[3]; + char* m_lt; // text sizes data + char m_numdes[3]; + char* m_ld; // des sizes data + char m_numres[3]; + char* m_lr; // res sizes data + char m_udhdl[5]; + char m_udhofl[3]; + char* m_udhd; + char m_xhdl[5]; + char m_xhdlofl[3]; + char* m_xhd; + + // DATA + + //std::ifstream hNITF; + + long n_fl; + long n_hl; + + int n_numi; + std::vector<long> n_lish; + std::vector<long> n_li; + image *m_images; + + int n_nums; + std::vector<long> n_lssh; + std::vector<long> n_ls; + graphic *m_graphics; + + int n_numt; + std::vector<long> n_ltsh; + std::vector<long> n_lt; + text *m_texts; + + int n_numdes; + std::vector<long> n_ldsh; + std::vector<long> n_ld; + des *m_des; + + int n_numres; + std::vector<long> n_lrsh; + std::vector<long> n_lr; + res *m_res; + + int n_udhdl; + int n_xhdl; + + bool isEmpty; + +public: + + nitf(); + ~nitf(); + + int read_file(std::string filename); + int read_headers_from(char* file_data, long file_length); + int read(std::istream &hNITF, bool read_image_data); + + int write_file(std::string filename); + + void image_to_pixel_sequential(int index); + + void stats() const; + void empty(); + bool checkempty(); + + long get_image_size(int index = 0) const; + int get_image_width(int index = 0) const; + int get_image_height(int index = 0) const; + int get_image_pixel_type(int index = 0) const; + long get_image_offset(int index = 0) const; + + bool isRGB(int image_index); + bool isGRAY(int image_index); + bool isBOOL(int image_index); + +}; + +} + +#endif diff --git a/conversion/ntf.cc b/conversion/ntf.cc new file mode 100644 index 0000000..7db1bc7 --- /dev/null +++ b/conversion/ntf.cc @@ -0,0 +1,218 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * SOURCE: ntf.cc + * + * MODULE: conversion + * + * CLASSES: r_Conv_NTF + * + * COMMENTS: + * + * Provides functions to convert data to NTF and back. + * +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <iostream> +#include <string.h> +#include <new> + +#include "raslib/rminit.hh" +#include "raslib/rmdebug.hh" +#include "raslib/parseparams.hh" +#include "conversion/ntf.hh" +#include "conversion/memfs.hh" + +// nitf reader library + +#include "nitf.h" +#include "image.h" + +r_Conv_NTF::r_Conv_NTF( const char *src, const r_Minterval &interv, const r_Type *tp ) + throw(r_Error):r_Convert_Memory(src, interv, tp) +{ +} + +r_Conv_NTF::r_Conv_NTF( const char *src, const r_Minterval &interv, int tp ) + throw(r_Error):r_Convert_Memory(src, interv, tp) +{ +} + +r_Conv_NTF::~r_Conv_NTF( void ){ +} + +/*********************************************************** + * NAME: r_Conv_NTF::convertFrom + * --------------------------------------------------------- + * PURPOSE: convert from NITF image file data to the + * corresponding rasdaman type pixel sequential data + ***********************************************************/ + +r_convDesc& r_Conv_NTF::convertFrom( const char *options ) throw(r_Error){ + + char *nitf_file_data = NULL; + char *nitf_img = NULL; + long fileSize = 0; + RasNITF::nitf nitf_file; + + nitf_file_data = (char*) desc.src; + + //READ NITF HEADERS + + nitf_file.read_headers_from(nitf_file_data, int(desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1)); + + // MOVE POINTER TO THE IMAGE DATA + + nitf_img = (char*)(desc.src + nitf_file.get_image_offset()); + fileSize = nitf_file.get_image_size(); + + // CONVERT ALL DATA TO PIXEL SEQUENTIAL + + nitf_file.image_to_pixel_sequential(0); // the address of the image is also known internaly so no need to pass the pointer + + // ALLOCATE STORAGE FOR DESC.DEST WITH? THE SIZE OF THE IMAGE + + if ((desc.dest = (char*)mystore.storage_alloc(fileSize)) == NULL) + { + RMInit::logOut << "r_Conv_NTF::convertTo(): out of memory!" << endl; + throw r_Error(MEMMORYALLOCATIONERROR); + } + + // COPY THE PIXEL SEQUENTIAL DATA TO THE DESC.DEST + + memcpy(desc.dest, nitf_img, fileSize); + + // SET THE INTERVALS + + desc.destInterv = r_Minterval(2); + desc.destInterv << r_Sinterval(( r_Range)0, (r_Range) ( nitf_file.get_image_width() - 1)) + << r_Sinterval(( r_Range)0, (r_Range) ( nitf_file.get_image_height() -1)); + + // SETR BASE TYPE + + int image_index = 0; + + if(nitf_file.isRGB(image_index)) { + desc.baseType = ctype_rgb; + } else if(nitf_file.isGRAY(image_index)) { + desc.baseType = ctype_char; + } else if(nitf_file.isBOOL(image_index)) { + desc.baseType = ctype_bool; + } + else { + RMInit::logOut << "r_Conv_NTF::convertFrom:" << "unsupported NITF file pixel type" << endl; + throw r_Error(r_Error::r_Error_General); + } + + + +/* switch (nitf_file.get_image_pixel_type()){ + case NITF_BI: + desc.baseType = ctype_bool; + break; + case NITF_GRAY: + desc.baseType = ctype_char; + break; + case NITF_RGB: + desc.baseType = ctype_rgb; + break; + default: + RMInit::logOut << "r_Conv_NTF::convertFrom:" << "unsupported NITF file pixel type" << endl; + } +*/ + desc.destType = get_external_type(desc.baseType); + + return desc; + +} + +/*********************************************************** + * NAME: r_Conv_NTF::convertTo + * --------------------------------------------------------- + * PURPOSE: convert from rasdaman data to the + * corresponding nitf storage type + ***********************************************************/ + +r_convDesc& r_Conv_NTF::convertTo( const char *options ) throw(r_Error){ + + int width=0, height=0; + int fileSize = 0; + + // DETERMINE WIDTH AND HEIGHT + + width = (int)(desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1); + height = (int)(desc.srcInterv[1].high() - desc.srcInterv[1].low() + 1); + + // CALCULATE THE SIZE OF THE IMAGE FILE + + switch (desc.baseType) + { + case ctype_bool: + fileSize = width * height * 1; + break; + case ctype_char: + fileSize = width * height * 1; + break; + case ctype_rgb: + fileSize = width * height * 3; + default: + RMInit::logOut << "r_Conv_BMP::convertTo(): Unknown base type!" << endl; + throw r_Error(r_Error::r_Error_General); + } + + // ALLOCATE STORAGE FOR THE IMAGE DATA + + if ((desc.dest = (char*)mystore.storage_alloc(fileSize)) == NULL) + { + RMInit::logOut << "r_Conv_NTF::convertTo(): out of memory!" << endl; + throw r_Error(MEMMORYALLOCATIONERROR); + } + + memcpy(desc.dest, desc.src, fileSize); + + // SET THE SIZE OF THE DATA + + desc.destInterv = r_Minterval(1); + desc.destInterv << r_Sinterval((r_Range)0, (r_Range)fileSize-1); + + // SET THE TYPE OF TEH DATA + + desc.destType = r_Type::get_any_type("char"); + + return desc; +} + + +r_Convertor* r_Conv_NTF::clone( void ) const{ + return new r_Conv_NTF(desc.src, desc.srcInterv, desc.baseType); +} + +const char * r_Conv_NTF::get_name( void ) const{ + return format_name_ntf; +} + +r_Data_Format r_Conv_NTF::get_data_format( void ) const{ + return r_NTF; +} diff --git a/conversion/ntf.hh b/conversion/ntf.hh new file mode 100644 index 0000000..e4800ae --- /dev/null +++ b/conversion/ntf.hh @@ -0,0 +1,80 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * INCLUDE: ntf.hh + * + * MODULE: conversion + * + * CLASSES: r_Conv_NTF + * + * COMMENTS: + * + * Provides interface to convert data to other formats. + * +*/ + +#ifndef _R_CONV_NTF_HH_ +#define _R_CONV_NTF_HH_ + +#include "conversion/convertor.hh" + +//@ManMemo: Module {\bf conversion} + +/*@Doc: + NTF convertor class. + Completely native implementation, doesn't use external libs. +*/ + +class r_Conv_NTF : public r_Convert_Memory +{ + public: + + /// constructor using an r_Type object + r_Conv_NTF( const char *src, const r_Minterval &interv, const r_Type *tp ) throw(r_Error); + + /// constructor using convert_type_e shortcut + r_Conv_NTF( const char *src, const r_Minterval &interv, int tp ) throw(r_Error); + + /// destructor + ~r_Conv_NTF( void ); + + /// convert to NTF + virtual r_convDesc &convertTo( const char *options=NULL ) throw(r_Error); + + /// convert from NTF + virtual r_convDesc &convertFrom( const char *options=NULL ) throw(r_Error); + + /// cloning + virtual r_Convertor *clone( void ) const; + + /// identification + virtual const char *get_name( void ) const; + virtual r_Data_Format get_data_format( void ) const; + private: + + ///keeps the block index + char *bl_num, *bl_size, *d_offset; + +}; + +#endif diff --git a/conversion/png.cc b/conversion/png.cc new file mode 100644 index 0000000..b869a82 --- /dev/null +++ b/conversion/png.cc @@ -0,0 +1,597 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * SOURCE: png.cc + * + * MODULE: conversion + * Provides functions to convert data to PNG and back. + * + * CLASSES: r_Conv_PNG + * + * COMMENTS: + * - option parsing known bugs: + * * no overflow check on options string buffer + * * missing ")" is silently ignored + * * on hex input, non-hex chars are silently discarded (!) + * * too large numbers are mapped to unsigned short's max int + * * negative numbers are mapped to unsigned short's max int + * - do not use "," within an option because this is the parse_param separator + * - FIXME: define some 3xxx error codes instead of general exception + * +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <iostream> +#include <string.h> + +#include "png.h" + +#include "raslib/rminit.hh" +#include "raslib/rmdebug.hh" +#include "debug.hh" + +#include "conversion/png.hh" +#include "conversion/memfs.hh" + +#include "raslib/parseparams.hh" + + +// transparency keyword in option string (cf. PNG standard): +#define TRANSP_KEY "tRNS" + + +/* memfs interface functions in C namespace */ + +extern "C" { + +static void png_mem_read_data(png_struct *png_ptr, png_byte *data, png_size_t length) +{ + void *handle=NULL; + + handle = (void*)png_get_io_ptr(png_ptr); + memfs_chunk_read(handle, (tdata_t)data, (tsize_t)length); +} + + +static void png_mem_write_data(png_struct *png_ptr, png_byte *data, png_size_t length) +{ + void *handle=NULL; + + handle = (void*)png_get_io_ptr(png_ptr); + memfs_write(handle, (tdata_t)data, (tsize_t)length); +} + + +static void png_mem_flush_data(png_struct *png_ptr) +{ + void *handle=NULL; + + handle = (void*)png_get_io_ptr(png_ptr); +} + + +/* Customized error handling */ +static void *png_user_error_ptr = NULL; + +static void png_user_warning_fn(png_struct *png_ptr, const char *warning_msg) +{ + fprintf(stdout, "r_Conv_PNG warning: %s\n", warning_msg); fflush(stdout); +} + +static void png_user_error_fn(png_struct *png_ptr, const char *error_msg) +{ + fprintf(stderr, "r_Conv_PNG error: %s\n", error_msg); + // return from this routine, exception will be thrown in setjmp code +} + +} // end of C namespace + + + + +/* + * r_Conv_PNG class for converting MDD to PNG and back + */ + +const char *r_Conv_PNG::name_InfoKey = "Description"; +const char *r_Conv_PNG::name_InfoText = "rasdaman MDD encoded as PNG"; +const char *r_Conv_PNG::method_convertTo = "r_Conv_PNG::convertTo()"; +const char *r_Conv_PNG::method_convertFrom = "r_Conv_PNG::convertFrom()"; + +r_Conv_PNG::r_Conv_PNG(const char *src, const r_Minterval &interv, int tp) throw(r_Error) +: r_Convert_Memory(src, interv, tp) +{ +} + + +r_Conv_PNG::r_Conv_PNG(const char *src, const r_Minterval &interv, const r_Type *tp) throw(r_Error) +: r_Convert_Memory(src, interv, tp) +{ +} + + +r_Conv_PNG::~r_Conv_PNG(void) +{ +} + + +r_convDesc &r_Conv_PNG::convertTo( const char *options ) throw(r_Error) +{ + ENTER( "r_Conv_PNG::convertTo( " << (options==NULL?"(null)":options) << " )" ); + + png_struct *write_ptr=NULL; + png_info *info_ptr = NULL; + int i=0, j=0; + png_uint_32 width=0, height=0; + int colourType=0, compType=0; + int spp=0, bps=0, lineAdd=0, pixelAdd=0; + png_color_8 sig_bit; + png_text infotext[1]; + char *trans_string = NULL; // transparency string buffer + int itemsScanned = 0; // # of items scanned in options string + bool transpFound = false; // keyword for transparency found in options? + + i = 0; // error state: 0 is ok, !=0 is error + + // option analysis: create parse object -- PB 2005-jul-12 + if (params == NULL) + params = new r_Parse_Params(); + params->add(TRANSP_KEY, &trans_string, r_Parse_Params::param_type_string); + transpFound = params->process(options); + + // check for good options, if any + if (options != NULL && ! transpFound) + { + RMInit::logOut << "Error: illegal PNG option string: " << options << endl; + throw r_Error(r_Error::r_Error_General); + } + + write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, png_user_error_ptr, png_user_error_fn, png_user_warning_fn); + + if (write_ptr == NULL) + i=1; + else + { + info_ptr = png_create_info_struct(write_ptr); + if (info_ptr == NULL) + { + RMInit::logOut << "Error: unable to allocate PNG header." << endl; + i=1; + } + else if (setjmp(write_ptr->jmpbuf)) + { + png_destroy_write_struct(&write_ptr, &info_ptr); + RMInit::logOut << "Error: unable to save PNG stack" << endl; + throw r_Error(r_Error::r_Error_General); + } + } + + if (i != 0) + { + png_destroy_write_struct(&write_ptr, &info_ptr); + throw r_Error(r_Error::r_Error_General); + } + + memfs_newfile(handle); + + png_set_write_fn(write_ptr, (void*)handle, png_mem_write_data, png_mem_flush_data); + + // Compression + compType = PNG_COMPRESSION_TYPE_BASE; + + // Size + width = desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1; + height = desc.srcInterv[1].high() - desc.srcInterv[1].low() + 1; + + // Depth and sample format and transparency + // added transparency -- PB 2005-jul-12 + switch (desc.baseType) + { + case ctype_bool: + spp = 1; bps = 1; pixelAdd = height; lineAdd = 1; + colourType = PNG_COLOR_TYPE_GRAY; sig_bit.gray = 1; + if (transpFound) + { + itemsScanned = sscanf( trans_string, " %hi ", &(info_ptr->trans_values.gray) ); + if (itemsScanned == 1) // all required items found? + { + info_ptr->valid |= PNG_INFO_tRNS; // activate tRNS chunk + } + else + { + RMInit::logOut << "Error: illegal syntax in transparency color specification - should be \"%i\", but is: " << trans_string << endl; + throw r_Error(r_Error::r_Error_General); + } + } + break; + + case ctype_char: + spp = 1; bps = 8; pixelAdd = height; lineAdd = 1; + colourType = PNG_COLOR_TYPE_GRAY; sig_bit.gray = 8; + if (transpFound) + { + itemsScanned = sscanf( trans_string, " %hi ", &(info_ptr->trans_values.gray) ); + if (itemsScanned == 1) // all required items found? + { + info_ptr->valid |= PNG_INFO_tRNS; // activate tRNS chunk + } + else + { + RMInit::logOut << "Error: illegal syntax in transparency color specification - should be \"%i\", but is: " << trans_string << endl; + throw r_Error(r_Error::r_Error_General); + } + } + break; + + case ctype_rgb: + spp = 3; bps = 8; pixelAdd = 3*height; lineAdd = 3; + colourType = PNG_COLOR_TYPE_RGB; + sig_bit.red = 8; sig_bit.green = 8; sig_bit.blue = 8; + if (transpFound) + { + itemsScanned = sscanf( trans_string, " ( %hi ; %hi ; %hi ) ", &(info_ptr->trans_values.red), &(info_ptr->trans_values.green), &(info_ptr->trans_values.blue) ); + if (itemsScanned == 3) // all required items found? + { + info_ptr->valid |= PNG_INFO_tRNS; // activate tRNS chunk + } + else + { + RMInit::logOut << "Error: illegal syntax in item #" << itemsScanned << " of transparency color specification - should be \"(%i;%i;%i)\", but is: " << trans_string << endl; + throw r_Error(r_Error::r_Error_General); + } + } + break; + + default: + RMInit::logOut << "Error: " << method_convertTo << ": Unknown base type." << endl; + throw r_Error(r_Error::r_Error_General); + } // switch + + // adjust transparency color value to pixel depth (unconditionally, even if transparency is unused) + if (bps == 8) + { + info_ptr->trans_values.red &= 0xff; + info_ptr->trans_values.green &= 0xff; + info_ptr->trans_values.blue &= 0xff; + info_ptr->trans_values.gray &= 0xff; + } + + if (trans_string != NULL) + { + delete [] trans_string; + trans_string = NULL; + } + + + png_set_IHDR(write_ptr, info_ptr, width, height, bps, colourType, PNG_INTERLACE_NONE, compType, PNG_FILTER_TYPE_BASE); + png_set_sBIT(write_ptr, info_ptr, &sig_bit); + + // Info text + infotext[0].key = new char[strlen(name_InfoKey)+1]; + strcpy(infotext[0].key, name_InfoKey); + infotext[0].text = new char[strlen(name_InfoText)+1]; + strcpy(infotext[0].text, name_InfoText); + infotext[0].compression = PNG_TEXT_COMPRESSION_NONE; + infotext[0].text_length = strlen(infotext[0].text); + png_set_text(write_ptr, info_ptr, infotext, 1); + + // Write header + png_write_info(write_ptr, info_ptr); + + png_byte *row=NULL, *rowPtr=NULL; + const unsigned char *src=NULL, *srcPtr=NULL; + + row = new png_byte[((bps * spp * width + 7) >> 3)]; + src = (const unsigned char*)(desc.src); + + for (j=0; j<height; j++) + { + rowPtr = row; srcPtr = src; + + switch (desc.baseType) + { + case ctype_bool: + { + int mask=0; + png_byte val=0; + + val = 0; mask = 0x80; // png docs: leftmost pixel in high-order bits + for (i=0; i<width; i++, srcPtr += pixelAdd) + { + if (*srcPtr != 0) val |= mask; + mask >>= 1; + if (mask == 0) + { + *rowPtr++ = val; val = 0; mask = 0x80; + } + } + if (mask != 0x80) *rowPtr++ = val; + } + break; + case ctype_char: + { + for (i=0; i<width; i++, srcPtr += pixelAdd) + { + *rowPtr++ = *srcPtr; + } + } + break; + case ctype_rgb: + { + for (i=0; i<width; i++, srcPtr += pixelAdd) + { + *rowPtr++ = srcPtr[0]; + *rowPtr++ = srcPtr[1]; + *rowPtr++ = srcPtr[2]; + } + } + break; + } + + png_write_row(write_ptr, row); + + src += lineAdd; + } + + delete [] row; row=NULL; + + png_write_end(write_ptr, info_ptr); + +#ifdef RMANDEBUG + // if (RManDebug >= 4) + { + RMInit::dbgOut << "wrote PNG image: width=" << width << ", height=" << height << ", bps=" << bps << ", colour="; + switch (desc.baseType) + { + case ctype_bool: + RMInit::dbgOut << "bw"; + if (transpFound) + RMInit::dbgOut << ", transparent=" << info_ptr->trans_values.gray; + break; + case ctype_char: + RMInit::dbgOut << "grey"; + if (transpFound) + RMInit::dbgOut << ", transparent=" << info_ptr->trans_values.gray; + break; + case ctype_rgb: + RMInit::dbgOut << "rgb"; + if (transpFound) + RMInit::dbgOut << ", transparent=(" << info_ptr->trans_values.red << info_ptr->trans_values.green << info_ptr->trans_values.blue << ")"; + break; + default: + RMInit::dbgOut << "(illegal)"; + break; + } + RMInit::dbgOut << endl; + } +#endif + + // --- Cleanup ------------------------------------------------------- + png_destroy_write_struct(&write_ptr, &info_ptr); + + delete [] infotext[0].key; infotext[0].key=NULL; + delete [] infotext[0].text; infotext[0].text=NULL; + + r_Long pngSize = memfs_size(handle); + + if ((desc.dest = (char*)mystore.storage_alloc(pngSize)) == NULL) + { + RMInit::logOut << "Error: " << method_convertTo << ": out of memory." << endl; + throw r_Error(MEMMORYALLOCATIONERROR); + } + memfs_seek(handle, 0, SEEK_SET); + memfs_read(handle, desc.dest, pngSize); + + desc.destInterv = r_Minterval(1); + desc.destInterv << r_Sinterval((r_Range)0, (r_Range)pngSize - 1); + + // set result type to char string + desc.destType = r_Type::get_any_type("char"); + + LEAVE( "r_Conv_PNG::convertTo()" ); + return desc; +} + + +r_convDesc &r_Conv_PNG::convertFrom(const char *options) throw(r_Error) +{ + png_struct *read_ptr=NULL; + png_info *info_ptr = NULL; + int i=0, j=0, pass=0, numPasses=0; + png_uint_32 width=0, height=0, pitch=0; + int colourType=0, interlaceType=0, compType=0, filterType=0; + int spp=0, bps=0, lineAdd=0, pixelAdd=0; + + i = 0; + read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png_user_error_ptr, png_user_error_fn, png_user_warning_fn); + if (read_ptr == NULL) i=1; + else + { + info_ptr = png_create_info_struct(read_ptr); + if (info_ptr == NULL) i=1; + else if (setjmp(read_ptr->jmpbuf)) + { + png_destroy_read_struct(&read_ptr, &info_ptr, NULL); + RMInit::logOut << "r_Conv_PNG::convertFrom(" << options << "): unable to save the stack" << endl; + throw r_Error(r_Error::r_Error_General); + } + } + if (i != 0) + { + png_destroy_read_struct(&read_ptr, &info_ptr, NULL); + throw r_Error(r_Error::r_Error_General); + } + + memfs_chunk_initfs(handle, (char*)desc.src, (r_Long)(desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1)); + + desc.dest = NULL; + + png_set_read_fn(read_ptr, (void*)handle, png_mem_read_data); + + png_read_info(read_ptr, info_ptr); + + png_get_IHDR(read_ptr, info_ptr, &width, &height, &bps, &colourType, &interlaceType, &compType, &filterType); + + if (bps > 8) + { + RMInit::logOut << method_convertFrom << " warning: 16 bit samples quantized to 8 bit" << endl; + png_set_strip_16(read_ptr); + } + + if ((colourType & PNG_COLOR_MASK_ALPHA) != 0) + { + RMInit::logOut << method_convertFrom << " warning: image contains alpha channel which will be lost" << endl; + png_set_strip_alpha(read_ptr); + } + + if (bps < 8) + { + png_set_packing(read_ptr); // extract depths 1-4 as 1 byte per pixel + } + + switch (colourType) + { + case PNG_COLOR_TYPE_GRAY: + case PNG_COLOR_TYPE_GRAY_ALPHA: + pitch = width; lineAdd = 1; pixelAdd = height; + if (bps == 1) desc.baseType = ctype_bool; else desc.baseType = ctype_char; + break; + case PNG_COLOR_TYPE_PALETTE: + png_set_expand(read_ptr); + case PNG_COLOR_TYPE_RGB: + case PNG_COLOR_TYPE_RGB_ALPHA: + pitch = 3*width; lineAdd = 3; pixelAdd = 3*height; + desc.baseType = ctype_rgb; + break; + default: + RMInit::logOut << method_convertFrom << ": don't understand image format" << endl; + throw r_Error(r_Error::r_Error_General); + } + + numPasses = png_set_interlace_handling(read_ptr); + +#ifdef RMANDEBUG + if (RManDebug >= 4) + { + RMInit::dbgOut << "PNG image: width " << width << ", height " << height << ", bps " << bps; + RMInit::dbgOut << ", colour "; + switch (desc.baseType) + { + case ctype_bool: RMInit::dbgOut << "bw"; break; + case ctype_char: RMInit::dbgOut << "grey"; break; + case ctype_rgb: RMInit::dbgOut << "rgb"; break; + } + RMInit::dbgOut << ", interlace level " << numPasses << endl; + } +#endif + + png_byte *row = new png_byte[pitch]; + + desc.dest = (char*)mystore.storage_alloc(pitch * height); + + for (pass=0; pass < numPasses; pass++) + { + unsigned char *dest, *destPtr; + + dest = (unsigned char*)(desc.dest); + for (j=0; j<height; j++, dest += lineAdd) + { + png_byte *rowPtr=NULL; + + destPtr = dest; rowPtr = row; + switch (desc.baseType) + { + case ctype_bool: + case ctype_char: + { + // In case of multiple passes set up the buffer according to the last pass + if (pass != 0) + { + for (i=0; i<width; i++, destPtr += pixelAdd) + { + *rowPtr++ = *destPtr; + } + destPtr = dest; rowPtr = row; + } + png_read_row(read_ptr, row, NULL); + for (i=0; i<width; i++, destPtr += pixelAdd) + { + *destPtr = *rowPtr++; + } + } + break; + case ctype_rgb: + { + if (pass != 0) + { + for (i=0; i<width; i++, destPtr += pixelAdd) + { + *rowPtr++ = destPtr[0]; *rowPtr++ = destPtr[1]; *rowPtr++ = destPtr[2]; + } + destPtr = dest; rowPtr = row; + } + png_read_row(read_ptr, row, NULL); + for (i=0; i<width; i++, destPtr += pixelAdd) + { + destPtr[0] = *rowPtr++; destPtr[1] = *rowPtr++; destPtr[2] = *rowPtr++; + } + } + break; + } + } + } + + png_read_end(read_ptr, info_ptr); + + delete [] row; row=NULL; + + png_destroy_read_struct(&read_ptr, &info_ptr, NULL); + + desc.destInterv = r_Minterval(2); + desc.destInterv << r_Sinterval((r_Range)0, (r_Range)width-1) + << r_Sinterval((r_Range)0, (r_Range)height-1); + + desc.destType = get_external_type(desc.baseType); + + return desc; +} + + + +const char *r_Conv_PNG::get_name( void ) const +{ + return format_name_png; +} + + +r_Data_Format r_Conv_PNG::get_data_format( void ) const +{ + return r_PNG; +} + + +r_Convertor *r_Conv_PNG::clone( void ) const +{ + return new r_Conv_PNG(desc.src, desc.srcInterv, desc.baseType); +} diff --git a/conversion/png.hh b/conversion/png.hh new file mode 100644 index 0000000..6b56300 --- /dev/null +++ b/conversion/png.hh @@ -0,0 +1,79 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * INCLUDE: png.hh + * + * MODULE: conversion + * + * CLASSES: r_Conv_PNG + * + * COMMENTS: + * + * Provides interface to convert data to other formats. + * +*/ + +#ifndef _R_CONV_PNG_HH_ +#define _R_CONV_PNG_HH_ + +#include "conversion/convertor.hh" + + + +//@ManMemo: Module {\bf conversion} + +/*@Doc: + PNG convertor class. + + This class doesn't have parameters. +*/ + +class r_Conv_PNG : public r_Convert_Memory +{ + public: + /// constructor using an r_Type object + r_Conv_PNG( const char *src, const r_Minterval &interv, const r_Type *tp ) throw(r_Error); + /// constructor using convert_type_e shortcut + r_Conv_PNG( const char *src, const r_Minterval &interv, int tp ) throw(r_Error); + /// destructor + ~r_Conv_PNG( void ); + + /// convert to PNG + virtual r_convDesc &convertTo( const char *options=NULL ) throw(r_Error); + /// convert from PNG + virtual r_convDesc &convertFrom( const char *options=NULL ) throw(r_Error); + /// cloning + virtual r_Convertor *clone( void ) const; + /// identification + virtual const char *get_name( void ) const; + virtual r_Data_Format get_data_format( void ) const; + + private: + /// names + static const char *name_InfoKey; + static const char *name_InfoText; + static const char *method_convertTo; + static const char *method_convertFrom; +}; + +#endif diff --git a/conversion/res.cc b/conversion/res.cc new file mode 100644 index 0000000..ffca7f9 --- /dev/null +++ b/conversion/res.cc @@ -0,0 +1,110 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +*/ + +#include <iostream> +#include <fstream> + +#include "res.h" +#include "nitf.h" +#include "utilities.h" + +using namespace std; +using namespace RasNITF; + +res::res(){ + + m_resshf = NULL; + m_resdata = NULL; +} + +res::~res(){ + + if(m_resshf != NULL){ + delete m_resshf; + m_resshf = NULL; + } + + if(m_resdata != NULL){ + delete m_resdata; + m_resdata = NULL; + } +} + +int res::read_file(istream &hNITF, long lrsh, long lr){ + + int charsread = 0; + + header_length = lrsh; + data_length = lr; + + charsread += read_verify2(hNITF, m_re, 2 + 25 + 2 + 167 + 4); + n_resshl = charptrtolong(m_resshl,4); + + if (n_resshl > 0) { + m_resshf = new char[n_resshl]; + charsread += read_verify2(hNITF, m_resshf, n_resshl); + } + + m_resdata = new char[data_length]; + charsread += read_verify2(hNITF, m_resdata, data_length); + + return charsread; +} + +int res::write_file(ofstream &fNITF) + +{ + + int charswritten = 0; + + fNITF.write(m_re, 2); + fNITF.write(m_restag, 25); + fNITF.write(m_resver, 2); + fNITF.write(m_ressg, 167); + fNITF.write(m_resshl, 4); + + if (fNITF.good()) charswritten += 2 + 25 + 2 + 167 + 4; + + if (n_resshl > 0) { + fNITF.write(m_resshf, n_resshl); + } + + if (fNITF.good()) charswritten += n_resshl; + + if( m_resdata != NULL) { + fNITF.write( m_resdata, data_length); + } + + if (fNITF.good()) charswritten += data_length; + + return charswritten; + +} + +string res::get_lr() const { + return res_dl; +} + +string res::get_lrsh() const { + return res_hl; +} diff --git a/conversion/res.h b/conversion/res.h new file mode 100644 index 0000000..a655938 --- /dev/null +++ b/conversion/res.h @@ -0,0 +1,64 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +*/ + +#ifndef __RASNITF_RES_H +#define __RASNITF_RES_H + +#include <vector> +#include <iostream> +#include <fstream> + +namespace RasNITF +{ + +class res { + + char m_re[2]; + char m_restag[25]; + char m_resver[2]; + char m_ressg[167]; + char m_resshl[4]; + char* m_resshf; + char* m_resdata; + + long n_resshl; + long data_length; + long header_length; + + std::string res_hl; + std::string res_dl; + public: + + res(); + ~res(); + + int read_file(std::istream &,long,long); + int write_file(std::ofstream &); + std::string get_lr() const; + std::string get_lrsh() const; + +}; + +} + +#endif diff --git a/conversion/test/Makefile b/conversion/test/Makefile new file mode 100644 index 0000000..410e1c4 --- /dev/null +++ b/conversion/test/Makefile @@ -0,0 +1,142 @@ +# -*-Makefile-*- +# +# 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 <http://www.gnu.org/licenses/>. +# +# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +# rasdaman GmbH. +# +# For more information please see <http://www.rasdaman.org> +# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build +# and/or deployed +# +# MAKEFILE FOR: +# test programs of module conversion +# +# COMMENTS: +# +################################################################## +# +# This is just an example Makefile for a test program. +# The dependency of the test program on the lib of the +# corresponding module is in the Makefile of the module. +# + +######################### Definitions ############################ + +# standard include with general options +include $(RMANBASE)/Makefile.inc + +# all test programs +ifeq ($(OSTYPE),linux-gnu) +ALLTESTS = test_convertor test_png test_jpeg test_bmp test_vff +else +ALLTESTS = test_convertor test_hdf test_png test_jpeg test_bmp test_vff +endif + +# For the time being: HDF includes / libs +HDFBASE = $(SUPPORT_BASE) +HDFINC = -I$(HDFBASE)/include +HDFLIB = -L$(HDFBASE)/lib -ldf -ljpeg -lz -lmfhdf -lnsl + +ifeq ($(OSTYPE),linux-gnu) + LINKLIBS=$(CONVERSION) $(CLIENTCOMM) $(COMPRESSION) $(RASLIB) $(RASODMG) + CLIENTLDFLAGS += -lz +else + ifdef RMANGCC + LINKLIBS=$(CONVERSION) $(CLIENTCOMM) $(COMPRESSION) $(RASLIB) $(RASODMG) + CLIENTLDFLAGS += -lsocket -lnsl -lz + else + LINKLIBS=$(CONVERSION) $(RASLIB) + endif +endif + +########################### Targets ############################## + +# test target for convertors like r_TIFF +.PHONY : convertor +convertor: test_module $(ALLTESTS) + +.PHONY : test_module +test_module: + cd $(RMANBASE)/conversion; $(MAKE) + +.PHONY : tiff +tiff: test_module test_convertor + +.PHONY : hdf +hdf: test_module test_hdf + +.PHONY : png +png: test_module test_png + +.PHONY : jpeg +jpeg: test_module test_jpeg + +.PHONY : bmp +bmp: test_module test_bmp + +.PHONY : vff +vff: test_module test_vff + + +test_convertor: test_convertor.o $(LINKLIBS) + $(PURIFY) $(CXX) $(CLIENTLDFLAGS) -o $@ $^ -L$(SUPPORT_BASE)/lib -ltiff -ljpeg -lz -lcrypto + +test_hdf: test_hdf.o $(LINKLIBS) + $(PURIFY) $(CXX) $(CLIENTLDFLAGS) -o $@ $^ -L$(SUPPORT_BASE)/lib -lcrypto -lz $(HDFLIB) + +test_png: test_png.o $(LINKLIBS) + $(PURIFY) $(CXX) $(CLIENTLDFLAGS) -o $@ $^ -L$(SUPPORT_BASE)/lib -lpng -lz -lcrypto + +test_jpeg: test_jpeg.o $(LINKLIBS) + $(PURIFY) $(CXX) $(CLIENTLDFLAGS) -o $@ $^ -L$(SUPPORT_BASE)/lib -ljpeg -lz -lcrypto + +test_bmp: test_bmp.o $(LINKLIBS) + $(PURIFY) $(CXX) $(CLIENTLDFLAGS) -o $@ $^ -L$(SUPPORT_BASE)/lib -lcrypto -lz + +test_vff: test_vff.o $(LINKLIBS) + $(PURIFY) $(CXX) $(CLIENTLDFLAGS) -o $@ $^ -L$(SUPPORT_BASE)/lib -lcrypto -lz + + +.PHONY : clean +clean: + -rm $(ALLTESTS) + -rm *.o + +# deletes all non modified, but checked out files +.PHONY : rcsclean +rcsclean: + -rcsclean + +######################## Dependencies ############################ + +test_convertor.o: test_convertor.cc + $(CXX) test_convertor.cc -c -o $@ $(CLIENTCXXFLAGS) + +test_hdf.o: test_hdf.cc + $(CXX) test_hdf.cc -c -o $@ $(HDFINC) $(CLIENTCXXFLAGS) + +test_png.o: test_png.cc + $(CXX) test_png.cc -c -o $@ $(CLIENTCXXFLAGS) + +test_jpeg.o: test_jpeg.cc + $(CXX) test_jpeg.cc -c -o $@ $(CLIENTCXXFLAGS) + +test_bmp.o: test_bmp.cc + $(CXX) test_bmp.cc -c -o $@ $(CLIENTCXXFLAGS) + +test_vff.o: test_vff.cc + $(CXX) test_vff.cc -c -o $@ $(CLIENTCXXFLAGS) diff --git a/conversion/test/test_bmp.cc b/conversion/test/test_bmp.cc new file mode 100644 index 0000000..c98712e --- /dev/null +++ b/conversion/test/test_bmp.cc @@ -0,0 +1,83 @@ +#include <stdlib.h> +#include <stdio.h> +#include <iostream> +#include <string.h> + + +#include "conversion/convertor.hh" +#include "conversion/bmp.hh" + +#ifdef EARLY_TEMPLATE +#define __EXECUTABLE__ +#include "raslib/template_inst.hh" +#endif + +int main(int argc, char *argv[]) +{ + char filename[256] = "Somewhere.bmp"; + long fsize=0; + FILE *fp=NULL; + char *data=NULL; + r_Minterval interv(1); + r_Minterval imgInterv; + r_Conv_BMP *bmp=NULL; + r_convDesc desc; + r_Type *baseType=NULL; + char *imgData=NULL; + + if (argc > 1) + strcpy(filename, argv[1]); + + fp = fopen(filename, "rb"); + if (fp == NULL) + { + cerr << "Unable to open file " << filename << endl; + exit(-1); + } + + fseek(fp, 0, SEEK_END); + fsize = ftell(fp); + fseek(fp, 0, SEEK_SET); + + data = new char[fsize]; + fread(data, 1, fsize, fp); + fclose(fp); + + interv << r_Sinterval((r_Range)0, (r_Range)fsize-1); + + cout << "Convert from BMP..." << endl; + bmp = new r_Conv_BMP(data, interv, r_Convertor::ctype_char); + desc = bmp->convertFrom(); + baseType = desc.destType; + imgData = desc.dest; + imgInterv = desc.destInterv; + delete [] data; + data=NULL; + delete bmp; + bmp=NULL; + + cout << "Convert to BMP..." << endl; + bmp = new r_Conv_BMP(imgData, imgInterv, baseType); + desc = bmp->convertTo("compress=1"); + fsize = desc.destInterv[0].high() - desc.destInterv[0].low() + 1; + + fp = fopen("result.bmp", "wb"); + fwrite(desc.dest, 1, fsize, fp); + fclose(fp); + + free(desc.dest); + desc.dest=NULL; + delete desc.destType; + desc.destType=NULL; + delete bmp; + bmp=NULL; + + cout << "Clean up..." << endl; + + delete baseType; + baseType=NULL; + free(imgData); + imgData=NULL; + + return 0; +} diff --git a/conversion/test/test_convertor.cc b/conversion/test/test_convertor.cc new file mode 100644 index 0000000..9305278 --- /dev/null +++ b/conversion/test/test_convertor.cc @@ -0,0 +1,276 @@ +#include <iostream> +#include <stdio.h> +#include <string.h> +#include "conversion/convertor.hh" +#include "conversion/tiff.hh" +#include "raslib/rminit.hh" +#include "rasodmg/gmarray.hh" + +#ifdef EARLY_TEMPLATE +#define __EXECUTABLE__ +#include "raslib/template_inst.hh" +#endif + +// define if you want to use r_Type variables to set the +// array type. +//#define TEST_CONV_USE_RTYPES + + +void ConvertToTIFFCore(r_Conv_TIFF *tiff, const char *save, const char *params) +{ + r_convDesc desc; + FILE *tfile; + long size; + + try + { + // desc will become invalid when the TIFF object is deleted. + // The same applies to all data allocated by the TIFF object, + // e.g. the buffer holding the resulting TIFF. + desc = tiff->convertTo(params); + + size = (long)(desc.destInterv[0].high() - desc.destInterv[0].low() + 1); + if ((tfile = fopen(save, "wb")) == NULL) + { + cerr << "Error opening file " << save << endl; + } + else + { + fwrite((void*)(desc.dest), (size_t)1, (size_t)size, tfile); + fclose(tfile); + } + cout << "test_convertor: r_Conv_TIFF::convertTo successful. " + << "size = " << size << ", type = "; + desc.destType->print_status(cout); cout << endl; + // This is the job of the client! + free(desc.dest); + delete desc.destType; + } + catch (r_Error &err) + { + cout << "An error occurred: " << err.what() << endl; + } +} + + +void ConvertToTIFF(char *data, r_Minterval &iv, r_Type *type, const char *save, const char *params) +{ + r_Conv_TIFF *tiff; + + cout << "test_convertor (r_Type): "; + if (type) + { + cout << "Base Type is "; type->print_status(cout); cout << endl; + } + else + { + cout << "Base type not defined!" << endl; + } + + tiff = new r_Conv_TIFF(data, iv, type); + ConvertToTIFFCore(tiff, save, params); + delete tiff; +} + + +void ConvertToTIFF(char *data, r_Minterval &iv, int type, const char *save, const char *params) +{ + r_Conv_TIFF *tiff; + + cout << "test_convertor (int):" << endl; + + tiff = new r_Conv_TIFF(data, iv, type); + ConvertToTIFFCore(tiff, save, params); + delete tiff; +} + + +void ConvertFromTIFF(char *name, const char *params, const char *save_as = NULL) +{ + FILE *fp; + long size; + r_convDesc desc; + r_Conv_TIFF *tiff; + char *data; + r_Minterval iv; + + fp = fopen(name, "r"); + fseek(fp, 0, SEEK_END); + size = ftell(fp); + data = new char[size]; + fseek(fp, 0, SEEK_SET); + fread((void*)data, (size_t)1, (size_t)size, fp); + fclose(fp); + + // Set interval + iv = r_Minterval(1); iv << r_Sinterval(r_Range(0), r_Range(size - 1)); + + // Base type is coded in TIFF + tiff = new r_Conv_TIFF(data, iv, (int)0); + + desc = tiff->convertFrom(); + + cout << "test_convertor: r_Conv_TIFF::convertFrom successful." + << " domain = " << desc.destInterv << ", type = "; + desc.destType->print_status(cout); cout << endl; + + delete [] data; + + // save file again as TIFF to check convertFrom validity? + if (save_as != NULL) + { + cout << "test_convertor: Saving data again as <" << save_as << ">..." << endl; + ConvertToTIFF(desc.dest, desc.destInterv, desc.baseType, save_as, params); + } + + // The order in which objects are deleted is important! + free(desc.dest); + delete desc.destType; + + // Delete this last. From then on desc is invalid. + delete tiff; +} + + + +// Flag bits for main() +#define CONVERTOR_WRITE_BACK 1 + + +// Calling convention: test_convertor [-x # -y # -c <compression> -v -h] +// Where -x: width, -y: height, -c: compression, -v: write again as TIFF after reading +// -h: Help on usage +// width, height default to 200, 100 +int main (int argc, char *argv[]) +{ + r_GMarray dummyArray; // need this for linking on Linux, don't know why + char *data, *lineBase, *line; + int width = 200, height = 100; + unsigned int flags = 0; + int i, j; + char params[256]; + const char *paramptr = NULL; +#ifdef TEST_CONV_USE_RTYPES + r_Type *type; +#endif + struct nametable {char *write, *verify;} tiffnames[] = { + {"grey.tif", "grey2.tif"}, + {"bool.tif", "bool2.tif"}, + {"rgb.tif", "rgb2.tif"} + }; + + i = 1; + while (i < argc) + { + if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'x': width = atoi(argv[++i]); break; + case 'y': height = atoi(argv[++i]); break; + case 'c': + sprintf(params, "comptype=%s", argv[++i]); + paramptr = params; + break; + case 'v': flags |= CONVERTOR_WRITE_BACK; break; + case 'h': + cout << "Usage: " << argv[0] << "[-w # -h # -c <string> -v -h]" << endl; + cout << "\t-x #: width" << endl; + cout << "\t-y #: height" << endl; + cout << "\t-c <string>: compression (see r_Conv_TIFF::compNames)" << endl; + cout << "\t-v: write the TIFF files just read back as TIFF files for verifying" << endl; + cout << "\t-h: this help" << endl; + exit(0); + default: cout << "Bad switch -" << argv[i][1] << endl; break; + } + } + i++; + } + + cout << "test_convertor: use images of size " << width << " * " << height + << ", compression: "; + + // Allocate enough room for _all_ types of data. + if ((data = new char[3*width*height]) == NULL) + { + cout << "Out of memory error!" << endl; exit(0); + } + + r_Minterval iv(2); + iv << r_Sinterval(r_Range(0), r_Range(width - 1)) + << r_Sinterval(r_Range(0), r_Range(height - 1)); + + // Take into account that MDD arrays are transposed compared to + // images! + cout << "Greyscale:" << endl; + lineBase = data; + for (j=0; j<height; j++, lineBase++) + { + line = lineBase; + for (i=0; i<width; i++, line += height) + { + *line = (char)((i+j) & 0xff); + } + } + +#ifdef TEST_CONV_USE_RTYPES + type = r_Type::get_base_type("char"); + ConvertToTIFF(data, iv, type, tiffnames[0].write, paramptr); + delete type; +#else + ConvertToTIFF(data, iv, (int)(r_Convertor::ctype_char), tiffnames[0].write, paramptr); +#endif + + cout << "Bitmap:" << endl; + lineBase = data; + for (j=0; j<height; j++, lineBase++) + { + line = lineBase; + for (i=0; i<width; i++, line += height) + { + *line = (char)((i + j) & 1); + } + } + +#ifdef TEST_CONV_USE_RTYPES + type = r_Type::get_base_type("boolean"); + ConvertToTIFF(data, iv, type, tiffnames[1].write, paramptr); + delete type; +#else + ConvertToTIFF(data, iv, (int)(r_Convertor::ctype_bool), tiffnames[1].write, paramptr); +#endif + + cout << "RGB:" << endl; + lineBase = data; + for (j=0; j<height; j++, lineBase += 3) + { + line = lineBase; + for (i=0; i<width; i++, line += 3*height) + { + line[0] = ((i+j) & 0xff); line [1] = ((0xff - (i+j)) & 0xff); + line[2] = (((i+j) >> 1) & 0xff); + } + } + +#ifdef TEST_CONV_USE_RTYPES + type = r_Type::get_base_type("struct{ char red, char green, char blue }"); + ConvertToTIFF(data, iv, type, tiffnames[2].write, paramptr); + delete type; +#else + ConvertToTIFF(data, iv, (int)(r_Convertor::ctype_rgb), tiffnames[2].write, paramptr); +#endif + + delete [] data; + + // Try the other way around: convert from TIFF + ConvertFromTIFF("rgb.tif", paramptr, + ((flags & CONVERTOR_WRITE_BACK) != 0) ? tiffnames[2].verify : NULL); + + ConvertFromTIFF("bool.tif", paramptr, + ((flags & CONVERTOR_WRITE_BACK) != 0) ? tiffnames[1].verify : NULL); + + ConvertFromTIFF("grey.tif", paramptr, + ((flags & CONVERTOR_WRITE_BACK) != 0) ? tiffnames[0].verify : NULL); + + return 0; +} diff --git a/conversion/test/test_hdf.cc b/conversion/test/test_hdf.cc new file mode 100644 index 0000000..a11b98a --- /dev/null +++ b/conversion/test/test_hdf.cc @@ -0,0 +1,309 @@ +#include "conversion/convertor.hh" +#include "conversion/hdf.hh" +#include "raslib/minterval.hh" +#include "raslib/primitivetype.hh" + + +#ifdef EARLY_TEMPLATE +#define __EXECUTABLE__ +#include "raslib/template_inst.hh" +#endif + +char *TypeIDToName(int tpid) +{ + switch (tpid) + { + case r_Primitive_Type::BOOL: return "bool"; break; + case r_Primitive_Type::CHAR: return "char"; break; + case r_Primitive_Type::OCTET: return "octet"; break; + case r_Primitive_Type::SHORT: return "short"; break; + case r_Primitive_Type::USHORT: return "ushort"; break; + case r_Primitive_Type::LONG: return "long"; break; + case r_Primitive_Type::ULONG: return "ulong"; break; + case r_Primitive_Type::FLOAT: return "float"; break; + case r_Primitive_Type::DOUBLE: return "double"; break; + default: return"?"; break; + } +} + + +int TestHDF(r_Minterval &domain, r_Type *tp, const char *params=NULL) +{ + r_Primitive_Type *prim; + char *src, *dest; + r_Minterval destInterv; + r_Conv_HDF *hdf; + r_Type *destType; + r_convDesc desc; + int i, j, k; + int rank, array_size, datasize; + int *dimsizes, *dimsteps, *dimidx; + char **srcPtrs; + int ptid, retid; + + if (tp->isStructType()) + { + cerr << "No structured types allowed!" << endl; + return -1; + } + prim = (r_Primitive_Type*)tp; + ptid = prim->type_id(); + cout << "Source domain = " << domain << ", type = " << TypeIDToName(ptid) << endl; + + switch (ptid) + { + case r_Primitive_Type::BOOL: + case r_Primitive_Type::CHAR: + case r_Primitive_Type::OCTET: + datasize = 1; break; + case r_Primitive_Type::SHORT: + case r_Primitive_Type::USHORT: + datasize = 2; break; + case r_Primitive_Type::LONG: + case r_Primitive_Type::ULONG: + case r_Primitive_Type::FLOAT: + datasize = 4; break; + case r_Primitive_Type::DOUBLE: + datasize = 8; break; + default: + cerr << "Unrecognized base type" << endl; + return -1; + } + + rank = domain.dimension(); + dimsizes = new int[rank]; dimsteps = new int[rank]; dimidx = new int[rank]; + srcPtrs = new char*[rank]; + for (i=0; i<rank; i++) + { + dimsizes[i] = domain[i].high() - domain[i].low() + 1; + dimidx[i] = 0; + } + array_size = datasize; + for (i=rank-1; i>=0; i--) + { + dimsteps[i] = array_size; array_size *= dimsizes[i]; + } + src = new char[array_size]; + + for (i=0; i<rank; i++) srcPtrs[i] = src; + + k = 0; + do + { + //cout << (int)(srcPtrs[0] - src) << endl; + + // A bit inefficient, but customized code for the entire loop for each type + // would result in way too much code for testing purposes only. + switch (ptid) + { + case r_Primitive_Type::BOOL: + case r_Primitive_Type::CHAR: + case r_Primitive_Type::OCTET: + *((char*)srcPtrs[0]) = (char)k; + break; + case r_Primitive_Type::SHORT: + case r_Primitive_Type::USHORT: + *((short*)srcPtrs[0]) = (short)k; + break; + case r_Primitive_Type::LONG: + case r_Primitive_Type::ULONG: + *((long*)srcPtrs[0]) = (long)k; + break; + case r_Primitive_Type::FLOAT: + *((float*)srcPtrs[0]) = (float)k; + break; + case r_Primitive_Type::DOUBLE: + *((double*)srcPtrs[0]) = (double)k; + break; + default: break; + } + k++; i = 0; + do + { + dimidx[i]++; + if (dimidx[i] < dimsizes[i]) break; + dimidx[i] = 0; i++; + } + while (i < rank); + if (i < rank) + { + srcPtrs[i] += dimsteps[i]; + if (i > 0) + { + // Init the array with the value x_0 + x_1 + ... + x_(n-1) + k = dimidx[0]; + for (j=1; j<rank; j++) k += dimidx[j]; + for (j=i; j>0; j--) {srcPtrs[j-1] = srcPtrs[j];;} + } + } + } + while (i < rank); + + hdf = new r_Conv_HDF(src, domain, tp); + + dest = NULL; + + try + { + desc = hdf->convertTo(params); + dest = desc.dest; + destInterv = desc.destInterv; + destType = desc.destType; + } + catch(r_Error &err) + { + cerr << "Exception! " << err.what() << endl; + } + + cout << "Encoded interval " << desc.destInterv << endl; + + delete hdf; + + if (dest != NULL) + { + try + { + hdf = new r_Conv_HDF(dest, destInterv, destType); + + desc = hdf->convertFrom(); + + cout << "retrieved type = "; desc.destType->print_status(); + retid = ((r_Primitive_Type*)(desc.destType))->type_id(); + cout << ", (" << ((retid == ptid) ? "OK" : "Differs") << ')' << endl; + cout << "retrieved domain " << desc.destInterv << ' '; + i = 0; + if (desc.destInterv.dimension() == rank) + { + for (i=0; i<rank; i++) + { + if (desc.destInterv[i].high() - desc.destInterv[i].low() != domain[i].high() - domain[i].low()) + break; + } + } + if (i < rank) + { + cout << "Incompatible!" << endl; + return -1; + } + cout << "(OK)" << endl; + + for (i=0; i<array_size; i++) + { + if (src[i] != desc.dest[i]) break; + } + if (i == array_size) + { + cout << "Data identical" << endl; + } + else + { + cout << "Data differs at " << i << endl; + } + + cout << endl; + + delete destType; + delete desc.destType; + + free(desc.dest); // HDF^-1 ( HDF (X) ) + } + catch(r_Error &err) + { + cerr << "Exception! " << err.what() << endl; + } + } + + delete hdf; + + if (dest != NULL) + free(dest); // HDF (X) + + delete [] src; // X + + delete [] dimsizes; delete [] dimsteps; delete [] dimidx; delete [] srcPtrs; + + // Delete the base type passed from the caller too + delete tp; + + return 0; +} + + + + + +int main(int argc, char *argv[]) +{ + r_Minterval interv; + r_Type *tp; + + // 3D data set over char + interv = r_Minterval(3); + interv << r_Sinterval(r_Range(0), r_Range(19)) + << r_Sinterval(r_Range(0), r_Range(29)) + << r_Sinterval(r_Range(0), r_Range(39)); + tp = r_Type::get_any_type("char"); + TestHDF(interv, tp); + + // 2D data set over short + interv = r_Minterval(2); + interv << r_Sinterval(r_Range(0), r_Range(100)) + << r_Sinterval(r_Range(0), r_Range(200)); + tp = r_Type::get_any_type("short"); + TestHDF(interv, tp); + + // 1D data set over long + interv = r_Minterval(1); + interv << r_Sinterval(r_Range(0), r_Range(400)); + tp = r_Type::get_any_type("long"); + TestHDF(interv, tp); + + // 2D data set over float + interv = r_Minterval(2); + interv << r_Sinterval(r_Range(0), r_Range(200)) + << r_Sinterval(r_Range(0), r_Range(300)); + tp = r_Type::get_any_type("float"); + TestHDF(interv, tp); + + // 2D data set over double + interv = r_Minterval(2); + interv << r_Sinterval(r_Range(100), r_Range(300)) + << r_Sinterval(r_Range(100), r_Range(400)); + tp = r_Type::get_any_type("double"); + TestHDF(interv, tp); + + // 1D data set over octet + interv = r_Minterval(1); + interv << r_Sinterval(r_Range(0), r_Range(200)); + tp = r_Type::get_any_type("octet"); + TestHDF(interv, tp); + + // 1D data set over bool + interv = r_Minterval(1); + interv << r_Sinterval(r_Range(0), r_Range(200)); + tp = r_Type::get_any_type("boolean"); + TestHDF(interv, tp); + + // 1D data set over unsigned short + interv = r_Minterval(1); + interv << r_Sinterval(r_Range(0), r_Range(200)); + tp = r_Type::get_any_type("ushort"); + TestHDF(interv, tp); + + // 1D data set over unsigned long + interv = r_Minterval(1); + interv << r_Sinterval(r_Range(0), r_Range(200)); + tp = r_Type::get_any_type("ulong"); + TestHDF(interv, tp); + + // 4D data set over char + interv = r_Minterval(4); + interv << r_Sinterval(r_Range(100), r_Range(149)) + << r_Sinterval(r_Range(110), r_Range(184)) + << r_Sinterval(r_Range(120), r_Range(219)) + << r_Sinterval(r_Range(130), r_Range(204)); + tp = r_Type::get_any_type("char"); + TestHDF(interv, tp); + + return 0; +} diff --git a/conversion/test/test_jpeg.cc b/conversion/test/test_jpeg.cc new file mode 100644 index 0000000..e56a3d4 --- /dev/null +++ b/conversion/test/test_jpeg.cc @@ -0,0 +1,295 @@ +#include <stdlib.h> +#include <stdio.h> +#include <iostream> +#include <string.h> +#include <math.h> + + +#include "conversion/convertor.hh" +#include "conversion/jpeg.hh" + +#ifdef EARLY_TEMPLATE +#define __EXECUTABLE__ +#include "raslib/template_inst.hh" +#endif + +static int init_identity(int offset) +{ + return offset; +} + +static int init_square(int offset) +{ + return offset * offset; +} + +static int SinTabOK = 0; +static int SinusTable[512]; + +static int init_sine(int offset) +{ + if (SinTabOK == 0) + { + int i; + + for (i=0; i<512; i++) + { + SinusTable[i] = (int)(255*sin(M_PI * offset / 512.0)); + } + SinTabOK = 1; + } + return SinusTable[offset & 511]; +} + +static int JpegErrorFileNumber; + +int test_picture(int width, int height, int bpp, const char *params, int (*init)(int)) +{ + char *data; + r_Minterval interv(2); + int datasize; + int baseType; + int bytespp; + int i; + + switch (bpp) + { + case 1: baseType = r_Convertor::ctype_bool; bytespp = 1; break; + case 8: baseType = r_Convertor::ctype_char; bytespp = 1; break; + case 24: baseType = r_Convertor::ctype_rgb; bytespp = 3; break; + default: + cerr << "Unknown bpp value " << bpp << endl; + return -1; + } + + interv << r_Sinterval((r_Range)0, (r_Range)width-1) + << r_Sinterval((r_Range)0, (r_Range)height-1); + + datasize = (width * bytespp * height); + data = new char[datasize]; + + cout << "Test: bpp = " << bpp << ", domain = " << interv << ", params = " << ((params == NULL) ? "" : params) << ", size = " << datasize << endl; + + if (bpp > 1) + { + for (i=0; i<datasize; i++) data[i] = (char)init(i); + } + else + { + int j, count; + + for (i=0; i<datasize; i+=8) + { + count = datasize - i; if (count > 8) count = 8; + for (j=0; j<count; j++) data[i+j] = ((init(i>>3) & (1<<j)) == 0) ? 0 : 1; + } + } + + r_Conv_JPEG *jpeg = NULL; + char *dest = NULL; + + try + { + r_convDesc desc; + int destsize; + int status = 0; + + jpeg = new r_Conv_JPEG(data, interv, baseType); + desc = jpeg->convertTo(params); + destsize = desc.destInterv[0].high() - desc.destInterv[0].low() + 1; + cout << "\tConverted to JPEG, domain " << desc.destInterv << endl; + dest = desc.dest; + r_Minterval destInterv(desc.destInterv); + delete desc.destType; + delete jpeg; + jpeg = new r_Conv_JPEG(dest, destInterv, r_Convertor::ctype_char); + desc = jpeg->convertFrom(); + cout << "\tConverted from JPEG, domain " << desc.destInterv << endl; + + if (interv == desc.destInterv) + { + unsigned char *b, *d; + double totalError; + unsigned char maxError; + int i; + + // Bitmaps get expanded to greyscale... + if (baseType == r_Convertor::ctype_bool) + { + for (i=0; i<datasize; i++) + { + if (data[i] != 0) data[i] = 0xff; + } + } + + b = (unsigned char*)data; d = (unsigned char*)desc.dest; + totalError = 0.0; maxError = abs(*b - *d); + for (i=0; i<datasize; i++) + { + b[i] = abs(b[i] - d[i]); + if (b[i] > maxError) maxError = b[i]; + totalError += (double)(b[i]); + } + + r_Conv_JPEG *errpeg; + r_convDesc cdsc; + char errfile[256]; + FILE *fp; + int errType; + + errType = (baseType == r_Convertor::ctype_bool) ? r_Convertor::ctype_char : baseType; + sprintf(errfile, "jerror%d.jpg", JpegErrorFileNumber++); + cout << "\tCreating error file <" << errfile << "> ..." << endl; + cout << "\t(max error = " << (int)maxError << ", avg error = " + << totalError / (double)datasize << ")" << endl; + + errpeg = new r_Conv_JPEG(data, interv, errType); + cdsc = errpeg->convertTo("quality=90"); + i = (int)(cdsc.destInterv[0].high() - cdsc.destInterv[0].low() + 1); + if ((fp = fopen(errfile, "wb")) == NULL) + { + cerr << "\tUnable to open output file!" << endl; + } + else + { + fwrite(cdsc.dest, 1, i, fp); + fclose(fp); + } + delete cdsc.destType; + free(cdsc.dest); + delete errpeg; + } + else + { + cout << "\t Domain differs!!!" << endl; + status = -1; + } + + delete jpeg; + delete [] data; + free(dest); + free(desc.dest); + delete desc.destType; + + return status; + } + catch (r_Error &err) + { + cerr << "Error: " << err.what() << endl; + + delete [] data; + if (dest != NULL) delete [] dest; + if (jpeg != NULL) delete jpeg; + + return -1; + } +} + +int main(int argc, char *argv[]) +{ + int i; + char jpegfile[256] = ""; + char params[256]; + const char *paramptr = NULL; + + i = 1; + while (i < argc) + { + if (strcmp(argv[i], "-file") == 0) + { + strcpy(jpegfile, argv[++i]); + } + else if (strcmp(argv[i], "-quality") == 0) + { + sprintf(params, "quality=%s", argv[++i]); + paramptr = params; + } + i++; + } + + if (jpegfile[0] == '\0') + { + JpegErrorFileNumber = 0; + test_picture(400, 300, 1, paramptr, init_identity); + test_picture(400, 300, 8, paramptr, init_identity); + test_picture(400, 300, 24, paramptr, init_identity); + test_picture(701, 333, 1, paramptr, init_square); + test_picture(701, 333, 8, paramptr, init_square); + test_picture(701, 333, 24, paramptr, init_square); + test_picture(3007, 3999, 1, paramptr, init_sine); + test_picture(3007, 3999, 8, paramptr, init_sine); + test_picture(3007, 3999, 24, paramptr, init_sine); + } + else + { + FILE *fp; + long fileSize; + char *data = NULL; + char *cdata = NULL; + r_convDesc desc; + r_Type *baseType; + r_Conv_JPEG *jpeg; + + if ((fp = fopen(jpegfile, "rb")) == NULL) + { + cerr << "Unable to open input file" << endl; + return -1; + } + fseek(fp, 0, SEEK_END); fileSize = ftell(fp); fseek(fp, 0, SEEK_SET); + data = new char[fileSize]; + fread(data, 1, fileSize, fp); + fclose(fp); + + jpeg = NULL; baseType = NULL; + try + { + r_Minterval interv(1); + interv << r_Sinterval((r_Range)0, (r_Range)fileSize-1); + + jpeg = new r_Conv_JPEG(data, interv, 0); + cout << "Converting file <" << jpegfile << "> to MDD..." << endl; + desc = jpeg->convertFrom(); + + r_Minterval imgInterv(desc.destInterv); + delete [] data; data = NULL; + cdata = desc.dest; + baseType = desc.destType; + delete jpeg; + + cout << "Resulting domain " << imgInterv << ", "; + baseType->print_status(); + cout << endl; + + jpeg = new r_Conv_JPEG(cdata, imgInterv, baseType); + cout << "Converting MDD back to JPEG..." << endl; + desc = jpeg->convertTo(paramptr); + free(cdata); + cdata = desc.dest; + + cout << "Resulting domain " << desc.destInterv << ", "; + desc.destType->print_status(); + cout << endl; + + fp = fopen("result.jpg", "wb"); + fileSize = desc.destInterv[0].high() - desc.destInterv[0].low() + 1; + fwrite(cdata, 1, fileSize, fp); + fclose(fp); + + delete baseType; + free(cdata); + + delete desc.destType; + delete jpeg; + } + catch (r_Error &err) + { + cerr << "Conversion failed: " << err.what() << endl; + if (baseType != NULL) delete baseType; + if (cdata != NULL) delete [] cdata; + if (jpeg != NULL) delete jpeg; + } + if (data != NULL) + delete [] data; + } + return 0; +} diff --git a/conversion/test/test_png.cc b/conversion/test/test_png.cc new file mode 100644 index 0000000..bc481fc --- /dev/null +++ b/conversion/test/test_png.cc @@ -0,0 +1,237 @@ +#include <stdlib.h> +#include <stdio.h> +#include <iostream> +#include <string.h> +#include <math.h> + + +#include "conversion/convertor.hh" +#include "conversion/png.hh" + +#ifdef EARLY_TEMPLATE +#define __EXECUTABLE__ +#include "raslib/template_inst.hh" +#endif + +static int init_identity(int offset) +{ + return offset; +} + +static int init_square(int offset) +{ + return offset * offset; +} + +static int SinTabOK = 0; +static int SinusTable[512]; + +static int init_sine(int offset) +{ + if (SinTabOK == 0) + { + int i; + + for (i=0; i<512; i++) + { + SinusTable[i] = (int)(255*sin(M_PI * offset / 512.0)); + } + SinTabOK = 1; + } + return SinusTable[offset & 511]; +} + +int test_picture(int width, int height, int bpp, int (*init)(int)) +{ + char *data; + r_Minterval interv(2); + int datasize; + int baseType; + int bytespp; + int i; + + switch (bpp) + { + case 1: baseType = r_Convertor::ctype_bool; bytespp = 1; break; + case 8: baseType = r_Convertor::ctype_char; bytespp = 1; break; + case 24: baseType = r_Convertor::ctype_rgb; bytespp = 3; break; + default: + cerr << "Unknown bpp value " << bpp << endl; + return -1; + } + + interv << r_Sinterval((r_Range)0, (r_Range)width-1) + << r_Sinterval((r_Range)0, (r_Range)height-1); + + datasize = (width * bytespp * height); + data = new char[datasize]; + + cout << "Test: bpp = " << bpp << ", domain = " << interv << ", size = " << datasize << endl; + + if (bpp > 1) + { + for (i=0; i<datasize; i++) data[i] = (char)init(i); + } + else + { + int j, count; + + for (i=0; i<datasize; i+=8) + { + count = datasize - i; if (count > 8) count = 8; + for (j=0; j<count; j++) data[i+j] = ((init(i>>3) & (1<<j)) == 0) ? 0 : 1; + //for (j=0; j<count; j++) cout << (char)(data[i+j] + '0'); cout << endl; + } + } + + r_Conv_PNG *png = NULL; + char *dest = NULL; + + try + { + r_convDesc desc; + int destsize; + int status = -1; + + png = new r_Conv_PNG(data, interv, baseType); + desc = png->convertTo(); + destsize = desc.destInterv[0].high() - desc.destInterv[0].low() + 1; + cout << "\tConverted to PNG, domain " << desc.destInterv << endl; + dest = desc.dest; + r_Minterval destInterv(desc.destInterv); + delete desc.destType; + delete png; + png = new r_Conv_PNG(dest, destInterv, r_Convertor::ctype_char); + desc = png->convertFrom(); + cout << "\tConverted from PNG, domain " << desc.destInterv << endl; + + if (interv == desc.destInterv) + status = memcmp(data, desc.dest, datasize); + + delete png; + delete [] data; + free(dest); + free(desc.dest); + delete desc.destType; + + if (status != 0) + { + cout << "\t!!! Data not identical !!!" << endl; + } + + return 0; + } + catch (r_Error &err) + { + cerr << "Error: " << err.what() << endl; + + delete [] data; + if (dest != NULL) free(dest); + if (png != NULL) delete png; + + return -1; + } +} + +int main(int argc, char *argv[]) +{ + int i; + char pngfile[256] = ""; + + i = 1; + while (i < argc) + { + if (strcmp(argv[i], "-file") == 0) + { + strcpy(pngfile, argv[++i]); + } + i++; + } + + if (pngfile[0] == '\0') + { + // No PNG-file given, standard test-suite + test_picture(400, 300, 1, init_identity); + test_picture(400, 300, 8, init_identity); + test_picture(400, 300, 24, init_identity); + test_picture(701, 333, 1, init_square); + test_picture(701, 333, 8, init_square); + test_picture(701, 333, 24, init_square); + test_picture(3007, 3999, 1, init_sine); + test_picture(3007, 3999, 8, init_sine); + test_picture(3007, 3999, 24, init_sine); + } + else + { + // Work on this file + FILE *fp; + size_t fsize; + char *data; + r_convDesc desc; + r_Conv_PNG *png; + r_Type *baseType; + + if ((fp = fopen(pngfile, "rb")) == NULL) + { + cerr << "Unable to open input file" << endl; + return -1; + } + fseek(fp, 0, SEEK_END); fsize = ftell(fp); fseek(fp, 0, SEEK_SET); + + data = new char[fsize]; + fread(data, 1, fsize, fp); + fclose(fp); + + png = NULL; baseType = NULL; + try + { + r_Minterval interv(1); + interv << r_Sinterval((r_Range)0, (r_Range)fsize-1); + + png = new r_Conv_PNG(data, interv, r_Convertor::ctype_char); + cout << "Converting file <" << pngfile << "> to MDD..." << endl; + desc = png->convertFrom(); + + cout << "Resulting domain " << desc.destInterv << ", "; + desc.destType->print_status(); + cout << endl; + + interv = r_Minterval(desc.destInterv); + + delete [] data; + data = desc.dest; + baseType = desc.destType; + delete png; + + fsize = (interv[0].high() - interv[0].low() + 1) * (interv[1].high() - interv[1].low() + 1); + + png = new r_Conv_PNG(data, interv, baseType); + cout << "Converting MDD back to PNG..." << endl; + desc = png->convertTo(); + + cout << "Resulting domain " << desc.destInterv << ", "; + desc.destType->print_status(); + cout << endl; + + fp = fopen("result.png", "wb"); + fwrite(desc.dest, 1, (desc.destInterv[0].high() - desc.destInterv[0].low() + 1), fp); + fclose(fp); + + delete baseType; + + free(data); + free(desc.dest); + delete desc.destType; + delete png; + } + catch (r_Error &err) + { + cerr << "Conversion failed: " << err.what() << endl; + if (baseType != NULL) delete baseType; + if (data != NULL) delete [] data; + if (png != NULL) delete png; + } + } + + return 0; +} diff --git a/conversion/test/test_vff.cc b/conversion/test/test_vff.cc new file mode 100644 index 0000000..e3d6016 --- /dev/null +++ b/conversion/test/test_vff.cc @@ -0,0 +1,169 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <iostream> + +#ifdef EARLY_TEMPLATE +#define __EXECUTABLE__ +#endif + +#include "conversion/vff.hh" +#include "raslib/rminit.hh" +#include "raslib/basetype.hh" + +#ifdef __GNUG__ +#include "rasodmg/transaction.hh" +#include "raslib/template_inst.hh" +#else +RMINITGLOBALS('C') +#endif + + + +static void PrintUsage(const char *name) +{ + cout << "Usage: " << name << " [-o <vffoutfile> -p <params> -h] <vffinfile>" << endl; +} + + +int main(int argc, char *argv[]) +{ + const char *infile=NULL; + const char *outfile=NULL; + const char *params=NULL; + int i; + + i=1; + while (i<argc) + { + if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'o': + outfile = argv[++i]; break; + case 'p': + params = argv[++i]; break; + case 'h': + PrintUsage(argv[0]); exit(0); + default: + cerr << "Unknown switch " << argv[i] << endl; + break; + } + } + else + { + if (infile != NULL) + cerr << "More than one input file, ignored" << endl; + else + infile = argv[i]; + } + i++; + } + + if (infile == NULL) + { + PrintUsage(argv[0]); + exit(-1); + } + + FILE *fp; + if ((fp = fopen(infile, "rb")) == NULL) + { + cerr << "Unable to open input file " << infile << endl; + return -1; + } + + size_t fsize; + char *data; + + fseek(fp, 0, SEEK_END); + fsize = ftell(fp); + + if ((data = new char[fsize]) == NULL) + { + cerr << "Unable to claim memory for file" << endl; + fclose(fp); + return -1; + } + fseek(fp, 0, SEEK_SET); + fread(data, 1, fsize, fp); + fclose(fp); + + r_Minterval interv(1); + interv << r_Sinterval((r_Range)0, (r_Range)fsize-1); + r_Conv_VFF conv(data, interv, r_Convertor::ctype_char); + r_convDesc desc; + + cout << "Convert from VFF... " << flush; + try + { + desc = conv.convertFrom(params); + cout << "OK" << endl; + + r_Conv_VFF convb(desc.dest, desc.destInterv, desc.destType); + r_convDesc descb; + + cout << "Convert back to VFF... " << flush; + try + { + descb = convb.convertTo(params); + cout << "OK" << endl; + + if (outfile != NULL) + { + if ((fp = fopen(outfile, "wb")) == NULL) + { + cerr << "Unable to write to file " << outfile << endl; + } + else + { + fsize = (size_t)(descb.destInterv[0].high() - descb.destInterv[0].low() + 1); + fwrite(descb.dest, 1, fsize, fp); + fclose(fp); + } + } + + // endianness-safe comparison of binary data: + // convert the just created VFF data back to an MDD and compare the + // result with the first MDD thus converted. + r_Conv_VFF convc(descb.dest, descb.destInterv, descb.destType); + r_convDesc descc; + + cout << "Compare binary data... " << flush; + try + { + descc = convc.convertFrom(params); + if (memcmp(descc.dest, desc.dest, desc.destInterv.cell_count() * ((r_Base_Type*)desc.destType)->size()) == 0) + cout << "identical" << endl; + else + cout << "differs!!!" << endl; + + delete descc.destType; + free(descc.dest); + } + catch (r_Error &err) + { + cerr << "failed: " << err.what() << endl; + } + + delete descb.destType; + free(descb.dest); + } + catch (r_Error &err) + { + cerr << "failed: " << err.what() << endl; + } + delete desc.destType; + free(desc.dest); + } + catch (r_Error &err) + { + cerr << "failed: " << err.what() << endl; + } + + delete [] data; + + return 0; +} diff --git a/conversion/text.cc b/conversion/text.cc new file mode 100644 index 0000000..82ec81b --- /dev/null +++ b/conversion/text.cc @@ -0,0 +1,138 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +*/ + +#include <iostream> +#include <fstream> + +#include "text.h" +#include "nitf.h" +#include "utilities.h" + +using namespace std; +using namespace RasNITF; + +RasNITF::text::text() +{ + m_text_data = NULL; + m_txshd = NULL; +} + +RasNITF::text::~text() +{ + if(m_text_data != NULL) + delete m_text_data; + m_text_data = NULL; + + if(m_txshd != NULL) + delete m_txshd; + m_txshd = NULL; + +} + +int RasNITF::text::read_file(istream &hNITF, long th_length, long text_length) +{ + int charsread = 0; + long starting_position = 0; + + header_length=th_length; + starting_position = hNITF.tellg(); + charsread += read_verify2(hNITF, m_te, 2 + 7 + 3 + 14 + 80 + 1 + 2 + 11 + 2 + 20 + 2 + 8+ 4+ 1+ 8+ 43 + 1 + 40 + 1 + 8+ 15+ 1+ 3); + + // read txshdl + + charsread += read_verify2(hNITF, m_txshdl, 5); + n_txshdl = charptrtolong(m_txshdl, 5); + + if (n_txshdl > 0) { + n_txshdl -= 3; + charsread += read_verify2(hNITF, m_txsofl, 3); + m_txshd = new char[n_txshdl]; + if(m_txshd == NULL) cerr<<"ERROR: could not allocate memory"; + charsread += read_verify2(hNITF, m_txshd, n_txshdl); + n_txshdl += 3; + + } + + // check if we are where we should be + if((long)(hNITF.tellg()) != starting_position + th_length) exit(2); + + // store the text data + + m_text_data = new char[text_length]; + if(m_text_data == NULL) cerr<<"ERROR: could not allocate memory"; + charsread += read_verify2(hNITF, m_text_data, text_length); + data_length = text_length; + + return charsread; +} + +int RasNITF::text::write_file(ofstream &fNITF) +{ + + fNITF.write(m_te, 2); + fNITF.write(m_textid, 7); + fNITF.write(m_txtalvl, 3); + fNITF.write(m_txtdt, 14); + fNITF.write(m_txtitl, 80); + fNITF.write(m_tsclas, 1); + fNITF.write(m_tsclsy, 2); + fNITF.write(m_tscode, 11); + fNITF.write(m_tsctlh, 2); + fNITF.write(m_tsrel, 20); + fNITF.write(m_tsdctp, 2); + fNITF.write(m_tsdcdt, 8); + fNITF.write(m_tsdcxm, 4); + fNITF.write(m_tsdg, 1); + fNITF.write(m_tsdgdt, 8); + fNITF.write(m_tscltx, 43); + fNITF.write(m_tscatp, 1); + fNITF.write(m_tscaut, 40); + fNITF.write(m_tscrsn, 1); + fNITF.write(m_tssrdt, 8); + fNITF.write(m_tsctln, 15); + fNITF.write(m_encryp, 1); + fNITF.write(m_txtfmt, 3); + + fNITF.write(m_txshdl, 5); + + if (n_txshdl > 0) { + fNITF.write(m_txsofl, 3); + fNITF.write(m_txshd, n_txshdl - 3); + } + + if( m_text_data != NULL) { + fNITF.write( m_text_data, data_length); + } + + //TODO: + return 0; + +} + +string RasNITF::text::get_lt() const { + return text_dl; +} + +string RasNITF::text::get_ltsh() const { + return text_hl; +} diff --git a/conversion/text.h b/conversion/text.h new file mode 100644 index 0000000..3746286 --- /dev/null +++ b/conversion/text.h @@ -0,0 +1,86 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +*/ + + +#ifndef __TEXT_H_INCLUDED +#define __TEXT_H_INCLUDED + +#include<vector> +#include <iostream> +#include <fstream> + +namespace RasNITF +{ +/* forward declarations follow : */ + +class nitf; + +class text +{ + private: + char m_te[2]; + char m_textid[7]; + char m_txtalvl[3]; + char m_txtdt[14]; + char m_txtitl[80]; + char m_tsclas[1]; + char m_tsclsy[2]; + char m_tscode[11]; + char m_tsctlh[2]; + char m_tsrel[20]; + char m_tsdctp[2]; + char m_tsdcdt[8]; + char m_tsdcxm[4]; + char m_tsdg[1]; + char m_tsdgdt[8]; + char m_tscltx[43]; + char m_tscatp[1]; + char m_tscaut[40]; + char m_tscrsn[1]; + char m_tssrdt[8]; + char m_tsctln[15]; + char m_encryp[1]; + char m_txtfmt[3]; + char m_txshdl[5]; + char m_txsofl[3]; + char* m_txshd; + char *m_text_data; + + int header_length; + int data_length; + int n_txshdl; + int n_txsofl; + + std::string text_hl ; + std::string text_dl ; + + public: + text(); + ~text(); //destructor freeing memory + int read_file(std::istream &,long,long); + int write_file(std::ofstream &); //writes the information to the data file + std::string get_lt() const; + std::string get_ltsh() const; +}; +} +#endif diff --git a/conversion/tiff.cc b/conversion/tiff.cc new file mode 100644 index 0000000..463f858 --- /dev/null +++ b/conversion/tiff.cc @@ -0,0 +1,653 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * SOURCE: tiff.cc + * + * MODULE: conversion + * + * CLASSES: r_Conv_TIFF + * + * COMMENTS: + * + * Provides functions to convert data to TIFF and back. + * +*/ + +#include <iostream> +#include <string.h> + +#ifdef AIX +#include <strings.h> +#endif + +#include "conversion/tiff.hh" +#include "conversion/memfs.hh" +#include "raslib/error.hh" +#include "raslib/rminit.hh" +#include "raslib/parseparams.hh" + +const int r_Conv_TIFF::defaultRPS = 32; + +const char r_Conv_TIFF::dummyFileFmt[] = "/tmp/%p.tif"; + +const struct r_Convertor::convert_string_s r_Conv_TIFF::compNames[] = { + {"none", COMPRESSION_NONE}, + {"ccittrle", COMPRESSION_CCITTRLE}, + {"ccittfax3", COMPRESSION_CCITTFAX3}, + {"ccittfax4", COMPRESSION_CCITTFAX4}, + {"lzw", COMPRESSION_LZW}, + {"ojpeg", COMPRESSION_OJPEG}, + {"jpeg", COMPRESSION_JPEG}, + {"next", COMPRESSION_NEXT}, + {"ccittrlew", COMPRESSION_CCITTRLEW}, + {"packbits", COMPRESSION_PACKBITS}, + {"thunderscan", COMPRESSION_THUNDERSCAN}, + {"pixarfilm", COMPRESSION_PIXARFILM}, + {"pixarlog", COMPRESSION_PIXARLOG}, + {"deflate", COMPRESSION_DEFLATE}, + {"dcs", COMPRESSION_DCS}, + {"jbig", COMPRESSION_JBIG}, +#ifndef LINUX + {"sgilog", COMPRESSION_SGILOG}, + {"sgilog24", COMPRESSION_SGILOG24}, + {"it8ctpad", COMPRESSION_IT8CTPAD}, + {"it8lw", COMPRESSION_IT8LW}, + {"it8mp", COMPRESSION_IT8MP}, + {"it8bl", COMPRESSION_IT8BL}, +#endif + {NULL, COMPRESSION_NONE} +}; + +const struct r_Convertor::convert_string_s r_Conv_TIFF::resunitNames[] = { + {"none", RESUNIT_NONE}, + {"inch", RESUNIT_INCH}, + {"centimeter", RESUNIT_CENTIMETER}, + {NULL, RESUNIT_NONE} +}; + +// Change these according to the platform! +// Fill order of bits in bitmap mode. Define 0 for LSB, otherwise MSB +#define _R_TIFF_BITFILLORDER 1 + + +// Setup internal macros according to the fill-order +#if (_R_TIFF_BITFILLORDER == 0) +#define _R_TIFF_MASK_VALUE 1 +#define _R_TIFF_MASK_SHIFT(x) (x) <<= 1; +#else +#define _R_TIFF_MASK_VALUE (1<<7) +#define _R_TIFF_MASK_SHIFT(x) (x) >>= 1; +#endif + + +// TIFF class functions + +// Translate string compression type to libtiff compression type +int r_Conv_TIFF::get_compression_from_name(const char* strComp) +{ + unsigned short i=0; + int tiffComp=COMPRESSION_NONE; + + if(strComp != NULL) + { + for (i=0; compNames[i].key != NULL; i++) + { + if (strcasecmp(compNames[i].key, strComp) == 0) + { + tiffComp = compNames[i].id; + break; + } + } + + if (compNames[i].key == NULL) + RMInit::logOut << "r_Conv_TIFF::get_compression_from_name(): unsupported compression type " << strComp << endl; + } + + return tiffComp; +} + +// Translate string resolution unit type to libtiff resolution unit type +int r_Conv_TIFF::get_resunit_from_name(const char* strResUnit) +{ + unsigned short i=0; + int tiffResUnit=RESUNIT_NONE; + + if(strResUnit != NULL) + { + for (i=0; resunitNames[i].key != NULL; i++) + { + if (strcasecmp(resunitNames[i].key, strResUnit) == 0) + { + tiffResUnit = resunitNames[i].id; + break; + } + } + + if (resunitNames[i].key == NULL) + RMInit::logOut << "r_Conv_TIFF::get_resunit_from_name(): unsupported resolution unit type " << strResUnit << endl; + } + + return tiffResUnit; +} + +void r_Conv_TIFF::initTIFF( void ) +{ + compType = NULL; + quality = 80; + override_bpp = 0; + override_bps = 0; + override_depth = 0; + + if (params == NULL) + params = new r_Parse_Params(); + + params->add("comptype", &compType, r_Parse_Params::param_type_string); + params->add("quality", &quality, r_Parse_Params::param_type_int); + params->add("bpp", &override_bpp, r_Parse_Params::param_type_int); + params->add("bps", &override_bps, r_Parse_Params::param_type_int); + params->add("depth", &override_depth, r_Parse_Params::param_type_int); +} + + +r_Conv_TIFF::r_Conv_TIFF(const char *src, const r_Minterval &interv, const r_Type *tp) throw(r_Error) +: r_Convert_Memory(src, interv, tp) +{ + initTIFF(); +} + + +r_Conv_TIFF::r_Conv_TIFF(const char *src, const r_Minterval &interv, int type) throw(r_Error) +: r_Convert_Memory(src, interv, type) +{ + initTIFF(); +} + + +r_Conv_TIFF::~r_Conv_TIFF(void) +{ + if (compType != NULL) + { + delete [] compType; + compType = NULL; + } +} + + +// Compression modes recommended: +// +// Bitmap, Greyscales: COMPRESSION_LZW, COMPRESSION_DEFLATE +// RGB: COMPRESSION_JPEG, COMPRESSION_SGILOG24 +r_convDesc &r_Conv_TIFF::convertTo( const char *options ) throw(r_Error) +{ + if (options != NULL) + printf("tiff convert option = %s\n", options); + else + printf("tiff options are null = %s\n"); + TIFF *tif=NULL; + char dummyFile[256]; + uint16 cmap[256]; // Colour map (for greyscale images) + uint32 pixelAdd=0, lineAdd=0; // number of _bytes_ to add to a pointer + // to the source data to get the address + // of the pixel to the right / downwards. + uint16 bps=0, bpp=0; + uint32 width=0, height=0, i=0; + int tiffcomp = COMPRESSION_NONE; + + params->process(options); + + // translate string compression type to libtiff compression type + if (compType != NULL) + tiffcomp=get_compression_from_name(compType); + + // Set dimensions + width = (uint32)(desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1); + height = (uint32)(desc.srcInterv[1].high() - desc.srcInterv[1].low() + 1); + + switch (desc.baseType) + { + // MDD arrays are transposed compared to the format needed for images. + // Therefore the pixelAdd and lineAdd values change places. + case ctype_bool: + bps = 1; bpp = 1; pixelAdd = height; lineAdd = 1; + break; + case ctype_char: + bps = 8; bpp = 8; pixelAdd = height; lineAdd = 1; + break; + case ctype_rgb: + bps = 8; bpp = 24; pixelAdd = 3*height; lineAdd = 3; + break; + default: RMInit::logOut << "r_Conv_TIFF::convertTo(): unknown base type!" << endl; + throw r_Error(BASETYPENOTSUPPORTEDBYOPERATION); + } + + // Just to make sure nothing serious goes wrong if this conversion + // function is called more than once. + memfs_newfile(handle); + + // Open a dummy output file (all operations will be redirected to + // Memory). Make dummy file unique for each object by using the + // address of its memFSContext (kind of a hack, I know...). That + // should ensure re-entrancy. + sprintf(dummyFile, dummyFileFmt, (void*)handle); + tif = TIFFClientOpen(dummyFile, "w", handle, + memfs_read, memfs_write, memfs_seek, memfs_close, memfs_size, + memfs_map, memfs_unmap); + + if (tif == NULL) + { + RMInit::logOut << "r_Conv_TIFF::convertTo(): couldn't open file " << dummyFile << endl; + throw r_Error(r_Error::r_Error_General); + } + + TIFFSetField(tif, TIFFTAG_ARTIST, "RasDaMan"); + TIFFSetField(tif, TIFFTAG_DOCUMENTNAME, "Image"); + TIFFSetField(tif, TIFFTAG_SOFTWARE, "RasDaMan"); + //TIFFSetField(tif, TIFFTAG_SUBFILETYPE, (uint32)0); + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps); + // UNIX doesn't mind which fill-order. NT only understands this one. + TIFFSetField(tif, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB); + TIFFSetField(tif, TIFFTAG_COMPRESSION, (uint16)tiffcomp); + TIFFSetField(tif, TIFFTAG_ORIENTATION, (uint16)ORIENTATION_TOPLEFT); + // Format-dependent tags + if (desc.baseType == ctype_rgb) + { + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, (uint16)PHOTOMETRIC_RGB); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (uint16)3); + } + else + { + if (desc.baseType == ctype_char) + { + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, (uint16)PHOTOMETRIC_PALETTE); + } + else + { + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, (uint16)PHOTOMETRIC_MINISBLACK); + } + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (uint16)1); + } + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, (uint16)PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, (uint32)-1)); + //TIFFSetField(tif, TIFFTAG_MINSAMPLEVALUE, (uint16)0); + //TIFFSetField(tif, TIFFTAG_MAXSAMPLEVALUE, (uint16)255); + TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, (uint16)RESUNIT_INCH); + TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)90.0); + TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)90.0); + TIFFSetField(tif, TIFFTAG_XPOSITION, (float)0.0); + TIFFSetField(tif, TIFFTAG_YPOSITION, (float)0.0); + if ((tiffcomp == COMPRESSION_JPEG) || (tiffcomp == COMPRESSION_OJPEG)) + { + if (quality == 100) + { + TIFFSetField(tif, TIFFTAG_JPEGPROC, JPEGPROC_LOSSLESS); + } + else + { + TIFFSetField(tif, TIFFTAG_JPEGQUALITY, quality); + } + } + + // build the colour-map (greyscale, i.e. all 3 components identical) + // TIFF needs 16 bit values for this (--> tools/tiffdither.c) + for (i=0; i<256; i++) cmap[i] = (uint16)(i*((1L << 16) - 1)/255); + TIFFSetField(tif, TIFFTAG_COLORMAP, cmap, cmap, cmap); + + // Be VERY, VERY careful about the order and the items you write + // out. TIFFWriteDirectory, e.g., has very ugly side-effects. + uint32 *tbuff=NULL; + const char *l=NULL, *line = desc.src; + uint8 *normal=NULL; // normalised source data + uint32 row=0; + + // cout << "r_Conv_TIFF: Main Loop:" << endl; + if ((tbuff = new uint32[((width * bpp + 31) >> 5)]) != NULL) + { + // now go line by line + for (row = 0; row < height; row++, line += lineAdd) + { + normal = (uint8 *)tbuff; l = line; + + // copy data in the correct format to the buffer + switch (desc.baseType) + { + case ctype_bool: + { + uint8 val = 0, mask = _R_TIFF_MASK_VALUE; + + // convert 8bpp bitmap to 1bpp bitmap + for (i=0; i < width; i++, l += pixelAdd) + { + // fill bits in lsb order + if (*l != 0) val |= mask; + _R_TIFF_MASK_SHIFT(mask); + if (mask == 0) {*normal++ = val; val = 0; mask = _R_TIFF_MASK_VALUE;} + } + if (mask != _R_TIFF_MASK_VALUE) *normal++ = val; + } + break; + case ctype_char: + { + // copy data (and transpose) + for (i=0; i < width; i++, l += pixelAdd) + { + *normal++ = *l; + } + } + break; + case ctype_rgb: + { + // copy data (and transpose) + for (i=0; i < width; i++, l += pixelAdd) + { + *normal++ = l[0]; *normal++ = l[1]; *normal++ = l[2]; + } + } + break; + } + if (TIFFWriteScanline(tif, (tdata_t)tbuff, row, 0) < 0) break; + } + + delete [] tbuff; tbuff = NULL; + } + + if (row < height) // error + { + RMInit::logOut << "r_Conv_TIFF::convertTo(): error writing data!" << endl; + TIFFClose(tif); remove(dummyFile); + throw r_Error(r_Error::r_Error_General); + } + + TIFFClose(tif); + // Now delete the dummy file + remove(dummyFile); + + r_Long tifSize = memfs_size(handle); + + // Allocate an array of just the right size and "load" object there + if ((desc.dest = (char*)mystore.storage_alloc(sizeof(char) * tifSize)) == NULL) + { + RMInit::logOut << "r_Conv_TIFF::convertTo(): out of memory" << endl; + throw r_Error(MEMMORYALLOCATIONERROR); + } + memfs_seek(handle, 0, SEEK_SET); + memfs_read(handle, desc.dest, tifSize); + + // Set up destination interval + desc.destInterv = r_Minterval(1); + desc.destInterv << r_Sinterval(r_Range(0), r_Range(tifSize - 1)); + + // define the base type as char for now + desc.destType = r_Type::get_any_type("char"); + + return desc; +} + + + +r_convDesc &r_Conv_TIFF::convertFrom(const char *options) throw(r_Error) +{ + if (options != NULL) + printf("tiff convert option = %s\n", options); + else + printf("tiff options are null = %s\n"); + params->process(options); + TIFF *tif=NULL; + char dummyFile[256]; + int isOK=0, typeSize=0; + uint16 bps=0, bpp=0, spp=0, planar=0, photometric=0; + uint32 width=0, height=0, pixelAdd=0, lineAdd=0, i=0; + uint16 *reds=NULL, *greens=NULL, *blues=NULL; + + // Init simple (chunky) memFS + memfs_chunk_initfs(handle, (char*)desc.src, (r_Long)(desc.srcInterv[0].high()-desc.srcInterv[0].low()+1)); + + desc.dest = NULL; + + // Create dummy file for use in the TIFF open function + sprintf(dummyFile, dummyFileFmt, (void*)handle); + fclose(fopen(dummyFile, "wb")); + //cout << "r_Conv_TIFF: Dummy created OK" << endl; + + // Open and force memory mapping mode + tif = TIFFClientOpen(dummyFile, "rM", handle, + memfs_chunk_read, memfs_chunk_read, memfs_chunk_seek, memfs_chunk_close, + memfs_chunk_size, memfs_chunk_map, memfs_chunk_unmap); + + if (tif == NULL) + { + RMInit::logOut << "r_Conv_TIFF::convertFrom(): unable to open file!" << endl; + throw r_Error(r_Error::r_Error_General); + } + //cout << "r_Conv_TIFF: Opened OK" << endl; + + //TIFFPrintDirectory(tif, stdout, 0); + + TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bps); + TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &spp); + bpp = spp * bps; + TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &planar); + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width); + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height); + TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric); + + // Filter out the kind of image we understand. + isOK = 1; + if ((bps != 1) && (bps != 8)) + { + RMInit::logOut << "r_Conv_TIFF::convertFrom(): bad number of bits per sample: " << bps << " (must be 1 or 8)" << endl; + if (override_bps) + bps = override_bps; + else + isOK = 0; + } + if ((bpp != 1) && (bpp != 8) && (bpp != 24)) + { + RMInit::logOut << "r_Conv_TIFF::convertFrom(): bad number of bits per pixel: " << bpp << " (must be 1, 8 or 24)" << endl; + if (override_bpp) + bpp = override_bpp; + else + isOK = 0; + } + if (planar != PLANARCONFIG_CONTIG) + { + RMInit::logOut << "r_Conv_TIFF::convertFrom(): can't handle bitplanes!" << endl; + isOK = 0; + } + + if (isOK) + { + //cout << "r_Conv_TIFF: Image OK: bps = " << bps << ", spp = " << spp << ", width = " << width << ", height = " << height << endl; + + if (bpp == 24) + { + pixelAdd = 3*height; lineAdd = 3; typeSize = 3; + desc.baseType = ctype_rgb; + } + else + { + if ((photometric == PHOTOMETRIC_PALETTE) && (override_depth != 1)) + { + TIFFGetField(tif, TIFFTAG_COLORMAP, &reds, &greens, &blues); + for (i=0; i<256; i++) + { + if ((reds[i] != greens[i]) || (greens[i] != blues[i])) break; + } + if (i < 256) + { + pixelAdd = 3*height; lineAdd = 3; typeSize = 3; + desc.baseType = ctype_rgb; + } + else + { + pixelAdd = height; lineAdd = 1; typeSize = 1; + desc.baseType = ctype_char; + } + if (override_depth) + { + switch (override_depth) + { + case 1: + pixelAdd = height; lineAdd = 1; typeSize = 1; + desc.baseType = ctype_bool; + break; + case 8: + pixelAdd = height; lineAdd = 1; typeSize = 1; + desc.baseType = ctype_char; + break; + case 24: + pixelAdd = 3*height; lineAdd = 3; typeSize = 3; + desc.baseType = ctype_rgb; + break; + } + } + } + else + { + pixelAdd = height; lineAdd = 1; typeSize = 1; + desc.baseType = (bpp == 1) ? ctype_bool : ctype_char; + } + } + + if ((desc.dest = (char*)mystore.storage_alloc(width*height*typeSize*sizeof(char))) == NULL) + { + RMInit::logOut << "r_Conv_TIFF::convertFrom(): out of memory error!" << endl; + } + else + { + //cout << "r_Conv_TIFF: baseType = " << desc.baseType << ", size = " << typeSize << ", pixelAdd = " << pixelAdd << ", lineAdd = " << lineAdd << endl; + + uint32 *tbuff=NULL; + char *l=NULL, *line = desc.dest; + uint8 *normal=NULL; + uint32 row = 0; + + if ((tbuff = new uint32[(width * bpp + 31) >> 5]) != NULL) + { + for (row = 0; row < height; row++, line += lineAdd) + { + if (TIFFReadScanline(tif, (tdata_t)tbuff, row, 0) < 0) break; + + normal = (uint8 *)tbuff; l = line; + + switch (desc.baseType) + { + case ctype_bool: + { + uint8 mask = _R_TIFF_MASK_VALUE; + + for (i=0; i < width; i++, l += pixelAdd) + { + *l = (((*normal) & mask) == 0) ? 0 : 1; + _R_TIFF_MASK_SHIFT(mask); + if (mask == 0) {normal++; mask = _R_TIFF_MASK_VALUE;} + } + } + break; + case ctype_char: + { + if (reds != NULL) + { + for (i=0; i < width; i++, l += pixelAdd) + { + *l = (reds[*normal++]) >> 8; + } + } + else + { + for (i=0; i < width; i++, l += pixelAdd) + { + *l = *normal++; + } + } + } + break; + case ctype_rgb: + { + if (reds != NULL) + { + for (i=0; i < width; i++, l += pixelAdd) + { + uint8 val = *normal++; + + l[0] = (reds[val]) >> 8; + l[1] = (greens[val]) >> 8; + l[2] = (blues[val]) >> 8; + } + } + else + { + for (i=0; i < width; i++, l += pixelAdd) + { + l[0] = *normal++; l[1] = *normal++; l[2] = *normal++; + } + } + } + break; + } + } + delete [] tbuff; tbuff = NULL; + } + + if (row < height) + { + RMInit::logOut << "r_Conv_TIFF::convertFrom(): error reading data!" << endl; + TIFFClose(tif); remove(dummyFile); + throw r_Error(r_Error::r_Error_General); + } + } + } + + TIFFClose(tif); + + remove(dummyFile); + + // Build destination interval + desc.destInterv = r_Minterval(2); + desc.destInterv << r_Sinterval(r_Range(0), r_Range(width - 1)) + << r_Sinterval( r_Range(0), r_Range(height - 1)); + + desc.destType = get_external_type(desc.baseType); + + return desc; +} + + + +const char *r_Conv_TIFF::get_name( void ) const +{ + return format_name_tiff; +} + + +r_Data_Format r_Conv_TIFF::get_data_format( void ) const +{ + return r_TIFF; +} + + +r_Convertor *r_Conv_TIFF::clone( void ) const +{ + return new r_Conv_TIFF(desc.src, desc.srcInterv, desc.baseType); +} diff --git a/conversion/tiff.hh b/conversion/tiff.hh new file mode 100644 index 0000000..008f1c5 --- /dev/null +++ b/conversion/tiff.hh @@ -0,0 +1,145 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * INCLUDE: tiff.hh + * + * MODULE: conversion + * + * PURPOSE: + * Provides interface to convert data between TIFF and internal format. + * The convertFrom() and convertTo() methods accept a null-terminated + * option string of the following syntax: + * optionString ::= ( option )* + * option ::= "comptype=" string + * "quality=" int + * "bpp=" int + * "bps=" int + * "depth=" int + * + * CLASSES: r_Conv_TIFF + * + * COMMENTS: + * +*/ + +#ifndef _R_CONV_TIFF_HH_ +#define _R_CONV_TIFF_HH_ + +#include "conversion/convertor.hh" + + + +//@ManMemo: Module {\bf conversion} + +/*@Doc: + TIFF convertor class. + + Supported parameters are + + \begin{tabular}{lcl} + {\tt comptype} && string && compression type (see below)\\ + {\tt quality} && int && quality parameter (JPEG)\\ + {\tt bpp} && int && override number of bits per p (if not set in the tiff)\\ + {\tt bps} && int && override number of bits per s (if not set in the tiff)\\ + {\tt depth} && int && override number of colors in the mdd\\ + \end{tabular} + + The compression type defaults to lzw, but it may be one of the + following (but not all types may be supported by the version of + the TIFF library; note also that some compression types are only + valid for specific colour depths): + + \begin{tabular}{ll} + {\tt none}\\ + {\tt ccittrle}\\ + {\tt ccittfax3}\\ + {\tt ccittfax4}\\ + {\tt lzw}\\ + {\tt ojpeg}\\ + {\tt jpeg}\\ + {\tt next}\\ + {\tt ccittrlew}\\ + {\tt packbits}\\ + {\tt thunderscan}\\ + {\tt pixarfilm}\\ + {\tt pixarlog}\\ + {\tt deflate}\\ + {\tt dcs}\\ + {\tt jbig}\\ + {\tt sgilog} && Not Linux\\ + {\tt sgilog24} && Not Linux\\ + {\tt it8ctpad} && Not Linux\\ + {\tt it8lw} && Not Linux\\ + {\tt it8mp} && Not Linux\\ + {\tt it8bl} && Not Linux\\ + \end{tabular} + + For more information refer to the TIFFlib manual pages. + */ + +class r_Conv_TIFF : public r_Convert_Memory +{ + public: + /// constructor using an r_Type object + r_Conv_TIFF( const char *src, const r_Minterval &interv, const r_Type *tp ) throw(r_Error); + /// constructor using convert_type_e shortcut + r_Conv_TIFF( const char *src, const r_Minterval &interv, int type ) throw(r_Error); + /// destructor + ~r_Conv_TIFF( void ); + + /// convert to TIFF + virtual r_convDesc &convertTo( const char *options=NULL) throw(r_Error); + /// convert from TIFF + virtual r_convDesc &convertFrom( const char *options=NULL ) throw(r_Error); + /// cloning + virtual r_Convertor *clone( void ) const; + /// identification + virtual const char *get_name( void ) const; + virtual r_Data_Format get_data_format( void ) const; + + /// translate string compression type to libtiff compression type + static int get_compression_from_name(const char* strComp); + + /// translate string resolution unit type to libtiff resolution unit type + static int get_resunit_from_name(const char* strComp); + + private: + /// init TIFF class + void initTIFF( void ); + /// parameters + char *compType; + int quality; + int override_bpp; + int override_bps; + int override_depth; + /// connection between string compression type and libtiff compression type + static const convert_string_t compNames[]; + /// connection between string resolution unit type and libtiff resolution unit type + static const convert_string_t resunitNames[]; + /// default rows per strip (32) + static const int defaultRPS; + /// temporary dummy file + static const char dummyFileFmt[]; +}; + +#endif diff --git a/conversion/tor.cc b/conversion/tor.cc new file mode 100644 index 0000000..0663fd4 --- /dev/null +++ b/conversion/tor.cc @@ -0,0 +1,230 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +*/ + +#include "conversion/tor.hh" +#include "raslib/endian.hh" +#include "raslib/rminit.hh" +#include "raslib/parseparams.hh" +#include "raslib/primitivetype.hh" + +void r_Conv_TOR::initTOR() +{ + if(params ==NULL) + { + params = new r_Parse_Params(3); + } +} + +r_Conv_TOR::r_Conv_TOR(const char* source, const r_Minterval& lengthordomain, const r_Type* tp) throw(r_Error) + : r_Convertor(source, lengthordomain, tp, true) + { + initTOR(); + } + +r_Conv_TOR::r_Conv_TOR(const char* source, const r_Minterval& lengthordomain, int tp) throw(r_Error) + : r_Convertor(source, lengthordomain, tp) + { + initTOR(); + } + +r_convDesc& +r_Conv_TOR::convertFrom(const char* options) throw (r_Error) + { + int swap = 0; + int rescale = 0; + char* domain = NULL; + params->add("swapendianness", &swap, r_Parse_Params::param_type_int); + params->add("rescale", &rescale, r_Parse_Params::param_type_int); + params->add("domain", &domain, r_Parse_Params::param_type_string); + params->process(options); + r_Minterval t; + RMInit::logOut << "r_Conv_TOR::convert swap " << swap << " rescale " << rescale << " domain " << (domain?domain:"NULL") << std::endl; + if (domain == NULL) + { + RMInit::logOut << "r_Conv_TOR::convertFrom no domain specified in options string" << std::endl; + throw r_Error(); + } + try { + t = r_Minterval(domain); + } + catch (r_Eno_interval& e) + { + RMInit::logOut << "r_Conv_TOR::convertFrom no correct domain specified in options string" << std::endl; + throw r_Error(); + } + if (t.dimension() != 2) + { + RMInit::logOut << "r_Conv_TOR::convertFrom domain in options string must have 2 dimensions" << std::endl; + throw r_Error(); + } + r_Range x = t[0].high() - t[0].low() + 1; + r_Range y = t[1].high() - t[1].low() + 1; + r_UShort* array = (r_UShort*)mystore.storage_alloc(x * y * sizeof(r_UShort)); + double max = 0; + double min = 0; + r_Char tc; + double maxu = 0; + double minu = 0; + r_UShort tu; + switch (desc.baseType) + { + case ctype_bool: + case ctype_char: + case ctype_uint8: + if (desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1 != t.cell_count() * sizeof(r_Char)) + { + RMInit::logOut << "r_Conv_TOR::convertFrom the supplied data is " << desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1 << " bytes, but " << t.cell_count() << " bytes were expected" << std::endl; + throw r_Error(); + } + get_limits(&tc, min, max); + get_limits(&tu, minu, maxu); + for(int i=0; i < x; i++) + { + for(int j=0; j < y; j++) + { + if (rescale) + array[i * x + j] = ((r_Octet*)desc.src)[j * x + i] / max * maxu; + else + array[i * x + j] = ((r_Octet*)desc.src)[j * x + i]; + } + } + break; + case ctype_uint16: + if (desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1 != t.cell_count() * sizeof(r_UShort)) + { + RMInit::logOut << "r_Conv_TOR::convertFrom the supplied data is " << desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1 << " bytes, but " << t.cell_count() << " bytes were expected" << std::endl; + throw r_Error(); + } + for(int i=0; i < x; i++) + { + for(int j=0; j < y; j++) + { + array[i * x + j] = ((r_UShort*)desc.src)[j * x + i]; + } + } + break; + default: + RMInit::logOut << "r_Conv_TOR unknown base type!" << std::endl; + throw r_Error(); + } + if (swap) + { + r_UShort* temp = (r_UShort*)mystore.storage_alloc(x * y * sizeof(r_UShort)); + r_Endian::swap_array(x * y * sizeof(r_UShort), array, temp); + mystore.storage_free(array); + array = temp; + } + + desc.dest = (char*)array; + desc.destInterv = t; + desc.destType = new r_Primitive_Type("UShort", r_Type::USHORT); + return desc; + } + +r_convDesc& +r_Conv_TOR::convertTo(const char* options) throw (r_Error) + { + int swap = 0; + int rescale = 0; + params->add("swapendianness", &swap, r_Parse_Params::param_type_int); + params->add("rescale", &rescale, r_Parse_Params::param_type_int); + params->process(options); + if (desc.srcInterv.dimension() != 2) + { + RMInit::logOut << "r_Conv_TOR::convertFrom domain in options string must have 2 dimensions" << std::endl; + throw r_Error(); + } + r_Range x = desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1; + r_Range y = desc.srcInterv[1].high() - desc.srcInterv[1].low() + 1; + r_UShort* array = (r_UShort*)mystore.storage_alloc(x * y * sizeof(r_UShort)); + double max = 0; + double min = 0; + r_Char tc; + double maxu = 0; + double minu = 0; + r_UShort tu; + switch (desc.baseType) + { + case ctype_bool: + case ctype_char: + case ctype_uint8: + get_limits(&tc, min, max); + get_limits(&tu, minu, maxu); + for(int i=0; i < x; i++) + { + for(int j=0; j < y; j++) + { + if (rescale) + array[i * x + j] = ((r_Octet*)desc.src)[j * x + i] / max * maxu; + else + array[i * x + j] = ((r_Octet*)desc.src)[j * x + i]; + } + } + break; + case ctype_uint16: + for(int i=0; i < x; i++) + { + for(int j=0; j < y; j++) + { + array[i * x + j] = ((r_UShort*)desc.src)[j * x + i]; + } + } + break; + default: + RMInit::logOut << "r_Conv_TOR unknown base type!" << std::endl; + throw r_Error(); + } + if (swap) + { + r_UShort* temp =(r_UShort*)mystore.storage_alloc(x * y * sizeof(r_UShort)); + r_Endian::swap_array(x * y * sizeof(r_UShort), array, temp); + mystore.storage_free(array); + array = temp; + } + + desc.dest = (char*)array; + r_Minterval td(1); + td << r_Sinterval((r_Range)0, (r_Range)(desc.srcInterv.cell_count() * sizeof(r_UShort) - 1)); + desc.destInterv = td; + desc.destType = new r_Primitive_Type("Char", r_Type::CHAR); + return desc; + } + +const char* +r_Conv_TOR::get_name() const + { + return get_name_from_data_format(r_TOR); + } + +r_Data_Format +r_Conv_TOR::get_data_format() const + { + return r_TOR; + } + +r_Convertor* +r_Conv_TOR::clone() const + { + return new r_Conv_TOR(desc.src, desc.srcInterv, desc.srcType); + } + diff --git a/conversion/tor.hh b/conversion/tor.hh new file mode 100644 index 0000000..d7bd189 --- /dev/null +++ b/conversion/tor.hh @@ -0,0 +1,82 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * INCLUDE: tor.hh + * + * MODULE: conversion + * + * CLASSES: r_Conv_TOR + * + * COMMENTS: + * + * Provides interface to convert data from/to TOR to/from r_Array + * +*/ + +#ifndef _R_CONV_TOR_HH_ +#define _R_CONV_TOR_HH_ +#include "conversion/convertor.hh" + +//@ManMemo: Module {\bf conversion} + +/*@Doc: + TOR convertor class. + + Supported parameters are + + \begin{tabular}{lcl} + {\tt swapendianness} && int && flag for swapendianness, default 0\\ + {\tt rescale} && int && flag for rescale, default 0\\ + {\tt domain} && string && domain string of TOR file\\ + \end{tabular} + + The "swapendianness" parameter is a flag for endianness change operation. + The "rescale" parameter is a flag for rescale operation. +*/ + + +class r_Conv_TOR : public r_Convertor + { + public: + r_Conv_TOR(const char* source, const r_Minterval& lengthordomain, const r_Type* tp) throw(r_Error); + + r_Conv_TOR(const char* source, const r_Minterval& lengthordomain, int tp) throw(r_Error); + + r_convDesc& convertFrom(const char* options = NULL) throw (r_Error); + + r_convDesc& convertTo(const char* options = NULL) throw (r_Error); + + const char* get_name() const; + + r_Data_Format get_data_format() const; + + r_Convertor* clone() const; + + + private: + void initTOR(); + + }; + +#endif + diff --git a/conversion/utilities.cc b/conversion/utilities.cc new file mode 100644 index 0000000..7b8df84 --- /dev/null +++ b/conversion/utilities.cc @@ -0,0 +1,109 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +*/ + +#include <cstdio> +#include <cstring> +#include <cstdlib> +#include <sys/types.h> +#include <unistd.h> +#include <iostream> +#include <fstream> +#include <string> + +#include "utilities.h" + +using namespace std; +using namespace RasNITF; + +long RasNITF::read_verify(std::istream &fNITF, char *destination, long length, char *sErrorMessage, bool nullify) + +{ + long rc; + + fNITF.read(destination, length); + rc = fNITF.gcount(); + + if (!fNITF.good()){ + cout<<sErrorMessage<<endl; + exit(1); + } + + if (rc != length) { + cout<<sErrorMessage<<endl; + exit(1); + } + + if (nullify) + destination[length] = '\0'; + + return rc; +} + +long RasNITF::read_verify2(std::istream &fNITF, char *destination, long length) + +{ + long rc; + + fNITF.read(destination, length); + rc = fNITF.gcount(); + + if (!fNITF.good()){ + exit(3); + } + + if (rc != length) { + exit(4); + } + + return rc; +} + + +int RasNITF::charptrtoint(const char *str, int length){ + + int num; + string temp; + + if (length > 5) { + + cout << "WARNING LOSING DATA from long to int conversion" << endl; + + } + + + temp.assign(str, length); + num = atoi(temp.c_str()); + + return num; +} + +long RasNITF::charptrtolong(const char *str, int length){ + + long num; + string temp; + + temp.assign(str, length); + num = atol(temp.c_str()); + + return num; +} diff --git a/conversion/utilities.h b/conversion/utilities.h new file mode 100644 index 0000000..3b74a38 --- /dev/null +++ b/conversion/utilities.h @@ -0,0 +1,35 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +*/ + +#ifndef __UTILITIES_H_INCLUDED +#define __UTILITIES_H_INCLUDED + +namespace RasNITF { + + long read_verify(std::istream &fNITF, char *destination, long length, char *sErrorMessage, bool nullify); + long read_verify2(std::istream &fNITF, char *destination, long length); + int charptrtoint(const char *str, int length); + long charptrtolong(const char *str, int length); + +} +#endif diff --git a/conversion/vff.cc b/conversion/vff.cc new file mode 100644 index 0000000..25b58f7 --- /dev/null +++ b/conversion/vff.cc @@ -0,0 +1,797 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * FILE: vff.cc + * + * MODULE: conversion + * + * CLASSES: r_Conv_VFF + * + * COMMENTS: + * + * Provides interface to convert data to VFF and back. + * +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include <iostream> +#include <strstream> + +#include "raslib/rminit.hh" +#include "raslib/endian.hh" +#include "raslib/miterd.hh" +#include "raslib/odmgtypes.hh" +#include "raslib/parseparams.hh" +#include "conversion/vff.hh" + + +// file magic +const char *r_Conv_VFF::fileMagic = "ncaa"; + +// keyword enumerators, must be kept in sync with keywords +enum vff_keyword_e { + vffkey_rank = 0, + vffkey_type, + vffkey_format, + vffkey_size, + vffkey_origin, + vffkey_extent, + vffkey_aspect, + vffkey_bands, + vffkey_bits, + vffkey_value, + vffkey_endian, + vffkey_dorder, + vffkey_NUMBER +}; + +// Keywords +const char *r_Conv_VFF::keywords[] = { + // mandatory + "rank", + "type", + "format", + "size", + "origin", + "extent", + "aspect", + "bands", + "bits", + // optional + "value", + "endianness", + "data_order" +}; + +// values +const char *r_Conv_VFF::kval_Raster = "raster"; +const char *r_Conv_VFF::kval_Slice = "slice"; +const char *r_Conv_VFF::kval_LEndian = "little_endian"; +const char *r_Conv_VFF::kval_BEndian = "big_endian"; + +// default data order +const char *r_Conv_VFF::dfltDataOrder2 = "xy"; +const char *r_Conv_VFF::dfltDataOrder3 = "yzx"; + +// default dimension order +const char *r_Conv_VFF::dfltDimOrder2 = "xy"; +const char *r_Conv_VFF::dfltDimOrder3 = "yzx"; + +// end of header +const char r_Conv_VFF::endOfHeader = 0x0c; + +// method names +const char *r_Conv_VFF::method_convTo = "r_Conv_VFF::convertTo()"; +const char *r_Conv_VFF::method_convFrom = "r_Conv_VFF::convertFrom()"; + + +r_Conv_VFF::r_Conv_VFF( const char *src, const r_Minterval &interv, int tp ) throw(r_Error) +: r_Convertor(src, interv, tp) +{ + initVFF(); +} + + +r_Conv_VFF::r_Conv_VFF( const char *src, const r_Minterval &interv, const r_Type *tp ) throw(r_Error) +: r_Convertor(src, interv, tp, true) +{ + initVFF(); +} + + +r_Conv_VFF::~r_Conv_VFF( void ) +{ + if (dorderParam != NULL) + delete [] dorderParam; + if (dimOrderParam != NULL) + delete [] dimOrderParam; +} + + +void r_Conv_VFF::initVFF( void ) +{ + dorderParam = NULL; + dimOrderParam = NULL; + dfltEndianness = 0; // big endian + + if (params == NULL) + params = new r_Parse_Params; + + params->add("dorder", &dorderParam, r_Parse_Params::param_type_string); + params->add("dimorder", &dimOrderParam, r_Parse_Params::param_type_string); + params->add("vffendian", &dfltEndianness, r_Parse_Params::param_type_int); +} + + +void r_Conv_VFF::skip_white( const char *&str ) +{ + while ((*str != endOfHeader) && (isspace((unsigned int)(*str)))) str++; +} + +void r_Conv_VFF::write_interval( const char *keyname, std::ostream &str, const r_Minterval &iv, const unsigned int *order, r_Range inc ) +{ + r_Dimension i; + str << keyname << '=' << (iv[order[0]].high() - iv[order[0]].low() + inc); + for (i=1; i<iv.dimension(); i++) + str << ' ' << (iv[order[i]].high() - iv[order[i]].low() + inc); + str << ";\n"; +} + +void r_Conv_VFF::write_origin( const char *keyname, std::ostream &str, const r_Minterval &iv, const unsigned int *order ) +{ + r_Dimension i; + str << keyname << '=' << iv[order[0]].low(); + for (i=1; i<iv.dimension(); i++) + str << ' ' << iv[order[i]].low(); + str << ";\n"; +} + +const char *r_Conv_VFF::read_vector( r_Dimension dim, const char *str, double *&vec ) +{ + if (dim == 0) + return NULL; + + vec = new double[dim]; + r_Dimension i; + + for (i=0; i<dim; i++) + { + const char *rest; + vec[i] = strtod(str, (char**)&rest); + if (str == rest) + break; + str = rest; + } + if (i < dim) + { + delete [] vec; + vec = NULL; + return NULL; + } + return str; +} + +const char *r_Conv_VFF::read_string( const char *str, char *dest, bool allowSpace ) +{ + const char *d = str; + char *b = dest; + + while (*d != ';') + { + if ((allowSpace == 1) && (isspace((unsigned int)(*d)))) + break; + *b++ = *d++; + } + *b++ = '\0'; + return d; +} + +const char *r_Conv_VFF::get_endian_id( void ) +{ + return ((r_Endian::get_endianness() == r_Endian::r_Endian_Big) ? kval_BEndian : kval_LEndian); +} + + +const char *r_Conv_VFF::get_default_order( r_Dimension dim ) +{ + return (dim == 2) ? dfltDataOrder2 : dfltDataOrder3; +} + + +const char *r_Conv_VFF::get_default_dim_order( r_Dimension dim ) +{ + return (dim == 2) ? dfltDimOrder2 : dfltDimOrder3; +} + + +int r_Conv_VFF::parse_data_order( r_Dimension dim, const char *dstr, unsigned int *order ) +{ + unsigned char *mapped = new unsigned char[dim]; + unsigned int i; + + memset(mapped, 0, dim); + for (i=0; i<dim; i++) + { + unsigned int map; + + switch (dstr[i]) + { + case 'x': + map = 1; break; + case 'y': + map = 2; break; + case 'z': + map = 3; break; + default: + map = 0; break; + } + + if ((map == 0) || (mapped[map-1] != 0)) + break; + + order[i] = map-1; + mapped[map-1] = 1; + //cout << order[i] << endl; + } + + delete [] mapped; + + if (i < dim) + { + RMInit::logOut << "r_Conv_VFF::parse_data_order(): descriptor " << dstr + << " inconsistent, revert to defaults" << endl; + + return parse_data_order(dim, get_default_order(dim), order); + } + + return 0; +} + + +unsigned int *r_Conv_VFF::get_dimension_order( r_Dimension dim ) const +{ + unsigned int *order = new unsigned int[dim]; + char dimOrder[8]; + + // Anders Ledberg: Karolinska reader _always_ uses yzx as dimension order + if (dimOrderParam == NULL) + strncpy(dimOrder, get_default_dim_order(dim), 8); + else + strncpy(dimOrder, dimOrderParam, 8); + + dimOrder[7] = '\0'; + parse_data_order(dim, dimOrder, order); + + return order; +} + + +const char *r_Conv_VFF::get_default_endianness( void ) const +{ + return (dfltEndianness == 0) ? kval_BEndian : kval_LEndian; +} + + +r_convDesc &r_Conv_VFF::convertTo( const char *options ) throw(r_Error) +{ + r_Dimension dim; + int bits, typeSize; + char header[1024]; // and ``640k should be enough for everyone''... + char dataOrder[8]; + + dim = desc.srcInterv.dimension(); + if ((dim < 2) || (dim > 3)) + { + r_Error err(r_Error::r_Error_General); + throw(err); + } + + switch (desc.baseType) + { + case ctype_bool: + case ctype_char: + case ctype_int8: + case ctype_uint8: + bits = 8; typeSize = 1; break; + case ctype_int16: + case ctype_uint16: + bits = 16; typeSize = 2; break; + case ctype_int32: + case ctype_uint32: + bits = 32; typeSize = 4; break; + default: + r_Error err(r_Error::r_Error_General); + throw(err); + break; + } + //cout << "TYPE " << desc.baseType << ", SIZE " << typeSize << endl; + + if (options != NULL) + params->process(options); + + if (dorderParam != NULL) + strcpy(dataOrder, dorderParam); + else + strcpy(dataOrder, get_default_order(dim)); + + std::ostrstream memstr(header, 1024); + + // order of dimensions in vectors + unsigned int *dimOrder = get_dimension_order(dim); + + // write header + memstr << fileMagic << '\n'; + memstr << keywords[vffkey_rank] << '=' << dim << ";\n"; + memstr << keywords[vffkey_type] << '=' << kval_Raster << ";\n"; + memstr << keywords[vffkey_format] << '=' << kval_Slice << ";\n"; + // the dimensions are still ordered like in the VFF file, only the internal + // linearization differs! + write_interval(keywords[vffkey_size], memstr, desc.srcInterv, dimOrder, 1); + write_origin(keywords[vffkey_origin], memstr, desc.srcInterv, dimOrder); + write_interval(keywords[vffkey_extent], memstr, desc.srcInterv, dimOrder); + if (dim == 2) + { + // FIXME, aspect should be modelled too + memstr << keywords[vffkey_aspect] << "=1.0 1.0;\n"; + } + else + { + // FIXME, ditto + memstr << keywords[vffkey_aspect] << "=1.0 1.0 1.0;\n"; + } + + // only suypport one band ATM + memstr << keywords[vffkey_bands] << "=1;\n"; + memstr << keywords[vffkey_bits] << '=' << bits << ";\n"; + memstr << keywords[vffkey_endian] << '=' << get_endian_id() << ";\n"; + memstr << keywords[vffkey_dorder] << '=' << dataOrder << ";\n"; + memstr << '\n' << endOfHeader << '\n' << '\0'; + + unsigned long headerSize, dataSize, totalSize; + + headerSize = strlen(header); + dataSize = desc.srcInterv.cell_count() * typeSize; + totalSize = headerSize + dataSize; + + if ((desc.dest = (char*)mystore.storage_alloc(headerSize + dataSize)) == NULL) + { + r_Error err(r_Error::r_Error_General); + throw(err); + } + memcpy(desc.dest, header, headerSize); + + // treat all dimensions alike thanks to generic iterators + + // source iterator, iterate in user order + r_MiterDirect iter((void*)desc.src, desc.srcInterv, desc.srcInterv, typeSize, 1); + unsigned int *order, *steps; + + order = new unsigned int[dim]; + steps = new unsigned int[dim]; + + for (unsigned int i=0; i<dim; i++) + steps[i] = 1; + + parse_data_order(dim, dataOrder, order); + + // note: dest may not be aligned to a position conforming to its base type, + // so copy byte-wise. + unsigned char *dptr = (unsigned char*)(desc.dest + headerSize); + switch (typeSize) + { + case 1: + { + while (iter.isDone() == 0) + { + *dptr = *((const unsigned char*)iter.getData(order)); + iter.iterateUserOrder(order, steps); + dptr++; + } + } + break; + case 2: + { + while (iter.isDone() == 0) + { + const unsigned char *sptr = (const unsigned char*)iter.getData(order); + dptr[0] = sptr[0]; + dptr[1] = sptr[1]; + //cout << iter << ':' << (long)((const char*)sptr-desc.src) << ':' << (unsigned short)((sptr[0] << 8) | (sptr[1])) << ' '; + iter.iterateUserOrder(order, steps); + dptr+=2; + } + } + break; + case 4: + { + while (iter.isDone() == 0) + { + const unsigned char *sptr = (const unsigned char*)iter.getData(order); + dptr[0] = sptr[0]; + dptr[1] = sptr[1]; + dptr[2] = sptr[2]; + dptr[3] = sptr[3]; + iter.iterateUserOrder(order, steps); + dptr+=4; + } + } + break; + default: + break; + } + + delete [] steps; + delete [] order; + delete [] dimOrder; + + desc.destInterv = r_Minterval(1); + desc.destInterv << r_Sinterval((r_Range)0, (r_Range)totalSize-1); + desc.destType = r_Type::get_any_type("char"); + + return desc; +} + + +r_convDesc &r_Conv_VFF::convertFrom( const char *options ) throw(r_Error) +{ + const char *header = desc.src; + unsigned char *keysRead; + unsigned int i; + r_Dimension dim=0; + int bits, bands; + double *vecSize, *vecOrigin, *vecValue; + char endian[32]; + char dataOrder[8]; + + if (strncmp(header, fileMagic, strlen(fileMagic)) != 0) + { + r_Error err(r_Error::r_Error_General); + throw(err); + } + + keysRead = new unsigned char[vffkey_NUMBER]; + memset(keysRead, 0, vffkey_NUMBER); + + header += strlen(fileMagic); + skip_white(header); + + vecSize = NULL; + vecOrigin = NULL; + vecValue = NULL; + + strcpy(endian, get_default_endianness()); + + if (options != NULL) + params->process(options); + + // no order -- check later if one was defined and init it _after_ we know the rank + dataOrder[0] = '\0'; + + do + { + if (*header != endOfHeader); + { + const char *rest; + double *vecTemp; + + for (i=0; i<(unsigned int)vffkey_NUMBER; i++) + { + if (strncmp(header, keywords[i], strlen(keywords[i])) == 0) + break; + } + + if (i == vffkey_NUMBER) + { + // skip unknown keywords + while ((*header != ';') && (*header != endOfHeader)) + header++; + if (*header == ';') + header++; + } + else + { + //cout << "KEY " << keywords[i] << endl; + + keysRead[i] = 1; + + header += strlen(keywords[i]); + skip_white(header); + + if (*header != '=') + break; + + header++; + skip_white(header); + + rest = header; + switch ((vff_keyword_e)i) + { + case vffkey_rank: + dim = strtol(header, (char**)&rest, 10); + if ((rest == header) || (dim < 2) || (dim > 3)) + { + RMInit::logOut << method_convFrom << ": bad rank " << dim << endl; + rest = NULL; + } + break; + case vffkey_type: + if (strncmp(header, kval_Raster, strlen(kval_Raster)) == 0) + rest = header + strlen(kval_Raster); + else + { + RMInit::logOut << method_convFrom << ": bad type" << endl; + rest = NULL; + } + break; + case vffkey_format: + if (strncmp(header, kval_Slice, strlen(kval_Slice)) == 0) + rest = header + strlen(kval_Slice); + else + { + RMInit::logOut << method_convFrom << ": bad format" << endl; + rest = NULL; + } + break; + case vffkey_size: + rest = read_vector(dim, header, vecSize); + break; + case vffkey_origin: + rest = read_vector(dim, header, vecOrigin); + break; + case vffkey_extent: + // extent just parsed, otherwise ignored + rest = read_vector(dim, header, vecTemp); + delete [] vecTemp; + break; + case vffkey_aspect: + // FIXME: aspect ignored + rest = read_vector(dim, header, vecTemp); + delete [] vecTemp; + break; + case vffkey_bands: + bands = strtol(header, (char**)&rest, 10); + if ((rest == header) || (bands != 1)) + { + RMInit::logOut << method_convFrom << ": bad number of bands " << bands << endl; + rest = NULL; + } + break; + case vffkey_bits: + bits = strtol(header, (char**)&rest, 10); + if ((rest == header) || ((bits != 8) && (bits != 16) && (bits != 32))) + { + RMInit::logOut << method_convFrom << ": bad number of bits " << bits << endl; + rest = NULL; + } + break; + case vffkey_value: + // FIXME: values ignored + rest = read_vector(2, header, vecValue); + break; + case vffkey_endian: + rest = read_string(header, endian); + break; + case vffkey_dorder: + rest = read_string(header, dataOrder); + break; + default: + break; + } + if (rest == NULL) + break; + + header = rest; + skip_white(header); + if (*header == ';') + header++; + } + } + skip_white(header); + } + while (*header != endOfHeader); + + // was there a data order? no ==> init either used-defined or default + if (dataOrder[0] == '\0') + { + if (dorderParam != NULL) + strcpy(dataOrder, dorderParam); + else + strcpy(dataOrder, get_default_order(dim)); + } + + //cout << "RANK " << dim << ", BANDS " << bands << ", BITS " << bits << endl; + + // check whether all mandatory keywords are present + for (i=0; i<(unsigned int)vffkey_value; i++) + { + if (keysRead[i] == 0) + { + header = NULL; + break; + } + } + + if ((header == NULL) || (*header != endOfHeader)) + { + // parse error + RMInit::logOut << method_convFrom << ": PARSE ERROR" << endl; + + delete [] keysRead; + + if (vecSize != NULL) + delete [] vecSize; + if (vecOrigin != NULL) + delete [] vecOrigin; + if (vecValue != NULL) + delete [] vecValue; + + r_Error err(r_Error::r_Error_General); + throw(err); + } + + // after this instruction, header points to the linefeed + header++; + // after this instruction, header points to the data + header++; + + desc.destInterv = r_Minterval(dim); + + // order of dimensions in vectors + unsigned int *dimOrder = get_dimension_order(dim); + + // the order of the dimensions is the same, only the linearization differs + for (i=0; i<dim; i++) + { + // the old method didn't work for high<0 (wrong rounding direction) + r_Range low, width; + low = (r_Range)(vecOrigin[i]); + width = (r_Range)(vecSize[i]); + //cout << "SIZE " << dimOrder[i] << ": " << width << ", ORG " << low << endl; + desc.destInterv[dimOrder[i]] = r_Sinterval(low, low+width-1); + } + //cout << desc.destInterv << endl; + + delete [] vecOrigin; + delete [] vecSize; + + int typeSize = (bits>>3); + unsigned long dataSize = desc.destInterv.cell_count() * typeSize; + //cout << "Type size " << typeSize << ", dim " << dim << endl; + + if ((desc.dest = (char*)mystore.storage_alloc(dataSize)) == NULL) + { + delete [] keysRead; + + if (vecValue != NULL) + delete [] vecValue; + + r_Error err(r_Error::r_Error_General); + throw(err); + } + + // treat all dimensions alike + + // must copy byte-by-byte because the source data may not be aligned! + r_MiterDirect iter(desc.dest, desc.destInterv, desc.destInterv, typeSize, 1); + unsigned int *order, *steps; + const unsigned char *sptr = (const unsigned char *)header; + + order = new unsigned int[dim]; + steps = new unsigned int[dim]; + + for (i=0; i<dim; i++) + steps[i] = 1; + + parse_data_order(dim, dataOrder, order); + + switch (typeSize) + { + case 1: + while (iter.isDone() == 0) + { + *((r_Char*)iter.getData(order)) = *sptr; + iter.iterateUserOrder(order, steps); + sptr++; + } + break; + case 2: + while (iter.isDone() == 0) + { + unsigned char *dptr = (unsigned char*)iter.getData(order); + dptr[0] = sptr[0]; + dptr[1] = sptr[1]; + //cout << iter << ':' << (long)((char*)dptr - desc.dest) << ':' << (long)((char*)sptr - header) << ':' << (unsigned short)((sptr[0] << 8) | sptr[1]) << ' '; + iter.iterateUserOrder(order, steps); + sptr+=2; + } + break; + case 4: + while (iter.isDone() == 0) + { + unsigned char *dptr = (unsigned char*)iter.getData(order); + dptr[0] = sptr[0]; + dptr[1] = sptr[1]; + dptr[2] = sptr[2]; + dptr[3] = sptr[3]; + iter.iterateUserOrder(order, steps); + sptr+=4; + } + break; + default: + break; + } + + delete [] order; + delete [] steps; + delete [] dimOrder; + + switch (typeSize) + { + case 1: + desc.destType = get_external_type(ctype_char); + break; + case 2: + desc.destType = get_external_type(ctype_uint16); + if (strcmp(endian, get_endian_id()) != 0) + r_Endian::swap_array(dataSize, (const r_UShort*)desc.dest, (r_UShort*)desc.dest); + break; + case 4: + desc.destType = get_external_type(ctype_uint32); + if (strcmp(endian, get_endian_id()) != 0) + r_Endian::swap_array(dataSize, (const r_ULong*)desc.dest, (r_ULong*)desc.dest); + break; + default: + break; + } + + //desc.destType->print_status(); + + if (vecValue != NULL) + delete [] vecValue; + + delete [] keysRead; + + return desc; +} + + +const char *r_Conv_VFF::get_name( void ) const +{ + return format_name_vff; +} + + +r_Data_Format r_Conv_VFF::get_data_format( void ) const +{ + return r_VFF; +} + + +r_Convertor *r_Conv_VFF::clone( void ) const +{ + return new r_Conv_VFF(desc.src, desc.srcInterv, desc.baseType); +} diff --git a/conversion/vff.hh b/conversion/vff.hh new file mode 100644 index 0000000..f1829b5 --- /dev/null +++ b/conversion/vff.hh @@ -0,0 +1,138 @@ +/* +* 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 <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * FILE: vff.hh + * + * MODULE: conversion + * + * CLASSES: r_Conv_VFF + * + * COMMENTS: + * + * Provides interface to convert data to VFF and back. + * +*/ + +#ifndef _R_CONV_VFF_HH_ +#define _R_CONV_VFF_HH_ + +#include "conversion/convertor.hh" + + + +//@ManMemo: Module {\bf conversion} + +/*@Doc: + VFF convertor class. + + Supported parameters are + + \begin{tabular}{rcl} + dorder && string && data order to read/write in 3D mode; permutations of "xyz"\\ + dimorder && string && dimension order for vectors (size, origin, ...)\\ + vffendian && int && default endianness, 0 for big endian, 1 for little\\ + \end{tabular} + +*/ + +class r_Conv_VFF : public r_Convertor +{ + public: + /// constructor using an r_Type object + r_Conv_VFF( const char *src, const r_Minterval &interv, const r_Type *tp ) throw(r_Error); + /// constructor using a convert_type_e shortcut + r_Conv_VFF( const char *src, const r_Minterval &interv, int tp ) throw(r_Error); + /// destructor + ~r_Conv_VFF( void ); + + /// convert to VFF + virtual r_convDesc &convertTo( const char *options=NULL ) throw(r_Error); + /// convert from VFF + virtual r_convDesc &convertFrom( const char *options=NULL ) throw(r_Error); + /// cloning + virtual r_Convertor *clone( void ) const; + /// identification + virtual const char *get_name( void ) const; + virtual r_Data_Format get_data_format( void ) const; + + + private: + /// shared init code + void initVFF( void ); + /// skip whitespace when parsing the header + static void skip_white( const char *&str ); + /// read a floating point vector from the header and return pointer to rest + static const char *read_vector( r_Dimension dim, const char *str, double *&vec ); + /// read a string from the header and return pointer to rest + static const char *read_string( const char *str, char *dest, bool allowSpace=0 ); + /// write an interval to a stream + static void write_interval( const char *keyname, std::ostream &str, const r_Minterval &iv, + const unsigned int *order, r_Range inc=0 ); + /// write an origin to a stream + static void write_origin( const char *keyname, std::ostream &str, const r_Minterval &iv, + const unsigned int *order ); + /// get the VFF-endian id for the host machine's + static const char *get_endian_id( void ); + /// parse data order string, revert to default if failed + static int parse_data_order( r_Dimension dim, const char *dstr, unsigned int *order ); + /// get default data order for a dimensionality + static const char *get_default_order( r_Dimension dim ); + /// get default dimension order for a dimensionality + static const char *get_default_dim_order( r_Dimension dim ); + + /// get dimension order in newly allocated array + unsigned int *get_dimension_order( r_Dimension dim ) const; + /// get the default endianness + const char *get_default_endianness( void ) const; + + /// data order parameter + char *dorderParam; + /// dimension order parameter + char *dimOrderParam; + /// default endianness parameter + int dfltEndianness; + + /// identifier (ncaa) in header + static const char *fileMagic; + /// keyword names + static const char *keywords[]; + /// special key values + static const char *kval_Raster; + static const char *kval_Slice; + static const char *kval_LEndian; + static const char *kval_BEndian; + /// default data order for 2D/3D + static const char *dfltDataOrder2; + static const char *dfltDataOrder3; + /// default dimension order fo 2D/3D + static const char *dfltDimOrder2; + static const char *dfltDimOrder3; + /// end-of-header marker + static const char endOfHeader; + /// name of convertTo() method + static const char *method_convTo; + /// name of convertFrom() method + static const char *method_convFrom; +}; + +#endif |
