mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-08-09 13:22:24 +03:00
0023272: Image comparison algorithm
A new class Image_Diff for comparison of images and a draw-command "diffimage", which compares 2 images. Image_PixMap redesigned to provide interface for low-level image operations. New Image_AlienPixMap class now intended for Save/Load functionality. Aspect_PixMap class dropped. Xw_PixMap and WNT_PixMap classes now do not inherit from Aspect_PixMap and deprecated. ToPixMap methods now retrieve Image_PixMap as argument. Conflicts: src/ViewerTest/ViewerTest.cxx Remarks applied Fix compilation (correct merging error) Eliminated Aspect <-> Image cyclic dependency Fixed GIF dump in case of BGR32 image format
This commit is contained in:
@@ -6,5 +6,11 @@ Image_PixelAddress.cxx
|
||||
Image_PixelAddress.hxx
|
||||
Image.edl
|
||||
Image_CMPLRS.edl
|
||||
Image_CRawBufferData.hxx
|
||||
Image_HPrivateImage.hxx
|
||||
Image_PixMap.hxx
|
||||
Image_PixMap.cxx
|
||||
Image_PixMapData.hxx
|
||||
Image_Color.hxx
|
||||
Image_AlienPixMap.hxx
|
||||
Image_AlienPixMap.cxx
|
||||
Image_Diff.hxx
|
||||
Image_Diff.cxx
|
||||
|
@@ -88,18 +88,16 @@ is
|
||||
IndexPixel from Aspect,
|
||||
IndexPixelMapHasher );
|
||||
|
||||
class PixMap;
|
||||
---Purpose: Aspect_PixMap implementation.
|
||||
|
||||
-----------------------------
|
||||
---Category: Imported types:
|
||||
-----------------------------
|
||||
|
||||
imported PixelAddress;
|
||||
|
||||
imported HPrivateImage;
|
||||
|
||||
imported CRawBufferData;
|
||||
imported PixMap;
|
||||
imported AlienPixMap;
|
||||
imported PixMap_Handle;
|
||||
imported AlienPixMap_Handle;
|
||||
imported Diff;
|
||||
|
||||
-----------------------------
|
||||
---Category: The Enumerations
|
||||
@@ -132,12 +130,7 @@ is
|
||||
---Purpose: Type of dithering method.
|
||||
|
||||
enumeration TypeOfImage is TOI_ColorImage,
|
||||
TOI_PseudoColorImage,
|
||||
TOI_RGB,
|
||||
TOI_RGBA,
|
||||
TOI_RGBF,
|
||||
TOI_RGBAF,
|
||||
TOI_FLOAT
|
||||
TOI_PseudoColorImage
|
||||
end TypeOfImage ;
|
||||
|
||||
Zoom ( aImage : mutable Image from Image ;
|
||||
|
516
src/Image/Image_AlienPixMap.cxx
Normal file
516
src/Image/Image_AlienPixMap.cxx
Normal file
@@ -0,0 +1,516 @@
|
||||
// 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 <FreeImage.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment( lib, "FreeImage.lib" )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <Image_AlienPixMap.hxx>
|
||||
#include <gp.hxx>
|
||||
#include <TCollection_AsciiString.hxx>
|
||||
#include <fstream>
|
||||
|
||||
#ifdef HAVE_FREEIMAGE
|
||||
namespace
|
||||
{
|
||||
static Image_PixMap::ImgFormat convertFromFreeFormat (FREE_IMAGE_TYPE theFormatFI,
|
||||
FREE_IMAGE_COLOR_TYPE theColorTypeFI,
|
||||
unsigned theBitsPerPixel)
|
||||
{
|
||||
switch (theFormatFI)
|
||||
{
|
||||
case FIT_RGBF: return Image_PixMap::ImgRGBF;
|
||||
case FIT_RGBAF: return Image_PixMap::ImgRGBAF;
|
||||
case FIT_FLOAT: return Image_PixMap::ImgGrayF;
|
||||
case FIT_BITMAP:
|
||||
{
|
||||
switch (theColorTypeFI)
|
||||
{
|
||||
case FIC_MINISBLACK:
|
||||
{
|
||||
return Image_PixMap::ImgGray;
|
||||
}
|
||||
case FIC_RGB:
|
||||
{
|
||||
if (Image_PixMap::IsBigEndianHost())
|
||||
{
|
||||
return (theBitsPerPixel == 32) ? Image_PixMap::ImgRGB32 : Image_PixMap::ImgRGB;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (theBitsPerPixel == 32) ? Image_PixMap::ImgBGR32 : Image_PixMap::ImgBGR;
|
||||
}
|
||||
}
|
||||
case FIC_RGBALPHA:
|
||||
{
|
||||
return Image_PixMap::IsBigEndianHost() ? Image_PixMap::ImgRGBA : Image_PixMap::ImgBGRA;
|
||||
}
|
||||
default:
|
||||
return Image_PixMap::ImgUNKNOWN;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return Image_PixMap::ImgUNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static FREE_IMAGE_TYPE convertToFreeFormat (Image_PixMap::ImgFormat theFormat)
|
||||
{
|
||||
switch (theFormat)
|
||||
{
|
||||
case Image_PixMap::ImgGrayF:
|
||||
return FIT_FLOAT;
|
||||
case Image_PixMap::ImgRGBAF:
|
||||
return FIT_RGBAF;
|
||||
case Image_PixMap::ImgRGBF:
|
||||
return FIT_RGBF;
|
||||
case Image_PixMap::ImgRGBA:
|
||||
case Image_PixMap::ImgBGRA:
|
||||
case Image_PixMap::ImgRGB32:
|
||||
case Image_PixMap::ImgBGR32:
|
||||
case Image_PixMap::ImgRGB:
|
||||
case Image_PixMap::ImgBGR:
|
||||
case Image_PixMap::ImgGray:
|
||||
return FIT_BITMAP;
|
||||
default:
|
||||
return FIT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
IMPLEMENT_STANDARD_HANDLE (Image_AlienPixMap, Image_PixMap)
|
||||
IMPLEMENT_STANDARD_RTTIEXT(Image_AlienPixMap, Image_PixMap)
|
||||
|
||||
// =======================================================================
|
||||
// function : Image_AlienPixMap
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Image_AlienPixMap::Image_AlienPixMap()
|
||||
: myLibImage (NULL)
|
||||
{
|
||||
SetTopDown (false);
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : ~Image_AlienPixMap
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Image_AlienPixMap::~Image_AlienPixMap()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : InitWrapper
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
bool Image_AlienPixMap::InitWrapper (ImgFormat thePixelFormat,
|
||||
Standard_Byte* theDataPtr,
|
||||
const Standard_Size theSizeX,
|
||||
const Standard_Size theSizeY,
|
||||
const Standard_Size theSizeRowBytes)
|
||||
{
|
||||
Clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : InitTrash
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
bool Image_AlienPixMap::InitTrash (ImgFormat thePixelFormat,
|
||||
const Standard_Size theSizeX,
|
||||
const Standard_Size theSizeY,
|
||||
const Standard_Size theSizeRowBytes)
|
||||
{
|
||||
Clear();
|
||||
#ifdef HAVE_FREEIMAGE
|
||||
FREE_IMAGE_TYPE aFormatFI = convertToFreeFormat (thePixelFormat);
|
||||
int aBitsPerPixel = (int )Image_PixMap::SizePixelBytes (thePixelFormat) * 8;
|
||||
if (aFormatFI == FIT_UNKNOWN)
|
||||
{
|
||||
aFormatFI = FIT_BITMAP;
|
||||
aBitsPerPixel = 24;
|
||||
}
|
||||
|
||||
FIBITMAP* anImage = FreeImage_AllocateT (aFormatFI, (int )theSizeX, (int )theSizeY, aBitsPerPixel);
|
||||
Image_PixMap::ImgFormat aFormat = convertFromFreeFormat (FreeImage_GetImageType (anImage),
|
||||
FreeImage_GetColorType (anImage),
|
||||
FreeImage_GetBPP (anImage));
|
||||
if (thePixelFormat == Image_PixMap::ImgBGR32
|
||||
|| thePixelFormat == Image_PixMap::ImgRGB32)
|
||||
{
|
||||
//FreeImage_SetTransparent (anImage, FALSE);
|
||||
aFormat = (aFormat == Image_PixMap::ImgBGRA) ? Image_PixMap::ImgBGR32 : Image_PixMap::ImgRGB32;
|
||||
}
|
||||
|
||||
Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage),
|
||||
FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage));
|
||||
SetTopDown (false);
|
||||
|
||||
// assign image after wrapper initialization (virtual Clear() called inside)
|
||||
myLibImage = anImage;
|
||||
return true;
|
||||
#else
|
||||
return Image_PixMap::InitTrash (thePixelFormat, theSizeX, theSizeY, theSizeRowBytes);
|
||||
#endif
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Clear
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
bool Image_AlienPixMap::InitCopy (const Image_PixMap& theCopy)
|
||||
{
|
||||
if (&theCopy == this)
|
||||
{
|
||||
// self-copying disallowed
|
||||
return false;
|
||||
}
|
||||
if (!InitTrash (theCopy.Format(), theCopy.SizeX(), theCopy.SizeY(), theCopy.SizeRowBytes()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (myImgFormat == theCopy.Format())
|
||||
{
|
||||
if (myData.mySizeRowBytes == theCopy.SizeRowBytes()
|
||||
&& myData.myTopToDown == theCopy.TopDownInc())
|
||||
{
|
||||
// copy with one call
|
||||
memcpy (myData.myDataPtr, theCopy.Data(), theCopy.SizeBytes());
|
||||
return true;
|
||||
}
|
||||
|
||||
// copy row-by-row
|
||||
const Standard_Size aRowSizeBytes = (myData.mySizeRowBytes > theCopy.SizeRowBytes())
|
||||
? theCopy.SizeRowBytes() : myData.mySizeRowBytes;
|
||||
for (Standard_Size aRow = 0; aRow < myData.mySizeY; ++aRow)
|
||||
{
|
||||
memcpy (ChangeRow (aRow), theCopy.Row (aRow), aRowSizeBytes);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// pixel format conversion required
|
||||
Clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Clear
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void Image_AlienPixMap::Clear (ImgFormat thePixelFormat)
|
||||
{
|
||||
Image_PixMap::Clear (thePixelFormat);
|
||||
#ifdef HAVE_FREEIMAGE
|
||||
if (myLibImage != NULL)
|
||||
{
|
||||
FreeImage_Unload (myLibImage);
|
||||
myLibImage = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Load
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
bool Image_AlienPixMap::Load (const TCollection_AsciiString& theImagePath)
|
||||
{
|
||||
Clear();
|
||||
#ifdef HAVE_FREEIMAGE
|
||||
|
||||
FREE_IMAGE_FORMAT aFIF = FreeImage_GetFileType (theImagePath.ToCString(), 0);
|
||||
if (aFIF == FIF_UNKNOWN)
|
||||
{
|
||||
// no signature? try to guess the file format from the file extension
|
||||
aFIF = FreeImage_GetFIFFromFilename (theImagePath.ToCString());
|
||||
}
|
||||
if ((aFIF == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading (aFIF))
|
||||
{
|
||||
// unsupported image format
|
||||
return false;
|
||||
}
|
||||
|
||||
int aLoadFlags = 0;
|
||||
if (aFIF == FIF_GIF)
|
||||
{
|
||||
// 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading
|
||||
aLoadFlags = GIF_PLAYBACK;
|
||||
}
|
||||
else if (aFIF == FIF_ICO)
|
||||
{
|
||||
// convert to 32bpp and create an alpha channel from the AND-mask when loading
|
||||
aLoadFlags = ICO_MAKEALPHA;
|
||||
}
|
||||
|
||||
FIBITMAP* anImage = FreeImage_Load (aFIF, theImagePath.ToCString(), aLoadFlags);
|
||||
if (anImage == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Image_PixMap::ImgFormat aFormat = convertFromFreeFormat (FreeImage_GetImageType (anImage),
|
||||
FreeImage_GetColorType (anImage),
|
||||
FreeImage_GetBPP (anImage));
|
||||
if (aFormat == Image_PixMap::ImgUNKNOWN)
|
||||
{
|
||||
//anImage = FreeImage_ConvertTo24Bits (anImage);
|
||||
return false;
|
||||
}
|
||||
|
||||
Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage),
|
||||
FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage));
|
||||
SetTopDown (false);
|
||||
|
||||
// assign image after wrapper initialization (virtual Clear() called inside)
|
||||
myLibImage = anImage;
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : savePPM
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
bool Image_AlienPixMap::savePPM (const TCollection_AsciiString& theFileName) const
|
||||
{
|
||||
if (IsEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Open file
|
||||
FILE* aFile = fopen (theFileName.ToCString(), "wb");
|
||||
if (aFile == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write header
|
||||
fprintf (aFile, "P6\n%d %d\n255\n", (int )SizeX(), (int )SizeY());
|
||||
fprintf (aFile, "# Image stored by OpenCASCADE framework in linear RGB colorspace\n");
|
||||
|
||||
// Write pixel data
|
||||
Quantity_Color aColor;
|
||||
Quantity_Parameter aDummy;
|
||||
Standard_Byte aByte;
|
||||
for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
|
||||
{
|
||||
for (Standard_Size aCol = 0; aCol < SizeY(); ++aCol)
|
||||
{
|
||||
// extremely SLOW but universal (implemented for all supported pixel formats)
|
||||
aColor = PixelColor (aCol, aRow, aDummy);
|
||||
aByte = Standard_Byte(aColor.Red() * 255.0); fwrite (&aByte, 1, 1, aFile);
|
||||
aByte = Standard_Byte(aColor.Green() * 255.0); fwrite (&aByte, 1, 1, aFile);
|
||||
aByte = Standard_Byte(aColor.Blue() * 255.0); fwrite (&aByte, 1, 1, aFile);
|
||||
}
|
||||
}
|
||||
|
||||
// Close file
|
||||
fclose (aFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Save
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
bool Image_AlienPixMap::Save (const TCollection_AsciiString& theFileName)
|
||||
{
|
||||
#ifdef HAVE_FREEIMAGE
|
||||
if (myLibImage == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilename (theFileName.ToCString());
|
||||
if (anImageFormat == FIF_UNKNOWN)
|
||||
{
|
||||
std::cerr << "Image_PixMap, image format doesn't supported!\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsTopDown())
|
||||
{
|
||||
FreeImage_FlipVertical (myLibImage);
|
||||
SetTopDown (false);
|
||||
}
|
||||
|
||||
// FreeImage doesn't provide flexible format convertion API
|
||||
// so we should perform multiple convertions in some cases!
|
||||
Standard_Boolean isCopied = Standard_False;
|
||||
FIBITMAP* anImageToDump = myLibImage;
|
||||
switch (anImageFormat)
|
||||
{
|
||||
case FIF_PNG:
|
||||
case FIF_BMP:
|
||||
{
|
||||
if (Format() == Image_PixMap::ImgBGR32
|
||||
|| Format() == Image_PixMap::ImgRGB32)
|
||||
{
|
||||
// stupid FreeImage treats reserved byte as alpha if some bytes not set to 0xFF
|
||||
Image_PixMapData<Image_ColorRGB32>& aData = Image_PixMap::EditData<Image_ColorRGB32>();
|
||||
for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
|
||||
{
|
||||
for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol)
|
||||
{
|
||||
aData.ChangeValue (aRow, aCol).a_() = 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
|
||||
{
|
||||
anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FIF_GIF:
|
||||
{
|
||||
FIBITMAP* aTmpBitmap = myLibImage;
|
||||
if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
|
||||
{
|
||||
aTmpBitmap = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
|
||||
if (aTmpBitmap == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (FreeImage_GetBPP (aTmpBitmap) != 24)
|
||||
{
|
||||
FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (aTmpBitmap);
|
||||
if (aTmpBitmap != myLibImage)
|
||||
{
|
||||
FreeImage_Unload (aTmpBitmap);
|
||||
}
|
||||
if (aTmpBitmap24 == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
aTmpBitmap = aTmpBitmap24;
|
||||
}
|
||||
|
||||
// need convertion to image with pallete (requires 24bit bitmap)
|
||||
anImageToDump = FreeImage_ColorQuantize (aTmpBitmap, FIQ_NNQUANT);
|
||||
if (aTmpBitmap != myLibImage)
|
||||
{
|
||||
FreeImage_Unload (aTmpBitmap);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FIF_EXR:
|
||||
{
|
||||
if (Format() == Image_PixMap::ImgGray)
|
||||
{
|
||||
anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_FLOAT);
|
||||
}
|
||||
else if (Format() == Image_PixMap::ImgRGBA
|
||||
|| Format() == Image_PixMap::ImgBGRA)
|
||||
{
|
||||
anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBAF);
|
||||
}
|
||||
else
|
||||
{
|
||||
FREE_IMAGE_TYPE aImgTypeFI = FreeImage_GetImageType (myLibImage);
|
||||
if (aImgTypeFI != FIT_RGBF
|
||||
&& aImgTypeFI != FIT_RGBAF
|
||||
&& aImgTypeFI != FIT_FLOAT)
|
||||
{
|
||||
anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBF);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
|
||||
{
|
||||
anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
|
||||
if (anImageToDump == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (FreeImage_GetBPP (anImageToDump) != 24)
|
||||
{
|
||||
FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (anImageToDump);
|
||||
if (anImageToDump != myLibImage)
|
||||
{
|
||||
FreeImage_Unload (anImageToDump);
|
||||
}
|
||||
if (aTmpBitmap24 == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
anImageToDump = aTmpBitmap24;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (anImageToDump == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isSaved = (FreeImage_Save (anImageFormat, anImageToDump, theFileName.ToCString()) != FALSE);
|
||||
if (anImageToDump != myLibImage)
|
||||
{
|
||||
FreeImage_Unload (anImageToDump);
|
||||
}
|
||||
return isSaved;
|
||||
#else
|
||||
const Standard_Integer aLen = theFileName.Length();
|
||||
if ((aLen >= 4) && (theFileName.Value (aLen - 3) == '.')
|
||||
&& TCollection_AsciiString::ISSIMILAR (theFileName.SubString (aLen - 2, aLen), "ppm"))
|
||||
{
|
||||
return savePPM (theFileName);
|
||||
}
|
||||
std::cerr << "Image_PixMap, no image library available! Image saved in PPM format.\n";
|
||||
return savePPM (theFileName);
|
||||
#endif
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : AdjustGamma
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_EXPORT bool Image_AlienPixMap::AdjustGamma (const Standard_Real theGammaCorr)
|
||||
{
|
||||
#ifdef HAVE_FREEIMAGE
|
||||
return FreeImage_AdjustGamma (myLibImage, theGammaCorr) != FALSE;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
96
src/Image/Image_AlienPixMap.hxx
Normal file
96
src/Image/Image_AlienPixMap.hxx
Normal file
@@ -0,0 +1,96 @@
|
||||
// Created on: 2012-07-18
|
||||
// Created by: Kirill GAVRILOV
|
||||
// Copyright (c) 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.
|
||||
|
||||
#ifndef _Image_AlienPixMap_H__
|
||||
#define _Image_AlienPixMap_H__
|
||||
|
||||
#include <Image_PixMap.hxx>
|
||||
#include <Image_TypeOfImage.hxx>
|
||||
|
||||
class TCollection_AsciiString;
|
||||
struct FIBITMAP;
|
||||
|
||||
//! Image class that support file reading/writing operations using auxiliary image library.
|
||||
//! Notice that supported images format could be limited.
|
||||
class Image_AlienPixMap : public Image_PixMap
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
//! Empty constructor.
|
||||
Standard_EXPORT Image_AlienPixMap();
|
||||
|
||||
//! Destructor
|
||||
Standard_EXPORT virtual ~Image_AlienPixMap();
|
||||
|
||||
//! Read image data from file.
|
||||
Standard_EXPORT bool Load (const TCollection_AsciiString& theFileName);
|
||||
|
||||
//! Write image data to file using file extension to determine compression format.
|
||||
Standard_EXPORT bool Save (const TCollection_AsciiString& theFileName);
|
||||
|
||||
//! Initialize image plane with required dimensions.
|
||||
//! thePixelFormat - if specified pixel format doesn't supported by image library
|
||||
//! than nearest supported will be used instead!
|
||||
//! theSizeRowBytes - may be ignored by this class and required alignemnt will be used instead!
|
||||
Standard_EXPORT virtual bool InitTrash (ImgFormat thePixelFormat,
|
||||
const Standard_Size theSizeX,
|
||||
const Standard_Size theSizeY,
|
||||
const Standard_Size theSizeRowBytes = 0);
|
||||
|
||||
//! Initialize by copying data.
|
||||
Standard_EXPORT virtual bool InitCopy (const Image_PixMap& theCopy);
|
||||
|
||||
//! Method correctly deallocate internal buffer.
|
||||
Standard_EXPORT virtual void Clear (ImgFormat thePixelFormat = ImgGray);
|
||||
|
||||
//! Performs gamma correction on image.
|
||||
//! theGamma - gamma value to use; a value of 1.0 leaves the image alone
|
||||
Standard_EXPORT bool AdjustGamma (const Standard_Real theGammaCorr);
|
||||
|
||||
private:
|
||||
|
||||
FIBITMAP* myLibImage;
|
||||
|
||||
private:
|
||||
|
||||
//! Copying allowed only within Handles
|
||||
Image_AlienPixMap (const Image_AlienPixMap& );
|
||||
Image_AlienPixMap& operator= (const Image_AlienPixMap& );
|
||||
|
||||
//! Wrapper initialization is disallowed for this class (will return false in any case)!
|
||||
//! Use only copying and allocation initializers.
|
||||
Standard_EXPORT virtual bool InitWrapper (ImgFormat thePixelFormat,
|
||||
Standard_Byte* theDataPtr,
|
||||
const Standard_Size theSizeX,
|
||||
const Standard_Size theSizeY,
|
||||
const Standard_Size theSizeRowBytes);
|
||||
|
||||
//! Built-in PPM export
|
||||
Standard_EXPORT bool savePPM (const TCollection_AsciiString& theFileName) const;
|
||||
|
||||
public:
|
||||
|
||||
DEFINE_STANDARD_RTTI(Image_AlienPixMap) // Type definition
|
||||
|
||||
};
|
||||
|
||||
DEFINE_STANDARD_HANDLE(Image_AlienPixMap, Image_PixMap)
|
||||
|
||||
#endif // _Image_AlienPixMap_H__
|
@@ -1,30 +0,0 @@
|
||||
// Copyright (c) 1999-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.
|
||||
|
||||
#ifndef _Image_CRawBufferData_HeaderFile
|
||||
#define _Image_CRawBufferData_HeaderFile
|
||||
|
||||
#include <InterfaceGraphic_RawBufferData.hxx>
|
||||
|
||||
typedef TRawBufferData Image_CRawBufferData;
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
#include <Standard_Type.hxx>
|
||||
const Handle(Standard_Type)& TYPE(Image_CRawBufferData);
|
||||
#endif
|
||||
|
||||
#endif /*_Image_CRawBufferData_HeaderFile*/
|
543
src/Image/Image_Color.hxx
Normal file
543
src/Image/Image_Color.hxx
Normal file
@@ -0,0 +1,543 @@
|
||||
// Created on: 2012-07-18
|
||||
// Created by: Kirill GAVRILOV
|
||||
// Copyright (c) 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.
|
||||
|
||||
#ifndef _Image_Color_H__
|
||||
#define _Image_Color_H__
|
||||
|
||||
#include <Standard.hxx>
|
||||
|
||||
//! POD structure for packed RGB color value (3 bytes)
|
||||
struct Image_ColorRGB
|
||||
{
|
||||
|
||||
//! Returns the number of components.
|
||||
static Standard_Integer Length()
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
public: // access methods
|
||||
|
||||
//! Alias to 1st component (red intensity).
|
||||
Standard_Byte r() const { return v[0]; }
|
||||
|
||||
//! Alias to 2nd component (green intensity).
|
||||
Standard_Byte g() const { return v[1]; }
|
||||
|
||||
//! Alias to 3rd component (blue intensity).
|
||||
Standard_Byte b() const { return v[2]; }
|
||||
|
||||
//! Alias to 1st component (red intensity).
|
||||
Standard_Byte& r() { return v[0]; }
|
||||
|
||||
//! Alias to 2nd component (green intensity).
|
||||
Standard_Byte& g() { return v[1]; }
|
||||
|
||||
//! Alias to 3rd component (blue intensity).
|
||||
Standard_Byte& b() { return v[2]; }
|
||||
|
||||
public:
|
||||
|
||||
Standard_Byte v[3];
|
||||
|
||||
};
|
||||
|
||||
//! POD structure for packed RGB color value (4 bytes with extra byte for alignment)
|
||||
struct Image_ColorRGB32
|
||||
{
|
||||
|
||||
//! Returns the number of components.
|
||||
static Standard_Integer Length()
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
//! Alias to 1st component (red intensity).
|
||||
Standard_Byte r() const { return v[0]; }
|
||||
|
||||
//! Alias to 2nd component (green intensity).
|
||||
Standard_Byte g() const { return v[1]; }
|
||||
|
||||
//! Alias to 3rd component (blue intensity).
|
||||
Standard_Byte b() const { return v[2]; }
|
||||
|
||||
//! Alias to 4th component (dummy).
|
||||
Standard_Byte a_() const { return v[3]; }
|
||||
|
||||
//! Alias to 1st component (red intensity).
|
||||
Standard_Byte& r() { return v[0]; }
|
||||
|
||||
//! Alias to 2nd component (green intensity).
|
||||
Standard_Byte& g() { return v[1]; }
|
||||
|
||||
//! Alias to 3rd component (blue intensity).
|
||||
Standard_Byte& b() { return v[2]; }
|
||||
|
||||
//! Alias to 4th component (dummy).
|
||||
Standard_Byte& a_() { return v[3]; }
|
||||
|
||||
public:
|
||||
|
||||
Standard_Byte v[4];
|
||||
|
||||
};
|
||||
|
||||
//! POD structure for packed RGBA color value (4 bytes)
|
||||
struct Image_ColorRGBA
|
||||
{
|
||||
|
||||
//! Returns the number of components.
|
||||
static Standard_Integer Length()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
//! Alias to 1st component (red intensity).
|
||||
Standard_Byte r() const { return v[0]; }
|
||||
|
||||
//! Alias to 2nd component (green intensity).
|
||||
Standard_Byte g() const { return v[1]; }
|
||||
|
||||
//! Alias to 3rd component (blue intensity).
|
||||
Standard_Byte b() const { return v[2]; }
|
||||
|
||||
//! Alias to 4th component (alpha value).
|
||||
Standard_Byte a() const { return v[3]; }
|
||||
|
||||
//! Alias to 1st component (red intensity).
|
||||
Standard_Byte& r() { return v[0]; }
|
||||
|
||||
//! Alias to 2nd component (green intensity).
|
||||
Standard_Byte& g() { return v[1]; }
|
||||
|
||||
//! Alias to 3rd component (blue intensity).
|
||||
Standard_Byte& b() { return v[2]; }
|
||||
|
||||
//! Alias to 4th component (alpha value).
|
||||
Standard_Byte& a() { return v[3]; }
|
||||
|
||||
public:
|
||||
|
||||
Standard_Byte v[4];
|
||||
|
||||
};
|
||||
|
||||
//! POD structure for packed BGR color value (3 bytes)
|
||||
struct Image_ColorBGR
|
||||
{
|
||||
|
||||
//! Returns the number of components.
|
||||
static Standard_Integer Length()
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
//! Alias to 3rd component (red intensity).
|
||||
Standard_Byte r() const { return v[2]; }
|
||||
|
||||
//! Alias to 2nd component (green intensity).
|
||||
Standard_Byte g() const { return v[1]; }
|
||||
|
||||
//! Alias to 1st component (blue intensity).
|
||||
Standard_Byte b() const { return v[0]; }
|
||||
|
||||
//! Alias to 3rd component (red intensity).
|
||||
Standard_Byte& r() { return v[2]; }
|
||||
|
||||
//! Alias to 2nd component (green intensity).
|
||||
Standard_Byte& g() { return v[1]; }
|
||||
|
||||
//! Alias to 1st component (blue intensity).
|
||||
Standard_Byte& b() { return v[0]; }
|
||||
|
||||
public:
|
||||
|
||||
Standard_Byte v[3];
|
||||
|
||||
};
|
||||
|
||||
//! POD structure for packed BGR color value (4 bytes with extra byte for alignment)
|
||||
struct Image_ColorBGR32
|
||||
{
|
||||
|
||||
//! Returns the number of components.
|
||||
static Standard_Integer Length()
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
//! Alias to 3rd component (red intensity).
|
||||
Standard_Byte r() const { return v[2]; }
|
||||
|
||||
//! Alias to 2nd component (green intensity).
|
||||
Standard_Byte g() const { return v[1]; }
|
||||
|
||||
//! Alias to 1st component (blue intensity).
|
||||
Standard_Byte b() const { return v[0]; }
|
||||
|
||||
//! Alias to 4th component (dummy).
|
||||
Standard_Byte a_() const { return v[3]; }
|
||||
|
||||
//! Alias to 3rd component (red intensity).
|
||||
Standard_Byte& r() { return v[2]; }
|
||||
|
||||
//! Alias to 2nd component (green intensity).
|
||||
Standard_Byte& g() { return v[1]; }
|
||||
|
||||
//! Alias to 1st component (blue intensity).
|
||||
Standard_Byte& b() { return v[0]; }
|
||||
|
||||
//! Alias to 4th component (dummy).
|
||||
Standard_Byte& a_() { return v[3]; }
|
||||
|
||||
public:
|
||||
|
||||
Standard_Byte v[4];
|
||||
|
||||
};
|
||||
|
||||
//! POD structure for packed BGRA color value (4 bytes)
|
||||
struct Image_ColorBGRA
|
||||
{
|
||||
|
||||
//! Returns the number of components.
|
||||
static Standard_Integer Length()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
//! Alias to 3rd component (red intensity).
|
||||
Standard_Byte r() const { return v[2]; }
|
||||
|
||||
//! Alias to 2nd component (green intensity).
|
||||
Standard_Byte g() const { return v[1]; }
|
||||
|
||||
//! Alias to 1st component (blue intensity).
|
||||
Standard_Byte b() const { return v[0]; }
|
||||
|
||||
//! Alias to 4th component (alpha value).
|
||||
Standard_Byte a() const { return v[3]; }
|
||||
|
||||
//! Alias to 3rd component (red intensity).
|
||||
Standard_Byte& r() { return v[2]; }
|
||||
|
||||
//! Alias to 2nd component (green intensity).
|
||||
Standard_Byte& g() { return v[1]; }
|
||||
|
||||
//! Alias to 1st component (blue intensity).
|
||||
Standard_Byte& b() { return v[0]; }
|
||||
|
||||
//! Alias to 4th component (alpha value).
|
||||
Standard_Byte& a() { return v[3]; }
|
||||
|
||||
public:
|
||||
|
||||
Standard_Byte v[4];
|
||||
|
||||
};
|
||||
|
||||
//! POD structure for packed float RGB color value (3 floats)
|
||||
struct Image_ColorRGBF
|
||||
{
|
||||
|
||||
//! Returns the number of components.
|
||||
static Standard_Integer Length()
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
//! Alias to 1st component (red intensity).
|
||||
Standard_ShortReal r() const { return v[0]; }
|
||||
|
||||
//! Alias to 2nd component (green intensity).
|
||||
Standard_ShortReal g() const { return v[1]; }
|
||||
|
||||
//! Alias to 3rd component (blue intensity).
|
||||
Standard_ShortReal b() const { return v[2]; }
|
||||
|
||||
//! Alias to 1st component (red intensity).
|
||||
Standard_ShortReal& r() { return v[0]; }
|
||||
|
||||
//! Alias to 2nd component (green intensity).
|
||||
Standard_ShortReal& g() { return v[1]; }
|
||||
|
||||
//! Alias to 3rd component (blue intensity).
|
||||
Standard_ShortReal& b() { return v[2]; }
|
||||
|
||||
public:
|
||||
|
||||
Standard_ShortReal v[3];
|
||||
|
||||
};
|
||||
|
||||
//! POD structure for packed BGR float color value (3 floats)
|
||||
struct Image_ColorBGRF
|
||||
{
|
||||
|
||||
//! Returns the number of components.
|
||||
static Standard_Integer Length()
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
//! Alias to 3rd component (red intensity).
|
||||
Standard_ShortReal r() const { return v[2]; }
|
||||
|
||||
//! Alias to 2nd component (green intensity).
|
||||
Standard_ShortReal g() const { return v[1]; }
|
||||
|
||||
//! Alias to 1st component (blue intensity).
|
||||
Standard_ShortReal b() const { return v[0]; }
|
||||
|
||||
//! Alias to 3rd component (red intensity).
|
||||
Standard_ShortReal& r() { return v[2]; }
|
||||
|
||||
//! Alias to 2nd component (green intensity).
|
||||
Standard_ShortReal& g() { return v[1]; }
|
||||
|
||||
//! Alias to 1st component (blue intensity).
|
||||
Standard_ShortReal& b() { return v[0]; }
|
||||
|
||||
public:
|
||||
|
||||
Standard_ShortReal v[3];
|
||||
|
||||
};
|
||||
|
||||
//! POD structure for packed RGBA color value (4 floats)
|
||||
struct Image_ColorRGBAF
|
||||
{
|
||||
|
||||
//! Returns the number of components.
|
||||
static Standard_Integer Length()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
//! Alias to 1st component (red intensity).
|
||||
Standard_ShortReal r() const { return v[0]; }
|
||||
|
||||
//! Alias to 2nd component (green intensity).
|
||||
Standard_ShortReal g() const { return v[1]; }
|
||||
|
||||
//! Alias to 3rd component (blue intensity).
|
||||
Standard_ShortReal b() const { return v[2]; }
|
||||
|
||||
//! Alias to 4th component (alpha value).
|
||||
Standard_ShortReal a() const { return v[3]; }
|
||||
|
||||
//! Alias to 1st component (red intensity).
|
||||
Standard_ShortReal& r() { return v[0]; }
|
||||
|
||||
//! Alias to 2nd component (green intensity).
|
||||
Standard_ShortReal& g() { return v[1]; }
|
||||
|
||||
//! Alias to 3rd component (blue intensity).
|
||||
Standard_ShortReal& b() { return v[2]; }
|
||||
|
||||
//! Alias to 4th component (alpha value).
|
||||
Standard_ShortReal& a() { return v[3]; }
|
||||
|
||||
public:
|
||||
|
||||
Standard_ShortReal v[4];
|
||||
|
||||
};
|
||||
|
||||
//! POD structure for packed float BGRA color value (4 floats)
|
||||
struct Image_ColorBGRAF
|
||||
{
|
||||
|
||||
//! Returns the number of components.
|
||||
static Standard_Integer Length()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
//! Alias to 3rd component (red intensity).
|
||||
Standard_ShortReal r() const { return v[2]; }
|
||||
|
||||
//! Alias to 2nd component (green intensity).
|
||||
Standard_ShortReal g() const { return v[1]; }
|
||||
|
||||
//! Alias to 1st component (blue intensity).
|
||||
Standard_ShortReal b() const { return v[0]; }
|
||||
|
||||
//! Alias to 4th component (alpha value).
|
||||
Standard_ShortReal a() const { return v[3]; }
|
||||
|
||||
//! Alias to 3rd component (red intensity).
|
||||
Standard_ShortReal& r() { return v[2]; }
|
||||
|
||||
//! Alias to 2nd component (green intensity).
|
||||
Standard_ShortReal& g() { return v[1]; }
|
||||
|
||||
//! Alias to 1st component (blue intensity).
|
||||
Standard_ShortReal& b() { return v[0]; }
|
||||
|
||||
//! Alias to 4th component (alpha value).
|
||||
Standard_ShortReal& a() { return v[3]; }
|
||||
|
||||
public:
|
||||
|
||||
Standard_ShortReal v[4];
|
||||
|
||||
};
|
||||
|
||||
//! Addition operator
|
||||
template<typename ColorType_t>
|
||||
inline ColorType_t Image_ColorSumm3 (const ColorType_t& theA, const ColorType_t& theB)
|
||||
{
|
||||
ColorType_t aRes = { theA.v[0] + theB.v[0],
|
||||
theA.v[1] + theB.v[1],
|
||||
theA.v[2] + theB.v[2] };
|
||||
return aRes;
|
||||
}
|
||||
|
||||
inline Image_ColorRGB operator+ (const Image_ColorRGB& theA, const Image_ColorRGB& theB)
|
||||
{
|
||||
return Image_ColorSumm3 (theA, theB);
|
||||
}
|
||||
|
||||
inline Image_ColorBGR operator+ (const Image_ColorBGR& theA, const Image_ColorBGR& theB)
|
||||
{
|
||||
return Image_ColorSumm3 (theA, theB);
|
||||
}
|
||||
|
||||
inline Image_ColorRGBF operator+ (const Image_ColorRGBF& theA, const Image_ColorRGBF& theB)
|
||||
{
|
||||
return Image_ColorSumm3 (theA, theB);
|
||||
}
|
||||
|
||||
inline Image_ColorBGRF operator+ (const Image_ColorBGRF& theA, const Image_ColorBGRF& theB)
|
||||
{
|
||||
return Image_ColorSumm3 (theA, theB);
|
||||
}
|
||||
|
||||
template<typename ColorType_t>
|
||||
inline ColorType_t Image_ColorSumm4 (const ColorType_t& theA, const ColorType_t& theB)
|
||||
{
|
||||
ColorType_t aRes = { theA.v[0] + theB.v[0],
|
||||
theA.v[1] + theB.v[1],
|
||||
theA.v[2] + theB.v[2],
|
||||
theA.v[3] + theB.v[3] };
|
||||
return aRes;
|
||||
}
|
||||
|
||||
inline Image_ColorRGBA operator+ (const Image_ColorRGBA& theA, const Image_ColorRGBA& theB)
|
||||
{
|
||||
return Image_ColorSumm4 (theA, theB);
|
||||
}
|
||||
|
||||
inline Image_ColorBGRA operator+ (const Image_ColorBGRA& theA, const Image_ColorBGRA& theB)
|
||||
{
|
||||
return Image_ColorSumm4 (theA, theB);
|
||||
}
|
||||
|
||||
inline Image_ColorRGB32 operator+ (const Image_ColorRGB32& theA, const Image_ColorRGB32& theB)
|
||||
{
|
||||
return Image_ColorSumm4 (theA, theB);
|
||||
}
|
||||
|
||||
inline Image_ColorBGR32 operator+ (const Image_ColorBGR32& theA, const Image_ColorBGR32& theB)
|
||||
{
|
||||
return Image_ColorSumm4 (theA, theB);
|
||||
}
|
||||
|
||||
inline Image_ColorRGBAF operator+ (const Image_ColorRGBAF& theA, const Image_ColorRGBAF& theB)
|
||||
{
|
||||
return Image_ColorSumm4 (theA, theB);
|
||||
}
|
||||
|
||||
inline Image_ColorBGRAF operator+ (const Image_ColorBGRAF& theA, const Image_ColorBGRAF& theB)
|
||||
{
|
||||
return Image_ColorSumm4 (theA, theB);
|
||||
}
|
||||
|
||||
//! Subtraction operator
|
||||
template<typename ColorType_t>
|
||||
inline ColorType_t Image_ColorSub3 (const ColorType_t& theA, const ColorType_t& theB)
|
||||
{
|
||||
ColorType_t aRes = { theA.v[0] - theB.v[0],
|
||||
theA.v[1] - theB.v[1],
|
||||
theA.v[2] - theB.v[2] };
|
||||
return aRes;
|
||||
}
|
||||
|
||||
inline Image_ColorRGB operator- (const Image_ColorRGB& theA, const Image_ColorRGB& theB)
|
||||
{
|
||||
return Image_ColorSub3 (theA, theB);
|
||||
}
|
||||
|
||||
inline Image_ColorBGR operator- (const Image_ColorBGR& theA, const Image_ColorBGR& theB)
|
||||
{
|
||||
return Image_ColorSub3 (theA, theB);
|
||||
}
|
||||
|
||||
inline Image_ColorRGBF operator- (const Image_ColorRGBF& theA, const Image_ColorRGBF& theB)
|
||||
{
|
||||
return Image_ColorSub3 (theA, theB);
|
||||
}
|
||||
|
||||
inline Image_ColorBGRF operator- (const Image_ColorBGRF& theA, const Image_ColorBGRF& theB)
|
||||
{
|
||||
return Image_ColorSub3 (theA, theB);
|
||||
}
|
||||
|
||||
template<typename ColorType_t>
|
||||
inline ColorType_t Image_ColorSub4 (const ColorType_t& theA, const ColorType_t& theB)
|
||||
{
|
||||
ColorType_t aRes = { theA.v[0] - theB.v[0],
|
||||
theA.v[1] - theB.v[1],
|
||||
theA.v[2] - theB.v[2],
|
||||
theA.v[3] - theB.v[3] };
|
||||
return aRes;
|
||||
}
|
||||
|
||||
inline Image_ColorRGBA operator- (const Image_ColorRGBA& theA, const Image_ColorRGBA& theB)
|
||||
{
|
||||
return Image_ColorSub4 (theA, theB);
|
||||
}
|
||||
|
||||
inline Image_ColorBGRA operator- (const Image_ColorBGRA& theA, const Image_ColorBGRA& theB)
|
||||
{
|
||||
return Image_ColorSub4 (theA, theB);
|
||||
}
|
||||
|
||||
inline Image_ColorRGB32 operator- (const Image_ColorRGB32& theA, const Image_ColorRGB32& theB)
|
||||
{
|
||||
return Image_ColorSub4 (theA, theB);
|
||||
}
|
||||
|
||||
inline Image_ColorBGR32 operator- (const Image_ColorBGR32& theA, const Image_ColorBGR32& theB)
|
||||
{
|
||||
return Image_ColorSub4 (theA, theB);
|
||||
}
|
||||
|
||||
inline Image_ColorRGBAF operator- (const Image_ColorRGBAF& theA, const Image_ColorRGBAF& theB)
|
||||
{
|
||||
return Image_ColorSub4 (theA, theB);
|
||||
}
|
||||
|
||||
inline Image_ColorBGRAF operator- (const Image_ColorBGRAF& theA, const Image_ColorBGRAF& theB)
|
||||
{
|
||||
return Image_ColorSub4 (theA, theB);
|
||||
}
|
||||
|
||||
#endif // _Image_Color_H__
|
526
src/Image/Image_Diff.cxx
Normal file
526
src/Image/Image_Diff.cxx
Normal file
@@ -0,0 +1,526 @@
|
||||
// Created on: 2012-07-10
|
||||
// Created by: VRO
|
||||
// Copyright (c) 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.
|
||||
|
||||
#include <Image_Diff.hxx>
|
||||
#include <Image_AlienPixMap.hxx>
|
||||
|
||||
#include <TColStd_MapIteratorOfMapOfInteger.hxx>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
IMPLEMENT_STANDARD_HANDLE (Image_Diff, Standard_Transient)
|
||||
IMPLEMENT_STANDARD_RTTIEXT(Image_Diff, Standard_Transient)
|
||||
|
||||
//! Dot squared for difference of two colors
|
||||
inline Standard_Integer dotSquared (const Image_ColorRGB& theColor)
|
||||
{
|
||||
// explicitly convert to integer
|
||||
const Standard_Integer r = theColor.r();
|
||||
const Standard_Integer g = theColor.g();
|
||||
const Standard_Integer b = theColor.b();
|
||||
return r * r + g * g + b * b;
|
||||
}
|
||||
|
||||
//! @return true if pixel is black
|
||||
inline bool isBlack (const Image_ColorRGB& theColor)
|
||||
{
|
||||
return theColor.r() == 0
|
||||
&& theColor.g() == 0
|
||||
&& theColor.b() == 0;
|
||||
}
|
||||
|
||||
//! Converts a pixel position (row, column) to one integer value
|
||||
inline Standard_Size pixel2Int (const Standard_Size aRow,
|
||||
const Standard_Size aCol)
|
||||
{
|
||||
return aCol + (aRow << 15);
|
||||
}
|
||||
|
||||
//! Converts an integer value to pixel coordinates (row, column)
|
||||
inline void int2Pixel (const Standard_Size theValue,
|
||||
Standard_Size& theRow,
|
||||
Standard_Size& theCol)
|
||||
{
|
||||
theRow = (theValue >> 15);
|
||||
theCol = theValue - (theRow << 15);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
static const Standard_Size NEIGHBOR_PIXELS_NB = 8;
|
||||
struct
|
||||
{
|
||||
Standard_Integer row_inc;
|
||||
Standard_Integer col_inc;
|
||||
|
||||
inline Standard_Size pixel2Int (const Standard_Size theRowCenter,
|
||||
const Standard_Size theColCenter) const
|
||||
{
|
||||
return ::pixel2Int (theRowCenter + Standard_Size(row_inc),
|
||||
theColCenter + Standard_Size(col_inc));
|
||||
}
|
||||
|
||||
inline bool isBlack (const Image_PixMapData<Image_ColorRGB>& theData,
|
||||
const Standard_Size theRowCenter,
|
||||
const Standard_Size theColCenter) const
|
||||
{
|
||||
return ::isBlack (theData.Value (theRowCenter + Standard_Size(row_inc),
|
||||
theColCenter + Standard_Size(col_inc)));
|
||||
}
|
||||
}
|
||||
static const NEIGHBOR_PIXELS[NEIGHBOR_PIXELS_NB] =
|
||||
{
|
||||
{-1, -1}, {-1, 0}, {-1, 1},
|
||||
{ 0, -1}, { 0, 1},
|
||||
{ 1, -1}, { 1, 0}, { 1, 1}
|
||||
};
|
||||
|
||||
static bool isSupportedFormat (const Image_PixMap::ImgFormat theFormat)
|
||||
{
|
||||
return theFormat == Image_PixMap::ImgRGB
|
||||
|| theFormat == Image_PixMap::ImgBGR
|
||||
|| theFormat == Image_PixMap::ImgRGB32
|
||||
|| theFormat == Image_PixMap::ImgBGR32
|
||||
|| theFormat == Image_PixMap::ImgRGBA
|
||||
|| theFormat == Image_PixMap::ImgBGRA;
|
||||
}
|
||||
};
|
||||
|
||||
// =======================================================================
|
||||
// function : Image_Diff
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Image_Diff::Image_Diff()
|
||||
: myColorTolerance (0.0),
|
||||
myIsBorderFilterOn (Standard_False)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : ~Image_Diff
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Image_Diff::~Image_Diff()
|
||||
{
|
||||
releaseGroupsOfDiffPixels();
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Init
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_Boolean Image_Diff::Init (const Handle(Image_PixMap)& theImageRef,
|
||||
const Handle(Image_PixMap)& theImageNew,
|
||||
const Standard_Boolean theToBlackWhite)
|
||||
{
|
||||
myImageRef.Nullify();
|
||||
myImageNew.Nullify();
|
||||
myDiffPixels.Clear();
|
||||
releaseGroupsOfDiffPixels();
|
||||
if (theImageRef.IsNull() || theImageNew.IsNull()
|
||||
|| theImageRef->IsEmpty() || theImageNew->IsEmpty()
|
||||
|| theImageRef->SizeX() != theImageNew->SizeX()
|
||||
|| theImageRef->SizeY() != theImageNew->SizeY()
|
||||
|| theImageRef->Format() != theImageNew->Format())
|
||||
{
|
||||
std::cerr << "Images has different format or dimensions\n";
|
||||
return Standard_False;
|
||||
}
|
||||
else if (!isSupportedFormat (theImageRef->Format()))
|
||||
{
|
||||
std::cerr << "Images has unsupported pixel format\n";
|
||||
return Standard_False;
|
||||
}
|
||||
else if (theImageRef->SizeX() >= 0xFFFF
|
||||
|| theImageRef->SizeY() >= 0xFFFF)
|
||||
{
|
||||
std::cerr << "Image too large\n";
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
myImageRef = theImageRef;
|
||||
myImageNew = theImageNew;
|
||||
|
||||
if (theToBlackWhite)
|
||||
{
|
||||
// Convert the images to white/black
|
||||
const Image_ColorRGB aWhite = {{255, 255, 255}};
|
||||
Image_PixMapData<Image_ColorRGB>& aDataRef = myImageRef->EditData<Image_ColorRGB>();
|
||||
Image_PixMapData<Image_ColorRGB>& aDataNew = myImageNew->EditData<Image_ColorRGB>();
|
||||
for (Standard_Size aRow = 0; aRow < aDataRef.SizeY(); ++aRow)
|
||||
{
|
||||
for (Standard_Size aCol = 0; aCol < aDataRef.SizeY(); ++aCol)
|
||||
{
|
||||
Image_ColorRGB& aPixel1 = aDataRef.ChangeValue (aRow, aCol);
|
||||
Image_ColorRGB& aPixel2 = aDataNew.ChangeValue (aRow, aCol);
|
||||
if (!isBlack (aPixel1))
|
||||
{
|
||||
aPixel1 = aWhite;
|
||||
}
|
||||
if (!isBlack (aPixel2))
|
||||
{
|
||||
aPixel2 = aWhite;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// function : Init
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_Boolean Image_Diff::Init (const TCollection_AsciiString& theImgPathRef,
|
||||
const TCollection_AsciiString& theImgPathNew,
|
||||
const Standard_Boolean theToBlackWhite)
|
||||
{
|
||||
Handle(Image_AlienPixMap) anImgRef = new Image_AlienPixMap();
|
||||
Handle(Image_AlienPixMap) anImgNew = new Image_AlienPixMap();
|
||||
if (!anImgRef->Load (theImgPathRef)
|
||||
|| !anImgNew->Load (theImgPathNew))
|
||||
{
|
||||
std::cerr << "Failed to load image(s) file(s)\n";
|
||||
return Standard_False;
|
||||
}
|
||||
return Init (anImgRef, anImgNew, theToBlackWhite);
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : SetColorTolerance
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void Image_Diff::SetColorTolerance (const Standard_Real theTolerance)
|
||||
{
|
||||
myColorTolerance = theTolerance;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : ColorTolerance
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_Real Image_Diff::ColorTolerance() const
|
||||
{
|
||||
return myColorTolerance;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : SetBorderFilterOn
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void Image_Diff::SetBorderFilterOn (const Standard_Boolean theToIgnore)
|
||||
{
|
||||
myIsBorderFilterOn = theToIgnore;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : IsBorderFilterOn
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_Boolean Image_Diff::IsBorderFilterOn() const
|
||||
{
|
||||
return myIsBorderFilterOn;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Compare
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_Integer Image_Diff::Compare()
|
||||
{
|
||||
// Number of different pixels (by color)
|
||||
Standard_Integer aNbDiffColors = 0;
|
||||
myDiffPixels.Clear();
|
||||
|
||||
if (myImageRef.IsNull() || myImageNew.IsNull())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Tolerance of comparison operation for color
|
||||
// Maximum difference between colors (white - black) = 100%
|
||||
Image_ColorRGB aDiff = {{255, 255, 255}};
|
||||
const Standard_Integer aMaxDiffColor = dotSquared (aDiff);
|
||||
const Standard_Integer aDiffThreshold = Standard_Integer(Standard_Real(aMaxDiffColor) * myColorTolerance);
|
||||
|
||||
// we don't care about RGB/BGR/RGBA/BGRA/RGB32/BGR32 differences
|
||||
// because we just compute summ of r g b components
|
||||
const Image_PixMapData<Image_ColorRGB>& aDataRef = myImageRef->ReadData<Image_ColorRGB>();
|
||||
const Image_PixMapData<Image_ColorRGB>& aDataNew = myImageNew->ReadData<Image_ColorRGB>();
|
||||
|
||||
// compare colors of each pixel
|
||||
for (Standard_Size aRow = 0; aRow < myImageRef->SizeY(); ++aRow)
|
||||
{
|
||||
for (Standard_Size aCol = 0; aCol < myImageRef->SizeX(); ++aCol)
|
||||
{
|
||||
aDiff = aDataNew.Value (aRow, aCol) - aDataRef.Value (aRow, aCol);
|
||||
if (dotSquared (aDiff) > aDiffThreshold)
|
||||
{
|
||||
const Standard_Size aValue = pixel2Int (aRow, aCol);
|
||||
myDiffPixels.Append (aValue);
|
||||
++aNbDiffColors;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// take into account a border effect
|
||||
if (myIsBorderFilterOn && myDiffPixels.Length() > 0)
|
||||
{
|
||||
aNbDiffColors = ignoreBorderEffect();
|
||||
}
|
||||
|
||||
return aNbDiffColors;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : SaveDiffImage
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_Boolean Image_Diff::SaveDiffImage (Image_PixMap& theDiffImage) const
|
||||
{
|
||||
if (myImageRef.IsNull() || myImageNew.IsNull())
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
if (theDiffImage.IsEmpty()
|
||||
|| theDiffImage.SizeX() != myImageRef->SizeX()
|
||||
|| theDiffImage.SizeY() != myImageRef->SizeY()
|
||||
|| !isSupportedFormat (theDiffImage.Format()))
|
||||
{
|
||||
if (!theDiffImage.InitTrash (Image_PixMap::ImgRGB, myImageRef->SizeX(), myImageRef->SizeY()))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
}
|
||||
|
||||
Standard_Size aRow, aCol;
|
||||
const Image_ColorRGB aWhite = {{255, 255, 255}};
|
||||
Image_PixMapData<Image_ColorRGB>& aDataOut = theDiffImage.EditData<Image_ColorRGB>();
|
||||
|
||||
// initialize black image for dump
|
||||
memset (theDiffImage.ChangeData(), 0, theDiffImage.SizeBytes());
|
||||
if (myGroupsOfDiffPixels.IsEmpty())
|
||||
{
|
||||
if (myIsBorderFilterOn)
|
||||
{
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
for (Standard_Integer aPixelId = 0; aPixelId < myDiffPixels.Length(); ++aPixelId)
|
||||
{
|
||||
const Standard_Size aValue = myDiffPixels.Value (aPixelId);
|
||||
int2Pixel (aValue, aRow, aCol);
|
||||
aDataOut.ChangeValue (aRow, aCol) = aWhite;
|
||||
}
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
Standard_Integer aGroupId = 1;
|
||||
for (ListOfMapOfInteger::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next(), ++aGroupId)
|
||||
{
|
||||
if (myLinearGroups.Contains (aGroupId))
|
||||
{
|
||||
continue; // skip linear groups
|
||||
}
|
||||
|
||||
const TColStd_MapOfInteger* aGroup = aGrIter.Value();
|
||||
for (TColStd_MapIteratorOfMapOfInteger aPixelIter(*aGroup);
|
||||
aPixelIter.More(); aPixelIter.Next())
|
||||
{
|
||||
int2Pixel (aPixelIter.Key(), aRow, aCol);
|
||||
aDataOut.ChangeValue (aRow, aCol) = aWhite;
|
||||
}
|
||||
}
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : SaveDiffImage
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_Boolean Image_Diff::SaveDiffImage (const TCollection_AsciiString& theDiffPath) const
|
||||
{
|
||||
if (myImageRef.IsNull() || myImageNew.IsNull() || theDiffPath.IsEmpty())
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
Image_AlienPixMap aDiff;
|
||||
if (!aDiff.InitTrash (Image_PixMap::ImgRGB, myImageRef->SizeX(), myImageRef->SizeY())
|
||||
|| !SaveDiffImage (aDiff))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
// save image
|
||||
return aDiff.Save (theDiffPath);
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : ignoreBorderEffect
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_Integer Image_Diff::ignoreBorderEffect()
|
||||
{
|
||||
if (myImageRef.IsNull() || myImageNew.IsNull())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Image_PixMapData<Image_ColorRGB>& aDataRef = myImageRef->ReadData<Image_ColorRGB>();
|
||||
|
||||
// allocate groups of different pixels
|
||||
releaseGroupsOfDiffPixels();
|
||||
|
||||
// Find a different area (a set of close to each other pixels which colors differ in both images).
|
||||
// It filters alone pixels with different color.
|
||||
Standard_Size aRow1, aCol1, aRow2, aCol2;
|
||||
Standard_Integer aLen1 = (myDiffPixels.Length() > 0) ? (myDiffPixels.Length() - 1) : 0;
|
||||
for (Standard_Integer aPixelId1 = 0; aPixelId1 < aLen1; ++aPixelId1)
|
||||
{
|
||||
const Standard_Size aValue1 = myDiffPixels.Value (aPixelId1);
|
||||
int2Pixel (aValue1, aRow1, aCol1);
|
||||
|
||||
// Check other pixels in the list looking for a neighbour of this one
|
||||
for (Standard_Integer aPixelId2 = aPixelId1 + 1; aPixelId2 < myDiffPixels.Length(); ++aPixelId2)
|
||||
{
|
||||
const Standard_Size aValue2 = myDiffPixels.Value (aPixelId2);
|
||||
int2Pixel (aValue2, aRow2, aCol2);
|
||||
if (std::abs (ptrdiff_t (aCol1 - aCol2)) <= 1 &&
|
||||
std::abs (ptrdiff_t (aRow1 - aRow2)) <= 1)
|
||||
{
|
||||
// A neighbour is found. Create a new group and add both pixels.
|
||||
if (myGroupsOfDiffPixels.IsEmpty())
|
||||
{
|
||||
TColStd_MapOfInteger* aGroup = new TColStd_MapOfInteger();
|
||||
aGroup->Add (aValue1);
|
||||
aGroup->Add (aValue2);
|
||||
myGroupsOfDiffPixels.Append (aGroup);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find a group the pixels belong to.
|
||||
Standard_Boolean isFound = Standard_False;
|
||||
for (ListOfMapOfInteger::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next())
|
||||
{
|
||||
TColStd_MapOfInteger*& aGroup = aGrIter.ChangeValue();
|
||||
if (aGroup->Contains (aValue1))
|
||||
{
|
||||
aGroup->Add (aValue2);
|
||||
isFound = Standard_True;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isFound)
|
||||
{
|
||||
// Create a new group
|
||||
TColStd_MapOfInteger* aGroup = new TColStd_MapOfInteger();
|
||||
aGroup->Add (aValue1);
|
||||
aGroup->Add (aValue2);
|
||||
myGroupsOfDiffPixels.Append (aGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// filter linear groups which represent border of a solid shape
|
||||
Standard_Integer aGroupId = 1;
|
||||
for (ListOfMapOfInteger::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next(), ++aGroupId)
|
||||
{
|
||||
Standard_Integer aNeighboursNb = 0;
|
||||
Standard_Boolean isLine = Standard_True;
|
||||
const TColStd_MapOfInteger* aGroup = aGrIter.Value();
|
||||
for (TColStd_MapIteratorOfMapOfInteger aPixelIter (*aGroup); aPixelIter.More(); aPixelIter.Next())
|
||||
{
|
||||
int2Pixel (aPixelIter.Key(), aRow1, aCol1);
|
||||
aNeighboursNb = 0;
|
||||
|
||||
// pixels of a line have only 1 or 2 neighbour pixels inside the same group
|
||||
// check all neighbour pixels on presence in the group
|
||||
for (Standard_Size aNgbrIter = 0; aNgbrIter < NEIGHBOR_PIXELS_NB; ++aNgbrIter)
|
||||
{
|
||||
if (aGroup->Contains (NEIGHBOR_PIXELS[aNgbrIter].pixel2Int (aRow1, aCol1)))
|
||||
{
|
||||
++aNeighboursNb;
|
||||
}
|
||||
}
|
||||
|
||||
if (aNeighboursNb > 2)
|
||||
{
|
||||
isLine = Standard_False;
|
||||
break;
|
||||
}
|
||||
} // for pixels inside group...
|
||||
|
||||
if (isLine)
|
||||
{
|
||||
// Test a pixel of the linear group on belonging to a solid shape.
|
||||
// Consider neighbour pixels of the last pixel of the linear group in the 1st image.
|
||||
// If the pixel has greater than 1 not black neighbour pixel, it is a border of a shape.
|
||||
// Otherwise, it may be a topological edge, for example.
|
||||
aNeighboursNb = 0;
|
||||
for (Standard_Size aNgbrIter = 0; aNgbrIter < NEIGHBOR_PIXELS_NB; ++aNgbrIter)
|
||||
{
|
||||
if (!NEIGHBOR_PIXELS[aNgbrIter].isBlack (aDataRef, aRow1, aCol1))
|
||||
{
|
||||
++aNeighboursNb;
|
||||
}
|
||||
}
|
||||
|
||||
if (aNeighboursNb > 1)
|
||||
{
|
||||
myLinearGroups.Add (aGroupId);
|
||||
}
|
||||
}
|
||||
} // for groups...
|
||||
|
||||
// number of different groups of pixels (except linear groups)
|
||||
Standard_Integer aNbDiffColors = 0;
|
||||
aGroupId = 1;
|
||||
for (ListOfMapOfInteger::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next(), ++aGroupId)
|
||||
{
|
||||
if (!myLinearGroups.Contains (aGroupId))
|
||||
++aNbDiffColors;
|
||||
}
|
||||
|
||||
return aNbDiffColors;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : releaseGroupsOfDiffPixels
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void Image_Diff::releaseGroupsOfDiffPixels()
|
||||
{
|
||||
for (ListOfMapOfInteger::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next())
|
||||
{
|
||||
TColStd_MapOfInteger*& aGroup = aGrIter.ChangeValue();
|
||||
delete aGroup;
|
||||
}
|
||||
myGroupsOfDiffPixels.Clear();
|
||||
myLinearGroups.Clear();
|
||||
}
|
135
src/Image/Image_Diff.hxx
Normal file
135
src/Image/Image_Diff.hxx
Normal file
@@ -0,0 +1,135 @@
|
||||
// Created on: 2012-07-10
|
||||
// Created by: VRO
|
||||
// Copyright (c) 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.
|
||||
|
||||
#ifndef _Image_Diff_H__
|
||||
#define _Image_Diff_H__
|
||||
|
||||
#include <Image_PixMap.hxx>
|
||||
#include <TCollection_AsciiString.hxx>
|
||||
#include <TColStd_MapOfInteger.hxx>
|
||||
#include <NCollection_List.hxx>
|
||||
#include <NCollection_Vector.hxx>
|
||||
|
||||
//! This class compares two images pixel-by-pixel.
|
||||
//! It uses the following methods to ignore the difference between images:
|
||||
//! - Black/White comparison. It makes the images 2-colored before the comparison.
|
||||
//! - Equality with tolerance. Colors of two pixels are considered the same if the
|
||||
//! differnce of their color is less than a tolerance.
|
||||
//! - Border filter. The algorithm ignores alone independent pixels,
|
||||
//! which are different on both images, ignores the "border effect" -
|
||||
//! the difference caused by triangles located at angle about 0 or 90 degrees to the user.
|
||||
//!
|
||||
//! Border filter ignores a difference in implementation of
|
||||
//! anti-aliasing and other effects on boundary of a shape.
|
||||
//! The triangles of a boundary zone are usually located so that their normals point aside the user
|
||||
//! (about 90 degree between the normal and the direction to the user's eye).
|
||||
//! Deflection of the light for such a triangle depends on implementation of the video driver.
|
||||
//! In order to skip this difference the following algorithm is used:
|
||||
//! a) "Different" pixels are groupped and checked on "one-pixel width line".
|
||||
//! indeed, the pixels may represent not a line, but any curve.
|
||||
//! But the width of this curve should be not more than a pixel.
|
||||
//! This group of pixels become a candidate to be ignored because of boundary effect.
|
||||
//! b) The group of pixels is checked on belonging to a "shape".
|
||||
//! Neighbour pixels are checked from the reference image.
|
||||
//! This test confirms a fact that the group of pixels belongs to a shape and
|
||||
//! represent a boundary of the shape.
|
||||
//! In this case the whole group of pixels is ignored (considered as same).
|
||||
//! Otherwise, the group of pixels may represent a geometrical curve in the viewer 3D
|
||||
//! and should be considered as "different".
|
||||
class Image_Diff : public Standard_Transient
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
//! An empty constructor. Init() should be called for initialization.
|
||||
Standard_EXPORT Image_Diff();
|
||||
|
||||
//! Desctructor.
|
||||
Standard_EXPORT virtual ~Image_Diff();
|
||||
|
||||
//! Initialize algorithm by two images.
|
||||
//! @return false if images has different or unsupported pixel format.
|
||||
Standard_EXPORT Standard_Boolean Init (const Handle(Image_PixMap)& theImageRef,
|
||||
const Handle(Image_PixMap)& theImageNew,
|
||||
const Standard_Boolean theToBlackWhite = Standard_False);
|
||||
|
||||
//! Initialize algorithm by two images (will be loaded from files).
|
||||
//! @return false if images couldn't be opened or their format is unsupported.
|
||||
Standard_EXPORT Standard_Boolean Init (const TCollection_AsciiString& theImgPathRef,
|
||||
const TCollection_AsciiString& theImgPathNew,
|
||||
const Standard_Boolean theToBlackWhite = Standard_False);
|
||||
|
||||
//! Color tolerance for equality check. Should be within range 0..1:
|
||||
//! Corresponds to a difference between white and black colors (maximum difference).
|
||||
//! By default, the tolerance is equal to 0 thus equality check will return false for any different colors.
|
||||
Standard_EXPORT void SetColorTolerance (const Standard_Real theTolerance);
|
||||
|
||||
//! Color tolerance for equality check.
|
||||
Standard_EXPORT Standard_Real ColorTolerance() const;
|
||||
|
||||
//! Sets taking into account (ignoring) a "border effect" on comparison of images.
|
||||
//! The border effect is caused by a border of shaded shapes in the viewer 3d.
|
||||
//! Triangles of this area are located at about 0 or 90 degrees to the user.
|
||||
//! Therefore, they deflect light differently according to implementation of a video card driver.
|
||||
//! This flag allows to detect such a "border" area and skip it from comparison of images.
|
||||
//! Filter turned OFF by default.
|
||||
Standard_EXPORT void SetBorderFilterOn (const Standard_Boolean theToIgnore);
|
||||
|
||||
//! Returns a flag of taking into account (ignoring) a border effect in comparison of images.
|
||||
Standard_EXPORT Standard_Boolean IsBorderFilterOn() const;
|
||||
|
||||
//! Compares two images. It returns a number of different pixels (or groups of pixels).
|
||||
//! It returns -1 if algorithm not initialized before.
|
||||
Standard_EXPORT Standard_Integer Compare();
|
||||
|
||||
//! Saves a difference between two images as white pixels on black backgroud.
|
||||
Standard_EXPORT Standard_Boolean SaveDiffImage (Image_PixMap& theDiffImage) const;
|
||||
|
||||
//! Saves a difference between two images as white pixels on black backgroud.
|
||||
Standard_EXPORT Standard_Boolean SaveDiffImage (const TCollection_AsciiString& theDiffPath) const;
|
||||
|
||||
protected:
|
||||
|
||||
//! Perform border filter algorithm.
|
||||
Standard_EXPORT Standard_Integer ignoreBorderEffect();
|
||||
|
||||
//! Release dynamically allocated memory.
|
||||
Standard_EXPORT void releaseGroupsOfDiffPixels();
|
||||
|
||||
protected:
|
||||
|
||||
typedef NCollection_List<TColStd_MapOfInteger* > ListOfMapOfInteger;
|
||||
|
||||
Handle(Image_PixMap) myImageRef; //!< reference image to compare (from)
|
||||
Handle(Image_PixMap) myImageNew; //!< new image to compare (to)
|
||||
Standard_Real myColorTolerance; //!< tolerance for equality check (0..1, 0 - any not equal, 1 - opposite colors)
|
||||
Standard_Boolean myIsBorderFilterOn; //!< perform algorithm with border effect filter
|
||||
ListOfMapOfInteger myGroupsOfDiffPixels;
|
||||
NCollection_Vector<Standard_Size> myDiffPixels; //!< different pixels (position packed into integer)
|
||||
TColStd_MapOfInteger myLinearGroups;
|
||||
|
||||
public:
|
||||
|
||||
DEFINE_STANDARD_RTTI(Image_Diff) // Type definition
|
||||
|
||||
};
|
||||
|
||||
DEFINE_STANDARD_HANDLE(Image_Diff, Standard_Transient)
|
||||
|
||||
#endif // _Image_Diff_H__
|
@@ -1,29 +0,0 @@
|
||||
// Copyright (c) 1999-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.
|
||||
|
||||
#ifndef _Image_HPrivateImage_HeaderFile
|
||||
#define _Image_HPrivateImage_HeaderFile
|
||||
|
||||
#include <NCollection_Handle.hxx>
|
||||
|
||||
// This typedef shadows the private image storage class
|
||||
// Currently FreeImagePlus is used
|
||||
|
||||
class fipImage;
|
||||
typedef NCollection_Handle<fipImage> Image_HPrivateImage;
|
||||
|
||||
#endif /*_Image_HPrivateImage_HeaderFile*/
|
@@ -1,147 +0,0 @@
|
||||
-- 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.
|
||||
|
||||
|
||||
class PixMap from Image
|
||||
|
||||
---Version:
|
||||
|
||||
---Purpose: This class defines a system-independent bitmap
|
||||
|
||||
---Keywords: Bitmap, Pixmap
|
||||
|
||||
inherits
|
||||
PixMap from Aspect
|
||||
|
||||
uses
|
||||
Handle from Aspect,
|
||||
TypeOfImage from Image,
|
||||
HPrivateImage from Image,
|
||||
CRawBufferData from Image,
|
||||
Color from Quantity,
|
||||
Parameter from Quantity
|
||||
|
||||
raises
|
||||
PixmapDefinitionError from Aspect,
|
||||
PixmapError from Aspect
|
||||
|
||||
is
|
||||
|
||||
Create ( theWidth, theHeight : Integer from Standard;
|
||||
theType : TypeOfImage from Image )
|
||||
returns mutable PixMap from Image
|
||||
raises PixmapDefinitionError from Aspect;
|
||||
---Level: Public
|
||||
---Purpose:
|
||||
-- Allocate the bitmap with requested dimensions.
|
||||
-- Allowed image types:
|
||||
-- - Image_TOI_RGB (color image, 1 byte per component);
|
||||
-- - Image_TOI_RGBA (color image with alpha channel);
|
||||
-- - Image_TOI_RGBF (color image, 1 float per component);
|
||||
-- - Image_TOI_RGBAF (color image with alpha channel);
|
||||
-- - Image_TOI_FLOAT (grey image, 1 float per pixel).
|
||||
|
||||
Create ( theDataPtr : PByte from Standard;
|
||||
theWidth, theHeight : Integer from Standard;
|
||||
thePitch : Integer from Standard;
|
||||
theBitsPerPixel : Integer from Standard;
|
||||
theIsTopDown : Boolean from Standard )
|
||||
returns mutable PixMap from Image
|
||||
raises PixmapDefinitionError from Aspect;
|
||||
---Level: Public
|
||||
---Purpose:
|
||||
-- Create a bitmap by copying an existing buffer.
|
||||
|
||||
---------------------------------------------------
|
||||
-- Category: Methods to modify the class definition
|
||||
---------------------------------------------------
|
||||
|
||||
Destroy ( me : mutable )
|
||||
---Level: Advanced
|
||||
---Purpose:
|
||||
-- Destroies the Bitmap
|
||||
---C++: alias ~
|
||||
---Trigger: Raises if Bitmap is not defined properly
|
||||
raises PixmapError from Aspect is virtual;
|
||||
|
||||
Dump ( me;
|
||||
theFilename : CString from Standard;
|
||||
theGammaCorr : Real from Standard = 1.0 )
|
||||
returns Boolean from Standard
|
||||
---Level: Advanced
|
||||
---Purpose:
|
||||
-- Dumps the Bitmap to an image file with
|
||||
-- an optional gamma correction value
|
||||
-- and returns TRUE if the dump occurs normaly.
|
||||
raises PixmapError from Aspect is virtual;
|
||||
|
||||
----------------------------
|
||||
-- Category: Inquire methods
|
||||
----------------------------
|
||||
|
||||
PixmapID ( me ) returns Handle from Aspect is virtual;
|
||||
---Level: Advanced
|
||||
---Purpose:
|
||||
-- Returns NULL handle
|
||||
---Category: Inquire methods
|
||||
|
||||
----------------------------
|
||||
-- Category: Access methods
|
||||
----------------------------
|
||||
|
||||
AccessBuffer ( me : in;
|
||||
theBufferInfo : in out CRawBufferData from Image )
|
||||
is static;
|
||||
---Purpose:
|
||||
-- Fill the structure for low-level access to the bitmap data.
|
||||
-- It is up to you to interpret these bytes correctly!
|
||||
-- Important notice: image stored upside-down in the memory,
|
||||
-- first image row is an last scanline in
|
||||
-- the memory buffer.
|
||||
-- If image was created with type Image_TOI_FLOAT buffer
|
||||
-- format will be set to TDepthComponent. You can override
|
||||
-- this field with another one-channel buffer format because
|
||||
-- it useless for bitmap definition.
|
||||
|
||||
PixelColor ( me : in;
|
||||
theX, theY : in Integer from Standard )
|
||||
returns Color from Quantity
|
||||
is virtual;
|
||||
---Purpose:
|
||||
-- Returns the pixel color. This function is relatively slow,
|
||||
-- use AccessBuffer() instead for stream operations.
|
||||
-- Note that this function convert input theY coordinate
|
||||
-- to count off from top of an image (while in memory it stored
|
||||
-- upside-down).
|
||||
|
||||
PixelColor ( me : in;
|
||||
theX, theY : in Integer from Standard;
|
||||
theAlpha : out Parameter from Quantity )
|
||||
returns Color from Quantity;
|
||||
---Purpose:
|
||||
-- Returns the pixel color. This function is relatively slow,
|
||||
-- use AccessBuffer() instead for stream operations.
|
||||
-- theAlpha argument is set to color intensity (0 - transparent, 1 - opaque)
|
||||
-- Note that this function convert input theY coordinate
|
||||
-- to count off from top of an image (while in memory it stored
|
||||
-- upside-down).
|
||||
|
||||
fields
|
||||
myImage : HPrivateImage from Image is protected;
|
||||
end PixMap;
|
@@ -1,6 +1,6 @@
|
||||
// Created on: 2010-09-16
|
||||
// Created by: KGV
|
||||
// Copyright (c) 2010-2012 OPEN CASCADE SAS
|
||||
// Created on: 2012-07-18
|
||||
// Created by: Kirill GAVRILOV
|
||||
// Copyright (c) 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
|
||||
@@ -17,414 +17,209 @@
|
||||
// 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>
|
||||
#include <Image_PixMap.hxx>
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <mm_malloc.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
|
||||
template<typename TypePtr>
|
||||
inline TypePtr MemAllocAligned (const Standard_Size& theBytesCount,
|
||||
const Standard_Size& theAlign = 16)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return (TypePtr )_aligned_malloc (theBytesCount, theAlign);
|
||||
#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,
|
||||
Quantity_Parameter& theAlpha) const
|
||||
{
|
||||
RGBQuad_t* aPixel = (RGBQuad_t* )&getScanLine (theRow)[theCol * myBytesPerPixel];
|
||||
theAlpha = (myBytesPerPixel > 3) ? (Standard_Real (aPixel->rgbReserved) / 255.0) : 1.0;
|
||||
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;
|
||||
|
||||
};
|
||||
return (TypePtr ) _mm_malloc (theBytesCount, theAlign);
|
||||
#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()
|
||||
inline void MemFreeAligned (void* thePtrAligned)
|
||||
{
|
||||
#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);
|
||||
#if defined(_MSC_VER)
|
||||
_aligned_free (thePtrAligned);
|
||||
#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);
|
||||
//
|
||||
_mm_free (thePtrAligned);
|
||||
#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
|
||||
}
|
||||
IMPLEMENT_STANDARD_HANDLE (Image_PixMap, Standard_Transient)
|
||||
IMPLEMENT_STANDARD_RTTIEXT(Image_PixMap, Standard_Transient)
|
||||
|
||||
// =======================================================================
|
||||
// function : PixelColor
|
||||
// function : Image_PixMap
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX,
|
||||
const Standard_Integer theY) const
|
||||
Image_PixMap::Image_PixMap()
|
||||
: myImgFormat (Image_PixMap::ImgGray),
|
||||
myIsOwnPointer (true)
|
||||
{
|
||||
Quantity_Parameter aDummy;
|
||||
return PixelColor (theX, theY, aDummy);
|
||||
memset (&myData, 0, sizeof(myData));
|
||||
myData.mySizeBPP = 1;
|
||||
myData.myTopToDown = 1;
|
||||
setFormat (Image_PixMap::ImgGray);
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : ~Image_PixMap
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Image_PixMap::~Image_PixMap()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
Standard_Size Image_PixMap::SizePixelBytes (const Image_PixMap::ImgFormat thePixelFormat)
|
||||
{
|
||||
switch (thePixelFormat)
|
||||
{
|
||||
case ImgGrayF:
|
||||
return sizeof(float);
|
||||
case ImgRGBAF:
|
||||
case ImgBGRAF:
|
||||
return sizeof(float) * 4;
|
||||
case ImgRGBF:
|
||||
case ImgBGRF:
|
||||
return sizeof(float) * 3;
|
||||
case ImgRGBA:
|
||||
case ImgBGRA:
|
||||
return 4;
|
||||
case ImgRGB32:
|
||||
case ImgBGR32:
|
||||
return 4;
|
||||
case ImgRGB:
|
||||
case ImgBGR:
|
||||
return 3;
|
||||
case ImgGray:
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : setFormat
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void Image_PixMap::setFormat (Image_PixMap::ImgFormat thePixelFormat)
|
||||
{
|
||||
myImgFormat = thePixelFormat;
|
||||
myData.mySizeBPP = SizePixelBytes (myImgFormat);
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : setTopDown
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void Image_PixMap::setTopDown()
|
||||
{
|
||||
myData.myTopRowPtr = ((myData.myTopToDown == 1 || myData.myDataPtr == NULL)
|
||||
? myData.myDataPtr : (myData.myDataPtr + myData.mySizeRowBytes * (myData.mySizeY - 1)));
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : InitWrapper
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
bool Image_PixMap::InitWrapper (Image_PixMap::ImgFormat thePixelFormat,
|
||||
Standard_Byte* theDataPtr,
|
||||
const Standard_Size theSizeX,
|
||||
const Standard_Size theSizeY,
|
||||
const Standard_Size theSizeRowBytes)
|
||||
{
|
||||
Clear (thePixelFormat);
|
||||
if ((theSizeX == 0) || (theSizeY == 0) || (theDataPtr == NULL))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
myData.mySizeX = theSizeX;
|
||||
myData.mySizeY = theSizeY;
|
||||
myData.mySizeRowBytes = (theSizeRowBytes != 0) ? theSizeRowBytes : (theSizeX * myData.mySizeBPP);
|
||||
myData.myDataPtr = theDataPtr;
|
||||
myIsOwnPointer = false;
|
||||
setTopDown();
|
||||
return true;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : InitTrash
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
bool Image_PixMap::InitTrash (Image_PixMap::ImgFormat thePixelFormat,
|
||||
const Standard_Size theSizeX,
|
||||
const Standard_Size theSizeY,
|
||||
const Standard_Size theSizeRowBytes)
|
||||
{
|
||||
Clear (thePixelFormat);
|
||||
if ((theSizeX == 0) || (theSizeY == 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
myData.mySizeX = theSizeX;
|
||||
myData.mySizeY = theSizeY;
|
||||
myData.mySizeRowBytes = myData.mySizeX * myData.mySizeBPP;
|
||||
if (theSizeRowBytes > myData.mySizeRowBytes)
|
||||
{
|
||||
// use argument only if it greater
|
||||
myData.mySizeRowBytes = theSizeRowBytes;
|
||||
}
|
||||
myData.myDataPtr = MemAllocAligned<Standard_Byte*> (SizeBytes());
|
||||
myIsOwnPointer = true;
|
||||
setTopDown();
|
||||
return myData.myDataPtr != NULL;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : InitZero
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
bool Image_PixMap::InitZero (Image_PixMap::ImgFormat thePixelFormat,
|
||||
const Standard_Size theSizeX,
|
||||
const Standard_Size theSizeY,
|
||||
const Standard_Size theSizeRowBytes,
|
||||
const Standard_Byte theValue)
|
||||
{
|
||||
if (!InitTrash (thePixelFormat, theSizeX, theSizeY, theSizeRowBytes))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
memset (myData.myDataPtr, (int )theValue, SizeBytes());
|
||||
return true;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : InitCopy
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
bool Image_PixMap::InitCopy (const Image_PixMap& theCopy)
|
||||
{
|
||||
if (&theCopy == this)
|
||||
{
|
||||
// self-copying disallowed
|
||||
return false;
|
||||
}
|
||||
if (InitTrash (theCopy.myImgFormat, theCopy.myData.mySizeX, theCopy.myData.mySizeY, theCopy.myData.mySizeRowBytes))
|
||||
{
|
||||
memcpy (myData.myDataPtr, theCopy.myData.myDataPtr, theCopy.SizeBytes());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Clear
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void Image_PixMap::Clear (Image_PixMap::ImgFormat thePixelFormat)
|
||||
{
|
||||
if (myIsOwnPointer && (myData.myDataPtr != NULL))
|
||||
{
|
||||
MemFreeAligned (myData.myDataPtr);
|
||||
}
|
||||
myData.myDataPtr = myData.myTopRowPtr = NULL;
|
||||
myIsOwnPointer = true;
|
||||
myData.mySizeX = myData.mySizeY = myData.mySizeRowBytes = 0;
|
||||
setFormat (thePixelFormat);
|
||||
myData.myTopToDown = 1;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
@@ -435,64 +230,130 @@ Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX,
|
||||
const Standard_Integer theY,
|
||||
Quantity_Parameter& theAlpha) const
|
||||
{
|
||||
Standard_Integer aScanlineId = myImage->getHeight() - theY - 1;
|
||||
if (theX < 0 || (unsigned int )theX >= (unsigned int )myImage->getWidth() ||
|
||||
theY < 0 || (unsigned int )theY >= (unsigned int )myImage->getHeight())
|
||||
if (IsEmpty() ||
|
||||
theX < 0 || (Standard_Size )theX >= myData.mySizeX ||
|
||||
theY < 0 || (Standard_Size )theY >= myData.mySizeY)
|
||||
{
|
||||
theAlpha = 0.0; // transparent
|
||||
return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB);
|
||||
}
|
||||
#ifdef HAVE_FREEIMAGE
|
||||
else if (myImage->getImageType() == FIT_BITMAP)
|
||||
|
||||
switch (myImgFormat)
|
||||
{
|
||||
RGBQUAD aValue; memset (&aValue, 0, sizeof(aValue));
|
||||
myImage->getPixelColor (theX, aScanlineId, &aValue);
|
||||
theAlpha = (myImage->getColorType() == FIC_RGBALPHA) ? (Standard_Real (aValue.rgbReserved) / 255.0) : 1.0;
|
||||
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 ImgGrayF:
|
||||
{
|
||||
case FIT_FLOAT:
|
||||
{
|
||||
float* aScanLine = (float* )myImage->getScanLine (aScanlineId);
|
||||
Quantity_Parameter aValue = Quantity_Parameter (aScanLine[theX]);
|
||||
theAlpha = 1.0; // opaque
|
||||
return Quantity_Color (aValue, aValue, aValue, Quantity_TOC_RGB);
|
||||
}
|
||||
case FIT_RGBF:
|
||||
{
|
||||
FIRGBF* aScanLine = (FIRGBF* )myImage->getScanLine (aScanlineId);
|
||||
FIRGBF* aPixel = &aScanLine[theX];
|
||||
theAlpha = 1.0; // opaque
|
||||
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];
|
||||
theAlpha = aPixel->alpha;
|
||||
return Quantity_Color (Quantity_Parameter (aPixel->red),
|
||||
Quantity_Parameter (aPixel->green),
|
||||
Quantity_Parameter (aPixel->blue),
|
||||
Quantity_TOC_RGB);
|
||||
}
|
||||
default:
|
||||
{
|
||||
// not supported image type
|
||||
theAlpha = 0.0; // transparent
|
||||
return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB);
|
||||
}
|
||||
const Standard_ShortReal& aPixel = Value<Standard_ShortReal> (theY, theX);
|
||||
theAlpha = 1.0; // opaque
|
||||
return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel)),
|
||||
Quantity_Parameter (Standard_Real (aPixel)),
|
||||
Quantity_Parameter (Standard_Real (aPixel)),
|
||||
Quantity_TOC_RGB);
|
||||
break;
|
||||
}
|
||||
case ImgRGBAF:
|
||||
{
|
||||
const Image_ColorRGBAF& aPixel = Value<Image_ColorRGBAF> (theY, theX);
|
||||
theAlpha = aPixel.a();
|
||||
return Quantity_Color (Quantity_Parameter (aPixel.r()),
|
||||
Quantity_Parameter (aPixel.g()),
|
||||
Quantity_Parameter (aPixel.b()),
|
||||
Quantity_TOC_RGB);
|
||||
}
|
||||
case ImgBGRAF:
|
||||
{
|
||||
const Image_ColorBGRAF& aPixel = Value<Image_ColorBGRAF> (theY, theX);
|
||||
theAlpha = aPixel.a();
|
||||
return Quantity_Color (Quantity_Parameter (aPixel.r()),
|
||||
Quantity_Parameter (aPixel.g()),
|
||||
Quantity_Parameter (aPixel.b()),
|
||||
Quantity_TOC_RGB);
|
||||
}
|
||||
case ImgRGBF:
|
||||
{
|
||||
const Image_ColorRGBF& aPixel = Value<Image_ColorRGBF> (theY, theX);
|
||||
theAlpha = 1.0; // opaque
|
||||
return Quantity_Color (Quantity_Parameter (aPixel.r()),
|
||||
Quantity_Parameter (aPixel.g()),
|
||||
Quantity_Parameter (aPixel.b()),
|
||||
Quantity_TOC_RGB);
|
||||
}
|
||||
case ImgBGRF:
|
||||
{
|
||||
const Image_ColorBGRF& aPixel = Value<Image_ColorBGRF> (theY, theX);
|
||||
theAlpha = 1.0; // opaque
|
||||
return Quantity_Color (Quantity_Parameter (aPixel.r()),
|
||||
Quantity_Parameter (aPixel.g()),
|
||||
Quantity_Parameter (aPixel.b()),
|
||||
Quantity_TOC_RGB);
|
||||
}
|
||||
case ImgRGBA:
|
||||
{
|
||||
const Image_ColorRGBA& aPixel = Value<Image_ColorRGBA> (theY, theX);
|
||||
theAlpha = Standard_Real (aPixel.a()) / 255.0;
|
||||
return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel.r()) / 255.0),
|
||||
Quantity_Parameter (Standard_Real (aPixel.g()) / 255.0),
|
||||
Quantity_Parameter (Standard_Real (aPixel.b()) / 255.0),
|
||||
Quantity_TOC_RGB);
|
||||
}
|
||||
case ImgBGRA:
|
||||
{
|
||||
const Image_ColorBGRA& aPixel = Value<Image_ColorBGRA> (theY, theX);
|
||||
theAlpha = Standard_Real (aPixel.a()) / 255.0;
|
||||
return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel.r()) / 255.0),
|
||||
Quantity_Parameter (Standard_Real (aPixel.g()) / 255.0),
|
||||
Quantity_Parameter (Standard_Real (aPixel.b()) / 255.0),
|
||||
Quantity_TOC_RGB);
|
||||
}
|
||||
case ImgRGB32:
|
||||
{
|
||||
const Image_ColorRGB32& aPixel = Value<Image_ColorRGB32> (theY, theX);
|
||||
theAlpha = 1.0; // opaque
|
||||
return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel.r()) / 255.0),
|
||||
Quantity_Parameter (Standard_Real (aPixel.g()) / 255.0),
|
||||
Quantity_Parameter (Standard_Real (aPixel.b()) / 255.0),
|
||||
Quantity_TOC_RGB);
|
||||
}
|
||||
case ImgBGR32:
|
||||
{
|
||||
const Image_ColorBGR32& aPixel = Value<Image_ColorBGR32> (theY, theX);
|
||||
theAlpha = 1.0; // opaque
|
||||
return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel.r()) / 255.0),
|
||||
Quantity_Parameter (Standard_Real (aPixel.g()) / 255.0),
|
||||
Quantity_Parameter (Standard_Real (aPixel.b()) / 255.0),
|
||||
Quantity_TOC_RGB);
|
||||
}
|
||||
case ImgRGB:
|
||||
{
|
||||
const Image_ColorRGB& aPixel = Value<Image_ColorRGB> (theY, theX);
|
||||
theAlpha = 1.0; // opaque
|
||||
return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel.r()) / 255.0),
|
||||
Quantity_Parameter (Standard_Real (aPixel.g()) / 255.0),
|
||||
Quantity_Parameter (Standard_Real (aPixel.b()) / 255.0),
|
||||
Quantity_TOC_RGB);
|
||||
}
|
||||
case ImgBGR:
|
||||
{
|
||||
const Image_ColorBGR& aPixel = Value<Image_ColorBGR> (theY, theX);
|
||||
theAlpha = 1.0; // opaque
|
||||
return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel.r()) / 255.0),
|
||||
Quantity_Parameter (Standard_Real (aPixel.g()) / 255.0),
|
||||
Quantity_Parameter (Standard_Real (aPixel.b()) / 255.0),
|
||||
Quantity_TOC_RGB);
|
||||
}
|
||||
case ImgGray:
|
||||
{
|
||||
const Standard_Byte& aPixel = Value<Standard_Byte> (theY, theX);
|
||||
theAlpha = 1.0; // opaque
|
||||
return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel) / 255.0),
|
||||
Quantity_Parameter (Standard_Real (aPixel) / 255.0),
|
||||
Quantity_Parameter (Standard_Real (aPixel) / 255.0),
|
||||
Quantity_TOC_RGB);
|
||||
}
|
||||
default:
|
||||
{
|
||||
// not supported image type
|
||||
theAlpha = 0.0; // transparent
|
||||
return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB);
|
||||
}
|
||||
}
|
||||
#else
|
||||
return myImage->getPixelColor (theX, aScanlineId, theAlpha);
|
||||
#endif
|
||||
}
|
||||
|
294
src/Image/Image_PixMap.hxx
Normal file
294
src/Image/Image_PixMap.hxx
Normal file
@@ -0,0 +1,294 @@
|
||||
// Created on: 2012-07-18
|
||||
// Created by: Kirill GAVRILOV
|
||||
// Copyright (c) 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.
|
||||
|
||||
#ifndef _Image_PixMap_H__
|
||||
#define _Image_PixMap_H__
|
||||
|
||||
#include <Image_PixMapData.hxx>
|
||||
#include <Standard_Transient.hxx>
|
||||
#include <Quantity_Color.hxx>
|
||||
|
||||
//! Class represents packed image plane.
|
||||
class Image_PixMap : public Standard_Transient
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
//! This enumeration define packed image plane formats
|
||||
typedef enum tagFormat {
|
||||
ImgUNKNOWN = 0, //!< unsupported or unknown format
|
||||
ImgGray = 1, //!< 1 byte per pixel
|
||||
ImgRGB, //!< 3 bytes packed RGB image plane
|
||||
ImgBGR, //!< same as RGB but with different components order
|
||||
ImgRGB32, //!< 4 bytes packed RGB image plane (1 extra byte for alignment, may have undefined value)
|
||||
ImgBGR32, //!< same as RGB but with different components order
|
||||
ImgRGBA, //!< 4 bytes packed RGBA image plane
|
||||
ImgBGRA, //!< same as RGBA but with different components order
|
||||
ImgGrayF, //!< 1 float (4-bytes) per pixel (1-component plane)
|
||||
ImgRGBF, //!< 3 floats (12-bytes) RGB image plane
|
||||
ImgBGRF, //!< same as RGBF but with different components order
|
||||
ImgRGBAF, //!< 4 floats (16-bytes) RGBA image plane
|
||||
ImgBGRAF, //!< same as RGBAF but with different components order
|
||||
} ImgFormat;
|
||||
|
||||
//! Determine Big-Endian at runtime
|
||||
static inline bool IsBigEndianHost()
|
||||
{
|
||||
union { int myInt; char myChar[sizeof(int)]; } aUnion;
|
||||
aUnion.myInt = 1;
|
||||
return !aUnion.myChar[0];
|
||||
}
|
||||
|
||||
public: // high-level API
|
||||
|
||||
inline ImgFormat Format() const
|
||||
{
|
||||
return myImgFormat;
|
||||
}
|
||||
|
||||
//! @return image width in pixels
|
||||
inline Standard_Size Width() const
|
||||
{
|
||||
return myData.mySizeX;
|
||||
}
|
||||
|
||||
//! @return image height in pixels
|
||||
inline Standard_Size Height() const
|
||||
{
|
||||
return myData.mySizeY;
|
||||
}
|
||||
|
||||
//! @return image width in pixels
|
||||
inline Standard_Size SizeX() const
|
||||
{
|
||||
return myData.mySizeX;
|
||||
}
|
||||
|
||||
//! @return image height in pixels
|
||||
inline Standard_Size SizeY() const
|
||||
{
|
||||
return myData.mySizeY;
|
||||
}
|
||||
|
||||
//! @return width / height.
|
||||
inline Standard_Real Ratio() const
|
||||
{
|
||||
return (myData.mySizeY > 0) ? (Standard_Real(myData.mySizeX) / Standard_Real(myData.mySizeY)) : 1.0;
|
||||
}
|
||||
|
||||
//! @return true if data is NULL.
|
||||
bool IsEmpty() const
|
||||
{
|
||||
return myData.myDataPtr == NULL;
|
||||
}
|
||||
|
||||
//! Empty constructor. Initialize the NULL image plane.
|
||||
Standard_EXPORT Image_PixMap();
|
||||
|
||||
//! Destructor
|
||||
Standard_EXPORT virtual ~Image_PixMap();
|
||||
|
||||
//! Returns the pixel color. This function is relatively slow.
|
||||
//! @param theX - column index from left
|
||||
//! @param theY - row index from top
|
||||
//! @return the pixel color
|
||||
inline Quantity_Color PixelColor (const Standard_Integer theX,
|
||||
const Standard_Integer theY) const
|
||||
{
|
||||
Quantity_Parameter aDummy;
|
||||
return PixelColor (theX, theY, aDummy);
|
||||
}
|
||||
|
||||
//! Returns the pixel color. This function is relatively slow.
|
||||
//! theAlpha argument is set to color intensity (0 - transparent, 1 - opaque)
|
||||
Standard_EXPORT Quantity_Color PixelColor (const Standard_Integer theX,
|
||||
const Standard_Integer theY,
|
||||
Quantity_Parameter& theAlpha) const;
|
||||
|
||||
//! Initialize image plane as wrapper over alien data.
|
||||
//! Data will not be copied! Notice that caller should ensure
|
||||
//! that data pointer will not be released during this wrapper lifetime.
|
||||
//! You may call InitCopy() to perform data copying.
|
||||
Standard_EXPORT virtual bool InitWrapper (ImgFormat thePixelFormat,
|
||||
Standard_Byte* theDataPtr,
|
||||
const Standard_Size theSizeX,
|
||||
const Standard_Size theSizeY,
|
||||
const Standard_Size theSizeRowBytes = 0);
|
||||
|
||||
//! Initialize image plane with required dimensions.
|
||||
//! Memory will be left uninitialized (performance trick).
|
||||
Standard_EXPORT virtual bool InitTrash (ImgFormat thePixelFormat,
|
||||
const Standard_Size theSizeX,
|
||||
const Standard_Size theSizeY,
|
||||
const Standard_Size theSizeRowBytes = 0);
|
||||
|
||||
//! Initialize by copying data.
|
||||
//! If you want to copy alien data you should create wrapper using InitWrapper() before.
|
||||
Standard_EXPORT virtual bool InitCopy (const Image_PixMap& theCopy);
|
||||
|
||||
//! Initialize image plane with required dimensions.
|
||||
//! Buffer will be zeroed (black color for most formats).
|
||||
Standard_EXPORT bool InitZero (ImgFormat thePixelFormat,
|
||||
const Standard_Size theSizeX,
|
||||
const Standard_Size theSizeY,
|
||||
const Standard_Size theSizeRowBytes = 0,
|
||||
const Standard_Byte theValue = 0);
|
||||
|
||||
//! Method correctly deallocate internal buffer.
|
||||
Standard_EXPORT virtual void Clear (ImgFormat thePixelFormat = ImgGray);
|
||||
|
||||
public: // low-level API for batch-processing (pixels reading / comparison / modification)
|
||||
|
||||
//! Returns true if image data stored from Top to the Down (default).
|
||||
//! Some external APIs can return bottom-up data instead
|
||||
//! (topmost scanlines starts from the bottom in memory).
|
||||
//! Notice that access methods within this class automatically
|
||||
//! convert input row-index to apply this flag!
|
||||
//! You should use this flag only if interconnect with alien APIs and buffers.
|
||||
//! @return true if image data is top-down.
|
||||
inline bool IsTopDown() const
|
||||
{
|
||||
return myData.myTopToDown == 1;
|
||||
}
|
||||
|
||||
//! Setup scanlines order in memory - top-down or bottom-up.
|
||||
//! Drawers should explicitly specify this value if current state IsTopDown() was ignored!
|
||||
//! @param theIsTopDown - top-down flag.
|
||||
inline void SetTopDown (bool theIsTopDown)
|
||||
{
|
||||
myData.myTopToDown = (theIsTopDown ? 1 : Standard_Size(-1));
|
||||
setTopDown();
|
||||
}
|
||||
|
||||
//! Returns +1 if scanlines ordered in Top->Down order in memory and -1 otherwise.
|
||||
//! @return scanline increment for Top->Down iteration
|
||||
inline Standard_Size TopDownInc() const
|
||||
{
|
||||
return myData.myTopToDown;
|
||||
}
|
||||
|
||||
//! @return data pointer for low-level operations (copying entire buffer, parsing with extra tools etc.).
|
||||
inline const Standard_Byte* Data() const
|
||||
{
|
||||
return myData.myDataPtr;
|
||||
}
|
||||
|
||||
//! @return data pointer for low-level operations (copying entire buffer, parsing with extra tools etc.).
|
||||
inline Standard_Byte* ChangeData()
|
||||
{
|
||||
return myData.myDataPtr;
|
||||
}
|
||||
|
||||
//! @return data pointer to requested row (first column).
|
||||
inline const Standard_Byte* Row (const Standard_Size theRow) const
|
||||
{
|
||||
return myData.Row (theRow);
|
||||
}
|
||||
|
||||
//! @return data pointer to requested row (first column).
|
||||
inline Standard_Byte* ChangeRow (const Standard_Size theRow)
|
||||
{
|
||||
return myData.ChangeRow (theRow);
|
||||
}
|
||||
|
||||
//! @return bytes reserved for one pixel (may include extra bytes for alignment).
|
||||
inline Standard_Size SizePixelBytes() const
|
||||
{
|
||||
return myData.mySizeBPP;
|
||||
}
|
||||
|
||||
//! @return bytes reserved for one pixel (may include extra bytes for alignment).
|
||||
static Standard_Size SizePixelBytes (const Image_PixMap::ImgFormat thePixelFormat);
|
||||
|
||||
//! @return bytes reserved per row.
|
||||
//! Could be larger than needed to store packed row (extra bytes for alignment etc.).
|
||||
inline Standard_Size SizeRowBytes() const
|
||||
{
|
||||
return myData.mySizeRowBytes;
|
||||
}
|
||||
|
||||
//! @return the extra bytes in the row.
|
||||
inline Standard_Size RowExtraBytes() const
|
||||
{
|
||||
return myData.mySizeRowBytes - myData.mySizeX * myData.mySizeBPP;
|
||||
}
|
||||
|
||||
//! Compute the maximal row alignment for current row size.
|
||||
//! @return maximal row alignment in bytes (up to 16 bytes).
|
||||
inline Standard_Size MaxRowAligmentBytes() const
|
||||
{
|
||||
return myData.MaxRowAligmentBytes();
|
||||
}
|
||||
|
||||
inline Standard_Size SizeBytes() const
|
||||
{
|
||||
return myData.SizeBytes();
|
||||
}
|
||||
|
||||
//! Access image buffer for write/read operations with specified color type.
|
||||
template <typename ColorType_t>
|
||||
inline Image_PixMapData<ColorType_t>& EditData()
|
||||
{
|
||||
return *(Image_PixMapData<ColorType_t>* )&myData;
|
||||
}
|
||||
|
||||
//! Access image buffer for read operations with specified color type.
|
||||
template <typename ColorType_t>
|
||||
inline const Image_PixMapData<ColorType_t>& ReadData() const
|
||||
{
|
||||
return *(Image_PixMapData<ColorType_t>* )&myData;
|
||||
}
|
||||
|
||||
//! Access image pixel with specified color type.
|
||||
template <typename ColorType_t>
|
||||
inline const ColorType_t& Value (const Standard_Size theRow,
|
||||
const Standard_Size theCol) const
|
||||
{
|
||||
return ((Image_PixMapData<ColorType_t>* )&myData)->Value (theRow, theCol);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
//! Setup pixel format
|
||||
Standard_EXPORT void setFormat (ImgFormat thePixelFormat);
|
||||
|
||||
//! Auxiliary method to setup myTopRowPtr
|
||||
Standard_EXPORT void setTopDown();
|
||||
|
||||
protected:
|
||||
|
||||
Image_PixMapData<Standard_Byte> myData;
|
||||
ImgFormat myImgFormat; //!< pixel format
|
||||
bool myIsOwnPointer; //!< if data was allocated by this class - flag is true
|
||||
|
||||
private:
|
||||
|
||||
//! Copying allowed only within Handles
|
||||
Image_PixMap (const Image_PixMap& );
|
||||
Image_PixMap& operator= (const Image_PixMap& );
|
||||
|
||||
public:
|
||||
|
||||
DEFINE_STANDARD_RTTI(Image_PixMap) // Type definition
|
||||
|
||||
};
|
||||
|
||||
DEFINE_STANDARD_HANDLE(Image_PixMap, Standard_Transient)
|
||||
|
||||
#endif // _Image_PixMap_H__
|
113
src/Image/Image_PixMapData.hxx
Normal file
113
src/Image/Image_PixMapData.hxx
Normal file
@@ -0,0 +1,113 @@
|
||||
// Created on: 2012-07-18
|
||||
// Created by: Kirill GAVRILOV
|
||||
// Copyright (c) 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.
|
||||
|
||||
#ifndef _Image_PixMapData_H__
|
||||
#define _Image_PixMapData_H__
|
||||
|
||||
#include <Image_Color.hxx>
|
||||
|
||||
//! POD template structure to access image buffer
|
||||
template<typename ColorType_t>
|
||||
struct Image_PixMapData
|
||||
{
|
||||
|
||||
//! @return data pointer for low-level operations (copying entire buffer, parsing with extra tools etc.).
|
||||
inline const ColorType_t* Data() const
|
||||
{
|
||||
return (const ColorType_t* )myDataPtr;
|
||||
}
|
||||
|
||||
//! @return data pointer for low-level operations (copying entire buffer, parsing with extra tools etc.).
|
||||
inline ColorType_t* ChangeData()
|
||||
{
|
||||
return (ColorType_t* )myDataPtr;
|
||||
}
|
||||
|
||||
//! @return data pointer to requested row (first column).
|
||||
inline const ColorType_t* Row (const Standard_Size theRow) const
|
||||
{
|
||||
return (ColorType_t* )(myTopRowPtr + mySizeRowBytes * theRow * myTopToDown);
|
||||
}
|
||||
|
||||
//! @return data pointer to requested row (first column).
|
||||
inline ColorType_t* ChangeRow (const Standard_Size theRow)
|
||||
{
|
||||
return (ColorType_t* )(myTopRowPtr + mySizeRowBytes * theRow * myTopToDown);
|
||||
}
|
||||
|
||||
//! @return data pointer to requested position.
|
||||
inline const ColorType_t& Value (const Standard_Size theRow,
|
||||
const Standard_Size theCol) const
|
||||
{
|
||||
return *(const ColorType_t* )(myTopRowPtr + mySizeRowBytes * theRow * myTopToDown + mySizeBPP * theCol);
|
||||
}
|
||||
|
||||
//! @return data pointer to requested position.
|
||||
inline ColorType_t& ChangeValue (const Standard_Size theRow,
|
||||
const Standard_Size theCol)
|
||||
{
|
||||
return *(ColorType_t* )(myTopRowPtr + mySizeRowBytes * theRow * myTopToDown + mySizeBPP * theCol);
|
||||
}
|
||||
|
||||
//! Compute the maximal row alignment for current row size.
|
||||
//! @return maximal row alignment in bytes (up to 16 bytes).
|
||||
inline Standard_Size MaxRowAligmentBytes() const
|
||||
{
|
||||
Standard_Size anAlignment = 2;
|
||||
for (; anAlignment <= 16; anAlignment <<= 1)
|
||||
{
|
||||
if ((mySizeRowBytes % anAlignment) != 0 || (Standard_Size(myDataPtr) % anAlignment) != 0)
|
||||
{
|
||||
return (anAlignment >> 1);
|
||||
}
|
||||
}
|
||||
return anAlignment;
|
||||
}
|
||||
|
||||
//! @return bytes allocated for the whole image plane.
|
||||
inline Standard_Size SizeBytes() const
|
||||
{
|
||||
return mySizeRowBytes * mySizeY;
|
||||
}
|
||||
|
||||
//! @return image width in pixels
|
||||
inline Standard_Size SizeX() const
|
||||
{
|
||||
return mySizeX;
|
||||
}
|
||||
|
||||
//! @return image height in pixels
|
||||
inline Standard_Size SizeY() const
|
||||
{
|
||||
return mySizeY;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Standard_Byte* myDataPtr; //!< pointer to the data
|
||||
Standard_Byte* myTopRowPtr; //!< pointer to the topmost row (depending on scanlines order in memory)
|
||||
Standard_Size mySizeBPP; //!< bytes per pixel
|
||||
Standard_Size mySizeX; //!< width in pixels
|
||||
Standard_Size mySizeY; //!< height in pixels
|
||||
Standard_Size mySizeRowBytes; //!< number of bytes per line (in most cases equal to 3 * sizeX)
|
||||
Standard_Size myTopToDown; //!< image scanlines direction in memory from Top to the Down
|
||||
|
||||
};
|
||||
|
||||
#endif // _Image_PixMapData_H__
|
Reference in New Issue
Block a user