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:
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
|
@@ -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__
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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
@@ -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)
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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)
|
||||
|
Reference in New Issue
Block a user