Files
OCCT/src/AlienImage/AlienImage_BMPAlienData.cxx
2012-03-05 19:23:40 +04:00

575 lines
19 KiB
C++
Executable File

// File: AlienImage_BMPAlienData.cxx
// Created: Quebex 20 October 1998
// Author: DCB
// Notes:
// Read()/Write() code is taken from ZOV's sources from Xw package.
// Copyright: MatraDatavision 1998
// include windows.h first to ensure that it is loaded completely
#ifdef WNT
#include <windows.h>
#endif
#include <AlienImage_BMPAlienData.ixx>
#include <AlienImage_BMPHeader.hxx>
#include <Aspect_ColorMap.hxx>
#include <Aspect_ColorMapEntry.hxx>
#include <Quantity_Color.hxx>
#include <Image_PseudoColorImage.hxx>
#include <Image_ColorImage.hxx>
#include <OSD_FromWhere.hxx>
#include <Standard.hxx>
static unsigned long __swaptest = 1;
WORD static _TestSwapWORD (WORD __w)
{
return LOW_VAL_AT_LOW_ADDR ? __w:
((__w&0xFF) << 8) | ((__w&0xFF00) >> 8);
}
DWORD static _TestSwapDWORD (DWORD __dw)
{
return LOW_VAL_AT_LOW_ADDR ? __dw:
((__dw&0x000000FF) << 24) | ((__dw&0x0000FF00) << 8)
| ((__dw&0xFF0000) >> 8) | ((__dw&0xFF000000) >> 24);
}
#define STGMGR_ALLOC(size) Standard::Allocate(size)
#define STGMGR_FREE(buf,size) Standard::Free((void*&)buf)
#define BPIXEL ((BYTE *) myData)
#define DWPIXEL ((DWORD*) myData)
//================================================================
AlienImage_BMPAlienData::AlienImage_BMPAlienData ()
: AlienImage_AlienImageData ()
{
myData = NULL;
myWidth = 0;
myHeight = 0;
myColorMap.Nullify ();
}
//================================================================
void AlienImage_BMPAlienData::Clear ()
{
if (myData) {
STGMGR_FREE (myData, (!myColorMap.IsNull() ? myWidth*myHeight :
myWidth*myHeight*4));
myData = NULL;
}
myWidth = 0;
myHeight = 0;
myColorMap.Nullify ();
}
//================================================================
Standard_Boolean AlienImage_BMPAlienData::Read (OSD_File& file)
{
BYTE *pData = NULL, *pbData=NULL; // pointer to bitmap pixels
BYTE *ptrByte;
int i, isize, ncolors, bytes_per_line, x, y, width, height;
DWORD dwRMask, dwGMask, dwBMask, dwSize;
int nRMult, nGMult, nBMult;
int isInsideOut, hasMask, nBitCount;
int iCompression, isOS2Format, hasColormap;
int nBytes, iDataSize;
char bmpSign[2];
AlienImage_BMPHeader bmfh; // Standard BMP file header
BITMAPINFOHEADER bmih; // Windows BMP header
BITMAPCOREHEADER bmch; // OS/2 BMP header
Standard_Address lpVoid;
Quantity_Color color;
Standard_Real r, g, b;
Aspect_ColorMapEntry entry;
RGBQUAD* pColors256 = (RGBQUAD*) STGMGR_ALLOC (sizeof(RGBQUAD)*256);
// Check 'BM' signature
file.Seek (0, OSD_FromBeginning);
lpVoid = Standard_Address(&bmpSign[0]);
file.Read ((void*&)lpVoid, 2, nBytes);
if (file.Failed () || strncmp (bmpSign, "BM", 2) || nBytes != 2) {
// cout << "AlienImage_BMPAlienData::Read() : 'BM' signature not found."
// << endl << flush;
goto _ExitReadError;
}
lpVoid = Standard_Address(&bmfh);
file.Read ((void*&)lpVoid, sizeof(AlienImage_BMPHeader), nBytes);
if (file.Failed () || nBytes != sizeof(AlienImage_BMPHeader)) {
cout << "AlienImage_BMPAlienData::Read() : Reading AlienImage_BMPHeader."
<< endl << flush;
goto _ExitReadError;
}
lpVoid = Standard_Address (&dwSize);
file.Read ((void*&)lpVoid, sizeof (DWORD), nBytes);
if (file.Failed() || nBytes != sizeof (DWORD)) {
cout << "AlienImage_BMPAlienData::Read() : BAD file size." << endl << flush;
goto _ExitReadError;
}
file.Seek (-(int)sizeof(DWORD), OSD_FromHere);
isOS2Format = _TestSwapDWORD(dwSize) == sizeof (BITMAPCOREHEADER);
if (isOS2Format) {
lpVoid = Standard_Address(&bmch);
file.Read ((void*&)lpVoid, sizeof(BITMAPCOREHEADER), nBytes);
if (file.Failed() || nBytes != sizeof(BITMAPCOREHEADER)) {
cout << "AlienImage_BMPAlienData::Read() : Reading BITMAPCOREHEADER."
<< endl << flush;
goto _ExitReadError;
}
} else {
lpVoid = Standard_Address(&bmih);
file.Read ((void*&)lpVoid, sizeof(BITMAPINFOHEADER), nBytes);
if (file.Failed() || nBytes != sizeof(BITMAPINFOHEADER)) {
cout << "AlienImage_BMPAlienData::Read() : Reading BITMAPINFOHEADER."
<< endl << flush;
goto _ExitReadError;
}
}
nBitCount = _TestSwapWORD (isOS2Format ? bmch.bcBitCount: bmih.biBitCount);
if ((nBitCount != 1 && nBitCount != 4 && nBitCount != 8 &&
nBitCount != 16 && nBitCount != 24 && nBitCount != 32) ||
isOS2Format && (nBitCount == 16 || nBitCount == 32)) {
cout << "AlienImage_BMPAlienData::Read() : Bad <nBitCount> value :"
<< nBitCount << " " << isOS2Format << endl << flush;
goto _ExitReadError;
}
iCompression = isOS2Format ? BI_RGB: _TestSwapDWORD (bmih.biCompression);
hasColormap = nBitCount <= 8;
hasMask = iCompression == BI_BITFIELDS;
ncolors = hasColormap ? 1 << nBitCount: 0;
width = isOS2Format ? _TestSwapWORD (bmch.bcWidth)
: _TestSwapDWORD (bmih.biWidth);
height = isOS2Format ? _TestSwapWORD (bmch.bcHeight)
: _TestSwapDWORD (bmih.biHeight);
isInsideOut = !isOS2Format && height < 0;
height = isInsideOut ? -height: height;
bytes_per_line = width * nBitCount;
bytes_per_line = (bytes_per_line>>3) + (bytes_per_line&0x7 ? 1: 0);
bytes_per_line += (bytes_per_line&0x3)? (4-(bytes_per_line&0x3)): 0;
myWidth = width;
myHeight = height;
if (hasColormap) {
// Retreive array of colors (as RGBQUAD sequence).
// Note, that there can be less then ncolors colors.
isize = ncolors * sizeof (RGBQUAD);
file.Read ((void*&)pColors256, isize, nBytes);
if (file.Failed() || nBytes != isize) {
cout << "AlienImage_BMPAlienData::Read() : Reading ColorMap."
<< endl << flush;
goto _ExitReadError;
}
// Build colormap
myColorMap = new Aspect_GenericColorMap ();
for (i=0; i<ncolors; i++) {
r = ((float)pColors256[i].rgbRed / 255.);
g = ((float)pColors256[i].rgbGreen / 255.);
b = ((float)pColors256[i].rgbBlue / 255.);
color.SetValues (r, g, b, Quantity_TOC_RGB);
entry.SetValue (i, color);
myColorMap -> AddEntry (entry);
}
}
if (hasMask) {
PDWORD pdw;
// Retrieve three DWORD's that contain the masks for R, G and B respectively
file.Read ((void*&)(pdw = &dwRMask), sizeof (DWORD), nBytes);
if (file.Failed() || nBytes != sizeof(DWORD)) {
cout << "AlienImage_BMPAlienData::Read() : BAD file size." << endl << flush;
goto _ExitReadError;
}
file.Read ((void*&)(pdw = &dwGMask), sizeof (DWORD), nBytes);
if (file.Failed() || nBytes != sizeof(DWORD)) {
cout << "AlienImage_BMPAlienData::Read() : BAD file size." << endl << flush;
goto _ExitReadError;
}
file.Read ((void*&)(pdw = &dwBMask), sizeof (DWORD), nBytes);
if (file.Failed() || nBytes != sizeof(DWORD)) {
cout << "AlienImage_BMPAlienData::Read() : BAD file size." << endl << flush;
goto _ExitReadError;
}
if (hasColormap || !dwRMask || !dwGMask || !dwBMask) {
cout << "AlienImage_BMPAlienData::Read() : BAD image colormap." << endl << flush;
goto _ExitReadError;
}
dwRMask = _TestSwapDWORD (dwRMask);
dwGMask = _TestSwapDWORD (dwGMask);
dwBMask = _TestSwapDWORD (dwBMask);
nRMult = nGMult = nBMult = 0;
for (i=dwRMask; (i&1)^1; i >>= 1)
nRMult++;
for (i=dwGMask; (i&1)^1; i >>= 1)
nGMult++;
for (i=dwBMask; (i&1)^1; i >>= 1)
nBMult++;
} else {
dwBMask = 0x000000ff, dwGMask = 0x0000ff00, dwRMask = 0x00ff0000,
nBMult = 0, nGMult = 8, nRMult = 16;
}
// Allocate the pixel buffer and load raw data from file
i = _TestSwapDWORD (bmfh.bfOffBits);
iDataSize = _TestSwapDWORD (bmfh.bfSize) - i;
pData = (BYTE *) STGMGR_ALLOC (iDataSize);
pbData = pData;
file.Seek (i, OSD_FromBeginning);
file.Read ((void*&)pData, iDataSize, nBytes);
if (file.Failed () || nBytes != iDataSize) {
cout << "AlienImage_BMPAlienData::Read() : Image data."
<< endl << flush;
goto _ExitReadError;
}
if (iCompression == BI_RLE4 || iCompression == BI_RLE8) {
pbData = (BYTE*) STGMGR_ALLOC (width*height);
// Note, that it is possible that "spots" could appear
// after decompressing the data encoded using RLE algorith.
// The method assumes that the image is drawn to an already
// defined background. That's why I have to fill in these
// probable spots with some color (I have chosen 0-indexed one).
memset (pbData, 0, iDataSize);
// Decompress the data to array of 8-bit color indices
x = 0;
y = 0;
ptrByte = pData;
for (;;) {
BYTE bPixCount = *ptrByte++;
BYTE bCode, bColor;
if (bPixCount) {
bColor = *ptrByte++;
//fprintf (stderr, "[%02x S]", (int)bPixCount);
if (iCompression == BI_RLE8) {
while (bPixCount--)
pbData [width*y + x++] = bColor;
} else {
BYTE bColor0 = (bColor & 0xf0) >> 4;
BYTE bColor1 = bColor & 0x0f;
i = 0;
while (bPixCount--)
pbData [width*y + x++] = i++ & 1 ? bColor1: bColor0;
}
continue;
}
// Zero code has been reached.
// Do the command specified in the second byte.
bCode = *ptrByte++;
if (!bCode) { // EOL
x = 0, y++; //,fprintf (stderr, "\r\n");
} else if (bCode == 1) { // EOF
break;
} else if (bCode == 2) { // Delta
x += (unsigned) *ptrByte++;
y += (unsigned) *ptrByte++;
//fprintf (stderr, "[POS=%d,%d]", x, y);
} else { // Absolute mode
bPixCount = bCode;
//fprintf (stderr, "[%02x D]", (int)bPixCount);
if (iCompression == BI_RLE8) {
while (bPixCount--)
pbData [width*y + x++] = *ptrByte++;
} else {
i = 0;
while (bPixCount--)
pbData [width*y + x++] = i++ & 1 ? *ptrByte & 0x0f
: (*ptrByte++ & 0xf0) >> 4;
}
// each run must aligned on a word boundary
if (iCompression == BI_RLE8 && (bCode & 1) ||
iCompression == BI_RLE4 && (bCode & 3))
ptrByte ++;
}
}
bytes_per_line = width;
nBitCount = 8;
STGMGR_FREE (pData, iDataSize);
iDataSize = width*height;
}
// Data isn't comressed. Can just use the raw data
// Alloc image data (pidata) and fill in the buffer with RGBQUAD's
isize = width*height;
myData = STGMGR_ALLOC (!myColorMap.IsNull() ? myWidth*myHeight : myWidth*myHeight*4);
x = 0;
y = isInsideOut? 0: height-1;
for (i = 0; i < isize; i++) {
DWORD dwValue=0;
BYTE* pbLine = pbData + y*bytes_per_line;
switch (nBitCount) {
case 32:
dwValue = *(((DWORD *) pbLine) + x); break; // next double word value
case 16:
dwValue = *(((WORD *) pbLine) + x); break; // next word
case 8:
dwValue = *(((BYTE *) pbLine) + x); break; // next byte
case 24: {
BYTE* pbTripple = pbLine + x+(x<<1);
dwValue = *pbTripple + (*(pbTripple +1) <<8) + (*(pbTripple +2) <<16);
} break;
case 4:
dwValue = (x&1) ? *(pbLine+(x>>1))&0x0f: (*(pbLine+(x>>1))&0xf0) >> 4; break;
case 1: {
int iBit = 7 - (x&7);
dwValue = (*(pbLine+(x>>3)) & (1 <<iBit)) >>iBit;
} break; // next bit
}
if (hasColormap) {
BPIXEL [i] = (BYTE) dwValue; // put index in colormap
} else {
DWPIXEL[i] = (DWORD) dwValue; // put RGB
}
if (++x == width) {
x = 0;
y += isInsideOut? 1: -1;
}
}
STGMGR_FREE (pColors256, sizeof(RGBQUAD)*256);
STGMGR_FREE (pbData, iDataSize);
return Standard_True;
_ExitReadError:
// cout << "AlienImage_BMPAlienData::Read() : Read file error." << endl << flush;
STGMGR_FREE (pColors256, sizeof(RGBQUAD)*256);
if (pbData) STGMGR_FREE (pbData, iDataSize);
Clear ();
return Standard_False;
}
//================================================================
Standard_Boolean AlienImage_BMPAlienData::Write (OSD_File& file) const
{
AlienImage_BMPHeader bfh;
BITMAPINFOHEADER bih;
int isize, x, y;
BYTE *pbData = NULL, *pbCell = NULL;
WORD sign = _TestSwapWORD(0x4D42); // BMP file signature: SWAP('MB')
DWORD dwPixel;
RGBQUAD* prgbColor = (RGBQUAD*)&dwPixel;
Quantity_Color color;
Standard_Real r, g, b;
if (myData == NULL || myWidth == 0 || myHeight == 0 )
return Standard_False;
// Get the size of array of pixels
isize = myWidth*3; // actual size of data in each scan line
isize += (isize & 3 ? 4 - (isize & 3): 0); // plus pad size
isize *= myHeight;
pbData = (BYTE*) STGMGR_ALLOC (isize);
// Build and write File Header.
bfh.bfSize = _TestSwapDWORD(2+sizeof (AlienImage_BMPHeader) +
sizeof (BITMAPINFOHEADER) +
sizeof (RGBQUAD)*0 +
isize);
bfh.bfReserved = 0;
bfh.bfOffBits = _TestSwapDWORD(2+sizeof (AlienImage_BMPHeader) +
sizeof (BITMAPINFOHEADER) +
sizeof (RGBQUAD)*0);
// Write file signature
file.Write (&sign, 2);
if (file.Failed ())
goto _ExitWriteError;
// Write file header
file.Write (&bfh, sizeof (bfh));
if (file.Failed ())
goto _ExitWriteError;
// Build and write Info Header.
bih.biSize = _TestSwapDWORD(sizeof (BITMAPINFOHEADER));
bih.biWidth = _TestSwapDWORD(myWidth );
bih.biHeight = _TestSwapDWORD(myHeight);
bih.biPlanes = _TestSwapWORD (1);
bih.biBitCount = _TestSwapWORD (24); // 8 bits per each of R,G and B value
bih.biCompression = 0; // BI_RGB
bih.biSizeImage = 0; // can be zero for BI_RGB
bih.biXPelsPerMeter = 0;
bih.biYPelsPerMeter = 0;
bih.biClrUsed = 0; // all colors used
bih.biClrImportant = 0; // all colors imortant
file.Write (&bih, sizeof (bih));
if (file.Failed ())
goto _ExitWriteError;
// Fill in array of pixels and write out the buffer.
pbCell = pbData;
for (y = myHeight-1; y >= 0; y--) {
for (x = 0; x < myWidth; x++) {
if (!myColorMap.IsNull ()) {
color = myColorMap -> FindEntry (BPIXEL[y*myWidth + x]).Color ();
color.Values (r, g, b, Quantity_TOC_RGB);
*pbCell++ = (BYTE)(b*255.);
*pbCell++ = (BYTE)(g*255.);
*pbCell++ = (BYTE)(r*255.);
} else {
dwPixel = _TestSwapDWORD (DWPIXEL[y*myWidth + x]);
*pbCell++ = prgbColor -> rgbBlue;
*pbCell++ = prgbColor -> rgbGreen;
*pbCell++ = prgbColor -> rgbRed;
}
}
x *= 3;
// Pad each scan line with zeroes to end on a LONG data-type boundary
while (x++ & 0x03) // i.e. until 4 devides x
*pbCell++ = 0;
}
file.Write (pbData, isize);
if (file.Failed ())
goto _ExitWriteError;
STGMGR_FREE (pbData, isize);
return Standard_True;
_ExitWriteError:
cout << "AlienImage_BMPAlienData::Write() : Write file error." << endl << flush;
STGMGR_FREE (pbData, isize);
return Standard_False;
}
//================================================================
Handle_Image_Image AlienImage_BMPAlienData::ToImage () const
{
Standard_Integer x, y, LowX, LowY;
Handle(Image_Image) theImage;
if (!myColorMap.IsNull()) {
Aspect_IndexPixel iPixel;
theImage = new Image_PseudoColorImage (0, 0, myWidth, myHeight, myColorMap);
LowX = theImage -> LowerX ();
LowY = theImage -> LowerY ();
for (y = 0; y < myHeight; y++) {
for (x = 0; x < myWidth; x++) {
iPixel.SetValue (BPIXEL[y*myWidth + x]);
theImage -> SetPixel (LowX + x, LowY + y, iPixel);
}
}
} else {
DWORD dwPixel;
RGBQUAD* pRgb = (RGBQUAD*)&dwPixel;
Standard_Real r, g, b;
Quantity_Color color;
Aspect_ColorPixel cPixel;
theImage = new Image_ColorImage (0, 0, myWidth, myHeight);
LowX = theImage -> LowerX ();
LowY = theImage -> LowerY ();
for (y = 0; y < myHeight; y++) {
for (x = 0; x < myWidth; x++) {
dwPixel = _TestSwapDWORD (DWPIXEL[y*myWidth + x]);
r = ((float)pRgb -> rgbRed / 255.);
g = ((float)pRgb -> rgbGreen / 255.);
b = ((float)pRgb -> rgbBlue / 255.);
color.SetValues (r, g, b, Quantity_TOC_RGB);
cPixel.SetValue (color);
theImage -> SetPixel (LowX + x, LowY + y, cPixel);
}
}
}
return theImage;
}
//================================================================
void AlienImage_BMPAlienData::FromImage (const Handle_Image_Image& anImage)
{
if (anImage -> Type() == Image_TOI_PseudoColorImage) {
// Build from PseudoColorImage
Handle(Image_PseudoColorImage) aPImage =
Handle(Image_PseudoColorImage)::DownCast(anImage);
FromPseudoColorImage (aPImage);
} else if (anImage -> Type() == Image_TOI_ColorImage) {
// Build from ColorImage
Handle(Image_ColorImage) aCImage =
Handle(Image_ColorImage)::DownCast(anImage);
FromColorImage (aCImage);
} else {
// Unknown type of image
Standard_TypeMismatch_Raise_if (Standard_True,
"Attempt to convert a unknown Image_Image type to a BMPAlienData");
}
}
//================================================================
void AlienImage_BMPAlienData::FromPseudoColorImage (
const Handle(Image_PseudoColorImage)& anImage)
{
int width = anImage -> Width ();
int height = anImage -> Height ();
int x, y, LowX = anImage -> LowerX(), LowY = anImage -> LowerY();
Aspect_IndexPixel iPixel;
BYTE index;
if (width*height > 0) {
Handle(Aspect_ColorMap) aColorMap = anImage -> ColorMap ();
// Clear old data if any
Clear ();
// Fill colormap
myColorMap = new Aspect_GenericColorMap ();
for (int i = 1; i <= aColorMap -> Size (); i++)
myColorMap -> AddEntry (aColorMap -> Entry (i));
// Fill image's data
myWidth = width;
myHeight = height;
myData = STGMGR_ALLOC (myWidth*myHeight);
for (y = 0; y < myHeight; y++) {
for (x = 0; x < myWidth; x++) {
iPixel = anImage -> Pixel (LowX + x, LowY + y);
index = aColorMap -> FindEntry (iPixel.Value ()).Index ();
BPIXEL[y*myWidth + x] = index;
}
}
}
}
//================================================================
void AlienImage_BMPAlienData::FromColorImage (
const Handle(Image_ColorImage)& anImage)
{
int width = anImage -> Width ();
int height = anImage -> Height ();
int x, y, LowX = anImage -> LowerX(), LowY = anImage -> LowerY();
Standard_Real r, g, b;
Quantity_Color color;
RGBQUAD rgbColor;
DWORD* pdwPixel = (DWORD*)&rgbColor;
if (width*height > 0) {
// Clear old data if any
Clear ();
// Fill image's data
myWidth = width;
myHeight = height;
myData = STGMGR_ALLOC (myWidth*myHeight*4);
for (y = 0; y < myHeight; y++) {
for (x = 0; x < myWidth; x++) {
color = anImage -> PixelColor (LowX + x, LowY + y);
color.Values (r, g, b, Quantity_TOC_RGB);
rgbColor.rgbRed = (int)(r*255.);
rgbColor.rgbGreen = (int)(g*255.);
rgbColor.rgbBlue = (int)(b*255.);
rgbColor.rgbReserved = 0;
DWPIXEL[y*myWidth + x] = _TestSwapDWORD (*pdwPixel);
}
}
}
}