diff options
Diffstat (limited to 'conversion/bmp.cc')
-rw-r--r-- | conversion/bmp.cc | 990 |
1 files changed, 990 insertions, 0 deletions
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); +} |