Files
OCCT/src/Image/Image_PixMap.cxx
2012-03-27 16:56:30 +04:00

475 lines
14 KiB
C++

// Created on: 2010-09-16
// Created by: KGV
// Copyright (c) 2010-2012 OPEN CASCADE SAS
//
// The content of this file is subject to the Open CASCADE Technology Public
// License Version 6.5 (the "License"). You may not use the content of this file
// except in compliance with the License. Please obtain a copy of the License
// at http://www.opencascade.org and read it completely before using this file.
//
// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
//
// The Original Code and all software distributed under the License is
// distributed on an "AS IS" basis, without warranty of any kind, and the
// Initial Developer hereby disclaims all such warranties, including without
// limitation, any warranties of merchantability, fitness for a particular
// purpose or non-infringement. Please see the License for the specific terms
// and conditions governing the rights and limitations under the License.
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef HAVE_FREEIMAGE
#include <FreeImagePlus.h>
#include <Image_PixMap.ixx>
/* OCC22216 NOTE: linker dependency can be switched off by undefining macro */
#ifdef _MSC_VER
#pragma comment( lib, "FreeImage.lib" )
#pragma comment( lib, "FreeImagePlus.lib" )
#endif
#else
#include <Image_PixMap.ixx>
#include <fstream>
#if (defined(BYTE_ORDER) && BYTE_ORDER==BIG_ENDIAN) || \
(defined(__BYTE_ORDER) && __BYTE_ORDER==__BIG_ENDIAN) || \
defined(__BIG_ENDIAN__)
#define THE_BIGENDIAN
#endif
// dummy class which can only dump to PPM format
class fipImage
{
public:
typedef struct tagRGBQuad {
#ifndef THE_BIGENDIAN
Standard_Byte rgbBlue;
Standard_Byte rgbGreen;
Standard_Byte rgbRed;
#else
Standard_Byte rgbRed;
Standard_Byte rgbGreen;
Standard_Byte rgbBlue;
#endif
Standard_Byte rgbReserved;
} RGBQuad_t;
public:
fipImage()
: myDataPtr(NULL),
mySizeX(0),
mySizeY(0),
myBytesPerLine(0),
myBytesPerPixel(3)
{
//
}
fipImage (const Standard_Integer theSizeX, const Standard_Integer theSizeY,
const Standard_Integer theBytesPerLine = 0, const Standard_Integer theBytesPerPixel = 3)
: myDataPtr(NULL),
mySizeX (theSizeX),
mySizeY (theSizeY),
myBytesPerLine (theBytesPerLine),
myBytesPerPixel (theBytesPerPixel)
{
if (myBytesPerLine == 0)
{
myBytesPerLine = mySizeX * myBytesPerPixel;
}
myDataPtr = new Standard_Byte[myBytesPerLine * mySizeY];
}
~fipImage()
{
delete[] myDataPtr;
}
Standard_Integer getHeight() const
{
return mySizeY;
}
Standard_Integer getWidth() const
{
return mySizeX;
}
Standard_Integer getBytesPerPixel() const
{
return myBytesPerPixel;
}
Standard_Integer getBytesPerLine() const
{
return myBytesPerLine;
}
Standard_Byte* getData() const
{
return myDataPtr;
}
Standard_Byte* getScanLine (const Standard_Integer theRow) const
{
return &myDataPtr[theRow * myBytesPerLine];
}
Quantity_Color getPixelColor (const Standard_Integer theCol,
const Standard_Integer theRow) const
{
RGBQuad_t* aPixel = (RGBQuad_t* )&getScanLine (theRow)[theCol * myBytesPerPixel];
return Quantity_Color (Standard_Real (aPixel->rgbRed) / 255.0,
Standard_Real (aPixel->rgbGreen) / 255.0,
Standard_Real (aPixel->rgbBlue) / 255.0,
Quantity_TOC_RGB);
}
Standard_Boolean savePPM (const Standard_CString theFileName) const
{
// Open file
FILE* pFile = fopen (theFileName, "wb");
if (pFile == NULL)
{
return Standard_False;
}
// Write header
fprintf (pFile, "P6\n%d %d\n255\n", mySizeX, mySizeY);
// Write pixel data
Standard_Byte* aScanLine;
RGBQuad_t* aPixel;
// image stored upside-down
for (Standard_Integer aRow = mySizeY - 1; aRow >= 0; --aRow)
{
aScanLine = getScanLine (aRow);
for (Standard_Integer aCol = 0; aCol < mySizeX; ++aCol)
{
aPixel = (RGBQuad_t* )&aScanLine[aCol * myBytesPerPixel];
fwrite (&aPixel->rgbRed, 1, 1, pFile);
fwrite (&aPixel->rgbGreen, 1, 1, pFile);
fwrite (&aPixel->rgbBlue, 1, 1, pFile);
}
}
// Close file
fclose (pFile);
return Standard_True;
}
Standard_Integer getMaxRowAligmentBytes() const
{
Standard_Integer aDeltaBytes = myBytesPerLine - myBytesPerPixel * mySizeX;
for (Standard_Integer anAligment = 16; anAligment > 1; anAligment /= 2)
{
if (isRowAlignedTo (anAligment, aDeltaBytes))
{
return anAligment;
}
}
return 1;
}
private:
Standard_Boolean isRowAlignedTo (const Standard_Integer theAligmentBytes,
const Standard_Integer theDeltaBytes) const
{
return (theDeltaBytes < theAligmentBytes) &&
((myBytesPerLine % theAligmentBytes) == 0);
}
private:
Standard_Byte* myDataPtr;
Standard_Integer mySizeX;
Standard_Integer mySizeY;
Standard_Integer myBytesPerLine;
Standard_Integer myBytesPerPixel;
};
#endif
#include <gp.hxx>
#include <TCollection_AsciiString.hxx>
//=======================================================================
//function : Image_PixMap
//purpose :
//=======================================================================
Image_PixMap::Image_PixMap (const Standard_Integer theWidth,
const Standard_Integer theHeight,
const Image_TypeOfImage theType)
: Aspect_PixMap (theWidth, theHeight, 1),
myImage()
{
#ifdef HAVE_FREEIMAGE
FREE_IMAGE_TYPE aFIType = FIT_UNKNOWN;
int aBitsPerPixel = 0;
switch (theType)
{
case Image_TOI_RGBA:
aFIType = FIT_BITMAP;
aBitsPerPixel = 32;
break;
case Image_TOI_RGBF:
aFIType = FIT_RGBF;
aBitsPerPixel = 96;
break;
case Image_TOI_RGBAF:
aFIType = FIT_RGBAF;
aBitsPerPixel = 128;
break;
case Image_TOI_FLOAT:
aFIType = FIT_FLOAT;
aBitsPerPixel = 32;
break;
case Image_TOI_RGB:
default:
aFIType = FIT_BITMAP;
aBitsPerPixel = 24;
break;
}
myImage = new fipImage (aFIType, theWidth, theHeight, aBitsPerPixel);
#else
Standard_Integer aBytesPerPixel = 0;
switch (theType)
{
case Image_TOI_RGBAF:
std::cerr << "Float formats not supported\n";
case Image_TOI_RGBA:
aBytesPerPixel = 4;
break;
case Image_TOI_RGBF:
case Image_TOI_FLOAT:
std::cerr << "Float formats not supported\n";
case Image_TOI_RGB:
default:
aBytesPerPixel = 3;
break;
}
myImage = new fipImage (theWidth, theHeight, 0, aBytesPerPixel);
//
#endif
}
//=======================================================================
//function : Image_PixMap
//purpose :
//=======================================================================
Image_PixMap::Image_PixMap (const Standard_PByte theDataPtr,
const Standard_Integer theWidth, const Standard_Integer theHeight,
const Standard_Integer thePitch, const Standard_Integer theBitsPerPixel,
const Standard_Boolean theIsTopDown)
: Aspect_PixMap (theWidth, theHeight, 1),
myImage (new fipImage())
{
#ifdef HAVE_FREEIMAGE
*myImage = FreeImage_ConvertFromRawBits (theDataPtr,
theWidth, theHeight,
thePitch, theBitsPerPixel,
0, 0, 0,
theIsTopDown);
if (theBitsPerPixel != 24)
{
myImage->convertTo24Bits();
}
#else
myImage = new fipImage (theWidth, theHeight, thePitch, theBitsPerPixel / 8);
Standard_Integer aRowStart = !theIsTopDown ? 0 : (theHeight - 1);
Standard_Integer aRowDelta = !theIsTopDown ? 1 : -1;
for (Standard_Integer aRowFrom (aRowStart), aRowTo (0);
aRowFrom >= 0 && aRowFrom < theHeight;
aRowFrom += aRowDelta, ++aRowTo)
{
memcpy (myImage->getScanLine (aRowTo),
&theDataPtr[aRowFrom * thePitch],
myImage->getBytesPerLine());
}
#endif
}
//=======================================================================
//function : Destroy
//purpose :
//=======================================================================
void Image_PixMap::Destroy()
{
myImage = Image_HPrivateImage();
}
//=======================================================================
//function : Dump
//purpose :
//=======================================================================
Standard_Boolean Image_PixMap::Dump (const Standard_CString theFilename,
const Standard_Real theGammaCorr) const
{
#ifdef HAVE_FREEIMAGE
FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilename (theFilename);
if (anImageFormat == FIF_UNKNOWN)
{
std::cerr << "Image_PixMap, image format doesn't supported!\n";
return Standard_False;
}
Standard_Boolean isCopied = Standard_False;
Image_HPrivateImage anImageToDump = myImage;
if (Abs (theGammaCorr - 1.0) > gp::Resolution())
{
if (!isCopied)
{
isCopied = Standard_True;
anImageToDump = new fipImage (*myImage);
}
anImageToDump->adjustGamma (theGammaCorr);
}
switch (anImageFormat)
{
case FIF_GIF:
if (!isCopied)
{
isCopied = Standard_True;
anImageToDump = new fipImage (*myImage);
}
// need convertion to image with pallete
anImageToDump->colorQuantize (FIQ_NNQUANT);
break;
case FIF_EXR:
if (myImage->getImageType() == FIT_BITMAP)
{
if (!isCopied)
{
isCopied = Standard_True;
anImageToDump = new fipImage (*myImage);
}
anImageToDump->convertToType (FIT_RGBF);
}
break;
default:
if (myImage->getImageType() != FIT_BITMAP)
{
if (!isCopied)
{
isCopied = Standard_True;
anImageToDump = new fipImage (*myImage);
}
anImageToDump->convertToType (FIT_BITMAP);
}
break;
}
return anImageToDump->save (theFilename);
#else
return myImage->savePPM (theFilename);
#endif
}
Aspect_Handle Image_PixMap::PixmapID() const
{
return Aspect_Handle();
}
void Image_PixMap::AccessBuffer (Image_CRawBufferData& theBuffer) const
{
theBuffer.widthPx = myImage->getWidth();
theBuffer.heightPx = myImage->getHeight();
#ifdef HAVE_FREEIMAGE
theBuffer.rowAligmentBytes = 4; // 32 bits according to FreeImage documentation
switch (myImage->getImageType())
{
case FIT_FLOAT:
theBuffer.format = TDepthComponent;
theBuffer.type = TFloat;
break;
case FIT_RGBF:
theBuffer.format = TRGB;
theBuffer.type = TFloat;
break;
case FIT_RGBAF:
theBuffer.format = TRGBA;
theBuffer.type = TFloat;
break;
case FIT_BITMAP:
default:
#if defined(FREEIMAGE_BIGENDIAN)
theBuffer.format = (myImage->getColorType() == FIC_RGBALPHA) ? TRGBA : TRGB;
#else
theBuffer.format = (myImage->getColorType() == FIC_RGBALPHA) ? TBGRA : TBGR;
#endif
theBuffer.type = TUByte;
break;
}
theBuffer.dataPtr = myImage->accessPixels();
#else
theBuffer.rowAligmentBytes = myImage->getMaxRowAligmentBytes();
theBuffer.format = (myImage->getBytesPerPixel() == 4) ? TBGRA : TBGR;
theBuffer.type = TUByte;
theBuffer.dataPtr = myImage->getData();
#endif
}
Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX,
const Standard_Integer theY) const
{
Standard_Integer aScanlineId = myImage->getHeight() - theY - 1;
if (theX < 0 || theX >= (unsigned int)myImage->getWidth() ||
theY < 0 || theY >= (unsigned int)myImage->getHeight())
{
return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB);
}
#ifdef HAVE_FREEIMAGE
else if (myImage->getImageType() == FIT_BITMAP)
{
RGBQUAD aValue; memset (&aValue, 0, sizeof(aValue));
myImage->getPixelColor (theX, aScanlineId, &aValue);
return Quantity_Color (Standard_Real (aValue.rgbRed) / 255.0,
Standard_Real (aValue.rgbGreen) / 255.0,
Standard_Real (aValue.rgbBlue) / 255.0,
Quantity_TOC_RGB);
}
else
{
switch (myImage->getImageType())
{
case FIT_FLOAT:
{
float* aScanLine = (float* )myImage->getScanLine (aScanlineId);
Quantity_Parameter aValue = Quantity_Parameter (aScanLine[theX]);
return Quantity_Color (aValue, aValue, aValue, Quantity_TOC_RGB);
}
case FIT_RGBF:
{
FIRGBF* aScanLine = (FIRGBF* )myImage->getScanLine (aScanlineId);
FIRGBF* aPixel = &aScanLine[theX];
return Quantity_Color (Quantity_Parameter (aPixel->red),
Quantity_Parameter (aPixel->green),
Quantity_Parameter (aPixel->blue),
Quantity_TOC_RGB);
}
case FIT_RGBAF:
{
FIRGBAF* aScanLine = (FIRGBAF* )myImage->getScanLine (aScanlineId);
FIRGBAF* aPixel = &aScanLine[theX];
return Quantity_Color (Quantity_Parameter (aPixel->red),
Quantity_Parameter (aPixel->green),
Quantity_Parameter (aPixel->blue),
Quantity_TOC_RGB);
}
default:
{
// not supported image type
return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB);
}
}
}
#else
return myImage->getPixelColor (theX, aScanlineId);
#endif
}