1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-09-08 14:17:06 +03:00

Coding - Apply .clang-format formatting #286

Update empty method guards to new style with regex (see PR).
Used clang-format 18.1.8.
New actions to validate code formatting is added.
Update .clang-format with disabling of include sorting.
  It is temporary changes, then include will be sorted.
Apply formatting for /src and /tools folder.
The files with .hxx,.cxx,.lxx,.h,.pxx,.hpp,*.cpp extensions.
This commit is contained in:
dpasukhi
2025-01-25 20:15:22 +00:00
parent dbba6f1289
commit a5a7b3185b
14005 changed files with 1273539 additions and 1195567 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -27,20 +27,21 @@ struct FIBITMAP;
//! - *.bmp - bitmap image, lossless format without compression.
//! - *.ppm - PPM (Portable Pixmap Format), lossless format without compression.
//! - *.png - PNG (Portable Network Graphics) lossless format with compression.
//! - *.jpg, *.jpe, *.jpeg - JPEG/JIFF (Joint Photographic Experts Group) lossy format (compressed with quality losses). YUV color space used (automatically converted from/to RGB).
//! - *.jpg, *.jpe, *.jpeg - JPEG/JIFF (Joint Photographic Experts Group) lossy format (compressed
//! with quality losses). YUV color space used (automatically converted from/to RGB).
//! - *.tif, *.tiff - TIFF (Tagged Image File Format).
//! - *.tga - TGA (Truevision Targa Graphic), lossless format.
//! - *.gif - GIF (Graphical Interchange Format), lossy format. Color stored using palette (up to 256 distinct colors).
//! - *.exr - OpenEXR high dynamic-range format (supports float pixel formats).
//! - *.gif - GIF (Graphical Interchange Format), lossy format. Color stored using palette (up to
//! 256 distinct colors).
//! - *.exr - OpenEXR high dynamic-range format (supports float pixel formats).
class Image_AlienPixMap : public Image_PixMap
{
DEFINE_STANDARD_RTTIEXT(Image_AlienPixMap, Image_PixMap)
public:
//! Return default rows order used by underlying image library.
Standard_EXPORT static bool IsTopDownDefault();
public:
public:
//! Empty constructor.
Standard_EXPORT Image_AlienPixMap();
@@ -48,36 +49,28 @@ public:
Standard_EXPORT virtual ~Image_AlienPixMap();
//! Read image data from file.
bool Load (const TCollection_AsciiString& theFileName)
{
return Load (NULL, 0, theFileName);
}
bool Load(const TCollection_AsciiString& theFileName) { return Load(NULL, 0, theFileName); }
//! Read image data from stream.
Standard_EXPORT bool Load (std::istream& theStream,
const TCollection_AsciiString& theFileName);
Standard_EXPORT bool Load(std::istream& theStream, const TCollection_AsciiString& theFileName);
//! Read image data from memory buffer.
//! @param[in] theData memory pointer to read from;
//! when NULL, function will attempt to open theFileName file
//! @param[in] theLength memory buffer length
//! @param[in] theFileName optional file name
Standard_EXPORT bool Load (const Standard_Byte* theData,
const Standard_Size theLength,
const TCollection_AsciiString& theFileName);
Standard_EXPORT bool Load(const Standard_Byte* theData,
const Standard_Size theLength,
const TCollection_AsciiString& theFileName);
//! Write image data to file.
//! @param[in] theFileName file name to save
bool Save (const TCollection_AsciiString& theFileName)
{
return Save (NULL, 0, theFileName);
}
bool Save(const TCollection_AsciiString& theFileName) { return Save(NULL, 0, theFileName); }
//! Write image data to stream.
//! @param[out] theStream stream where to write
//! @param[in] theExtension image format
Standard_EXPORT bool Save (std::ostream& theStream,
const TCollection_AsciiString& theExtension);
Standard_EXPORT bool Save(std::ostream& theStream, const TCollection_AsciiString& theExtension);
//! Write image data to file or memory buffer using file extension to determine format.
//! @param[out] theBuffer buffer pointer where to write
@@ -85,28 +78,29 @@ public:
//! @param[in] theLength memory buffer length
//! @param[in] theFileName file name to save;
//! when theBuffer isn't NULL used only to determine format
Standard_EXPORT bool Save (Standard_Byte* theBuffer,
const Standard_Size theLength,
const TCollection_AsciiString& theFileName);
Standard_EXPORT bool Save(Standard_Byte* theBuffer,
const Standard_Size theLength,
const TCollection_AsciiString& theFileName);
//! Initialize image plane with required dimensions.
//! @param[in] thePixelFormat if specified pixel format doesn't supported by image library
//! than nearest supported will be used instead!
//! @param[in] theSizeRowBytes may be ignored by this class and required alignment will be used instead!
Standard_EXPORT virtual bool InitTrash (Image_Format thePixelFormat,
const Standard_Size theSizeX,
const Standard_Size theSizeY,
const Standard_Size theSizeRowBytes = 0) Standard_OVERRIDE;
//! @param[in] theSizeRowBytes may be ignored by this class and required alignment will be used
//! instead!
Standard_EXPORT virtual bool InitTrash(Image_Format thePixelFormat,
const Standard_Size theSizeX,
const Standard_Size theSizeY,
const Standard_Size theSizeRowBytes = 0) Standard_OVERRIDE;
//! Initialize by copying data.
Standard_EXPORT virtual bool InitCopy (const Image_PixMap& theCopy) Standard_OVERRIDE;
Standard_EXPORT virtual bool InitCopy(const Image_PixMap& theCopy) Standard_OVERRIDE;
//! Method correctly deallocate internal buffer.
Standard_EXPORT virtual void Clear() Standard_OVERRIDE;
//! Performs gamma correction on image.
//! @param[in] theGamma - gamma value to use; a value of 1.0 leaves the image alone
Standard_EXPORT bool AdjustGamma (const Standard_Real theGammaCorr);
Standard_EXPORT bool AdjustGamma(const Standard_Real theGammaCorr);
#if !defined(HAVE_FREEIMAGE) && defined(_WIN32)
//! Returns image palette.
@@ -114,29 +108,26 @@ public:
#endif
private:
//! Copying allowed only within Handles
Image_AlienPixMap (const Image_AlienPixMap& );
Image_AlienPixMap& operator= (const Image_AlienPixMap& );
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 (Image_Format thePixelFormat,
Standard_Byte* theDataPtr,
const Standard_Size theSizeX,
const Standard_Size theSizeY,
const Standard_Size theSizeRowBytes) Standard_OVERRIDE;
Standard_EXPORT virtual bool InitWrapper(Image_Format thePixelFormat,
Standard_Byte* theDataPtr,
const Standard_Size theSizeX,
const Standard_Size theSizeY,
const Standard_Size theSizeRowBytes) Standard_OVERRIDE;
//! Built-in PPM export
Standard_EXPORT bool savePPM (const TCollection_AsciiString& theFileName) const;
Standard_EXPORT bool savePPM(const TCollection_AsciiString& theFileName) const;
FIBITMAP* getImageToDump (const Standard_Integer theFormat);
FIBITMAP* getImageToDump(const Standard_Integer theFormat);
private:
FIBITMAP* myLibImage;
FIBITMAP* myLibImage;
IWICPalette* myPalette;
};
DEFINE_STANDARD_HANDLE(Image_AlienPixMap, Image_PixMap)

View File

@@ -26,13 +26,9 @@ struct Image_ColorRGB
typedef Standard_Byte ComponentType_t;
//! Returns the number of components.
static Standard_Integer Length()
{
return 3;
}
static Standard_Integer Length() { return 3; }
public: // access methods
//! Alias to 1st component (red intensity).
Standard_Byte r() const { return v[0]; }
@@ -52,9 +48,7 @@ public: // access methods
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)
@@ -65,10 +59,7 @@ struct Image_ColorRGB32
typedef Standard_Byte ComponentType_t;
//! Returns the number of components.
static Standard_Integer Length()
{
return 3;
}
static Standard_Integer Length() { return 3; }
//! Alias to 1st component (red intensity).
Standard_Byte r() const { return v[0]; }
@@ -95,9 +86,7 @@ struct Image_ColorRGB32
Standard_Byte& a_() { return v[3]; }
public:
Standard_Byte v[4];
};
//! POD structure for packed RGBA color value (4 bytes)
@@ -108,10 +97,7 @@ struct Image_ColorRGBA
typedef Standard_Byte ComponentType_t;
//! Returns the number of components.
static Standard_Integer Length()
{
return 4;
}
static Standard_Integer Length() { return 4; }
//! Alias to 1st component (red intensity).
Standard_Byte r() const { return v[0]; }
@@ -138,9 +124,7 @@ struct Image_ColorRGBA
Standard_Byte& a() { return v[3]; }
public:
Standard_Byte v[4];
};
//! POD structure for packed BGR color value (3 bytes)
@@ -151,10 +135,7 @@ struct Image_ColorBGR
typedef Standard_Byte ComponentType_t;
//! Returns the number of components.
static Standard_Integer Length()
{
return 3;
}
static Standard_Integer Length() { return 3; }
//! Alias to 3rd component (red intensity).
Standard_Byte r() const { return v[2]; }
@@ -175,9 +156,7 @@ struct Image_ColorBGR
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)
@@ -188,10 +167,7 @@ struct Image_ColorBGR32
typedef Standard_Byte ComponentType_t;
//! Returns the number of components.
static Standard_Integer Length()
{
return 3;
}
static Standard_Integer Length() { return 3; }
//! Alias to 3rd component (red intensity).
Standard_Byte r() const { return v[2]; }
@@ -218,9 +194,7 @@ struct Image_ColorBGR32
Standard_Byte& a_() { return v[3]; }
public:
Standard_Byte v[4];
};
//! POD structure for packed BGRA color value (4 bytes)
@@ -231,10 +205,7 @@ struct Image_ColorBGRA
typedef Standard_Byte ComponentType_t;
//! Returns the number of components.
static Standard_Integer Length()
{
return 4;
}
static Standard_Integer Length() { return 4; }
//! Alias to 3rd component (red intensity).
Standard_Byte r() const { return v[2]; }
@@ -261,9 +232,7 @@ struct Image_ColorBGRA
Standard_Byte& a() { return v[3]; }
public:
Standard_Byte v[4];
};
//! POD structure for packed float RG color value (2 floats)
@@ -299,10 +268,7 @@ struct Image_ColorRGBF
typedef Standard_ShortReal ComponentType_t;
//! Returns the number of components.
static Standard_Integer Length()
{
return 3;
}
static Standard_Integer Length() { return 3; }
//! Alias to 1st component (red intensity).
Standard_ShortReal r() const { return v[0]; }
@@ -323,9 +289,7 @@ struct Image_ColorRGBF
Standard_ShortReal& b() { return v[2]; }
public:
Standard_ShortReal v[3];
};
//! POD structure for packed BGR float color value (3 floats)
@@ -336,10 +300,7 @@ struct Image_ColorBGRF
typedef Standard_ShortReal ComponentType_t;
//! Returns the number of components.
static Standard_Integer Length()
{
return 3;
}
static Standard_Integer Length() { return 3; }
//! Alias to 3rd component (red intensity).
Standard_ShortReal r() const { return v[2]; }
@@ -360,9 +321,7 @@ struct Image_ColorBGRF
Standard_ShortReal& b() { return v[0]; }
public:
Standard_ShortReal v[3];
};
//! POD structure for packed RGBA color value (4 floats)
@@ -373,10 +332,7 @@ struct Image_ColorRGBAF
typedef Standard_ShortReal ComponentType_t;
//! Returns the number of components.
static Standard_Integer Length()
{
return 4;
}
static Standard_Integer Length() { return 4; }
//! Alias to 1st component (red intensity).
Standard_ShortReal r() const { return v[0]; }
@@ -403,9 +359,7 @@ struct Image_ColorRGBAF
Standard_ShortReal& a() { return v[3]; }
public:
Standard_ShortReal v[4];
};
//! POD structure for packed float BGRA color value (4 floats)
@@ -416,10 +370,7 @@ struct Image_ColorBGRAF
typedef Standard_ShortReal ComponentType_t;
//! Returns the number of components.
static Standard_Integer Length()
{
return 4;
}
static Standard_Integer Length() { return 4; }
//! Alias to 3rd component (red intensity).
Standard_ShortReal r() const { return v[2]; }
@@ -446,9 +397,7 @@ struct Image_ColorBGRAF
Standard_ShortReal& a() { return v[3]; }
public:
Standard_ShortReal v[4];
};
#endif // _Image_Color_H__

View File

@@ -16,16 +16,20 @@
#include <Image_Format.hxx>
//! List of compressed pixel formats natively supported by various graphics hardware (e.g. for efficient decoding on-the-fly).
//! It is defined as extension of Image_Format.
//! List of compressed pixel formats natively supported by various graphics hardware (e.g. for
//! efficient decoding on-the-fly). It is defined as extension of Image_Format.
enum Image_CompressedFormat
{
Image_CompressedFormat_UNKNOWN = Image_Format_UNKNOWN,
Image_CompressedFormat_UNKNOWN = Image_Format_UNKNOWN,
Image_CompressedFormat_RGB_S3TC_DXT1 = Image_Format_NB,
Image_CompressedFormat_RGBA_S3TC_DXT1,
Image_CompressedFormat_RGBA_S3TC_DXT3,
Image_CompressedFormat_RGBA_S3TC_DXT5
};
enum { Image_CompressedFormat_NB = Image_CompressedFormat_RGBA_S3TC_DXT5 + 1 };
enum
{
Image_CompressedFormat_NB = Image_CompressedFormat_RGBA_S3TC_DXT5 + 1
};
#endif // _Image_CompressedFormat_HeaderFile

View File

@@ -26,24 +26,23 @@ class Image_CompressedPixMap : public Standard_Transient
{
DEFINE_STANDARD_RTTIEXT(Image_CompressedPixMap, Standard_Transient)
public:
//! Return base (uncompressed) pixel format.
Image_Format BaseFormat() const { return myBaseFormat; }
//! Set base (uncompressed) pixel format.
void SetBaseFormat (Image_Format theFormat) { myBaseFormat = theFormat; }
void SetBaseFormat(Image_Format theFormat) { myBaseFormat = theFormat; }
//! Return compressed format.
Image_CompressedFormat CompressedFormat() const { return myFormat; }
//! Set compressed format.
void SetCompressedFormat (Image_CompressedFormat theFormat) { myFormat = theFormat; }
void SetCompressedFormat(Image_CompressedFormat theFormat) { myFormat = theFormat; }
//! Return raw (compressed) data.
const Handle(NCollection_Buffer)& FaceData() const { return myFaceData; }
//! Set raw (compressed) data.
void SetFaceData (const Handle(NCollection_Buffer)& theBuffer) { myFaceData = theBuffer; }
void SetFaceData(const Handle(NCollection_Buffer)& theBuffer) { myFaceData = theBuffer; }
//! Return Array of mipmap sizes, including base level.
const NCollection_Array1<Standard_Integer>& MipMaps() const { return myMipMaps; }
@@ -55,13 +54,13 @@ public:
Standard_Boolean IsCompleteMipMapSet() const { return myIsCompleteMips; }
//! Set if complete mip map level set (up to 1x1 resolution).
void SetCompleteMipMapSet (Standard_Boolean theIsComplete) { myIsCompleteMips = theIsComplete; }
void SetCompleteMipMapSet(Standard_Boolean theIsComplete) { myIsCompleteMips = theIsComplete; }
//! Return surface length in bytes.
Standard_Size FaceBytes() const { return myFaceBytes; }
//! Set surface length in bytes.
void SetFaceBytes (Standard_Size theSize) { myFaceBytes = theSize; }
void SetFaceBytes(Standard_Size theSize) { myFaceBytes = theSize; }
//! Return surface width.
Standard_Integer SizeX() const { return mySizeX; }
@@ -70,7 +69,7 @@ public:
Standard_Integer SizeY() const { return mySizeY; }
//! Set surface width x height.
void SetSize (Standard_Integer theSizeX, Standard_Integer theSizeY)
void SetSize(Standard_Integer theSizeX, Standard_Integer theSizeY)
{
mySizeX = theSizeX;
mySizeY = theSizeY;
@@ -83,28 +82,33 @@ public:
Standard_Integer NbFaces() const { return myNbFaces; }
//! Set number of faces in the file.
void SetNbFaces (Standard_Integer theSize) { myNbFaces = theSize; }
void SetNbFaces(Standard_Integer theSize) { myNbFaces = theSize; }
public:
//! Empty constructor.
Image_CompressedPixMap()
: myFaceBytes (0), myNbFaces (0), mySizeX (0), mySizeY (0), myBaseFormat (Image_Format_UNKNOWN), myFormat (Image_CompressedFormat_UNKNOWN), myIsCompleteMips (false) {}
: myFaceBytes(0),
myNbFaces(0),
mySizeX(0),
mySizeY(0),
myBaseFormat(Image_Format_UNKNOWN),
myFormat(Image_CompressedFormat_UNKNOWN),
myIsCompleteMips(false)
{
}
protected:
NCollection_Array1<Standard_Integer> myMipMaps; //!< Array of mipmap sizes, including base level
Handle(NCollection_Buffer) myFaceData; //!< raw compressed data
Standard_Size myFaceBytes; //!< surface length in bytes
Standard_Integer myNbFaces; //!< number of faces in the file
Standard_Integer mySizeX; //!< surface width
Standard_Integer mySizeY; //!< surface height
Image_Format myBaseFormat; //!< base (uncompressed) pixel format
Image_CompressedFormat myFormat; //!< compressed format
// clang-format off
NCollection_Array1<Standard_Integer> myMipMaps; //!< Array of mipmap sizes, including base level
Handle(NCollection_Buffer) myFaceData; //!< raw compressed data
Standard_Size myFaceBytes; //!< surface length in bytes
Standard_Integer myNbFaces; //!< number of faces in the file
Standard_Integer mySizeX; //!< surface width
Standard_Integer mySizeY; //!< surface height
Image_Format myBaseFormat; //!< base (uncompressed) pixel format
Image_CompressedFormat myFormat; //!< compressed format
// clang-format off
Standard_Boolean myIsCompleteMips; //!< flag indicating complete mip map level set (up to 1x1 resolution)
// clang-format on
// clang-format on
};
#endif // _Image_CompressedPixMap_HeaderFile

View File

@@ -37,38 +37,46 @@ struct Image_DDSParser::DDSPixelFormat
struct Image_DDSParser::DDSFileHeader
{
//! Caps2 flag indicating complete (6 faces) cubemap.
enum { DDSCompleteCubemap = 0xFE00 };
enum
{
DDSCompleteCubemap = 0xFE00
};
//! Return TRUE if cubmap flag is set.
bool IscompleteCubemap() const { return (Caps2 & DDSFileHeader::DDSCompleteCubemap) == DDSFileHeader::DDSCompleteCubemap; }
bool IscompleteCubemap() const
{
return (Caps2 & DDSFileHeader::DDSCompleteCubemap) == DDSFileHeader::DDSCompleteCubemap;
}
uint32_t Size;
uint32_t Flags;
uint32_t Height;
uint32_t Width;
uint32_t PitchOrLinearSize;
uint32_t Depth;
uint32_t MipMapCount;
uint32_t Reserved1[11];
uint32_t Size;
uint32_t Flags;
uint32_t Height;
uint32_t Width;
uint32_t PitchOrLinearSize;
uint32_t Depth;
uint32_t MipMapCount;
uint32_t Reserved1[11];
DDSPixelFormat PixelFormatDef;
uint32_t Caps;
uint32_t Caps2;
uint32_t Caps3;
uint32_t Caps4;
uint32_t Reserved2;
uint32_t Caps;
uint32_t Caps2;
uint32_t Caps3;
uint32_t Caps4;
uint32_t Reserved2;
};
// =======================================================================
// function : Load
// purpose :
// =======================================================================
Handle(Image_CompressedPixMap) Image_DDSParser::Load (const Handle(Image_SupportedFormats)& theSupported,
const TCollection_AsciiString& theFile,
const Standard_Integer theFaceIndex,
const int64_t theFileOffset)
Handle(Image_CompressedPixMap) Image_DDSParser::Load(
const Handle(Image_SupportedFormats)& theSupported,
const TCollection_AsciiString& theFile,
const Standard_Integer theFaceIndex,
const int64_t theFileOffset)
{
const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
std::shared_ptr<std::istream> aFile = aFileSystem->OpenIStream (theFile, std::ios::in | std::ios::binary);
std::shared_ptr<std::istream> aFile =
aFileSystem->OpenIStream(theFile, std::ios::in | std::ios::binary);
char aHeader[128] = {};
if (aFile.get() == NULL || !aFile->good())
{
@@ -76,24 +84,22 @@ Handle(Image_CompressedPixMap) Image_DDSParser::Load (const Handle(Image_Support
}
if (theFileOffset != 0)
{
aFile->seekg ((std::streamoff )theFileOffset, std::ios::beg);
aFile->seekg((std::streamoff)theFileOffset, std::ios::beg);
}
aFile->read (aHeader, 128);
Standard_Size aNbReadBytes = (Standard_Size )aFile->gcount();
if (aNbReadBytes < 128
|| ::memcmp (aHeader, "DDS ", 4) != 0)
aFile->read(aHeader, 128);
Standard_Size aNbReadBytes = (Standard_Size)aFile->gcount();
if (aNbReadBytes < 128 || ::memcmp(aHeader, "DDS ", 4) != 0)
{
return Handle(Image_CompressedPixMap)();
}
Handle(Image_CompressedPixMap) aDef = parseHeader (*(const DDSFileHeader* )(aHeader + 4));
Handle(Image_CompressedPixMap) aDef = parseHeader(*(const DDSFileHeader*)(aHeader + 4));
if (aDef.IsNull())
{
return Handle(Image_CompressedPixMap)();
}
if (!theSupported.IsNull()
&& !theSupported->IsSupported (aDef->CompressedFormat()))
if (!theSupported.IsNull() && !theSupported->IsSupported(aDef->CompressedFormat()))
{
return Handle(Image_CompressedPixMap)();
}
@@ -103,27 +109,29 @@ Handle(Image_CompressedPixMap) Image_DDSParser::Load (const Handle(Image_Support
return aDef;
}
if (theFaceIndex >= aDef->NbFaces()
|| aDef->FaceBytes() == 0)
if (theFaceIndex >= aDef->NbFaces() || aDef->FaceBytes() == 0)
{
Message::SendFail (TCollection_AsciiString ("DDS Reader error - invalid face index #") + theFaceIndex + " within file\n" + theFile);
Message::SendFail(TCollection_AsciiString("DDS Reader error - invalid face index #")
+ theFaceIndex + " within file\n" + theFile);
return Handle(Image_CompressedPixMap)();
}
const Standard_Size anOffset = aDef->FaceBytes() * theFaceIndex;
if (anOffset != 0)
{
aFile->seekg ((std::streamoff )anOffset, std::ios::cur);
aFile->seekg((std::streamoff)anOffset, std::ios::cur);
}
Handle(NCollection_Buffer) aBuffer = new NCollection_Buffer (Image_PixMap::DefaultAllocator(), aDef->FaceBytes());
aFile->read ((char* )aBuffer->ChangeData(), aDef->FaceBytes());
aNbReadBytes = (Standard_Size )aFile->gcount();
Handle(NCollection_Buffer) aBuffer =
new NCollection_Buffer(Image_PixMap::DefaultAllocator(), aDef->FaceBytes());
aFile->read((char*)aBuffer->ChangeData(), aDef->FaceBytes());
aNbReadBytes = (Standard_Size)aFile->gcount();
if (aNbReadBytes < aDef->FaceBytes())
{
Message::SendFail (TCollection_AsciiString ("DDS Reader error - unable to read face #") + theFaceIndex + " data from file\n" + theFile);
Message::SendFail(TCollection_AsciiString("DDS Reader error - unable to read face #")
+ theFaceIndex + " data from file\n" + theFile);
return Handle(Image_CompressedPixMap)();
}
aDef->SetFaceData (aBuffer);
aDef->SetFaceData(aBuffer);
return aDef;
}
@@ -131,25 +139,23 @@ Handle(Image_CompressedPixMap) Image_DDSParser::Load (const Handle(Image_Support
// function : Load
// purpose :
// =======================================================================
Handle(Image_CompressedPixMap) Image_DDSParser::Load (const Handle(Image_SupportedFormats)& theSupported,
const Handle(NCollection_Buffer)& theBuffer,
const Standard_Integer theFaceIndex)
Handle(Image_CompressedPixMap) Image_DDSParser::Load(
const Handle(Image_SupportedFormats)& theSupported,
const Handle(NCollection_Buffer)& theBuffer,
const Standard_Integer theFaceIndex)
{
if (theBuffer.IsNull()
|| theBuffer->Size() < 128
|| ::memcmp (theBuffer->Data(), "DDS ", 4) != 0)
if (theBuffer.IsNull() || theBuffer->Size() < 128 || ::memcmp(theBuffer->Data(), "DDS ", 4) != 0)
{
return Handle(Image_CompressedPixMap)();
}
Handle(Image_CompressedPixMap) aDef = parseHeader (*(const DDSFileHeader* )(theBuffer->Data() + 4));
Handle(Image_CompressedPixMap) aDef = parseHeader(*(const DDSFileHeader*)(theBuffer->Data() + 4));
if (aDef.IsNull())
{
return Handle(Image_CompressedPixMap)();
}
if (!theSupported.IsNull()
&& !theSupported->IsSupported (aDef->CompressedFormat()))
if (!theSupported.IsNull() && !theSupported->IsSupported(aDef->CompressedFormat()))
{
return Handle(Image_CompressedPixMap)();
}
@@ -159,23 +165,25 @@ Handle(Image_CompressedPixMap) Image_DDSParser::Load (const Handle(Image_Support
return aDef;
}
if (theFaceIndex >= aDef->NbFaces()
|| aDef->FaceBytes() == 0)
if (theFaceIndex >= aDef->NbFaces() || aDef->FaceBytes() == 0)
{
Message::SendFail (TCollection_AsciiString ("DDS Reader error - invalid face index #") + theFaceIndex + " within buffer");
Message::SendFail(TCollection_AsciiString("DDS Reader error - invalid face index #")
+ theFaceIndex + " within buffer");
return Handle(Image_CompressedPixMap)();
}
const Standard_Size anOffset = aDef->FaceBytes() * theFaceIndex + 128;
if (theBuffer->Size() < anOffset + aDef->FaceBytes())
{
Message::SendFail (TCollection_AsciiString ("DDS Reader error - unable to read face #") + theFaceIndex + " data from buffer");
Message::SendFail(TCollection_AsciiString("DDS Reader error - unable to read face #")
+ theFaceIndex + " data from buffer");
return Handle(Image_CompressedPixMap)();
}
Handle(NCollection_Buffer) aBuffer = new NCollection_Buffer (Image_PixMap::DefaultAllocator(), aDef->FaceBytes());
memcpy (aBuffer->ChangeData(), theBuffer->Data() + anOffset, aDef->FaceBytes());
aDef->SetFaceData (aBuffer);
Handle(NCollection_Buffer) aBuffer =
new NCollection_Buffer(Image_PixMap::DefaultAllocator(), aDef->FaceBytes());
memcpy(aBuffer->ChangeData(), theBuffer->Data() + anOffset, aDef->FaceBytes());
aDef->SetFaceData(aBuffer);
return aDef;
}
@@ -183,36 +191,35 @@ Handle(Image_CompressedPixMap) Image_DDSParser::Load (const Handle(Image_Support
// function : parseHeader
// purpose :
// =======================================================================
Handle(Image_CompressedPixMap) Image_DDSParser::parseHeader (const DDSFileHeader& theHeader)
Handle(Image_CompressedPixMap) Image_DDSParser::parseHeader(const DDSFileHeader& theHeader)
{
if (theHeader.Size != 124
|| theHeader.Width == 0
|| theHeader.Height == 0
|| theHeader.PixelFormatDef.Size != 32)
if (theHeader.Size != 124 || theHeader.Width == 0 || theHeader.Height == 0
|| theHeader.PixelFormatDef.Size != 32)
{
return Handle(Image_CompressedPixMap)();
}
Image_Format aBaseFormat = Image_Format_UNKNOWN;
Image_CompressedFormat aFormat = Image_CompressedFormat_UNKNOWN;
Standard_Integer aBlockSize = 8;
const bool hasAlpha = (theHeader.PixelFormatDef.Flags & 0x1) != 0;
if (::memcmp (&theHeader.PixelFormatDef.FourCC, "DXT5", 4) == 0)
Image_Format aBaseFormat = Image_Format_UNKNOWN;
Image_CompressedFormat aFormat = Image_CompressedFormat_UNKNOWN;
Standard_Integer aBlockSize = 8;
const bool hasAlpha = (theHeader.PixelFormatDef.Flags & 0x1) != 0;
if (::memcmp(&theHeader.PixelFormatDef.FourCC, "DXT5", 4) == 0)
{
aBaseFormat = Image_Format_RGBA;
aFormat = Image_CompressedFormat_RGBA_S3TC_DXT5;
aBlockSize = 16;
aFormat = Image_CompressedFormat_RGBA_S3TC_DXT5;
aBlockSize = 16;
}
else if (::memcmp (&theHeader.PixelFormatDef.FourCC, "DXT3", 4) == 0)
else if (::memcmp(&theHeader.PixelFormatDef.FourCC, "DXT3", 4) == 0)
{
aBaseFormat = Image_Format_RGBA;
aFormat = Image_CompressedFormat_RGBA_S3TC_DXT3;
aBlockSize = 16;
aFormat = Image_CompressedFormat_RGBA_S3TC_DXT3;
aBlockSize = 16;
}
else if (::memcmp (&theHeader.PixelFormatDef.FourCC, "DXT1", 4) == 0)
else if (::memcmp(&theHeader.PixelFormatDef.FourCC, "DXT1", 4) == 0)
{
aBaseFormat = hasAlpha ? Image_Format_RGBA : Image_Format_RGB;
aFormat = hasAlpha ? Image_CompressedFormat_RGBA_S3TC_DXT1 : Image_CompressedFormat_RGB_S3TC_DXT1;
aFormat =
hasAlpha ? Image_CompressedFormat_RGBA_S3TC_DXT1 : Image_CompressedFormat_RGB_S3TC_DXT1;
aBlockSize = 8;
}
if (aFormat == Image_CompressedFormat_UNKNOWN)
@@ -221,32 +228,39 @@ Handle(Image_CompressedPixMap) Image_DDSParser::parseHeader (const DDSFileHeader
}
Handle(Image_CompressedPixMap) aDef = new Image_CompressedPixMap();
aDef->SetSize ((Standard_Integer )theHeader.Width, (Standard_Integer )theHeader.Height);
aDef->SetNbFaces (theHeader.IscompleteCubemap() != 0 ? 6 : 1);
aDef->SetBaseFormat (aBaseFormat);
aDef->SetCompressedFormat (aFormat);
aDef->SetSize((Standard_Integer)theHeader.Width, (Standard_Integer)theHeader.Height);
aDef->SetNbFaces(theHeader.IscompleteCubemap() != 0 ? 6 : 1);
aDef->SetBaseFormat(aBaseFormat);
aDef->SetCompressedFormat(aFormat);
const Standard_Integer aNbMipMaps = Max ((Standard_Integer )theHeader.MipMapCount, 1);
aDef->ChangeMipMaps().Resize (0, aNbMipMaps - 1, false);
const Standard_Integer aNbMipMaps = Max((Standard_Integer)theHeader.MipMapCount, 1);
aDef->ChangeMipMaps().Resize(0, aNbMipMaps - 1, false);
{
Standard_Size aFaceSize = 0;
NCollection_Vec2<Standard_Integer> aMipSizeXY (aDef->SizeX(), aDef->SizeY());
Standard_Size aFaceSize = 0;
NCollection_Vec2<Standard_Integer> aMipSizeXY(aDef->SizeX(), aDef->SizeY());
for (Standard_Integer aMipIter = 0;; ++aMipIter)
{
const Standard_Integer aMipLength = ((aMipSizeXY.x() + 3) / 4) * ((aMipSizeXY.y() + 3) / 4) * aBlockSize;
const Standard_Integer aMipLength =
((aMipSizeXY.x() + 3) / 4) * ((aMipSizeXY.y() + 3) / 4) * aBlockSize;
aFaceSize += aMipLength;
aDef->ChangeMipMaps().SetValue (aMipIter, aMipLength);
aDef->ChangeMipMaps().SetValue(aMipIter, aMipLength);
if (aMipIter + 1 >= aNbMipMaps)
{
break;
}
aMipSizeXY /= 2;
if (aMipSizeXY.x() == 0) { aMipSizeXY.x() = 1; }
if (aMipSizeXY.y() == 0) { aMipSizeXY.y() = 1; }
if (aMipSizeXY.x() == 0)
{
aMipSizeXY.x() = 1;
}
if (aMipSizeXY.y() == 0)
{
aMipSizeXY.y() = 1;
}
}
aDef->SetCompleteMipMapSet (aMipSizeXY.x() == 1 && aMipSizeXY.y() == 1);
aDef->SetFaceBytes (aFaceSize);
aDef->SetCompleteMipMapSet(aMipSizeXY.x() == 1 && aMipSizeXY.y() == 1);
aDef->SetFaceBytes(aFaceSize);
}
return aDef;

View File

@@ -23,7 +23,6 @@ class Image_SupportedFormats;
class Image_DDSParser
{
public:
//! Load the face from DDS file.
//! @param[in] theSupported list of supported image formats
//! @param[in] theFile file path
@@ -31,32 +30,31 @@ public:
//! use -1 to skip reading the face data
//! @param[in] theFileOffset offset to the DDS data
//! @return loaded face or NULL if file cannot be read or not valid DDS file
Standard_EXPORT static Handle(Image_CompressedPixMap) Load (const Handle(Image_SupportedFormats)& theSupported,
const TCollection_AsciiString& theFile,
const Standard_Integer theFaceIndex,
const int64_t theFileOffset = 0);
Standard_EXPORT static Handle(Image_CompressedPixMap) Load(
const Handle(Image_SupportedFormats)& theSupported,
const TCollection_AsciiString& theFile,
const Standard_Integer theFaceIndex,
const int64_t theFileOffset = 0);
//! Load the face from DDS file.
//! @param[in] theSupported list of supported image formats
//! @param[in] theBuffer pre-loaded file data, should be at least of 128 bytes long defining DDS header.
//! @param[in] theBuffer pre-loaded file data, should be at least of 128 bytes long defining
//! DDS header.
//! @param[in] theFaceIndex face index, within [0, Image_CompressedPixMap::NbFaces()) range;
//! use -1 to skip reading the face data
//! @return loaded face or NULL if file cannot be read or not valid DDS file
Standard_EXPORT static Handle(Image_CompressedPixMap) Load (const Handle(Image_SupportedFormats)& theSupported,
const Handle(NCollection_Buffer)& theBuffer,
const Standard_Integer theFaceIndex);
Standard_EXPORT static Handle(Image_CompressedPixMap) Load(
const Handle(Image_SupportedFormats)& theSupported,
const Handle(NCollection_Buffer)& theBuffer,
const Standard_Integer theFaceIndex);
private:
struct DDSPixelFormat;
struct DDSFileHeader;
private:
//! Parse DDS header.
static Handle(Image_CompressedPixMap) parseHeader (const DDSFileHeader& theHeader);
static Handle(Image_CompressedPixMap) parseHeader(const DDSFileHeader& theHeader);
};
#endif // _Image_DDSParser_HeaderFile

View File

@@ -22,64 +22,53 @@
#include <cstdlib>
IMPLEMENT_STANDARD_RTTIEXT(Image_Diff,Standard_Transient)
IMPLEMENT_STANDARD_RTTIEXT(Image_Diff, Standard_Transient)
namespace
{
//! Number of neighbor pixels.
static const Standard_Size Image_Diff_NbOfNeighborPixels = 8;
//! Number of neighbor pixels.
static const Standard_Size Image_Diff_NbOfNeighborPixels = 8;
//! List of neighbor pixels (offsets).
static const int Image_Diff_NEIGHBOR_PIXELS[Image_Diff_NbOfNeighborPixels][2] =
{
{-1, -1}, {0, -1}, {1, -1},
{-1, 0}, {1, 0},
{-1, 1}, {0, 1}, {1, 1}
};
//! List of neighbor pixels (offsets).
static const int Image_Diff_NEIGHBOR_PIXELS[Image_Diff_NbOfNeighborPixels][2] =
{{-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
//! @return true if pixel is black
static bool isBlackPixel (const Image_PixMap& theData, Standard_Size theY, Standard_Size theX)
//! @return true if pixel is black
static bool isBlackPixel(const Image_PixMap& theData, Standard_Size theY, Standard_Size theX)
{
switch (theData.Format())
{
switch (theData.Format())
{
case Image_Format_Gray:
case Image_Format_Alpha:
{
return theData.Value<unsigned char> (theY, theX) == 0;
}
case Image_Format_RGB:
case Image_Format_BGR:
case Image_Format_RGB32:
case Image_Format_BGR32:
case Image_Format_RGBA:
case Image_Format_BGRA:
{
const Standard_Byte* aColor = theData.RawValue (theY, theX);
return aColor[0] == 0
&& aColor[1] == 0
&& aColor[2] == 0;
}
default:
{
const Quantity_ColorRGBA aPixelRgba = theData.PixelColor ((int)theY, (int)theX);
const NCollection_Vec4<float>& aPixel = aPixelRgba;
return aPixel.r() == 0.0f
&& aPixel.g() == 0.0f
&& aPixel.b() == 0.0f;
}
case Image_Format_Gray:
case Image_Format_Alpha: {
return theData.Value<unsigned char>(theY, theX) == 0;
}
case Image_Format_RGB:
case Image_Format_BGR:
case Image_Format_RGB32:
case Image_Format_BGR32:
case Image_Format_RGBA:
case Image_Format_BGRA: {
const Standard_Byte* aColor = theData.RawValue(theY, theX);
return aColor[0] == 0 && aColor[1] == 0 && aColor[2] == 0;
}
default: {
const Quantity_ColorRGBA aPixelRgba = theData.PixelColor((int)theY, (int)theX);
const NCollection_Vec4<float>& aPixel = aPixelRgba;
return aPixel.r() == 0.0f && aPixel.g() == 0.0f && aPixel.b() == 0.0f;
}
}
}
} // namespace
// =======================================================================
// function : Image_Diff
// purpose :
// =======================================================================
Image_Diff::Image_Diff()
: myColorTolerance (0.0),
myIsBorderFilterOn (Standard_False)
: myColorTolerance(0.0),
myIsBorderFilterOn(Standard_False)
{
//
}
@@ -97,27 +86,25 @@ Image_Diff::~Image_Diff()
// function : Init
// purpose :
// =======================================================================
Standard_Boolean Image_Diff::Init (const Handle(Image_PixMap)& theImageRef,
const Handle(Image_PixMap)& theImageNew,
const Standard_Boolean theToBlackWhite)
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())
if (theImageRef.IsNull() || theImageNew.IsNull() || theImageRef->IsEmpty()
|| theImageNew->IsEmpty() || theImageRef->SizeX() != theImageNew->SizeX()
|| theImageRef->SizeY() != theImageNew->SizeY()
|| theImageRef->Format() != theImageNew->Format())
{
Message::SendFail ("Error: Images have different format or dimensions");
Message::SendFail("Error: Images have different format or dimensions");
return Standard_False;
}
else if (theImageRef->SizeX() >= 0xFFFF
|| theImageRef->SizeY() >= 0xFFFF)
else if (theImageRef->SizeX() >= 0xFFFF || theImageRef->SizeY() >= 0xFFFF)
{
Message::SendFail ("Error: Images are too large");
Message::SendFail("Error: Images are too large");
return Standard_False;
}
@@ -125,8 +112,8 @@ Standard_Boolean Image_Diff::Init (const Handle(Image_PixMap)& theImageRef,
myImageNew = theImageNew;
if (theToBlackWhite)
{
Image_PixMap::ToBlackWhite (*myImageRef);
Image_PixMap::ToBlackWhite (*myImageNew);
Image_PixMap::ToBlackWhite(*myImageRef);
Image_PixMap::ToBlackWhite(*myImageNew);
}
return Standard_True;
}
@@ -135,19 +122,18 @@ Standard_Boolean Image_Diff::Init (const Handle(Image_PixMap)& theImageRef,
// function : Init
// purpose :
// =======================================================================
Standard_Boolean Image_Diff::Init (const TCollection_AsciiString& theImgPathRef,
const TCollection_AsciiString& theImgPathNew,
const Standard_Boolean theToBlackWhite)
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))
if (!anImgRef->Load(theImgPathRef) || !anImgNew->Load(theImgPathNew))
{
Message::SendFail ("Error: Failed to load image(s) file(s)");
Message::SendFail("Error: Failed to load image(s) file(s)");
return Standard_False;
}
return Init (anImgRef, anImgNew, theToBlackWhite);
return Init(anImgRef, anImgNew, theToBlackWhite);
}
// =======================================================================
@@ -167,7 +153,7 @@ Standard_Integer Image_Diff::Compare()
// first check if images are exactly the same
if (myImageNew->SizeBytes() == myImageRef->SizeBytes()
&& memcmp (myImageNew->Data(), myImageRef->Data(), myImageRef->SizeBytes()) == 0)
&& memcmp(myImageNew->Data(), myImageRef->Data(), myImageRef->SizeBytes()) == 0)
{
return 0;
}
@@ -175,18 +161,19 @@ Standard_Integer Image_Diff::Compare()
switch (myImageRef->Format())
{
case Image_Format_Gray:
case Image_Format_Alpha:
{
case Image_Format_Alpha: {
// Tolerance of comparison operation for color
const Standard_Integer aDiffThreshold = Standard_Integer(255.0 * myColorTolerance);
for (Standard_Size aRow = 0; aRow < myImageRef->SizeY(); ++aRow)
{
for (Standard_Size aCol = 0; aCol < myImageRef->SizeX(); ++aCol)
{
const Standard_Integer aDiff = Standard_Integer(myImageNew->Value<unsigned char> (aRow, aCol)) - Standard_Integer(myImageRef->Value<unsigned char> (aRow, aCol));
if (Abs (aDiff) > aDiffThreshold)
const Standard_Integer aDiff =
Standard_Integer(myImageNew->Value<unsigned char>(aRow, aCol))
- Standard_Integer(myImageRef->Value<unsigned char>(aRow, aCol));
if (Abs(aDiff) > aDiffThreshold)
{
myDiffPixels.Append (PackXY ((uint16_t)aCol, (uint16_t)aRow));
myDiffPixels.Append(PackXY((uint16_t)aCol, (uint16_t)aRow));
++aNbDiffColors;
}
}
@@ -198,8 +185,7 @@ Standard_Integer Image_Diff::Compare()
case Image_Format_RGB32:
case Image_Format_BGR32:
case Image_Format_RGBA:
case Image_Format_BGRA:
{
case Image_Format_BGRA: {
// Tolerance of comparison operation for color
// Maximum difference between colors (white - black) = 100%
const Standard_Integer aDiffThreshold = Standard_Integer(255.0 * myColorTolerance);
@@ -211,22 +197,23 @@ Standard_Integer Image_Diff::Compare()
for (Standard_Size aCol = 0; aCol < myImageRef->SizeX(); ++aCol)
{
// compute Chebyshev distance between two colors
const Standard_Byte* aColorRef = myImageRef->RawValue (aRow, aCol);
const Standard_Byte* aColorNew = myImageNew->RawValue (aRow, aCol);
const int aDiff = NCollection_Vec3<int> (int(aColorRef[0]) - int(aColorNew[0]),
int(aColorRef[1]) - int(aColorNew[1]),
int(aColorRef[2]) - int(aColorNew[2])).cwiseAbs().maxComp();
const Standard_Byte* aColorRef = myImageRef->RawValue(aRow, aCol);
const Standard_Byte* aColorNew = myImageNew->RawValue(aRow, aCol);
const int aDiff = NCollection_Vec3<int>(int(aColorRef[0]) - int(aColorNew[0]),
int(aColorRef[1]) - int(aColorNew[1]),
int(aColorRef[2]) - int(aColorNew[2]))
.cwiseAbs()
.maxComp();
if (aDiff > aDiffThreshold)
{
myDiffPixels.Append (PackXY ((uint16_t)aCol, (uint16_t)aRow));
myDiffPixels.Append(PackXY((uint16_t)aCol, (uint16_t)aRow));
++aNbDiffColors;
}
}
}
break;
}
default:
{
default: {
// Tolerance of comparison operation for color
// Maximum difference between colors (white - black) = 100%
const float aDiffThreshold = float(myColorTolerance);
@@ -235,14 +222,16 @@ Standard_Integer Image_Diff::Compare()
for (Standard_Size aCol = 0; aCol < myImageRef->SizeX(); ++aCol)
{
// compute Chebyshev distance between two colors
const Quantity_ColorRGBA aPixel1Rgba = myImageRef->PixelColor (Standard_Integer(aCol), Standard_Integer(aRow));
const Quantity_ColorRGBA aPixel2Rgba = myImageNew->PixelColor (Standard_Integer(aCol), Standard_Integer(aRow));
const Quantity_ColorRGBA aPixel1Rgba =
myImageRef->PixelColor(Standard_Integer(aCol), Standard_Integer(aRow));
const Quantity_ColorRGBA aPixel2Rgba =
myImageNew->PixelColor(Standard_Integer(aCol), Standard_Integer(aRow));
const NCollection_Vec3<float>& aPixel1 = aPixel1Rgba.GetRGB();
const NCollection_Vec3<float>& aPixel2 = aPixel2Rgba.GetRGB();
const float aDiff = (aPixel2 - aPixel1).cwiseAbs().maxComp();
const float aDiff = (aPixel2 - aPixel1).cwiseAbs().maxComp();
if (aDiff > aDiffThreshold)
{
myDiffPixels.Append (PackXY ((uint16_t)aCol, (uint16_t)aRow));
myDiffPixels.Append(PackXY((uint16_t)aCol, (uint16_t)aRow));
++aNbDiffColors;
}
}
@@ -264,27 +253,26 @@ Standard_Integer Image_Diff::Compare()
// function : SaveDiffImage
// purpose :
// =======================================================================
Standard_Boolean Image_Diff::SaveDiffImage (Image_PixMap& theDiffImage) const
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())
if (theDiffImage.IsEmpty() || theDiffImage.SizeX() != myImageRef->SizeX()
|| theDiffImage.SizeY() != myImageRef->SizeY())
{
if (!theDiffImage.InitTrash (Image_Format_Gray, myImageRef->SizeX(), myImageRef->SizeY()))
if (!theDiffImage.InitTrash(Image_Format_Gray, myImageRef->SizeX(), myImageRef->SizeY()))
{
return Standard_False;
}
}
const Quantity_ColorRGBA aWhiteRgba (1.0f, 1.0f, 1.0f, 1.0f);
const Quantity_ColorRGBA aWhiteRgba(1.0f, 1.0f, 1.0f, 1.0f);
// initialize black image for dump
memset (theDiffImage.ChangeData(), 0, theDiffImage.SizeBytes());
memset(theDiffImage.ChangeData(), 0, theDiffImage.SizeBytes());
if (myGroupsOfDiffPixels.IsEmpty())
{
if (myIsBorderFilterOn)
@@ -295,11 +283,13 @@ Standard_Boolean Image_Diff::SaveDiffImage (Image_PixMap& theDiffImage) const
switch (theDiffImage.Format())
{
case Image_Format_Gray:
case Image_Format_Alpha:
{
for (NCollection_Vector<Standard_Integer>::Iterator aPixelIter (myDiffPixels); aPixelIter.More(); aPixelIter.Next())
case Image_Format_Alpha: {
for (NCollection_Vector<Standard_Integer>::Iterator aPixelIter(myDiffPixels);
aPixelIter.More();
aPixelIter.Next())
{
theDiffImage.ChangeValue<unsigned char> (UnpackY(aPixelIter.Value()), UnpackX(aPixelIter.Value())) = 255;
theDiffImage.ChangeValue<unsigned char>(UnpackY(aPixelIter.Value()),
UnpackX(aPixelIter.Value())) = 255;
}
break;
}
@@ -308,19 +298,26 @@ Standard_Boolean Image_Diff::SaveDiffImage (Image_PixMap& theDiffImage) const
case Image_Format_RGB32:
case Image_Format_BGR32:
case Image_Format_RGBA:
case Image_Format_BGRA:
{
for (NCollection_Vector<Standard_Integer>::Iterator aPixelIter (myDiffPixels); aPixelIter.More(); aPixelIter.Next())
case Image_Format_BGRA: {
for (NCollection_Vector<Standard_Integer>::Iterator aPixelIter(myDiffPixels);
aPixelIter.More();
aPixelIter.Next())
{
memset (theDiffImage.ChangeRawValue (UnpackY(aPixelIter.Value()), UnpackX(aPixelIter.Value())), 255, 3);
memset(
theDiffImage.ChangeRawValue(UnpackY(aPixelIter.Value()), UnpackX(aPixelIter.Value())),
255,
3);
}
break;
}
default:
{
for (NCollection_Vector<Standard_Integer>::Iterator aPixelIter (myDiffPixels); aPixelIter.More(); aPixelIter.Next())
default: {
for (NCollection_Vector<Standard_Integer>::Iterator aPixelIter(myDiffPixels);
aPixelIter.More();
aPixelIter.Next())
{
theDiffImage.SetPixelColor (UnpackX(aPixelIter.Value()), UnpackY(aPixelIter.Value()), aWhiteRgba);
theDiffImage.SetPixelColor(UnpackX(aPixelIter.Value()),
UnpackY(aPixelIter.Value()),
aWhiteRgba);
}
break;
}
@@ -329,9 +326,12 @@ Standard_Boolean Image_Diff::SaveDiffImage (Image_PixMap& theDiffImage) const
}
Standard_Integer aGroupId = 1;
for (NCollection_List<Handle(TColStd_HPackedMapOfInteger)>::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next(), ++aGroupId)
for (NCollection_List<Handle(TColStd_HPackedMapOfInteger)>::Iterator aGrIter(
myGroupsOfDiffPixels);
aGrIter.More();
aGrIter.Next(), ++aGroupId)
{
if (myLinearGroups.Contains (aGroupId))
if (myLinearGroups.Contains(aGroupId))
{
continue; // skip linear groups
}
@@ -340,12 +340,12 @@ Standard_Boolean Image_Diff::SaveDiffImage (Image_PixMap& theDiffImage) const
switch (theDiffImage.Format())
{
case Image_Format_Gray:
case Image_Format_Alpha:
{
for (TColStd_MapIteratorOfPackedMapOfInteger aPixelIter (aGroup->Map()); aPixelIter.More(); aPixelIter.Next())
case Image_Format_Alpha: {
for (TColStd_MapIteratorOfPackedMapOfInteger aPixelIter(aGroup->Map()); aPixelIter.More();
aPixelIter.Next())
{
Standard_Integer aDiffPixel (aPixelIter.Key());
theDiffImage.ChangeValue<unsigned char> (UnpackY(aDiffPixel), UnpackX(aDiffPixel)) = 255;
Standard_Integer aDiffPixel(aPixelIter.Key());
theDiffImage.ChangeValue<unsigned char>(UnpackY(aDiffPixel), UnpackX(aDiffPixel)) = 255;
}
break;
}
@@ -354,21 +354,23 @@ Standard_Boolean Image_Diff::SaveDiffImage (Image_PixMap& theDiffImage) const
case Image_Format_RGB32:
case Image_Format_BGR32:
case Image_Format_RGBA:
case Image_Format_BGRA:
{
for (TColStd_MapIteratorOfPackedMapOfInteger aPixelIter (aGroup->Map()); aPixelIter.More(); aPixelIter.Next())
case Image_Format_BGRA: {
for (TColStd_MapIteratorOfPackedMapOfInteger aPixelIter(aGroup->Map()); aPixelIter.More();
aPixelIter.Next())
{
Standard_Integer aDiffPixel (aPixelIter.Key());
memset (theDiffImage.ChangeValue<Standard_Byte*> (UnpackY(aDiffPixel), UnpackX(aDiffPixel)), 255, 3);
Standard_Integer aDiffPixel(aPixelIter.Key());
memset(theDiffImage.ChangeValue<Standard_Byte*>(UnpackY(aDiffPixel), UnpackX(aDiffPixel)),
255,
3);
}
break;
}
default:
{
for (TColStd_MapIteratorOfPackedMapOfInteger aPixelIter (aGroup->Map()); aPixelIter.More(); aPixelIter.Next())
default: {
for (TColStd_MapIteratorOfPackedMapOfInteger aPixelIter(aGroup->Map()); aPixelIter.More();
aPixelIter.Next())
{
Standard_Integer aDiffPixel (aPixelIter.Key());
theDiffImage.SetPixelColor (UnpackX(aDiffPixel), UnpackY(aDiffPixel), aWhiteRgba);
Standard_Integer aDiffPixel(aPixelIter.Key());
theDiffImage.SetPixelColor(UnpackX(aDiffPixel), UnpackY(aDiffPixel), aWhiteRgba);
}
break;
}
@@ -382,7 +384,7 @@ Standard_Boolean Image_Diff::SaveDiffImage (Image_PixMap& theDiffImage) const
// function : SaveDiffImage
// purpose :
// =======================================================================
Standard_Boolean Image_Diff::SaveDiffImage (const TCollection_AsciiString& theDiffPath) const
Standard_Boolean Image_Diff::SaveDiffImage(const TCollection_AsciiString& theDiffPath) const
{
if (myImageRef.IsNull() || myImageNew.IsNull() || theDiffPath.IsEmpty())
{
@@ -390,14 +392,14 @@ Standard_Boolean Image_Diff::SaveDiffImage (const TCollection_AsciiString& theDi
}
Image_AlienPixMap aDiff;
if (!aDiff.InitTrash (Image_Format_Gray, myImageRef->SizeX(), myImageRef->SizeY())
|| !SaveDiffImage (aDiff))
if (!aDiff.InitTrash(Image_Format_Gray, myImageRef->SizeX(), myImageRef->SizeY())
|| !SaveDiffImage(aDiff))
{
return Standard_False;
}
// save image
return aDiff.Save (theDiffPath);
return aDiff.Save(theDiffPath);
}
// =======================================================================
@@ -419,33 +421,36 @@ Standard_Integer Image_Diff::ignoreBorderEffect()
const Standard_Integer aLen1 = !myDiffPixels.IsEmpty() ? (myDiffPixels.Length() - 1) : 0;
for (Standard_Integer aPixelId1 = 0; aPixelId1 < aLen1; ++aPixelId1)
{
Standard_Integer aValue1 = myDiffPixels.Value (aPixelId1);
Standard_Integer aValue1 = myDiffPixels.Value(aPixelId1);
// Check other pixels in the list looking for a neighbour of this one
for (Standard_Integer aPixelId2 = aPixelId1 + 1; aPixelId2 < myDiffPixels.Length(); ++aPixelId2)
{
Standard_Integer aValue2 = myDiffPixels.Value (aPixelId2);
if (Abs (Standard_Integer(UnpackX(aValue1)) - Standard_Integer(UnpackX(aValue2))) <= 1
&& Abs (Standard_Integer(UnpackY(aValue1)) - Standard_Integer(UnpackY(aValue2))) <= 1)
Standard_Integer aValue2 = myDiffPixels.Value(aPixelId2);
if (Abs(Standard_Integer(UnpackX(aValue1)) - Standard_Integer(UnpackX(aValue2))) <= 1
&& Abs(Standard_Integer(UnpackY(aValue1)) - Standard_Integer(UnpackY(aValue2))) <= 1)
{
// A neighbour is found. Create a new group and add both pixels.
if (myGroupsOfDiffPixels.IsEmpty())
{
Handle(TColStd_HPackedMapOfInteger) aGroup = new TColStd_HPackedMapOfInteger();
aGroup->ChangeMap().Add (aValue1);
aGroup->ChangeMap().Add (aValue2);
myGroupsOfDiffPixels.Append (aGroup);
aGroup->ChangeMap().Add(aValue1);
aGroup->ChangeMap().Add(aValue2);
myGroupsOfDiffPixels.Append(aGroup);
}
else
{
// Find a group the pixels belong to.
Standard_Boolean isFound = Standard_False;
for (NCollection_List<Handle(TColStd_HPackedMapOfInteger)>::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next())
for (NCollection_List<Handle(TColStd_HPackedMapOfInteger)>::Iterator aGrIter(
myGroupsOfDiffPixels);
aGrIter.More();
aGrIter.Next())
{
const Handle(TColStd_HPackedMapOfInteger)& aGroup = aGrIter.ChangeValue();
if (aGroup->Map().Contains (aValue1))
if (aGroup->Map().Contains(aValue1))
{
aGroup->ChangeMap().Add (aValue2);
aGroup->ChangeMap().Add(aValue2);
isFound = Standard_True;
break;
}
@@ -455,9 +460,9 @@ Standard_Integer Image_Diff::ignoreBorderEffect()
{
// Create a new group
Handle(TColStd_HPackedMapOfInteger) aGroup = new TColStd_HPackedMapOfInteger();
aGroup->ChangeMap().Add (aValue1);
aGroup->ChangeMap().Add (aValue2);
myGroupsOfDiffPixels.Append (aGroup);
aGroup->ChangeMap().Add(aValue1);
aGroup->ChangeMap().Add(aValue2);
myGroupsOfDiffPixels.Append(aGroup);
}
}
}
@@ -466,20 +471,24 @@ Standard_Integer Image_Diff::ignoreBorderEffect()
// filter linear groups which represent border of a solid shape
Standard_Integer aGroupId = 1;
for (NCollection_List<Handle(TColStd_HPackedMapOfInteger)>::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next(), ++aGroupId)
for (NCollection_List<Handle(TColStd_HPackedMapOfInteger)>::Iterator aGrIter(
myGroupsOfDiffPixels);
aGrIter.More();
aGrIter.Next(), ++aGroupId)
{
Standard_Integer aNeighboursNb = 0;
Standard_Boolean isLine = Standard_True;
const Handle(TColStd_HPackedMapOfInteger)& aGroup = aGrIter.Value();
Standard_Integer aNeighboursNb = 0;
Standard_Boolean isLine = Standard_True;
const Handle(TColStd_HPackedMapOfInteger)& aGroup = aGrIter.Value();
if (aGroup->Map().IsEmpty())
{
continue;
}
Standard_Integer aDiffPixel = 0;
for (TColStd_MapIteratorOfPackedMapOfInteger aPixelIter (aGroup->Map()); aPixelIter.More(); aPixelIter.Next())
for (TColStd_MapIteratorOfPackedMapOfInteger aPixelIter(aGroup->Map()); aPixelIter.More();
aPixelIter.Next())
{
aDiffPixel = aPixelIter.Key();
aDiffPixel = aPixelIter.Key();
aNeighboursNb = 0;
// pixels of a line have only 1 or 2 neighbour pixels inside the same group
@@ -488,9 +497,10 @@ Standard_Integer Image_Diff::ignoreBorderEffect()
{
Standard_Integer anX = UnpackX(aDiffPixel) + Image_Diff_NEIGHBOR_PIXELS[aNgbrIter][0];
Standard_Integer anY = UnpackY(aDiffPixel) + Image_Diff_NEIGHBOR_PIXELS[aNgbrIter][1];
if (Standard_Size(anX) < myImageRef->SizeX() // this unsigned math checks Standard_Size(-1) at-once
&& Standard_Size(anY) < myImageRef->SizeY()
&& aGroup->Map().Contains (PackXY((uint16_t)anX, (uint16_t)anY)))
if (Standard_Size(anX)
< myImageRef->SizeX() // this unsigned math checks Standard_Size(-1) at-once
&& Standard_Size(anY) < myImageRef->SizeY()
&& aGroup->Map().Contains(PackXY((uint16_t)anX, (uint16_t)anY)))
{
++aNeighboursNb;
}
@@ -514,9 +524,10 @@ Standard_Integer Image_Diff::ignoreBorderEffect()
{
Standard_Integer anX = UnpackX(aDiffPixel) + Image_Diff_NEIGHBOR_PIXELS[aNgbrIter][0];
Standard_Integer anY = UnpackY(aDiffPixel) + Image_Diff_NEIGHBOR_PIXELS[aNgbrIter][1];
if (Standard_Size(anX) < myImageRef->SizeX() // this unsigned math checks Standard_Size(-1) at-once
&& Standard_Size(anY) < myImageRef->SizeY()
&& !isBlackPixel (*myImageRef, Standard_Size(anY), Standard_Size(anX)))
if (Standard_Size(anX)
< myImageRef->SizeX() // this unsigned math checks Standard_Size(-1) at-once
&& Standard_Size(anY) < myImageRef->SizeY()
&& !isBlackPixel(*myImageRef, Standard_Size(anY), Standard_Size(anX)))
{
++aNeighboursNb;
}
@@ -524,17 +535,20 @@ Standard_Integer Image_Diff::ignoreBorderEffect()
if (aNeighboursNb > 1)
{
myLinearGroups.Add (aGroupId);
myLinearGroups.Add(aGroupId);
}
}
}
// number of different groups of pixels (except linear groups)
Standard_Integer aNbDiffColors = 0;
aGroupId = 1;
for (NCollection_List<Handle(TColStd_HPackedMapOfInteger)>::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next(), ++aGroupId)
aGroupId = 1;
for (NCollection_List<Handle(TColStd_HPackedMapOfInteger)>::Iterator aGrIter(
myGroupsOfDiffPixels);
aGrIter.More();
aGrIter.Next(), ++aGroupId)
{
if (!myLinearGroups.Contains (aGroupId))
if (!myLinearGroups.Contains(aGroupId))
{
++aNbDiffColors;
}

View File

@@ -53,13 +53,13 @@
//! 1. http://pdiff.sourceforge.net/ypg01.pdf
//! 2. http://pdiff.sourceforge.net/metric.html
//! 3. http://www.cs.ucf.edu/~sumant/publications/sig99.pdf
//! 4. http://www.worldscientific.com/worldscibooks/10.1142/2641#t=toc (there is a list of articles and books in PDF format)
//! 4. http://www.worldscientific.com/worldscibooks/10.1142/2641#t=toc (there is a list of
//! articles and books in PDF format)
class Image_Diff : public Standard_Transient
{
public:
//! An empty constructor. Init() should be called for initialization.
Standard_EXPORT Image_Diff();
@@ -68,20 +68,21 @@ public:
//! 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);
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);
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.
void SetColorTolerance (const Standard_Real theTolerance) { myColorTolerance = theTolerance; }
//! By default, the tolerance is equal to 0 thus equality check will return false for any
//! different colors.
void SetColorTolerance(const Standard_Real theTolerance) { myColorTolerance = theTolerance; }
//! Color tolerance for equality check.
Standard_Real ColorTolerance() const { return myColorTolerance; }
@@ -92,7 +93,7 @@ public:
//! 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.
void SetBorderFilterOn (const Standard_Boolean theToIgnore) { myIsBorderFilterOn = theToIgnore; }
void SetBorderFilterOn(const Standard_Boolean theToIgnore) { myIsBorderFilterOn = theToIgnore; }
//! Returns a flag of taking into account (ignoring) a border effect in comparison of images.
Standard_Boolean IsBorderFilterOn() const { return myIsBorderFilterOn; }
@@ -102,13 +103,12 @@ public:
Standard_EXPORT Standard_Integer Compare();
//! Saves a difference between two images as white pixels on black background.
Standard_EXPORT Standard_Boolean SaveDiffImage (Image_PixMap& theDiffImage) const;
Standard_EXPORT Standard_Boolean SaveDiffImage(Image_PixMap& theDiffImage) const;
//! Saves a difference between two images as white pixels on black background.
Standard_EXPORT Standard_Boolean SaveDiffImage (const TCollection_AsciiString& theDiffPath) const;
Standard_EXPORT Standard_Boolean SaveDiffImage(const TCollection_AsciiString& theDiffPath) const;
protected:
//! Perform border filter algorithm.
Standard_EXPORT Standard_Integer ignoreBorderEffect();
@@ -116,46 +116,40 @@ protected:
Standard_EXPORT void releaseGroupsOfDiffPixels();
protected:
//! Map two pixel coordinates to 32-bit integer
static Standard_Integer PackXY (uint16_t theX, uint16_t theY)
static Standard_Integer PackXY(uint16_t theX, uint16_t theY)
{
return Standard_Integer((unsigned int)theY |
((unsigned int)theX << 16));
return Standard_Integer((unsigned int)theY | ((unsigned int)theX << 16));
}
//! Get pixel X coordinate from 32-bit packed integer
static uint16_t UnpackX (Standard_Integer theXY)
static uint16_t UnpackX(Standard_Integer theXY)
{
return (uint16_t)(((unsigned int)theXY & 0xffff0000) >> 16);
}
//! Get pixel Y coordinate from 32-bit packed integer
static uint16_t UnpackY (Standard_Integer theXY)
static uint16_t UnpackY(Standard_Integer theXY)
{
return (uint16_t)((unsigned int)theXY & 0xffff);
}
protected:
Handle(Image_PixMap) myImageRef; //!< reference image to compare (from)
Handle(Image_PixMap) myImageNew; //!< new image to compare (to)
// clang-format off
Handle(Image_PixMap) myImageRef; //!< reference image to compare (from)
Handle(Image_PixMap) myImageNew; //!< new image to compare (to)
// clang-format off
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
// clang-format on
// clang-format on
//! coordinates of different pixels, packed in one int using 16-bit integers to save memory
NCollection_Vector<Standard_Integer> myDiffPixels;
TColStd_PackedMapOfInteger myLinearGroups;
NCollection_List<Handle(TColStd_HPackedMapOfInteger)>
myGroupsOfDiffPixels;
NCollection_Vector<Standard_Integer> myDiffPixels;
TColStd_PackedMapOfInteger myLinearGroups;
NCollection_List<Handle(TColStd_HPackedMapOfInteger)> myGroupsOfDiffPixels;
public:
DEFINE_STANDARD_RTTIEXT(Image_Diff,Standard_Transient) // Type definition
DEFINE_STANDARD_RTTIEXT(Image_Diff, Standard_Transient) // Type definition
};
DEFINE_STANDARD_HANDLE(Image_Diff, Standard_Transient)

View File

@@ -22,22 +22,27 @@ enum Image_Format
Image_Format_Alpha, //!< 1 byte per pixel, transparency
Image_Format_RGB, //!< 3 bytes packed RGB image plane
Image_Format_BGR, //!< same as RGB but with different components order
Image_Format_RGB32, //!< 4 bytes packed RGB image plane (1 extra byte for alignment, may have undefined value)
Image_Format_BGR32, //!< same as RGB but with different components order
Image_Format_RGBA, //!< 4 bytes packed RGBA image plane
Image_Format_BGRA, //!< same as RGBA but with different components order
Image_Format_GrayF, //!< 1 float (4-bytes) per pixel (1-component plane), intensity of the color
Image_Format_AlphaF, //!< 1 float (4-bytes) per pixel (1-component plane), transparency
Image_Format_RGF, //!< 2 floats (8-bytes) RG image plane
Image_Format_RGBF, //!< 3 floats (12-bytes) RGB image plane
Image_Format_BGRF, //!< same as RGBF but with different components order
Image_Format_RGBAF, //!< 4 floats (16-bytes) RGBA image plane
Image_Format_BGRAF, //!< same as RGBAF but with different components order
Image_Format_GrayF_half, //!< 1 half-float (2-bytes) intensity of color
Image_Format_RGF_half, //!< 2 half-floats (4-bytes) RG image plane
Image_Format_RGBAF_half, //!< 4 half-floats (8-bytes) RGBA image plane
Image_Format_Gray16, //!< 2 bytes per pixel (unsigned short integer), intensity of the color
Image_Format_RGB32, //!< 4 bytes packed RGB image plane (1 extra byte for alignment, may have
//!< undefined value)
Image_Format_BGR32, //!< same as RGB but with different components order
Image_Format_RGBA, //!< 4 bytes packed RGBA image plane
Image_Format_BGRA, //!< same as RGBA but with different components order
Image_Format_GrayF, //!< 1 float (4-bytes) per pixel (1-component plane), intensity of the color
Image_Format_AlphaF, //!< 1 float (4-bytes) per pixel (1-component plane), transparency
Image_Format_RGF, //!< 2 floats (8-bytes) RG image plane
Image_Format_RGBF, //!< 3 floats (12-bytes) RGB image plane
Image_Format_BGRF, //!< same as RGBF but with different components order
Image_Format_RGBAF, //!< 4 floats (16-bytes) RGBA image plane
Image_Format_BGRAF, //!< same as RGBAF but with different components order
Image_Format_GrayF_half, //!< 1 half-float (2-bytes) intensity of color
Image_Format_RGF_half, //!< 2 half-floats (4-bytes) RG image plane
Image_Format_RGBAF_half, //!< 4 half-floats (8-bytes) RGBA image plane
Image_Format_Gray16, //!< 2 bytes per pixel (unsigned short integer), intensity of the color
};
enum
{
Image_Format_NB = Image_Format_Gray16 + 1
};
enum { Image_Format_NB = Image_Format_Gray16 + 1 };
#endif // _Image_Format_HeaderFile

File diff suppressed because it is too large Load Diff

View File

@@ -26,17 +26,20 @@ class Image_PixMap : public Standard_Transient
{
DEFINE_STANDARD_RTTIEXT(Image_PixMap, Standard_Transient)
public:
//! Determine Big-Endian at runtime
static inline bool IsBigEndianHost()
{
union { int myInt; char myChar[sizeof(int)]; } aUnion;
union {
int myInt;
char myChar[sizeof(int)];
} aUnion;
aUnion.myInt = 1;
return !aUnion.myChar[0];
}
//! Return bytes reserved for one pixel (may include extra bytes for alignment).
Standard_EXPORT static Standard_Size SizePixelBytes (const Image_Format thePixelFormat);
Standard_EXPORT static Standard_Size SizePixelBytes(const Image_Format thePixelFormat);
//! Auxiliary method for swapping bytes between RGB and BGR formats.
//! This method modifies the image data but does not change pixel format!
@@ -46,44 +49,46 @@ public:
//! - Image_Format_RGB / Image_Format_BGR
//! - Image_Format_RGBF / Image_Format_BGRF
//! - Image_Format_RGBAF / Image_Format_BGRAF
Standard_EXPORT static bool SwapRgbaBgra (Image_PixMap& theImage);
Standard_EXPORT static bool SwapRgbaBgra(Image_PixMap& theImage);
//! Convert image to Black/White.
Standard_EXPORT static void ToBlackWhite (Image_PixMap& theImage);
Standard_EXPORT static void ToBlackWhite(Image_PixMap& theImage);
//! Reverse line order as it draws it from bottom to top.
Standard_EXPORT static bool FlipY (Image_PixMap& theImage);
Standard_EXPORT static bool FlipY(Image_PixMap& theImage);
//! Return default image data allocator.
Standard_EXPORT static const Handle(NCollection_BaseAllocator)& DefaultAllocator();
//! Return string representation of pixel format.
Standard_EXPORT static Standard_CString ImageFormatToString (Image_Format theFormat);
Standard_EXPORT static Standard_CString ImageFormatToString(Image_Format theFormat);
//! Return string representation of compressed pixel format.
Standard_EXPORT static Standard_CString ImageFormatToString (Image_CompressedFormat theFormat);
Standard_EXPORT static Standard_CString ImageFormatToString(Image_CompressedFormat theFormat);
//! Convert raw pixel value into Quantity_ColorRGBA. This function is relatively slow.
//! @param[in] theRawValue pointer to pixel definition
//! @param[in] theFormat pixel format
//! @param[in] theToLinearize when TRUE, the color stored in non-linear color space (e.g. Image_Format_RGB) will be linearized
//! @param[in] theToLinearize when TRUE, the color stored in non-linear color space (e.g.
//! Image_Format_RGB) will be linearized
//! @return the pixel color
Standard_EXPORT static Quantity_ColorRGBA ColorFromRawPixel (const Standard_Byte* theRawValue,
const Image_Format theFormat,
const Standard_Boolean theToLinearize = false);
Standard_EXPORT static Quantity_ColorRGBA ColorFromRawPixel(
const Standard_Byte* theRawValue,
const Image_Format theFormat,
const Standard_Boolean theToLinearize = false);
//! Set raw pixel value from Quantity_ColorRGBA. This function is relatively slow.
//! @param[out] theRawValue pointer to pixel definition to modify
//! @param[in] theFormat pixel format
//! @param[in] theColor color value to convert from
//! @param[in] theToDeLinearize when TRUE, the gamma correction will be applied for storing in non-linear color space (e.g. Image_Format_RGB)
Standard_EXPORT static void ColorToRawPixel (Standard_Byte* theRawValue,
const Image_Format theFormat,
const Quantity_ColorRGBA& theColor,
const Standard_Boolean theToDeLinearize = false);
//! @param[in] theToDeLinearize when TRUE, the gamma correction will be applied for storing in
//! non-linear color space (e.g. Image_Format_RGB)
Standard_EXPORT static void ColorToRawPixel(Standard_Byte* theRawValue,
const Image_Format theFormat,
const Quantity_ColorRGBA& theColor,
const Standard_Boolean theToDeLinearize = false);
public: // high-level API
//! Return pixel format.
Image_Format Format() const { return myImgFormat; }
@@ -91,7 +96,7 @@ public: // high-level API
//! Will throw exception if pixel size of new format is not equal to currently initialized format.
//! Intended to switch formats indicating different interpretation of the same data
//! (e.g. ImgGray and ImgAlpha).
Standard_EXPORT void SetFormat (const Image_Format thePixelFormat);
Standard_EXPORT void SetFormat(const Image_Format thePixelFormat);
//! Return image width in pixels.
Standard_Size Width() const { return myData.SizeX; }
@@ -114,7 +119,7 @@ public: // high-level API
//! Return image width x height x depth in pixels.
NCollection_Vec3<Standard_Size> SizeXYZ() const
{
return NCollection_Vec3<Standard_Size> (myData.SizeX, myData.SizeY, myData.SizeZ);
return NCollection_Vec3<Standard_Size>(myData.SizeX, myData.SizeY, myData.SizeZ);
}
//! Return width / height.
@@ -133,123 +138,128 @@ public: // high-level API
Standard_EXPORT virtual ~Image_PixMap();
//! Returns the pixel color. This function is relatively slow.
//! Beware that this method takes coordinates in opposite order in contrast to ::Value() and ::ChangeValue().
//! Beware that this method takes coordinates in opposite order in contrast to ::Value() and
//! ::ChangeValue().
//! @param[in] theX column index from left, starting from 0
//! @param[in] theY row index from top, starting from 0
//! @param[in] theToLinearize when TRUE, the color stored in non-linear color space (e.g. Image_Format_RGB) will be linearized
//! @param[in] theToLinearize when TRUE, the color stored in non-linear color space (e.g.
//! Image_Format_RGB) will be linearized
//! @return the pixel color
Quantity_ColorRGBA PixelColor (Standard_Integer theX,
Standard_Integer theY,
Standard_Boolean theToLinearize = false) const
Quantity_ColorRGBA PixelColor(Standard_Integer theX,
Standard_Integer theY,
Standard_Boolean theToLinearize = false) const
{
if (IsEmpty()
|| theX < 0 || (Standard_Size )theX >= SizeX()
|| theY < 0 || (Standard_Size )theY >= SizeY())
if (IsEmpty() || theX < 0 || (Standard_Size)theX >= SizeX() || theY < 0
|| (Standard_Size)theY >= SizeY())
{
return Quantity_ColorRGBA (0.0f, 0.0f, 0.0f, 0.0f); // transparent
return Quantity_ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f); // transparent
}
const Standard_Byte* aRawPixel = RawValueXY (theX, theY);
return ColorFromRawPixel (aRawPixel, myImgFormat, theToLinearize);
const Standard_Byte* aRawPixel = RawValueXY(theX, theY);
return ColorFromRawPixel(aRawPixel, myImgFormat, theToLinearize);
}
//! Sets the pixel color. This function is relatively slow.
//! Beware that this method takes coordinates in opposite order in contrast to ::Value() and ::ChangeValue().
//! Beware that this method takes coordinates in opposite order in contrast to ::Value() and
//! ::ChangeValue().
//! @param[in] theX column index from left
//! @param[in] theY row index from top
//! @param[in] theColor color to store
//! @param[in] theToDeLinearize when TRUE, the gamma correction will be applied for storing in non-linear color space (e.g. Image_Format_RGB)
void SetPixelColor (const Standard_Integer theX,
const Standard_Integer theY,
const Quantity_Color& theColor,
const Standard_Boolean theToDeLinearize = false)
//! @param[in] theToDeLinearize when TRUE, the gamma correction will be applied for storing in
//! non-linear color space (e.g. Image_Format_RGB)
void SetPixelColor(const Standard_Integer theX,
const Standard_Integer theY,
const Quantity_Color& theColor,
const Standard_Boolean theToDeLinearize = false)
{
SetPixelColor (theX, theY, Quantity_ColorRGBA (theColor, 1.0f), theToDeLinearize);
SetPixelColor(theX, theY, Quantity_ColorRGBA(theColor, 1.0f), theToDeLinearize);
}
//! Sets the pixel color. This function is relatively slow.
//! Beware that this method takes coordinates in opposite order in contrast to ::Value() and ::ChangeValue().
//! Beware that this method takes coordinates in opposite order in contrast to ::Value() and
//! ::ChangeValue().
//! @param[in] theX column index from left
//! @param[in] theY row index from top
//! @param[in] theColor color to store
//! @param[in] theToDeLinearize when TRUE, the gamma correction will be applied for storing in non-linear color space (e.g. Image_Format_RGB)
void SetPixelColor (const Standard_Integer theX,
const Standard_Integer theY,
const Quantity_ColorRGBA& theColor,
const Standard_Boolean theToDeLinearize = false)
//! @param[in] theToDeLinearize when TRUE, the gamma correction will be applied for storing in
//! non-linear color space (e.g. Image_Format_RGB)
void SetPixelColor(const Standard_Integer theX,
const Standard_Integer theY,
const Quantity_ColorRGBA& theColor,
const Standard_Boolean theToDeLinearize = false)
{
if (IsEmpty()
|| theX < 0 || Standard_Size(theX) >= SizeX()
|| theY < 0 || Standard_Size(theY) >= SizeY())
if (IsEmpty() || theX < 0 || Standard_Size(theX) >= SizeX() || theY < 0
|| Standard_Size(theY) >= SizeY())
{
return;
}
Standard_Byte* aRawPixel = ChangeRawValueXY (theX, theY);
ColorToRawPixel (aRawPixel, myImgFormat, theColor, theToDeLinearize);
Standard_Byte* aRawPixel = ChangeRawValueXY(theX, theY);
ColorToRawPixel(aRawPixel, myImgFormat, theColor, theToDeLinearize);
}
//! 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 (Image_Format thePixelFormat,
Standard_Byte* theDataPtr,
const Standard_Size theSizeX,
const Standard_Size theSizeY,
const Standard_Size theSizeRowBytes = 0);
Standard_EXPORT virtual bool InitWrapper(Image_Format 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 (Image_Format thePixelFormat,
const Standard_Size theSizeX,
const Standard_Size theSizeY,
const Standard_Size theSizeRowBytes = 0);
Standard_EXPORT virtual bool InitTrash(Image_Format 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);
Standard_EXPORT virtual bool InitCopy(const Image_PixMap& theCopy);
//! Initialize image plane with required dimensions.
//! Buffer will be zeroed (black color for most formats).
bool InitZero (Image_Format thePixelFormat,
const Standard_Size theSizeX,
const Standard_Size theSizeY,
const Standard_Size theSizeRowBytes = 0,
const Standard_Byte theValue = 0)
bool InitZero(Image_Format thePixelFormat,
const Standard_Size theSizeX,
const Standard_Size theSizeY,
const Standard_Size theSizeRowBytes = 0,
const Standard_Byte theValue = 0)
{
return InitZero3D (thePixelFormat, NCollection_Vec3<Standard_Size> (theSizeX, theSizeY, 1), theSizeRowBytes, theValue);
return InitZero3D(thePixelFormat,
NCollection_Vec3<Standard_Size>(theSizeX, theSizeY, 1),
theSizeRowBytes,
theValue);
}
//! Method correctly deallocate internal buffer.
Standard_EXPORT virtual void Clear();
public:
//! Initialize 2D/3D image 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 InitWrapper3D (Image_Format thePixelFormat,
Standard_Byte* theDataPtr,
const NCollection_Vec3<Standard_Size>& theSizeXYZ,
const Standard_Size theSizeRowBytes = 0);
Standard_EXPORT virtual bool InitWrapper3D(Image_Format thePixelFormat,
Standard_Byte* theDataPtr,
const NCollection_Vec3<Standard_Size>& theSizeXYZ,
const Standard_Size theSizeRowBytes = 0);
//! Initialize 2D/3D image with required dimensions.
//! Memory will be left uninitialized (performance trick).
Standard_EXPORT virtual bool InitTrash3D (Image_Format thePixelFormat,
const NCollection_Vec3<Standard_Size>& theSizeXYZ,
const Standard_Size theSizeRowBytes = 0);
Standard_EXPORT virtual bool InitTrash3D(Image_Format thePixelFormat,
const NCollection_Vec3<Standard_Size>& theSizeXYZ,
const Standard_Size theSizeRowBytes = 0);
//! Initialize 2D/3D image with required dimensions.
//! Buffer will be zeroed (black color for most formats).
Standard_EXPORT bool InitZero3D (Image_Format thePixelFormat,
const NCollection_Vec3<Standard_Size>& theSizeXYZ,
const Standard_Size theSizeRowBytes = 0,
const Standard_Byte theValue = 0);
Standard_EXPORT bool InitZero3D(Image_Format thePixelFormat,
const NCollection_Vec3<Standard_Size>& theSizeXYZ,
const Standard_Size theSizeRowBytes = 0,
const Standard_Byte theValue = 0);
public: //! @name low-level API for batch-processing (pixels reading / comparison / modification)
//! Returns TRUE if image data is stored from Top to the Down.
//! By default Bottom Up order is used instead
//! (topmost scanlines starts from the bottom in memory).
@@ -264,48 +274,48 @@ public: //! @name low-level API for batch-processing (pixels reading / compariso
//! 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
void SetTopDown (const bool theIsTopDown) { myData.SetTopDown (theIsTopDown); }
void SetTopDown(const bool theIsTopDown) { myData.SetTopDown(theIsTopDown); }
//! Returns +1 if scanlines ordered in Top->Down order in memory and -1 otherwise.
//! @return scanline increment for Top->Down iteration
Standard_Size TopDownInc() const { return myData.TopToDown; }
//! Return data pointer for low-level operations (copying entire buffer, parsing with extra tools etc.).
//! Return data pointer for low-level operations (copying entire buffer, parsing with extra tools
//! etc.).
const Standard_Byte* Data() const { return myData.Data(); }
//! Return data pointer for low-level operations (copying entire buffer, parsing with extra tools etc.).
//! Return data pointer for low-level operations (copying entire buffer, parsing with extra tools
//! etc.).
Standard_Byte* ChangeData() { return myData.ChangeData(); }
//! Return data pointer to requested row (first column).
//! Indexation starts from 0.
const Standard_Byte* Row (Standard_Size theRow) const { return myData.Row (theRow); }
const Standard_Byte* Row(Standard_Size theRow) const { return myData.Row(theRow); }
//! Return data pointer to requested row (first column).
//! Indexation starts from 0.
Standard_Byte* ChangeRow (Standard_Size theRow) { return myData.ChangeRow (theRow); }
Standard_Byte* ChangeRow(Standard_Size theRow) { return myData.ChangeRow(theRow); }
//! Return data pointer to requested 2D slice.
//! Indexation starts from 0.
const Standard_Byte* Slice (Standard_Size theSlice) const { return myData.Slice (theSlice); }
const Standard_Byte* Slice(Standard_Size theSlice) const { return myData.Slice(theSlice); }
//! Return data pointer to requested 2D slice.
//! Indexation starts from 0.
Standard_Byte* ChangeSlice (Standard_Size theSlice) { return myData.ChangeSlice (theSlice); }
Standard_Byte* ChangeSlice(Standard_Size theSlice) { return myData.ChangeSlice(theSlice); }
//! Return data pointer to requested row (first column).
//! Indexation starts from 0.
const Standard_Byte* SliceRow (Standard_Size theSlice,
Standard_Size theRow) const
const Standard_Byte* SliceRow(Standard_Size theSlice, Standard_Size theRow) const
{
return myData.SliceRow (theSlice, theRow);
return myData.SliceRow(theSlice, theRow);
}
//! Return data pointer to requested row (first column).
//! Indexation starts from 0.
Standard_Byte* ChangeSliceRow (Standard_Size theSlice,
Standard_Size theRow)
Standard_Byte* ChangeSliceRow(Standard_Size theSlice, Standard_Size theRow)
{
return myData.ChangeSliceRow (theSlice, theRow);
return myData.ChangeSliceRow(theSlice, theRow);
}
//! Return bytes reserved for one pixel (may include extra bytes for alignment).
@@ -316,10 +326,7 @@ public: //! @name low-level API for batch-processing (pixels reading / compariso
Standard_Size SizeRowBytes() const { return myData.SizeRowBytes; }
//! Return the extra bytes in the row.
Standard_Size RowExtraBytes() const
{
return SizeRowBytes() - SizeX() * SizePixelBytes();
}
Standard_Size RowExtraBytes() const { return SizeRowBytes() - SizeX() * SizePixelBytes(); }
//! Compute the maximal row alignment for current row size.
//! @return maximal row alignment in bytes (up to 16 bytes).
@@ -332,47 +339,46 @@ public: //! @name low-level API for batch-processing (pixels reading / compariso
Standard_Size SizeBytes() const { return myData.Size(); }
public:
//! Access image pixel with specified color type.
//! Indexation starts from 0.
//! This method does not perform any type checks - use on own risk (check Format() before)!
//! WARNING: Input parameters are defined in the decreasing majority following memory layout - e.g. row first, column next.
//! WARNING: Input parameters are defined in the decreasing majority following memory layout -
//! e.g. row first, column next.
template <typename ColorType_t>
const ColorType_t& Value (Standard_Size theRow,
Standard_Size theCol) const
const ColorType_t& Value(Standard_Size theRow, Standard_Size theCol) const
{
return *reinterpret_cast<const ColorType_t*>(myData.Value (theRow, theCol));
return *reinterpret_cast<const ColorType_t*>(myData.Value(theRow, theCol));
}
//! Access image pixel with specified color type.
//! Indexation starts from 0.
//! This method does not perform any type checks - use on own risk (check Format() before)!
//! WARNING: Input parameters are defined in the decreasing majority following memory layout - e.g. row first, column next.
//! WARNING: Input parameters are defined in the decreasing majority following memory layout -
//! e.g. row first, column next.
template <typename ColorType_t>
ColorType_t& ChangeValue (Standard_Size theRow,
Standard_Size theCol)
ColorType_t& ChangeValue(Standard_Size theRow, Standard_Size theCol)
{
return *reinterpret_cast<ColorType_t* >(myData.ChangeValue (theRow, theCol));
return *reinterpret_cast<ColorType_t*>(myData.ChangeValue(theRow, theCol));
}
//! Access image pixel as raw data pointer.
//! Indexation starts from 0.
//! This method does not perform any type checks - use on own risk (check Format() before)!
//! WARNING: Input parameters are defined in the decreasing majority following memory layout - e.g. row first, column next.
const Standard_Byte* RawValue (Standard_Size theRow,
Standard_Size theCol) const
//! WARNING: Input parameters are defined in the decreasing majority following memory layout -
//! e.g. row first, column next.
const Standard_Byte* RawValue(Standard_Size theRow, Standard_Size theCol) const
{
return myData.Value (theRow, theCol);
return myData.Value(theRow, theCol);
}
//! Access image pixel as raw data pointer.
//! Indexation starts from 0.
//! This method does not perform any type checks - use on own risk (check Format() before)!
//! WARNING: Input parameters are defined in the decreasing majority following memory layout - e.g. row first, column next.
Standard_Byte* ChangeRawValue (Standard_Size theRow,
Standard_Size theCol)
//! WARNING: Input parameters are defined in the decreasing majority following memory layout -
//! e.g. row first, column next.
Standard_Byte* ChangeRawValue(Standard_Size theRow, Standard_Size theCol)
{
return myData.ChangeValue (theRow, theCol);
return myData.ChangeValue(theRow, theCol);
}
//! Access image pixel with specified color type.
@@ -380,10 +386,9 @@ public:
//! This method does not perform any type checks - use on own risk (check Format() before)!
//! WARNING: Input parameters are defined in traditional X, Y order.
template <typename ColorType_t>
const ColorType_t& ValueXY (Standard_Size theX,
Standard_Size theY) const
const ColorType_t& ValueXY(Standard_Size theX, Standard_Size theY) const
{
return *reinterpret_cast<const ColorType_t*>(myData.ValueXY (theX, theY));
return *reinterpret_cast<const ColorType_t*>(myData.ValueXY(theX, theY));
}
//! Access image pixel with specified color type.
@@ -391,44 +396,38 @@ public:
//! This method does not perform any type checks - use on own risk (check Format() before)!
//! WARNING: Input parameters are defined in traditional X, Y order.
template <typename ColorType_t>
ColorType_t& ChangeValueXY (Standard_Size theX,
Standard_Size theY)
ColorType_t& ChangeValueXY(Standard_Size theX, Standard_Size theY)
{
return *reinterpret_cast<ColorType_t* >(myData.ChangeValueXY (theX, theY));
return *reinterpret_cast<ColorType_t*>(myData.ChangeValueXY(theX, theY));
}
//! Access image pixel as raw data pointer.
//! Indexation starts from 0.
//! This method does not perform any type checks - use on own risk (check Format() before)!
//! WARNING: Input parameters are defined in traditional X, Y order.
const Standard_Byte* RawValueXY (Standard_Size theX,
Standard_Size theY) const
const Standard_Byte* RawValueXY(Standard_Size theX, Standard_Size theY) const
{
return myData.ValueXY (theX, theY);
return myData.ValueXY(theX, theY);
}
//! Access image pixel as raw data pointer.
//! Indexation starts from 0.
//! This method does not perform any type checks - use on own risk (check Format() before)!
//! WARNING: Input parameters are defined in traditional X, Y order.
Standard_Byte* ChangeRawValueXY (Standard_Size theX,
Standard_Size theY)
Standard_Byte* ChangeRawValueXY(Standard_Size theX, Standard_Size theY)
{
return myData.ChangeValueXY (theX, theY);
return myData.ChangeValueXY(theX, theY);
}
public:
//! Access image pixel with specified color type.
//! Indexation starts from 0.
//! This method does not perform any type checks - use on own risk (check Format() before)!
//! WARNING: Input parameters are defined in traditional X, Y, Z order.
template <typename ColorType_t>
const ColorType_t& ValueXYZ (Standard_Size theX,
Standard_Size theY,
Standard_Size theZ) const
const ColorType_t& ValueXYZ(Standard_Size theX, Standard_Size theY, Standard_Size theZ) const
{
return *reinterpret_cast<const ColorType_t*>(myData.ValueXYZ (theX, theY, theZ));
return *reinterpret_cast<const ColorType_t*>(myData.ValueXYZ(theX, theY, theZ));
}
//! Access image pixel with specified color type.
@@ -436,80 +435,77 @@ public:
//! This method does not perform any type checks - use on own risk (check Format() before)!
//! WARNING: Input parameters are defined in traditional X, Y, Z order.
template <typename ColorType_t>
ColorType_t& ChangeValueXYZ (Standard_Size theX,
Standard_Size theY,
Standard_Size theZ)
ColorType_t& ChangeValueXYZ(Standard_Size theX, Standard_Size theY, Standard_Size theZ)
{
return *reinterpret_cast<ColorType_t* >(myData.ChangeValueXYZ (theX, theY, theZ));
return *reinterpret_cast<ColorType_t*>(myData.ChangeValueXYZ(theX, theY, theZ));
}
//! Access image pixel as raw data pointer.
//! Indexation starts from 0.
//! This method does not perform any type checks - use on own risk (check Format() before)!
//! WARNING: Input parameters are defined in traditional X, Y, Z order.
const Standard_Byte* RawValueXYZ (Standard_Size theX,
Standard_Size theY,
Standard_Size theZ) const
const Standard_Byte* RawValueXYZ(Standard_Size theX, Standard_Size theY, Standard_Size theZ) const
{
return myData.ValueXYZ (theX, theY, theZ);
return myData.ValueXYZ(theX, theY, theZ);
}
//! Access image pixel as raw data pointer.
//! Indexation starts from 0.
//! This method does not perform any type checks - use on own risk (check Format() before)!
//! WARNING: Input parameters are defined in traditional X, Y, Z order.
Standard_Byte* ChangeRawValueXYZ (Standard_Size theX,
Standard_Size theY,
Standard_Size theZ)
Standard_Byte* ChangeRawValueXYZ(Standard_Size theX, Standard_Size theY, Standard_Size theZ)
{
return myData.ChangeValueXYZ (theX, theY, theZ);
return myData.ChangeValueXYZ(theX, theY, theZ);
}
public:
//! Convert 16-bit half-float value into 32-bit float (simple conversion).
static float ConvertFromHalfFloat (const uint16_t theHalf)
static float ConvertFromHalfFloat(const uint16_t theHalf)
{
union FloatUint32 { float Float32; uint32_t UInt32; };
union FloatUint32 {
float Float32;
uint32_t UInt32;
};
const uint32_t e = (theHalf & 0x7C00) >> 10; // exponent
const uint32_t m = (theHalf & 0x03FF) << 13; // mantissa
FloatUint32 mf, aRes;
mf.Float32 = (float )m;
// clang-format off
FloatUint32 mf, aRes;
mf.Float32 = (float)m;
// clang-format off
const uint32_t v = mf.UInt32 >> 23; // evil log2 bit hack to count leading zeros in denormalized format
aRes.UInt32 = (theHalf & 0x8000)<<16 | (e != 0) * ((e + 112) << 23 | m) | ((e == 0) & (m != 0)) * ((v - 37) << 23 | ((m << (150 - v)) & 0x007FE000)); // sign : normalized : denormalized
// clang-format on
// clang-format on
return aRes.Float32;
}
//! Convert 32-bit float value into IEEE-754 16-bit floating-point format without infinity:
//! 1-5-10, exp-15, +-131008.0, +-6.1035156E-5, +-5.9604645E-8, 3.311 digits.
static uint16_t ConvertToHalfFloat (const float theFloat)
static uint16_t ConvertToHalfFloat(const float theFloat)
{
union FloatUint32 { float Float32; uint32_t UInt32; };
union FloatUint32 {
float Float32;
uint32_t UInt32;
};
FloatUint32 anInput;
anInput.Float32 = theFloat;
// clang-format off
// clang-format off
const uint32_t b = anInput.UInt32 + 0x00001000; // round-to-nearest-even: add last bit after truncated mantissa
const uint32_t e = (b & 0x7F800000) >> 23; // exponent
const uint32_t m = b & 0x007FFFFF; // mantissa; in line below: 0x007FF000 = 0x00800000-0x00001000 = decimal indicator flag - initial rounding
return (uint16_t)((b & 0x80000000) >> 16 | (e > 112) * ((((e - 112) << 10) & 0x7C00) | m >> 13)
| ((e < 113) & (e > 101)) * ((((0x007FF000 + m) >> (125 - e)) + 1) >> 1) | (e > 143) * 0x7FFF); // sign : normalized : denormalized : saturate
// clang-format on
// clang-format on
}
protected:
Image_PixMapData myData; //!< data buffer
Image_Format myImgFormat; //!< pixel format
private:
//! Copying allowed only within Handles
Image_PixMap (const Image_PixMap& );
Image_PixMap& operator= (const Image_PixMap& );
Image_PixMap(const Image_PixMap&);
Image_PixMap& operator=(const Image_PixMap&);
};
DEFINE_STANDARD_HANDLE(Image_PixMap, Standard_Transient)

View File

@@ -24,56 +24,59 @@
class Image_PixMapData : public NCollection_Buffer
{
public:
//! Empty constructor.
Image_PixMapData()
: NCollection_Buffer (Handle(NCollection_BaseAllocator)()),
myTopRowPtr (NULL),
SizeBPP (0),
SizeX (0),
SizeY (0),
SizeZ (0),
SizeRowBytes (0),
SizeSliceBytes (0),
TopToDown (Standard_Size(-1))
: NCollection_Buffer(Handle(NCollection_BaseAllocator)()),
myTopRowPtr(NULL),
SizeBPP(0),
SizeX(0),
SizeY(0),
SizeZ(0),
SizeRowBytes(0),
SizeSliceBytes(0),
TopToDown(Standard_Size(-1))
{
//
}
//! Initializer.
bool Init (const Handle(NCollection_BaseAllocator)& theAlloc,
const Standard_Size theSizeBPP,
const Standard_Size theSizeX,
const Standard_Size theSizeY,
const Standard_Size theSizeRowBytes,
Standard_Byte* theDataPtr)
bool Init(const Handle(NCollection_BaseAllocator)& theAlloc,
const Standard_Size theSizeBPP,
const Standard_Size theSizeX,
const Standard_Size theSizeY,
const Standard_Size theSizeRowBytes,
Standard_Byte* theDataPtr)
{
return Init (theAlloc, theSizeBPP, NCollection_Vec3<Standard_Size> (theSizeX, theSizeY, 1), theSizeRowBytes, theDataPtr);
return Init(theAlloc,
theSizeBPP,
NCollection_Vec3<Standard_Size>(theSizeX, theSizeY, 1),
theSizeRowBytes,
theDataPtr);
}
//! Initializer.
bool Init (const Handle(NCollection_BaseAllocator)& theAlloc,
const Standard_Size theSizeBPP,
const NCollection_Vec3<Standard_Size>& theSizeXYZ,
const Standard_Size theSizeRowBytes,
Standard_Byte* theDataPtr)
bool Init(const Handle(NCollection_BaseAllocator)& theAlloc,
const Standard_Size theSizeBPP,
const NCollection_Vec3<Standard_Size>& theSizeXYZ,
const Standard_Size theSizeRowBytes,
Standard_Byte* theDataPtr)
{
SetAllocator (theAlloc); // will free old data as well
SetAllocator(theAlloc); // will free old data as well
myData = theDataPtr;
myTopRowPtr = NULL;
SizeBPP = theSizeBPP;
SizeX = theSizeXYZ.x();
SizeY = theSizeXYZ.y();
SizeZ = theSizeXYZ.z();
SizeRowBytes = theSizeRowBytes != 0 ? theSizeRowBytes : (SizeX * theSizeBPP);
myData = theDataPtr;
myTopRowPtr = NULL;
SizeBPP = theSizeBPP;
SizeX = theSizeXYZ.x();
SizeY = theSizeXYZ.y();
SizeZ = theSizeXYZ.z();
SizeRowBytes = theSizeRowBytes != 0 ? theSizeRowBytes : (SizeX * theSizeBPP);
SizeSliceBytes = SizeRowBytes * SizeY;
mySize = SizeSliceBytes * SizeZ;
mySize = SizeSliceBytes * SizeZ;
if (myData == NULL)
{
Allocate (mySize);
Allocate(mySize);
}
SetTopDown (TopToDown == 1);
SetTopDown(TopToDown == 1);
return !IsEmpty();
}
@@ -82,92 +85,85 @@ public:
{
if (myData != NULL)
{
memset (myData, 0, mySize);
memset(myData, 0, mySize);
}
}
//! Return data pointer to requested row (first column).
const Standard_Byte* Row (const Standard_Size theRow) const
const Standard_Byte* Row(const Standard_Size theRow) const
{
return myTopRowPtr + ptrdiff_t(SizeRowBytes * theRow * TopToDown);
}
//! Return data pointer to requested row (first column).
Standard_Byte* ChangeRow (const Standard_Size theRow)
Standard_Byte* ChangeRow(const Standard_Size theRow)
{
return myTopRowPtr + ptrdiff_t(SizeRowBytes * theRow * TopToDown);
}
//! Return data pointer to requested position.
const Standard_Byte* Value (const Standard_Size theRow,
const Standard_Size theCol) const
const Standard_Byte* Value(const Standard_Size theRow, const Standard_Size theCol) const
{
return myTopRowPtr + ptrdiff_t(SizeRowBytes * theRow * TopToDown) + SizeBPP * theCol;
}
//! Return data pointer to requested position.
Standard_Byte* ChangeValue (Standard_Size theRow,
Standard_Size theCol)
Standard_Byte* ChangeValue(Standard_Size theRow, Standard_Size theCol)
{
return myTopRowPtr + ptrdiff_t(SizeRowBytes * theRow * TopToDown) + SizeBPP * theCol;
}
//! Return data pointer to requested position.
const Standard_Byte* ValueXY (Standard_Size theX,
Standard_Size theY) const
const Standard_Byte* ValueXY(Standard_Size theX, Standard_Size theY) const
{
return myTopRowPtr + ptrdiff_t(SizeRowBytes * theY * TopToDown) + SizeBPP * theX;
}
//! Return data pointer to requested position.
Standard_Byte* ChangeValueXY (Standard_Size theX,
Standard_Size theY)
Standard_Byte* ChangeValueXY(Standard_Size theX, Standard_Size theY)
{
return myTopRowPtr + ptrdiff_t(SizeRowBytes * theY * TopToDown) + SizeBPP * theX;
}
public:
//! Return data pointer to requested 2D slice.
const Standard_Byte* Slice (Standard_Size theSlice) const
const Standard_Byte* Slice(Standard_Size theSlice) const
{
return myData + ptrdiff_t(SizeSliceBytes * theSlice);
}
//! Return data pointer to requested 2D slice.
Standard_Byte* ChangeSlice (Standard_Size theSlice)
Standard_Byte* ChangeSlice(Standard_Size theSlice)
{
return myData + ptrdiff_t(SizeSliceBytes * theSlice);
}
//! Return data pointer to requested row (first column).
const Standard_Byte* SliceRow (Standard_Size theSlice,
Standard_Size theRow) const
const Standard_Byte* SliceRow(Standard_Size theSlice, Standard_Size theRow) const
{
return myTopRowPtr + ptrdiff_t(SizeRowBytes * theRow * TopToDown) + ptrdiff_t(SizeSliceBytes * theSlice);
return myTopRowPtr + ptrdiff_t(SizeRowBytes * theRow * TopToDown)
+ ptrdiff_t(SizeSliceBytes * theSlice);
}
//! Return data pointer to requested row (first column).
Standard_Byte* ChangeSliceRow (Standard_Size theSlice,
Standard_Size theRow)
Standard_Byte* ChangeSliceRow(Standard_Size theSlice, Standard_Size theRow)
{
return myTopRowPtr + ptrdiff_t(SizeRowBytes * theRow * TopToDown) + ptrdiff_t(SizeSliceBytes * theSlice);
return myTopRowPtr + ptrdiff_t(SizeRowBytes * theRow * TopToDown)
+ ptrdiff_t(SizeSliceBytes * theSlice);
}
//! Return data pointer to requested position.
const Standard_Byte* ValueXYZ (Standard_Size theX,
Standard_Size theY,
Standard_Size theZ) const
const Standard_Byte* ValueXYZ(Standard_Size theX, Standard_Size theY, Standard_Size theZ) const
{
return myTopRowPtr + ptrdiff_t(SizeRowBytes * theY * TopToDown) + SizeBPP * theX + ptrdiff_t(SizeSliceBytes * theZ);
return myTopRowPtr + ptrdiff_t(SizeRowBytes * theY * TopToDown) + SizeBPP * theX
+ ptrdiff_t(SizeSliceBytes * theZ);
}
//! Return data pointer to requested position.
Standard_Byte* ChangeValueXYZ (Standard_Size theX,
Standard_Size theY,
Standard_Size theZ)
Standard_Byte* ChangeValueXYZ(Standard_Size theX, Standard_Size theY, Standard_Size theZ)
{
return myTopRowPtr + ptrdiff_t(SizeRowBytes * theY * TopToDown) + SizeBPP * theX + ptrdiff_t(SizeSliceBytes * theZ);
return myTopRowPtr + ptrdiff_t(SizeRowBytes * theY * TopToDown) + SizeBPP * theX
+ ptrdiff_t(SizeSliceBytes * theZ);
}
//! Compute the maximal row alignment for current row size.
@@ -188,33 +184,29 @@ public:
//! 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
void SetTopDown (const bool theIsTopDown)
void SetTopDown(const bool theIsTopDown)
{
TopToDown = (theIsTopDown ? 1 : Standard_Size(-1));
myTopRowPtr = ((TopToDown == 1 || myData == NULL)
? myData : (myData + SizeRowBytes * (SizeY - 1)));
TopToDown = (theIsTopDown ? 1 : Standard_Size(-1));
myTopRowPtr =
((TopToDown == 1 || myData == NULL) ? myData : (myData + SizeRowBytes * (SizeY - 1)));
}
protected:
// clang-format off
// clang-format off
Standard_Byte* myTopRowPtr; //!< pointer to the topmost row (depending on scanlines order in memory)
// clang-format on
// clang-format on
public:
Standard_Size SizeBPP; //!< bytes per pixel
Standard_Size SizeX; //!< width in pixels
Standard_Size SizeY; //!< height in pixels
Standard_Size SizeZ; //!< depth in pixels
Standard_Size SizeRowBytes; //!< number of bytes per line (in most cases equal to 3 * sizeX)
Standard_Size SizeSliceBytes; //!< number of bytes per 2D slice
Standard_Size TopToDown; //!< image scanlines direction in memory from Top to the Down
Standard_Size SizeBPP; //!< bytes per pixel
Standard_Size SizeX; //!< width in pixels
Standard_Size SizeY; //!< height in pixels
Standard_Size SizeZ; //!< depth in pixels
Standard_Size SizeRowBytes; //!< number of bytes per line (in most cases equal to 3 * sizeX)
Standard_Size SizeSliceBytes; //!< number of bytes per 2D slice
Standard_Size TopToDown; //!< image scanlines direction in memory from Top to the Down
public:
DEFINE_STANDARD_RTTIEXT(Image_PixMapData, NCollection_Buffer)
};
DEFINE_STANDARD_HANDLE(Image_PixMapData, NCollection_Buffer)

View File

@@ -17,7 +17,7 @@
#include <Image_PixMapData.hxx>
//! Structure to manage image buffer with predefined pixel type.
template<typename PixelType_t>
template <typename PixelType_t>
class Image_PixMapTypedData : public Image_PixMapData
{
public:
@@ -25,40 +25,56 @@ public:
Image_PixMapTypedData() {}
//! Initializer.
bool Init (const Handle(NCollection_BaseAllocator)& theAlloc,
Standard_Size theSizeX,
Standard_Size theSizeY,
Standard_Size theSizeRowBytes = 0,
Standard_Byte* theDataPtr = 0)
bool Init(const Handle(NCollection_BaseAllocator)& theAlloc,
Standard_Size theSizeX,
Standard_Size theSizeY,
Standard_Size theSizeRowBytes = 0,
Standard_Byte* theDataPtr = 0)
{
const Standard_Size aSizeBPP = sizeof(PixelType_t);
return Image_PixMapData::Init (theAlloc, aSizeBPP, theSizeX, theSizeY, theSizeRowBytes, theDataPtr);
return Image_PixMapData::Init(theAlloc,
aSizeBPP,
theSizeX,
theSizeY,
theSizeRowBytes,
theDataPtr);
}
//! Reset all values to specified one.
void Init (const PixelType_t& theValue)
void Init(const PixelType_t& theValue)
{
for (Standard_Size aRowIter = 0; aRowIter < SizeY; ++aRowIter)
{
for (Standard_Size aColIter = 0; aColIter < SizeX; ++aColIter)
{
ChangeValue (aRowIter, aColIter) = theValue;
ChangeValue(aRowIter, aColIter) = theValue;
}
}
}
//! @return data pointer to requested row (first column).
const PixelType_t* Row (Standard_Size theRow) const { return (const PixelType_t* )Image_PixMapData::Row (theRow); }
const PixelType_t* Row(Standard_Size theRow) const
{
return (const PixelType_t*)Image_PixMapData::Row(theRow);
}
//! @return data pointer to requested row (first column).
PixelType_t* ChangeRow (Standard_Size theRow) { return (PixelType_t* )Image_PixMapData::ChangeRow (theRow); }
PixelType_t* ChangeRow(Standard_Size theRow)
{
return (PixelType_t*)Image_PixMapData::ChangeRow(theRow);
}
//! @return data pointer to requested position.
const PixelType_t& Value (Standard_Size theRow, Standard_Size theCol) const { return *(const PixelType_t* )Image_PixMapData::Value (theRow, theCol); }
const PixelType_t& Value(Standard_Size theRow, Standard_Size theCol) const
{
return *(const PixelType_t*)Image_PixMapData::Value(theRow, theCol);
}
//! @return data pointer to requested position.
PixelType_t& ChangeValue (Standard_Size theRow, Standard_Size theCol) { return *(PixelType_t* )Image_PixMapData::ChangeValue (theRow, theCol); }
PixelType_t& ChangeValue(Standard_Size theRow, Standard_Size theCol)
{
return *(PixelType_t*)Image_PixMapData::ChangeValue(theRow, theCol);
}
};
#endif // _Image_PixMapTypedData_Header

View File

@@ -20,8 +20,8 @@ IMPLEMENT_STANDARD_RTTIEXT(Image_SupportedFormats, Standard_Transient)
// purpose :
// =======================================================================
Image_SupportedFormats::Image_SupportedFormats()
: myFormats (Image_Format_UNKNOWN, Image_CompressedFormat_NB - 1),
myHasCompressed (false)
: myFormats(Image_Format_UNKNOWN, Image_CompressedFormat_NB - 1),
myHasCompressed(false)
{
myFormats.Init (false);
myFormats.Init(false);
}

View File

@@ -23,43 +23,40 @@ class Image_SupportedFormats : public Standard_Transient
{
DEFINE_STANDARD_RTTIEXT(Image_SupportedFormats, Standard_Transient)
public:
//! Empty constructor.
Standard_EXPORT Image_SupportedFormats();
//! Return TRUE if image format is supported.
bool IsSupported (Image_Format theFormat) const { return myFormats.Value (theFormat); }
bool IsSupported(Image_Format theFormat) const { return myFormats.Value(theFormat); }
//! Set if image format is supported or not.
void Add (Image_Format theFormat) { myFormats.SetValue (theFormat, true); }
void Add(Image_Format theFormat) { myFormats.SetValue(theFormat, true); }
//! Return TRUE if there are compressed image formats supported.
bool HasCompressed() const { return myHasCompressed; }
//! Return TRUE if compressed image format is supported.
bool IsSupported (Image_CompressedFormat theFormat) const { return myFormats.Value (theFormat); }
bool IsSupported(Image_CompressedFormat theFormat) const { return myFormats.Value(theFormat); }
//! Set if compressed image format is supported or not.
void Add (Image_CompressedFormat theFormat)
void Add(Image_CompressedFormat theFormat)
{
myFormats.SetValue (theFormat, true);
myFormats.SetValue(theFormat, true);
myHasCompressed = true;
}
//! Reset flags.
void Clear()
{
myFormats.Init (false);
myFormats.Init(false);
myHasCompressed = false;
}
protected:
NCollection_Array1<bool> myFormats; //!< list of supported formats
// clang-format off
// clang-format off
Standard_Boolean myHasCompressed; //!< flag indicating that some compressed image formats are supported
// clang-format on
// clang-format on
};
#endif // _Image_SupportedFormats_HeaderFile

View File

@@ -27,15 +27,15 @@ IMPLEMENT_STANDARD_RTTIEXT(Image_Texture, Standard_Transient)
// Function : Image_Texture
// Purpose :
// ================================================================
Image_Texture::Image_Texture (const TCollection_AsciiString& theFileName)
: myImagePath (theFileName),
myOffset (-1),
myLength (-1)
Image_Texture::Image_Texture(const TCollection_AsciiString& theFileName)
: myImagePath(theFileName),
myOffset(-1),
myLength(-1)
{
// share textures with unique file paths
if (!theFileName.IsEmpty())
{
myTextureId = TCollection_AsciiString ("texture://") + theFileName;
myTextureId = TCollection_AsciiString("texture://") + theFileName;
}
}
@@ -43,19 +43,19 @@ Image_Texture::Image_Texture (const TCollection_AsciiString& theFileName)
// Function : Image_Texture
// Purpose :
// ================================================================
Image_Texture::Image_Texture (const TCollection_AsciiString& theFileName,
int64_t theOffset,
int64_t theLength)
: myImagePath (theFileName),
myOffset (theOffset),
myLength (theLength)
Image_Texture::Image_Texture(const TCollection_AsciiString& theFileName,
int64_t theOffset,
int64_t theLength)
: myImagePath(theFileName),
myOffset(theOffset),
myLength(theLength)
{
// share textures with unique file paths
if (!theFileName.IsEmpty())
{
char aBuff[60];
Sprintf (aBuff, ";%" PRId64 ",%" PRId64, theOffset, theLength);
myTextureId = TCollection_AsciiString ("texture://") + theFileName + aBuff;
Sprintf(aBuff, ";%" PRId64 ",%" PRId64, theOffset, theLength);
myTextureId = TCollection_AsciiString("texture://") + theFileName + aBuff;
}
}
@@ -63,15 +63,15 @@ Image_Texture::Image_Texture (const TCollection_AsciiString& theFileName,
// Function : Image_Texture
// Purpose :
// ================================================================
Image_Texture::Image_Texture (const Handle(NCollection_Buffer)& theBuffer,
const TCollection_AsciiString& theId)
: myBuffer (theBuffer),
myOffset (-1),
myLength (-1)
Image_Texture::Image_Texture(const Handle(NCollection_Buffer)& theBuffer,
const TCollection_AsciiString& theId)
: myBuffer(theBuffer),
myOffset(-1),
myLength(-1)
{
if (!theId.IsEmpty())
{
myTextureId = TCollection_AsciiString ("texturebuf://") + theId;
myTextureId = TCollection_AsciiString("texturebuf://") + theId;
}
}
@@ -79,7 +79,8 @@ Image_Texture::Image_Texture (const Handle(NCollection_Buffer)& theBuffer,
// Function : ReadCompressedImage
// Purpose :
// ================================================================
Handle(Image_CompressedPixMap) Image_Texture::ReadCompressedImage (const Handle(Image_SupportedFormats)& theSupported) const
Handle(Image_CompressedPixMap) Image_Texture::ReadCompressedImage(
const Handle(Image_SupportedFormats)& theSupported) const
{
if (!theSupported->HasCompressed())
{
@@ -88,41 +89,41 @@ Handle(Image_CompressedPixMap) Image_Texture::ReadCompressedImage (const Handle(
if (!myBuffer.IsNull())
{
return Image_DDSParser::Load (theSupported, myBuffer, 0);
return Image_DDSParser::Load(theSupported, myBuffer, 0);
}
else if (myOffset >= 0)
{
return Image_DDSParser::Load (theSupported, myImagePath, 0, myOffset);
return Image_DDSParser::Load(theSupported, myImagePath, 0, myOffset);
}
TCollection_AsciiString aFilePathLower = myImagePath;
aFilePathLower.LowerCase();
if (!aFilePathLower.EndsWith (".dds"))
if (!aFilePathLower.EndsWith(".dds"))
{
// do not waste time on file system access in case of wrong file extension
return Handle(Image_CompressedPixMap)();
}
return Image_DDSParser::Load (theSupported, myImagePath, 0);
return Image_DDSParser::Load(theSupported, myImagePath, 0);
}
// ================================================================
// Function : ReadImage
// Purpose :
// ================================================================
Handle(Image_PixMap) Image_Texture::ReadImage (const Handle(Image_SupportedFormats)& ) const
Handle(Image_PixMap) Image_Texture::ReadImage(const Handle(Image_SupportedFormats)&) const
{
Handle(Image_PixMap) anImage;
if (!myBuffer.IsNull())
{
anImage = loadImageBuffer (myBuffer, myTextureId);
anImage = loadImageBuffer(myBuffer, myTextureId);
}
else if (myOffset >= 0)
{
anImage = loadImageOffset (myImagePath, myOffset, myLength);
anImage = loadImageOffset(myImagePath, myOffset, myLength);
}
else
{
anImage = loadImageFile (myImagePath);
anImage = loadImageFile(myImagePath);
}
if (anImage.IsNull())
@@ -136,10 +137,10 @@ Handle(Image_PixMap) Image_Texture::ReadImage (const Handle(Image_SupportedForma
// Function : loadImageFile
// Purpose :
// ================================================================
Handle(Image_PixMap) Image_Texture::loadImageFile (const TCollection_AsciiString& thePath) const
Handle(Image_PixMap) Image_Texture::loadImageFile(const TCollection_AsciiString& thePath) const
{
Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap();
if (!anImage->Load (thePath))
if (!anImage->Load(thePath))
{
return Handle(Image_PixMap)();
}
@@ -150,21 +151,21 @@ Handle(Image_PixMap) Image_Texture::loadImageFile (const TCollection_AsciiString
// Function : loadImageBuffer
// Purpose :
// ================================================================
Handle(Image_PixMap) Image_Texture::loadImageBuffer (const Handle(NCollection_Buffer)& theBuffer,
const TCollection_AsciiString& theId) const
Handle(Image_PixMap) Image_Texture::loadImageBuffer(const Handle(NCollection_Buffer)& theBuffer,
const TCollection_AsciiString& theId) const
{
if (theBuffer.IsNull())
{
return Handle(Image_PixMap)();
}
else if (theBuffer->Size() > (Standard_Size )IntegerLast())
else if (theBuffer->Size() > (Standard_Size)IntegerLast())
{
Message::SendFail (TCollection_AsciiString ("Error: Image file size is too big '") + theId + "'");
Message::SendFail(TCollection_AsciiString("Error: Image file size is too big '") + theId + "'");
return Handle(Image_PixMap)();
}
Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap();
if (!anImage->Load (theBuffer->Data(), (int )theBuffer->Size(), theId))
if (!anImage->Load(theBuffer->Data(), (int)theBuffer->Size(), theId))
{
return Handle(Image_PixMap)();
}
@@ -175,32 +176,36 @@ Handle(Image_PixMap) Image_Texture::loadImageBuffer (const Handle(NCollection_Bu
// Function : loadImageOffset
// Purpose :
// ================================================================
Handle(Image_PixMap) Image_Texture::loadImageOffset (const TCollection_AsciiString& thePath,
int64_t theOffset,
int64_t theLength) const
Handle(Image_PixMap) Image_Texture::loadImageOffset(const TCollection_AsciiString& thePath,
int64_t theOffset,
int64_t theLength) const
{
if (theLength > IntegerLast())
{
Message::SendFail (TCollection_AsciiString ("Error: Image file size is too big '") + thePath + "'");
Message::SendFail(TCollection_AsciiString("Error: Image file size is too big '") + thePath
+ "'");
return Handle(Image_PixMap)();
}
const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
std::shared_ptr<std::istream> aFile = aFileSystem->OpenIStream (thePath, std::ios::in | std::ios::binary);
std::shared_ptr<std::istream> aFile =
aFileSystem->OpenIStream(thePath, std::ios::in | std::ios::binary);
if (aFile.get() == NULL)
{
Message::SendFail (TCollection_AsciiString ("Error: Image file '") + thePath + "' cannot be opened");
Message::SendFail(TCollection_AsciiString("Error: Image file '") + thePath
+ "' cannot be opened");
return Handle(Image_PixMap)();
}
aFile->seekg ((std::streamoff )theOffset, std::ios_base::beg);
aFile->seekg((std::streamoff)theOffset, std::ios_base::beg);
if (!aFile->good())
{
Message::SendFail (TCollection_AsciiString ("Error: Image is defined with invalid file offset '") + thePath + "'");
Message::SendFail(TCollection_AsciiString("Error: Image is defined with invalid file offset '")
+ thePath + "'");
return Handle(Image_PixMap)();
}
Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap();
if (!anImage->Load (*aFile, thePath))
if (!anImage->Load(*aFile, thePath))
{
return Handle(Image_PixMap)();
}
@@ -218,13 +223,9 @@ TCollection_AsciiString Image_Texture::MimeType() const
{
return "image/jpeg";
}
else if (aType == "png"
|| aType == "bmp"
|| aType == "webp"
|| aType == "gif"
|| aType == "tiff")
else if (aType == "png" || aType == "bmp" || aType == "webp" || aType == "gif" || aType == "tiff")
{
return TCollection_AsciiString ("image/") + aType;
return TCollection_AsciiString("image/") + aType;
}
else if (aType == "dds")
{
@@ -232,7 +233,7 @@ TCollection_AsciiString Image_Texture::MimeType() const
}
else if (!aType.IsEmpty())
{
return TCollection_AsciiString ("image/x-") + aType;
return TCollection_AsciiString("image/x-") + aType;
}
return TCollection_AsciiString();
}
@@ -244,65 +245,75 @@ TCollection_AsciiString Image_Texture::MimeType() const
TCollection_AsciiString Image_Texture::ProbeImageFileFormat() const
{
static const Standard_Size THE_PROBE_SIZE = 20;
char aBuffer[THE_PROBE_SIZE];
char aBuffer[THE_PROBE_SIZE];
if (!myBuffer.IsNull())
{
memcpy (aBuffer, myBuffer->Data(), myBuffer->Size() < THE_PROBE_SIZE ? myBuffer->Size() : THE_PROBE_SIZE);
memcpy(aBuffer,
myBuffer->Data(),
myBuffer->Size() < THE_PROBE_SIZE ? myBuffer->Size() : THE_PROBE_SIZE);
}
else
{
const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
std::shared_ptr<std::istream> aFileIn = aFileSystem->OpenIStream (myImagePath, std::ios::in | std::ios::binary);
std::shared_ptr<std::istream> aFileIn =
aFileSystem->OpenIStream(myImagePath, std::ios::in | std::ios::binary);
if (aFileIn.get() == NULL)
{
Message::SendFail (TCollection_AsciiString ("Error: Unable to open file '") + myImagePath + "'");
Message::SendFail(TCollection_AsciiString("Error: Unable to open file '") + myImagePath
+ "'");
return false;
}
if (myOffset >= 0)
{
aFileIn->seekg ((std::streamoff )myOffset, std::ios_base::beg);
aFileIn->seekg((std::streamoff)myOffset, std::ios_base::beg);
if (!aFileIn->good())
{
Message::SendFail (TCollection_AsciiString ("Error: Image is defined with invalid file offset '") + myImagePath + "'");
Message::SendFail(
TCollection_AsciiString("Error: Image is defined with invalid file offset '")
+ myImagePath + "'");
return false;
}
}
if (!aFileIn->read (aBuffer, THE_PROBE_SIZE))
if (!aFileIn->read(aBuffer, THE_PROBE_SIZE))
{
Message::SendFail (TCollection_AsciiString ("Error: unable to read image file '") + myImagePath + "'");
Message::SendFail(TCollection_AsciiString("Error: unable to read image file '") + myImagePath
+ "'");
return false;
}
}
if (memcmp (aBuffer, "\x89" "PNG\r\n" "\x1A" "\n", 8) == 0)
if (memcmp(aBuffer,
"\x89"
"PNG\r\n"
"\x1A"
"\n",
8)
== 0)
{
return "png";
}
else if (memcmp (aBuffer, "\xFF\xD8\xFF", 3) == 0)
else if (memcmp(aBuffer, "\xFF\xD8\xFF", 3) == 0)
{
return "jpg";
}
else if (memcmp (aBuffer, "GIF87a", 6) == 0
|| memcmp (aBuffer, "GIF89a", 6) == 0)
else if (memcmp(aBuffer, "GIF87a", 6) == 0 || memcmp(aBuffer, "GIF89a", 6) == 0)
{
return "gif";
}
else if (memcmp (aBuffer, "II\x2A\x00", 4) == 0
|| memcmp (aBuffer, "MM\x00\x2A", 4) == 0)
else if (memcmp(aBuffer, "II\x2A\x00", 4) == 0 || memcmp(aBuffer, "MM\x00\x2A", 4) == 0)
{
return "tiff";
}
else if (memcmp (aBuffer, "BM", 2) == 0)
else if (memcmp(aBuffer, "BM", 2) == 0)
{
return "bmp";
}
else if (memcmp (aBuffer, "RIFF", 4) == 0
&& memcmp (aBuffer + 8, "WEBP", 4) == 0)
else if (memcmp(aBuffer, "RIFF", 4) == 0 && memcmp(aBuffer + 8, "WEBP", 4) == 0)
{
return "webp";
}
else if (memcmp (aBuffer, "DDS ", 4) == 0)
else if (memcmp(aBuffer, "DDS ", 4) == 0)
{
return "dds";
}
@@ -313,17 +324,18 @@ TCollection_AsciiString Image_Texture::ProbeImageFileFormat() const
// Function : WriteImage
// Purpose :
// ================================================================
Standard_Boolean Image_Texture::WriteImage (const TCollection_AsciiString& theFile)
Standard_Boolean Image_Texture::WriteImage(const TCollection_AsciiString& theFile)
{
const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
std::shared_ptr<std::ostream> aFileOut = aFileSystem->OpenOStream (theFile, std::ios::out | std::ios::binary | std::ios::trunc);
std::shared_ptr<std::ostream> aFileOut =
aFileSystem->OpenOStream(theFile, std::ios::out | std::ios::binary | std::ios::trunc);
if (aFileOut.get() == NULL)
{
Message::SendFail (TCollection_AsciiString ("Error: Unable to create file '") + theFile + "'");
Message::SendFail(TCollection_AsciiString("Error: Unable to create file '") + theFile + "'");
return false;
}
if (!WriteImage (*aFileOut, theFile))
if (!WriteImage(*aFileOut, theFile))
{
return false;
}
@@ -331,7 +343,7 @@ Standard_Boolean Image_Texture::WriteImage (const TCollection_AsciiString& theFi
aFileOut->flush();
if (!aFileOut->good())
{
Message::SendFail (TCollection_AsciiString ("Error: Unable to write file '") + theFile + "'");
Message::SendFail(TCollection_AsciiString("Error: Unable to write file '") + theFile + "'");
return false;
}
aFileOut.reset();
@@ -342,81 +354,83 @@ Standard_Boolean Image_Texture::WriteImage (const TCollection_AsciiString& theFi
// Function : WriteImage
// Purpose :
// ================================================================
Standard_Boolean Image_Texture::WriteImage (std::ostream& theStream,
const TCollection_AsciiString& theFile)
Standard_Boolean Image_Texture::WriteImage(std::ostream& theStream,
const TCollection_AsciiString& theFile)
{
if (!myBuffer.IsNull())
{
theStream.write ((const char* )myBuffer->Data(), myBuffer->Size());
theStream.write((const char*)myBuffer->Data(), myBuffer->Size());
if (!theStream.good())
{
Message::SendFail (TCollection_AsciiString ("File '") + theFile + "' cannot be written");
Message::SendFail(TCollection_AsciiString("File '") + theFile + "' cannot be written");
return false;
}
return true;
}
const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
std::shared_ptr<std::istream> aFileIn = aFileSystem->OpenIStream (myImagePath, std::ios::in | std::ios::binary);
std::shared_ptr<std::istream> aFileIn =
aFileSystem->OpenIStream(myImagePath, std::ios::in | std::ios::binary);
if (aFileIn.get() == NULL)
{
Message::SendFail (TCollection_AsciiString ("Error: Unable to open file ") + myImagePath + "!");
Message::SendFail(TCollection_AsciiString("Error: Unable to open file ") + myImagePath + "!");
return false;
}
int64_t aLen = myLength;
if (myOffset >= 0)
{
aFileIn->seekg ((std::streamoff )myOffset, std::ios_base::beg);
aFileIn->seekg((std::streamoff)myOffset, std::ios_base::beg);
if (!aFileIn->good())
{
Message::SendFail (TCollection_AsciiString ("Error: Image is defined with invalid file offset '") + myImagePath + "'");
Message::SendFail(
TCollection_AsciiString("Error: Image is defined with invalid file offset '") + myImagePath
+ "'");
return false;
}
}
else
{
aFileIn->seekg (0, std::ios_base::end);
aLen = (int64_t )aFileIn->tellg();
aFileIn->seekg (0, std::ios_base::beg);
aFileIn->seekg(0, std::ios_base::end);
aLen = (int64_t)aFileIn->tellg();
aFileIn->seekg(0, std::ios_base::beg);
}
Standard_Integer aChunkSize = 4096;
NCollection_Array1<Standard_Byte> aBuffer (0, aChunkSize - 1);
Standard_Integer aChunkSize = 4096;
NCollection_Array1<Standard_Byte> aBuffer(0, aChunkSize - 1);
for (int64_t aChunkIter = 0; aChunkIter < aLen; aChunkIter += aChunkSize)
{
if (aChunkIter + aChunkSize >= aLen)
{
aChunkSize = Standard_Integer(aLen - aChunkIter);
}
if (!aFileIn->read ((char* )&aBuffer.ChangeFirst(), aChunkSize))
if (!aFileIn->read((char*)&aBuffer.ChangeFirst(), aChunkSize))
{
Message::SendFail (TCollection_AsciiString ("Error: unable to read image file '") + myImagePath + "'");
Message::SendFail(TCollection_AsciiString("Error: unable to read image file '") + myImagePath
+ "'");
return false;
}
theStream.write ((const char* )&aBuffer.First(), aChunkSize);
theStream.write((const char*)&aBuffer.First(), aChunkSize);
}
if (!theStream.good())
{
Message::SendFail (TCollection_AsciiString ("File '") + theFile + "' can not be written");
Message::SendFail(TCollection_AsciiString("File '") + theFile + "' can not be written");
return false;
}
return true;
}
//=======================================================================
//function : DumpJson
//purpose :
//=======================================================================
void Image_Texture::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
//=================================================================================================
void Image_Texture::DumpJson(Standard_OStream& theOStream, Standard_Integer theDepth) const
{
OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
OCCT_DUMP_TRANSIENT_CLASS_BEGIN(theOStream)
OCCT_DUMP_FIELD_VALUE_STRING (theOStream, myTextureId)
OCCT_DUMP_FIELD_VALUE_STRING (theOStream, myImagePath)
OCCT_DUMP_FIELD_VALUE_STRING(theOStream, myTextureId)
OCCT_DUMP_FIELD_VALUE_STRING(theOStream, myImagePath)
OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myBuffer.get())
OCCT_DUMP_FIELD_VALUES_DUMPED(theOStream, theDepth, myBuffer.get())
OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myOffset)
OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myLength)
OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, myOffset)
OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, myLength)
}

View File

@@ -23,23 +23,23 @@ class Image_SupportedFormats;
class Image_PixMap;
//! Texture image definition.
//! The image can be stored as path to image file, as file path with the given offset and as a data buffer of encoded image.
//! The image can be stored as path to image file, as file path with the given offset and as a data
//! buffer of encoded image.
class Image_Texture : public Standard_Transient
{
DEFINE_STANDARD_RTTIEXT(Image_Texture, Standard_Transient)
public:
//! Constructor pointing to file location.
Standard_EXPORT explicit Image_Texture (const TCollection_AsciiString& theFileName);
Standard_EXPORT explicit Image_Texture(const TCollection_AsciiString& theFileName);
//! Constructor pointing to file part.
Standard_EXPORT explicit Image_Texture (const TCollection_AsciiString& theFileName,
int64_t theOffset,
int64_t theLength);
Standard_EXPORT explicit Image_Texture(const TCollection_AsciiString& theFileName,
int64_t theOffset,
int64_t theLength);
//! Constructor pointing to buffer.
Standard_EXPORT explicit Image_Texture (const Handle(NCollection_Buffer)& theBuffer,
const TCollection_AsciiString& theId);
Standard_EXPORT explicit Image_Texture(const Handle(NCollection_Buffer)& theBuffer,
const TCollection_AsciiString& theId);
//! Return generated texture id.
const TCollection_AsciiString& TextureId() const { return myTextureId; }
@@ -63,77 +63,76 @@ public:
Standard_EXPORT TCollection_AsciiString ProbeImageFileFormat() const;
//! Image reader without decoding data for formats supported natively by GPUs.
Standard_EXPORT virtual Handle(Image_CompressedPixMap) ReadCompressedImage (const Handle(Image_SupportedFormats)& theSupported) const;
Standard_EXPORT virtual Handle(Image_CompressedPixMap) ReadCompressedImage(
const Handle(Image_SupportedFormats)& theSupported) const;
//! Image reader.
Standard_EXPORT virtual Handle(Image_PixMap) ReadImage (const Handle(Image_SupportedFormats)& theSupported) const;
Standard_EXPORT virtual Handle(Image_PixMap) ReadImage(
const Handle(Image_SupportedFormats)& theSupported) const;
//! Write image to specified file without decoding data.
Standard_EXPORT virtual Standard_Boolean WriteImage (const TCollection_AsciiString& theFile);
Standard_EXPORT virtual Standard_Boolean WriteImage(const TCollection_AsciiString& theFile);
//! Write image to specified stream without decoding data.
Standard_EXPORT virtual Standard_Boolean WriteImage (std::ostream& theStream,
const TCollection_AsciiString& theFile);
Standard_EXPORT virtual Standard_Boolean WriteImage(std::ostream& theStream,
const TCollection_AsciiString& theFile);
public: //! @name hasher interface
//! Dumps the content of me into the stream
Standard_EXPORT virtual void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const;
Standard_EXPORT virtual void DumpJson(Standard_OStream& theOStream,
Standard_Integer theDepth = -1) const;
protected:
//! Read image from normal image file.
Standard_EXPORT virtual Handle(Image_PixMap) loadImageFile (const TCollection_AsciiString& thePath) const;
Standard_EXPORT virtual Handle(Image_PixMap) loadImageFile(
const TCollection_AsciiString& thePath) const;
//! Read image from file with some offset.
Standard_EXPORT virtual Handle(Image_PixMap) loadImageOffset (const TCollection_AsciiString& thePath,
int64_t theOffset,
int64_t theLength) const;
Standard_EXPORT virtual Handle(Image_PixMap) loadImageOffset(
const TCollection_AsciiString& thePath,
int64_t theOffset,
int64_t theLength) const;
//! Read image from buffer.
Standard_EXPORT virtual Handle(Image_PixMap) loadImageBuffer (const Handle(NCollection_Buffer)& theBuffer,
const TCollection_AsciiString& theId) const;
Standard_EXPORT virtual Handle(Image_PixMap) loadImageBuffer(
const Handle(NCollection_Buffer)& theBuffer,
const TCollection_AsciiString& theId) const;
protected:
TCollection_AsciiString myTextureId; //!< generated texture id
TCollection_AsciiString myImagePath; //!< image file path
Handle(NCollection_Buffer) myBuffer; //!< image buffer
int64_t myOffset; //!< offset within file
int64_t myLength; //!< length within file
TCollection_AsciiString myTextureId; //!< generated texture id
TCollection_AsciiString myImagePath; //!< image file path
Handle(NCollection_Buffer) myBuffer; //!< image buffer
int64_t myOffset; //!< offset within file
int64_t myLength; //!< length within file
};
namespace std
{
template<>
struct equal_to<Handle(Image_Texture)>
template <>
struct equal_to<Handle(Image_Texture)>
{
bool operator()(const Handle(Image_Texture)& theTex1, const Handle(Image_Texture)& theTex2) const
{
bool operator()(const Handle(Image_Texture)& theTex1,
const Handle(Image_Texture)& theTex2) const
if (theTex1.IsNull() != theTex2.IsNull())
{
if (theTex1.IsNull() != theTex2.IsNull())
{
return Standard_False;
}
else if (theTex1.IsNull())
{
return Standard_True;
}
return theTex1->TextureId().IsEqual(theTex2->TextureId());
return Standard_False;
}
};
else if (theTex1.IsNull())
{
return Standard_True;
}
return theTex1->TextureId().IsEqual(theTex2->TextureId());
}
};
template<>
struct hash<Handle(Image_Texture)>
template <>
struct hash<Handle(Image_Texture)>
{
size_t operator()(const Handle(Image_Texture)& theTexture) const noexcept
{
size_t operator()(const Handle(Image_Texture)& theTexture) const noexcept
{
return !theTexture.IsNull()
? std::hash<TCollection_AsciiString>{}(theTexture->TextureId())
: 0;
}
};
}
return !theTexture.IsNull() ? std::hash<TCollection_AsciiString>{}(theTexture->TextureId()) : 0;
}
};
} // namespace std
#endif // _Image_Texture_HeaderFile

View File

@@ -25,54 +25,51 @@
#ifdef HAVE_FFMPEG
// Suppress deprecation warnings - it is difficult to provide compatibility with old and new API at once
// since new APIs are introduced too often.
// Should be disabled from time to time to clean up usage of old APIs.
#if (defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
#else
Standard_DISABLE_DEPRECATION_WARNINGS
#endif
// Suppress deprecation warnings - it is difficult to provide compatibility with old and new API
// at once since new APIs are introduced too often. Should be disabled from time to time to clean
// up usage of old APIs.
#if (defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
#else
Standard_DISABLE_DEPRECATION_WARNINGS
#endif
extern "C"
{
#ifdef _MSC_VER
// suppress some common warnings in FFmpeg headers
#pragma warning(disable : 4244)
#endif
extern "C" {
#ifdef _MSC_VER
// suppress some common warnings in FFmpeg headers
#pragma warning(disable : 4244)
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
#ifdef _MSC_VER
#pragma warning(default : 4244)
#endif
};
#ifdef _MSC_VER
#pragma warning(default : 4244)
#endif
};
// Undefine macro that clashes with name used by field of Image_VideoParams;
// this macro is defined in headers of older versions of libavutil
// (see definition of macro FF_API_PIX_FMT in version.h)
#ifdef PixelFormat
#undef PixelFormat
#endif
// Undefine macro that clashes with name used by field of Image_VideoParams;
// this macro is defined in headers of older versions of libavutil
// (see definition of macro FF_API_PIX_FMT in version.h)
#ifdef PixelFormat
#undef PixelFormat
#endif
#endif
IMPLEMENT_STANDARD_RTTIEXT(Image_VideoRecorder, Standard_Transient)
//=============================================================================
//function : Constructor
//purpose :
//=============================================================================
//=================================================================================================
Image_VideoRecorder::Image_VideoRecorder()
: myAVContext (NULL),
myVideoStream (NULL),
myVideoCodec (NULL),
myFrame (NULL),
myScaleCtx (NULL),
myFrameCount (0)
: myAVContext(NULL),
myVideoStream(NULL),
myVideoCodec(NULL),
myFrame(NULL),
myScaleCtx(NULL),
myFrameCount(0)
{
myFrameRate.num = 1;
myFrameRate.den = 30;
@@ -83,40 +80,34 @@ Image_VideoRecorder::Image_VideoRecorder()
#endif
}
//=============================================================================
//function : ~Image_VideoRecorder
//purpose :
//=============================================================================
//=================================================================================================
Image_VideoRecorder::~Image_VideoRecorder()
{
Close();
}
//=============================================================================
//function : formatAvError
//purpose :
//=============================================================================
TCollection_AsciiString Image_VideoRecorder::formatAvError (const int theError) const
//=================================================================================================
TCollection_AsciiString Image_VideoRecorder::formatAvError(const int theError) const
{
#ifdef HAVE_FFMPEG
char anErrBuf[AV_ERROR_MAX_STRING_SIZE] = {};
av_strerror (theError, anErrBuf, AV_ERROR_MAX_STRING_SIZE);
av_strerror(theError, anErrBuf, AV_ERROR_MAX_STRING_SIZE);
return anErrBuf;
#else
return TCollection_AsciiString(theError);
#endif
}
//=============================================================================
//function : Close
//purpose :
//=============================================================================
//=================================================================================================
void Image_VideoRecorder::Close()
{
#ifdef HAVE_FFMPEG
if (myScaleCtx != NULL)
{
sws_freeContext (myScaleCtx);
sws_freeContext(myScaleCtx);
myScaleCtx = NULL;
}
@@ -126,113 +117,115 @@ void Image_VideoRecorder::Close()
return;
}
// Write the trailer, if any. The trailer must be written before you close the CodecContexts open when you wrote the header;
// otherwise av_write_trailer() may try to use memory that was freed on av_codec_close().
// Write the trailer, if any. The trailer must be written before you close the CodecContexts open
// when you wrote the header; otherwise av_write_trailer() may try to use memory that was freed on
// av_codec_close().
if (myFrameCount != 0)
{
av_write_trailer (myAVContext);
av_write_trailer(myAVContext);
myFrameCount = 0;
}
// close each codec
if (myVideoStream != NULL)
{
avcodec_close (myVideoStream->codec);
avcodec_close(myVideoStream->codec);
myVideoStream = NULL;
}
if (myFrame != NULL)
{
av_free (myFrame->data[0]);
av_frame_free (&myFrame);
av_free(myFrame->data[0]);
av_frame_free(&myFrame);
myFrame = NULL;
}
if (!(myAVContext->oformat->flags & AVFMT_NOFILE))
{
// close the output file
avio_close (myAVContext->pb);
avio_close(myAVContext->pb);
}
// free the stream
avformat_free_context (myAVContext);
avformat_free_context(myAVContext);
myAVContext = NULL;
#endif
}
//=============================================================================
//function : Open
//purpose :
//=============================================================================
Standard_Boolean Image_VideoRecorder::Open (const char* theFileName,
const Image_VideoParams& theParams)
//=================================================================================================
Standard_Boolean Image_VideoRecorder::Open(const char* theFileName,
const Image_VideoParams& theParams)
{
#ifdef HAVE_FFMPEG
Close();
if (theParams.Width <= 0
|| theParams.Height <= 0)
if (theParams.Width <= 0 || theParams.Height <= 0)
{
return Standard_False;
}
// allocate the output media context
avformat_alloc_output_context2 (&myAVContext, NULL, theParams.Format.IsEmpty() ? NULL : theParams.Format.ToCString(), theFileName);
avformat_alloc_output_context2(&myAVContext,
NULL,
theParams.Format.IsEmpty() ? NULL : theParams.Format.ToCString(),
theFileName);
if (myAVContext == NULL)
{
::Message::SendFail ("ViewerTest_VideoRecorder, could not deduce output format from file extension");
::Message::SendFail(
"ViewerTest_VideoRecorder, could not deduce output format from file extension");
return Standard_False;
}
// add the audio stream using the default format codecs and initialize the codecs
if (!addVideoStream (theParams, myAVContext->oformat->video_codec))
if (!addVideoStream(theParams, myAVContext->oformat->video_codec))
{
Close();
return Standard_False;
}
// open video codec and allocate the necessary encode buffers
if (!openVideoCodec (theParams))
if (!openVideoCodec(theParams))
{
Close();
return Standard_False;
}
#ifdef OCCT_DEBUG
av_dump_format (myAVContext, 0, theFileName, 1);
#endif
#ifdef OCCT_DEBUG
av_dump_format(myAVContext, 0, theFileName, 1);
#endif
// open the output file, if needed
if ((myAVContext->oformat->flags & AVFMT_NOFILE) == 0)
{
const int aResAv = avio_open (&myAVContext->pb, theFileName, AVIO_FLAG_WRITE);
const int aResAv = avio_open(&myAVContext->pb, theFileName, AVIO_FLAG_WRITE);
if (aResAv < 0)
{
::Message::SendFail (TCollection_AsciiString ("Error: could not open '") + theFileName + "', " + formatAvError (aResAv));
::Message::SendFail(TCollection_AsciiString("Error: could not open '") + theFileName + "', "
+ formatAvError(aResAv));
Close();
return Standard_False;
}
}
// write the stream header, if any
const int aResAv = avformat_write_header (myAVContext, NULL);
const int aResAv = avformat_write_header(myAVContext, NULL);
if (aResAv < 0)
{
::Message::SendFail (TCollection_AsciiString ("Error: can not open output file '") + theFileName + "', " + formatAvError (aResAv));
::Message::SendFail(TCollection_AsciiString("Error: can not open output file '") + theFileName
+ "', " + formatAvError(aResAv));
Close();
return Standard_False;
}
#else
(void )theFileName;
(void )theParams;
(void)theFileName;
(void)theParams;
#endif
return Standard_True;
}
//=============================================================================
//function : addVideoStream
//purpose :
//=============================================================================
Standard_Boolean Image_VideoRecorder::addVideoStream (const Image_VideoParams& theParams,
const Standard_Integer theDefCodecId)
//=================================================================================================
Standard_Boolean Image_VideoRecorder::addVideoStream(const Image_VideoParams& theParams,
const Standard_Integer theDefCodecId)
{
myFrameRate.num = theParams.FpsNum;
myFrameRate.den = theParams.FpsDen;
@@ -242,36 +235,37 @@ Standard_Boolean Image_VideoRecorder::addVideoStream (const Image_VideoParams& t
TCollection_AsciiString aCodecName;
if (!theParams.VideoCodec.IsEmpty())
{
myVideoCodec = avcodec_find_encoder_by_name (theParams.VideoCodec.ToCString());
myVideoCodec = avcodec_find_encoder_by_name(theParams.VideoCodec.ToCString());
aCodecName = theParams.VideoCodec;
}
else
{
myVideoCodec = avcodec_find_encoder ((AVCodecID )theDefCodecId);
aCodecName = avcodec_get_name ((AVCodecID )theDefCodecId);
myVideoCodec = avcodec_find_encoder((AVCodecID)theDefCodecId);
aCodecName = avcodec_get_name((AVCodecID)theDefCodecId);
}
if (myVideoCodec == NULL)
{
::Message::SendFail (TCollection_AsciiString ("Error: can not find encoder for ") + aCodecName);
::Message::SendFail(TCollection_AsciiString("Error: can not find encoder for ") + aCodecName);
return Standard_False;
}
const AVCodecID aCodecId = myVideoCodec->id;
myVideoStream = avformat_new_stream (myAVContext, myVideoCodec);
myVideoStream = avformat_new_stream(myAVContext, myVideoCodec);
if (myVideoStream == NULL)
{
::Message::SendFail ("Error: can not allocate stream");
::Message::SendFail("Error: can not allocate stream");
return Standard_False;
}
myVideoStream->id = myAVContext->nb_streams - 1;
AVCodecContext* aCodecCtx = myVideoStream->codec;
aCodecCtx->codec_id = aCodecId;
aCodecCtx->codec_id = aCodecId;
// resolution must be a multiple of two
aCodecCtx->width = theParams.Width;
aCodecCtx->height = theParams.Height;
// Timebase is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented.
// For fixed-fps content, timebase should be 1/framerate and timestamp increments should be identical to 1.
aCodecCtx->width = theParams.Width;
aCodecCtx->height = theParams.Height;
// Timebase is the fundamental unit of time (in seconds) in terms of which frame timestamps are
// represented. For fixed-fps content, timebase should be 1/framerate and timestamp increments
// should be identical to 1.
aCodecCtx->time_base.den = myFrameRate.num;
aCodecCtx->time_base.num = myFrameRate.den;
aCodecCtx->gop_size = 12; // emit one intra frame every twelve frames at most
@@ -283,99 +277,101 @@ Standard_Boolean Image_VideoRecorder::addVideoStream (const Image_VideoParams& t
}
return Standard_True;
#else
(void )theParams;
(void )theDefCodecId;
(void)theParams;
(void)theDefCodecId;
return Standard_False;
#endif
}
//=============================================================================
//function : openVideoCodec
//purpose :
//=============================================================================
Standard_Boolean Image_VideoRecorder::openVideoCodec (const Image_VideoParams& theParams)
//=================================================================================================
Standard_Boolean Image_VideoRecorder::openVideoCodec(const Image_VideoParams& theParams)
{
#ifdef HAVE_FFMPEG
AVDictionary* anOptions = NULL;
AVDictionary* anOptions = NULL;
AVCodecContext* aCodecCtx = myVideoStream->codec;
// setup default values
aCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
//av_dict_set (&anOptions, "threads", "auto", 0);
if (aCodecCtx->codec == avcodec_find_encoder_by_name ("mpeg2video"))
// av_dict_set (&anOptions, "threads", "auto", 0);
if (aCodecCtx->codec == avcodec_find_encoder_by_name("mpeg2video"))
{
// just for testing, we also add B frames
aCodecCtx->max_b_frames = 2;
aCodecCtx->bit_rate = 6000000;
aCodecCtx->bit_rate = 6000000;
}
else if (aCodecCtx->codec == avcodec_find_encoder_by_name ("mpeg4"))
else if (aCodecCtx->codec == avcodec_find_encoder_by_name("mpeg4"))
{
//
}
else if (aCodecCtx->codec == avcodec_find_encoder_by_name ("mjpeg"))
else if (aCodecCtx->codec == avcodec_find_encoder_by_name("mjpeg"))
{
aCodecCtx->pix_fmt = AV_PIX_FMT_YUVJ420P;
aCodecCtx->qmin = aCodecCtx->qmax = 5;
}
else if (aCodecCtx->codec == avcodec_find_encoder_by_name ("huffyuv"))
else if (aCodecCtx->codec == avcodec_find_encoder_by_name("huffyuv"))
{
aCodecCtx->pix_fmt = AV_PIX_FMT_RGB24;
}
else if (aCodecCtx->codec == avcodec_find_encoder_by_name ("png"))
else if (aCodecCtx->codec == avcodec_find_encoder_by_name("png"))
{
aCodecCtx->pix_fmt = AV_PIX_FMT_RGB24;
aCodecCtx->pix_fmt = AV_PIX_FMT_RGB24;
aCodecCtx->compression_level = 9; // 0..9
}
else if (aCodecCtx->codec == avcodec_find_encoder_by_name ("h264")
|| aCodecCtx->codec == avcodec_find_encoder_by_name ("libx264"))
else if (aCodecCtx->codec == avcodec_find_encoder_by_name("h264")
|| aCodecCtx->codec == avcodec_find_encoder_by_name("libx264"))
{
// use CRF (Constant Rate Factor) as best single-pass compressing method
// clang-format off
// clang-format off
av_dict_set (&anOptions, "crf", "20", 0); // quality 18-28, 23 is default (normal), 18 is almost lossless
av_dict_set (&anOptions, "preset", "slow", 0); // good compression (see also "veryslow", "ultrafast")
// clang-format on
// clang-format on
// live-capturing
//av_dict_set (&anOptions, "qp", "0", 0); // instead of crf
//av_dict_set (&anOptions, "preset", "ultrafast", 0);
// av_dict_set (&anOptions, "qp", "0", 0); // instead of crf
// av_dict_set (&anOptions, "preset", "ultrafast", 0);
// compatibility with devices
//av_dict_set (&anOptions, "profile", "baseline", 0);
//av_dict_set (&anOptions, "level", "3.0", 0);
// av_dict_set (&anOptions, "profile", "baseline", 0);
// av_dict_set (&anOptions, "level", "3.0", 0);
}
else if (aCodecCtx->codec == avcodec_find_encoder_by_name ("vp8")
|| aCodecCtx->codec == avcodec_find_encoder_by_name ("vp9"))
else if (aCodecCtx->codec == avcodec_find_encoder_by_name("vp8")
|| aCodecCtx->codec == avcodec_find_encoder_by_name("vp9"))
{
av_dict_set (&anOptions, "crf", "20", 0); // quality 4-63, 10 is normal
av_dict_set(&anOptions, "crf", "20", 0); // quality 4-63, 10 is normal
}
// override defaults with specified options
if (!theParams.PixelFormat.IsEmpty())
{
const AVPixelFormat aPixFormat = av_get_pix_fmt (theParams.PixelFormat.ToCString());
const AVPixelFormat aPixFormat = av_get_pix_fmt(theParams.PixelFormat.ToCString());
if (aPixFormat == AV_PIX_FMT_NONE)
{
::Message::SendFail (TCollection_AsciiString ("Error: unknown pixel format has been specified '") + theParams.PixelFormat + "'");
::Message::SendFail(
TCollection_AsciiString("Error: unknown pixel format has been specified '")
+ theParams.PixelFormat + "'");
return Standard_False;
}
aCodecCtx->pix_fmt = aPixFormat;
for (Resource_DataMapOfAsciiStringAsciiString::Iterator aParamIter (theParams.VideoCodecParams);
aParamIter.More(); aParamIter.Next())
for (Resource_DataMapOfAsciiStringAsciiString::Iterator aParamIter(theParams.VideoCodecParams);
aParamIter.More();
aParamIter.Next())
{
av_dict_set (&anOptions, aParamIter.Key().ToCString(), aParamIter.Value().ToCString(), 0);
av_dict_set(&anOptions, aParamIter.Key().ToCString(), aParamIter.Value().ToCString(), 0);
}
}
// open codec
int aResAv = avcodec_open2 (aCodecCtx, myVideoCodec, &anOptions);
int aResAv = avcodec_open2(aCodecCtx, myVideoCodec, &anOptions);
if (anOptions != NULL)
{
av_dict_free (&anOptions);
av_dict_free(&anOptions);
}
if (aResAv < 0)
{
::Message::SendFail (TCollection_AsciiString ("Error: can not open video codec, ") + formatAvError (aResAv));
::Message::SendFail(TCollection_AsciiString("Error: can not open video codec, ")
+ formatAvError(aResAv));
return Standard_False;
}
@@ -383,19 +379,24 @@ Standard_Boolean Image_VideoRecorder::openVideoCodec (const Image_VideoParams& t
myFrame = av_frame_alloc();
if (myFrame == NULL)
{
::Message::SendFail ("Error: can not allocate video frame");
::Message::SendFail("Error: can not allocate video frame");
return Standard_False;
}
// allocate the encoded raw picture
aResAv = av_image_alloc (myFrame->data, myFrame->linesize,
aCodecCtx->width, aCodecCtx->height, aCodecCtx->pix_fmt, 1);
aResAv = av_image_alloc(myFrame->data,
myFrame->linesize,
aCodecCtx->width,
aCodecCtx->height,
aCodecCtx->pix_fmt,
1);
if (aResAv < 0)
{
memset (myFrame->data, 0, sizeof(myFrame->data));
memset (myFrame->linesize, 0, sizeof(myFrame->linesize));
::Message::SendFail (TCollection_AsciiString ("Error: can not allocate picture ")
+ aCodecCtx->width+ "x" + aCodecCtx->height + ", " + formatAvError (aResAv));
memset(myFrame->data, 0, sizeof(myFrame->data));
memset(myFrame->linesize, 0, sizeof(myFrame->linesize));
::Message::SendFail(TCollection_AsciiString("Error: can not allocate picture ")
+ aCodecCtx->width + "x" + aCodecCtx->height + ", "
+ formatAvError(aResAv));
return Standard_False;
}
// copy data and linesize picture pointers to frame
@@ -404,63 +405,72 @@ Standard_Boolean Image_VideoRecorder::openVideoCodec (const Image_VideoParams& t
myFrame->height = aCodecCtx->height;
const Standard_Size aStride = aCodecCtx->width + 16 - (aCodecCtx->width % 16);
if (!myImgSrcRgba.InitZero (Image_Format_RGBA, aCodecCtx->width, aCodecCtx->height, aStride))
if (!myImgSrcRgba.InitZero(Image_Format_RGBA, aCodecCtx->width, aCodecCtx->height, aStride))
{
::Message::SendFail (TCollection_AsciiString ("Error: can not allocate RGBA32 picture ")
+ aCodecCtx->width+ "x" + aCodecCtx->height);
::Message::SendFail(TCollection_AsciiString("Error: can not allocate RGBA32 picture ")
+ aCodecCtx->width + "x" + aCodecCtx->height);
return Standard_False;
}
myScaleCtx = sws_getContext (aCodecCtx->width, aCodecCtx->height, AV_PIX_FMT_RGBA,
aCodecCtx->width, aCodecCtx->height, aCodecCtx->pix_fmt,
SWS_BICUBIC, NULL, NULL, NULL);
myScaleCtx = sws_getContext(aCodecCtx->width,
aCodecCtx->height,
AV_PIX_FMT_RGBA,
aCodecCtx->width,
aCodecCtx->height,
aCodecCtx->pix_fmt,
SWS_BICUBIC,
NULL,
NULL,
NULL);
if (myScaleCtx == NULL)
{
::Message::SendFail ("Error: can not initialize the conversion context");
::Message::SendFail("Error: can not initialize the conversion context");
return Standard_False;
}
return Standard_True;
#else
(void )theParams;
(void)theParams;
return Standard_False;
#endif
}
//=============================================================================
//function : writeVideoFrame
//purpose :
//=============================================================================
Standard_Boolean Image_VideoRecorder::writeVideoFrame (const Standard_Boolean theToFlush)
//=================================================================================================
Standard_Boolean Image_VideoRecorder::writeVideoFrame(const Standard_Boolean theToFlush)
{
#ifdef HAVE_FFMPEG
if (myImgSrcRgba.Format() != Image_Format_RGBA)
{
throw Standard_ProgramError ("Image_VideoRecorder, unsupported image format");
throw Standard_ProgramError("Image_VideoRecorder, unsupported image format");
}
int aResAv = 0;
int aResAv = 0;
AVCodecContext* aCodecCtx = myVideoStream->codec;
if (!theToFlush)
{
uint8_t* aSrcData[4] = { (uint8_t*)myImgSrcRgba.ChangeData(), NULL, NULL, NULL };
int aSrcLinesize[4] = { (int )myImgSrcRgba.SizeRowBytes(), 0, 0, 0 };
sws_scale (myScaleCtx,
aSrcData, aSrcLinesize,
0, aCodecCtx->height,
myFrame->data, myFrame->linesize);
uint8_t* aSrcData[4] = {(uint8_t*)myImgSrcRgba.ChangeData(), NULL, NULL, NULL};
int aSrcLinesize[4] = {(int)myImgSrcRgba.SizeRowBytes(), 0, 0, 0};
sws_scale(myScaleCtx,
aSrcData,
aSrcLinesize,
0,
aCodecCtx->height,
myFrame->data,
myFrame->linesize);
}
AVPacket aPacket;
memset (&aPacket, 0, sizeof(aPacket));
av_init_packet (&aPacket);
memset(&aPacket, 0, sizeof(aPacket));
av_init_packet(&aPacket);
{
// encode the image
myFrame->pts = myFrameCount;
myFrame->pts = myFrameCount;
int isGotPacket = 0;
aResAv = avcodec_encode_video2 (aCodecCtx, &aPacket, theToFlush ? NULL : myFrame, &isGotPacket);
aResAv = avcodec_encode_video2(aCodecCtx, &aPacket, theToFlush ? NULL : myFrame, &isGotPacket);
if (aResAv < 0)
{
::Message::SendFail (TCollection_AsciiString ("Error: can not encode video frame, ") + formatAvError (aResAv));
::Message::SendFail(TCollection_AsciiString("Error: can not encode video frame, ")
+ formatAvError(aResAv));
return Standard_False;
}
@@ -470,13 +480,19 @@ Standard_Boolean Image_VideoRecorder::writeVideoFrame (const Standard_Boolean th
const AVRational& aTimeBase = aCodecCtx->time_base;
// rescale output packet timestamp values from codec to stream timebase
aPacket.pts = av_rescale_q_rnd (aPacket.pts, aTimeBase, myVideoStream->time_base, AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
aPacket.dts = av_rescale_q_rnd (aPacket.dts, aTimeBase, myVideoStream->time_base, AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
aPacket.duration = av_rescale_q (aPacket.duration, aTimeBase, myVideoStream->time_base);
aPacket.pts = av_rescale_q_rnd(aPacket.pts,
aTimeBase,
myVideoStream->time_base,
AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
aPacket.dts = av_rescale_q_rnd(aPacket.dts,
aTimeBase,
myVideoStream->time_base,
AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
aPacket.duration = av_rescale_q(aPacket.duration, aTimeBase, myVideoStream->time_base);
aPacket.stream_index = myVideoStream->index;
// write the compressed frame to the media file
aResAv = av_interleaved_write_frame (myAVContext, &aPacket);
aResAv = av_interleaved_write_frame(myAVContext, &aPacket);
}
else
{
@@ -486,7 +502,8 @@ Standard_Boolean Image_VideoRecorder::writeVideoFrame (const Standard_Boolean th
if (aResAv < 0)
{
::Message::SendFail (TCollection_AsciiString ("Error: can not write video frame, ") + formatAvError (aResAv));
::Message::SendFail(TCollection_AsciiString("Error: can not write video frame, ")
+ formatAvError(aResAv));
return Standard_False;
}

View File

@@ -32,39 +32,45 @@ struct SwsContext;
// this macro is defined in headers of older versions of libavutil
// (see definition of macro FF_API_PIX_FMT in version.h)
#ifdef PixelFormat
#undef PixelFormat
#undef PixelFormat
#endif
//! Auxiliary structure defining video parameters.
//! Please refer to FFmpeg documentation for defining text values.
struct Image_VideoParams
{
// clang-format off
// clang-format off
TCollection_AsciiString Format; //!< [optional] video format (container), if empty - will be determined from the file name
TCollection_AsciiString VideoCodec; //!< [optional] codec identifier, if empty - default codec from file format will be used
TCollection_AsciiString PixelFormat; //!< [optional] pixel format, if empty - default codec pixel format will be used
// clang-format on
Standard_Integer Width; //!< [mandatory] video frame width
Standard_Integer Height; //!< [mandatory] video frame height
Standard_Integer FpsNum; //!< [mandatory] framerate numerator
Standard_Integer FpsDen; //!< [mandatory] framerate denumerator
// clang-format on
Standard_Integer Width; //!< [mandatory] video frame width
Standard_Integer Height; //!< [mandatory] video frame height
Standard_Integer FpsNum; //!< [mandatory] framerate numerator
Standard_Integer FpsDen; //!< [mandatory] framerate denumerator
Resource_DataMapOfAsciiStringAsciiString
VideoCodecParams; //!< map of advanced video codec parameters
VideoCodecParams; //!< map of advanced video codec parameters
//! Empty constructor.
Image_VideoParams() : Width (0), Height (0), FpsNum (0), FpsDen (1) {}
Image_VideoParams()
: Width(0),
Height(0),
FpsNum(0),
FpsDen(1)
{
}
//! Setup playback FPS.
void SetFramerate (const Standard_Integer theNumerator,
const Standard_Integer theDenominator)
void SetFramerate(const Standard_Integer theNumerator, const Standard_Integer theDenominator)
{
FpsNum = theNumerator;
FpsDen = theDenominator;
}
//! Setup playback FPS.
//! For fixed-fps content, timebase should be 1/framerate and timestamp increments should be identical to 1.
void SetFramerate (const Standard_Integer theValue)
//! For fixed-fps content, timebase should be 1/framerate and timestamp increments should be
//! identical to 1.
void SetFramerate(const Standard_Integer theValue)
{
FpsNum = theValue;
FpsDen = 1;
@@ -76,7 +82,6 @@ class Image_VideoRecorder : public Standard_Transient
{
DEFINE_STANDARD_RTTIEXT(Image_VideoRecorder, Standard_Transient)
public:
//! Empty constructor.
Standard_EXPORT Image_VideoRecorder();
@@ -89,8 +94,8 @@ public:
//! Open output stream - initialize recorder.
//! @param[in] theFileName video filename
//! @param[in] theParams video parameters
Standard_EXPORT Standard_Boolean Open (const char* theFileName,
const Image_VideoParams& theParams);
Standard_EXPORT Standard_Boolean Open(const char* theFileName,
const Image_VideoParams& theParams);
//! Access RGBA frame, should NOT be re-initialized outside.
//! Note that image is expected to have upper-left origin.
@@ -100,30 +105,25 @@ public:
int64_t FrameCount() const { return myFrameCount; }
//! Push new frame, should be called after Open().
Standard_Boolean PushFrame()
{
return writeVideoFrame (Standard_False);
}
Standard_Boolean PushFrame() { return writeVideoFrame(Standard_False); }
protected:
//! Wrapper for av_strerror().
Standard_EXPORT TCollection_AsciiString formatAvError (const int theError) const;
Standard_EXPORT TCollection_AsciiString formatAvError(const int theError) const;
//! Append video stream.
//! theParams[in] video parameters
//! theDefCodecId[in] identifier of codec managed by FFmpeg library (AVCodecID enum)
Standard_EXPORT Standard_Boolean addVideoStream (const Image_VideoParams& theParams,
const Standard_Integer theDefCodecId);
Standard_EXPORT Standard_Boolean addVideoStream(const Image_VideoParams& theParams,
const Standard_Integer theDefCodecId);
//! Open video codec.
Standard_EXPORT Standard_Boolean openVideoCodec (const Image_VideoParams& theParams);
Standard_EXPORT Standard_Boolean openVideoCodec(const Image_VideoParams& theParams);
//! Write new video frame.
Standard_EXPORT Standard_Boolean writeVideoFrame (const Standard_Boolean theToFlush);
Standard_EXPORT Standard_Boolean writeVideoFrame(const Standard_Boolean theToFlush);
protected:
//! AVRational alias.
struct VideoRational
{
@@ -132,17 +132,15 @@ protected:
};
protected:
AVFormatContext* myAVContext; //!< video context
AVStream* myVideoStream; //!< video stream
AVCodec* myVideoCodec; //!< video codec
AVFrame* myFrame; //!< frame to record
SwsContext* myScaleCtx; //!< scale context for conversion from RGBA to YUV
Image_PixMap myImgSrcRgba; //!< input RGBA image
VideoRational myFrameRate; //!< video framerate
int64_t myFrameCount; //!< current frame index
Image_PixMap myImgSrcRgba; //!< input RGBA image
VideoRational myFrameRate; //!< video framerate
int64_t myFrameCount; //!< current frame index
};
DEFINE_STANDARD_HANDLE(Image_VideoRecorder, Standard_Transient)