//================================================================================
// lib2D image library
//
// Image header file
//
// AUTHOR:  Gabor Nagy
// DATE:    2026-Jul-25 18:34:55
//
// Copyright (C) 1996-2026 by Gabor Nagy. All rights reserved.
//================================================================================
#ifndef _EImage_h
#define _EImage_h

#include <stdio.h>

#ifndef _EClass_h
#include <EClass.h>
#endif

#include <ELog.h>

#include <Color/Color.h>
#include <Xe/Progress.h>


#if defined (__cplusplus) && (!(defined (__CPLUSLIBS)))
extern "C" {
#endif

typedef uint32_t  EpChannelFlags;


#define EpROTATE_RIGHT  0x0001    // By 90 degrees
#define EpROTATE_LEFT   0x0002    // By 90 degrees
#define EpFLIP_H        0x0004
#define EpFLIP_V        0x0008

typedef struct
{
	int  Type;             // Pixel semantic: EpGRAY, EpRGB, EpRGBA, EpSPECTRAL etc.

// Number of components per pixel. E.g. 4 for RGBA. Not all components may be used. E.g. in RGBX format, Type will be EpRGB,
// and NComponents will be 4, even though the last component is not used. It's only there for memory alignment.
	int  NComponents;

	int  ComponentType;    // EResUINT8, EResUINT16, etc.
} EpPixelFormat;
EList_t(EpPixelFormat);

static inline void EpPixelFormat_Set(EpPixelFormat* PFormat,  const uint16_t PType, const uint16_t PNComponents, const uint16_t PComponentType)
{
	PFormat->Type = PType;
	PFormat->NComponents = PNComponents;
	PFormat->ComponentType = PComponentType;
}

typedef float     EpCoordinate;

typedef struct
{
	EpCoordinate  X, Y;
} EpCoord2;

static inline EpCoord2 EpCoord2_s(const EpCoordinate PX, const EpCoordinate PY)
{
	const EpCoord2  LV = { PX, PY };
	return(LV);
}

typedef struct
{
	EpCoordinate  X, Y, Z;
} EpCoord3;

static inline EpCoord3 EpCoord3_s(const EpCoordinate PX, const EpCoordinate PY, const EpCoordinate PZ)
{
	const EpCoord3  LV = { PX, PY, PZ };
	return(LV);
}

typedef struct
{
	float  V, W;
} EpWeightedValue;

typedef struct
{
	EIndex2  Position, Size;
} EpRegion;

typedef struct
{
	EIndex2       Position;
	EcRGBAiColor  Color;
} EpColoredPixelRGBAi;

#define Ep_AddPointRGBAi(pPoints, pCounter,  pX, pY,  pColor) do\
{\
	EpColoredPixelRGBAi*  lPoint = (pPoints) + pCounter;\
	lPoint->Position.X = pX;\
	lPoint->Position.Y = pY;\
	lPoint->Color = pColor;\
	pCounter++;\
} while(0)


// Channel masks
//
typedef uint32_t  EpChannelMask;

#define	EpRED        0x0001
#define	EpGREEN      0x0002
#define	EpBLUE       0x0004
#define	EpALPHA      0x0008
#define	EpINTENSITY  0x1000
#define	EpZ          0x2000

#define	EpR          EpRED
#define	EpG          EpGREEN
#define	EpB          EpBLUE
#define	EpA          EpALPHA

#define EpChRGB   (0x07)
#define EpChRGBA  (0x0F)
#define EpChALL   (0x3F)

#define EpAUTO  -1

typedef enum
{
	EpTOP_TO_BOTTOM = 1,
	EpBOTTOM_TO_TOP
} EpOrientation;


#define EpRGBf_MAX  1000000.0


typedef float  (*EpConvertComponentFunc)(const EIndex PComponentIndex, const float PComponentValue, const void* PStruct);


// Operations for Images with alpha channels
// 0: overwrite (no blending)
enum
{
	EpSRCxALPHA_plus_DSTxONE_MINUS_ALPHA = 1,  // Traditional alpha-blending (src * A + dst * (1 - A))

// Alpha-blending with premultiplied-alpha source image (src + dst * (1 - A)). This makes interpolating RGBA colors more correct
	EpSRC_plus_DSTxONE_MINUS_ALPHA,

// Alpha-blending with premultiplied-alpha source image (src + dst * A). This makes interpolating RGBA colors more correct and it makes blending
// with the target possible with A > 1.0.
// For realistic shadow casting and relighting the background.
	EpSRC_plus_DSTxALPHA,

// Alpha-blending with premultiplied-alpha source image (src + dst * A). Allows for brightening the background with A > 1.0, even with UInt8 pixels.
	EpSRC_plus_DSTxALPHAx2,

// When used with EpACCUMULATEOPACITY, it produces an intermediate Image that can be composited on another Image with EpSRCxALPHA_plus_DSTxONE_MINUS_ALPHA,
// resulting in the proper blending as if the background was composited first, then the decal on top.
	EpFOR_COMPOSITABLE_IMAGE,

// When used with EpACCUMULATEOPACITY, it produces an intermediate Image that can be composited on another Image with EpSRC_plus_DSTxONE_MINUS_ALPHA,
// resulting in the proper blending as if the background was composited first, then the decal on top.
	EpFOR_COMPOSITABLE_IMAGE_PREMULTALPHA,

	EpSRC_plus_DSTxONE_MINUS_SRC,              // The source pixel value is also the alpha (e.g. FreeType glyphs)
	EpSRC                                      // Simply overwrite the destination
};

enum
{
	EpTO_BLACK_PLUS_ALPHA = 1,
	EpTO_WHITE_PLUS_ALPHA,
	EpTO_WHITE_PLUS_ALPHA_PREMULT
};


// PAlphaSource values for EpImage_Composite
enum
{
	EpFROM_SOURCE0 = 1,
	EpFROM_SOURCE1,
	EpADD,                                    // Simply add up alpha values
	EpACCUMULATEOPACITY,                      // Physically accurate way: multiply together transparency values (1-A)
	EpACCUMULATEOPACITY_DST_IS_TRANSPARENCY,  // Physically accurate way: multiply together transparency values (1-A). The destination alpha is transparency (not opacity)

// Physically accurate way: multiply together transparency values (1-A). Both the sourca and the destination alpha are transparency (not opacity)
	EpACCUMULATETRANSPARENCY
};


#define EpLUT_MAX_DIM  3

typedef struct
{
	EEntityCore;

	int       Dimensions;             // E.g. 1D or 3D
	EIndex    Size[EpLUT_MAX_DIM];
	float     DomainMin[EpLUT_MAX_DIM], DomainMax[EpLUT_MAX_DIM];
	int       NChannels;
	uint16_t  ComponentType;
	void*     Data;
} EpLUT;


typedef struct
{
	float                   WhiteBalance[3];float  ColorSaturation;
	float                   Bias, Gain, Gamma;
	EBool                   AdaptiveExposure;  // Non-linear tone-mapping: out = exp(-input);

	EpConvertComponentFunc  ToneMapR, ToneMapG, ToneMapB;
	EBool                   FastExposure;

	float                   InvGamma;
} EpExposure;


typedef struct
{
	EpConvertComponentFunc  ConvertComponentFunc;
	float*                  ResponseTablef32;  // For fast tone-mapping
	uint16_t*               ResponseTable16;
	uint8_t*                ResponseTable8;
	float                   Min, Mult;
	int                     Type;
} EpToneMapperChannel;
EList_t(EpToneMapperChannel);

typedef struct
{
	EpLUT*                  LUT;
	EBool                   LUTActive;

	EList_s(, EpToneMapperChannel, Channels);    // For example, R,G,B

	float                 ColorSaturation;

	void*                 Struct;       // Custom data passed down to Channel ConvertComponentFunc()
	int                   TableSize;    // Look-up table resolution for fast tone-mapping

// Maximum input value in 16-bit images (e.g. a camera might output 10-bit RAW, in 16 bit values, where only the lowest 10 bits in a 16-bit pixe component are used)
	int                   MaxVal16;

	EBool                 Uptodate;

	pthread_mutex_t       Update_mutex;
} EpToneMapper;



#define EpZERO_BLANKED  1

#define EpMAX_COLORNUM  4096


typedef struct
{
	float  I, A;  // Intensity + Alpha
} EpGrayAf32Pixel;

typedef struct
{
	uint16_t  I, A;  // Intensity + Alpha
} EpGrayAu16Pixel;

typedef struct
{
	int16_t  I, A;   // Intensity + Alpha
} EpGrayAi16Pixel;

typedef struct
{
	uint8_t  I, A;  // Intensity + Alpha
} EpGrayAu8Pixel;


typedef float     EpGrayf32Pixel;
typedef uint16_t  EpGrayu16Pixel;
typedef int16_t   EpGrayi16Pixel;
typedef uint8_t   EpGray8Pixel;


typedef EcRGBAf32Color   EpRGBAf32Pixel;
typedef EcRGBAu16Color   EpRGBAu16Pixel;
typedef EcRGBAi16Color   EpRGBAi16Pixel;

typedef EcRGBf32Color    EpRGBf32Pixel;
typedef EcRGBu16Color    EpRGBu16Pixel;
typedef EcRGBi16Color    EpRGBi16Pixel;

typedef EcRGf32Color     EpRGf32Pixel;
typedef EcRGu16Color     EpRGu16Pixel;
typedef EcRGi16Color     EpRGi16Pixel;
typedef EcRGu8Color      EpRGu8Pixel;
typedef EcRGi8Color      EpRGi8Pixel;

typedef EcRGBAu8Color     EpRGBA8Pixel;
static inline EpRGBA8Pixel EpRGBA8Pixel_s(const uint8_t PR, const uint8_t PG, const uint8_t PB, const uint8_t PA)
{
	const EpRGBA8Pixel  LV = { PR, PG, PB, PA };
	return(LV);
}


typedef EcRGBAu8Color     EpRGBX8Pixel;
typedef EcRGB8Color      EpRGB8Pixel;

typedef uint8_t          EpGray8Pixel;

typedef uint8_t          EpColorIndex8Pixel;
typedef uint16_t         EpColorIndex16Pixel;
typedef uint32_t         EpPRGBA8Pixel;


//------------------------------------------------
// Dithering algorithms
//------------------------------------------------
enum
{
	EpDITHER_NONE = 0,
	EpDITHER_BAYER44,
	EpDITHER_BAYER88,
	EpDITHER_MATDASH,
	EpDITHER_LINES,
	EpDITHER_HALFTONE,
	EpDITHER_FLOYD_STEINBERG,
	EpDITHER_FAX
};


// Pixel semantics
//
enum
{
	EpGRAY = 1,
	EpGRAYA,
	EpCOLORINDEX,
	EpRG,
	EpRGB,
	EpRGBA,
	EpSPECTRAL,   // Hyper-spectral
	EpSPECTRALA,  // Hyper-spectral + alpha (e.g. 16+1 channels)
	EpDEPTH,

	EpPixelTypeALL = 4096
};


//--------------------------------------------------------------------------------------------------------------------------------
// Pixel format IDs.
// These uniquely identify some common pixel formats, in a more compact way than the fully generic values in EpPixelBuffer.
// Used for capturing images (e.g. from cameras), transferring images trough a network etc.
//--------------------------------------------------------------------------------------------------------------------------------
enum
{
	EpPixelFormatGRAYu8 = 1,
	EpPixelFormatGRAYu16,
	EpPixelFormatGRAYf32,
	EpPixelFormatGRAYAu8,
	EpPixelFormatGRAYAu16,
	EpPixelFormatGRAYAf32,
	EpPixelFormatCOLORINDEX8,
	EpPixelFormatCOLORINDEX16,
	EpPixelFormatRGu8,
	EpPixelFormatRGu16,
	EpPixelFormatRGi16,
	EpPixelFormatRGf32,
	EpPixelFormatRGBu8,
	EpPixelFormatRGBu16,
	EpPixelFormatRGBi16,
	EpPixelFormatRGBf32,
	EpPixelFormatRGBAu8,
	EpPixelFormatRGBAu16,
	EpPixelFormatRGBAf32,

// Just get the green channels from the RAW image without de-bayering. Camera calibration / response curve acquisition
// will be more accurate when not affected by demosaicing-artifacts.
	EpPixelFormatRAW_G,

	EpPixelFormatRAW8,             // 8-bit Bayer (unspecified filter layout. e.g. the app requesting doesn't know).
	EpPixelFormatBGGR8,            // 8-bit Bayer
	EpPixelFormatGBRG8,            // 8-bit Bayer
	EpPixelFormatGRBG8,            // 8-bit Bayer
	EpPixelFormatRGGB8,            // 8-bit Bayer
	EpPixelFormatRAW10,            // 10-bit Bayer packed into uint16s (unspecified filter layout. e.g. the app requesting doesn't know)

// 10-bit Bayer Ximea 16 pixels x 10 bits = 160 bits are grouped in 20 bytes (60% more bandwidth efficient)  https://www.ximea.com/support/wiki/allprod/Transport_Data_Packing
	EpPixelFormatRAW10_PACK160,

	EpPixelFormatBGGR10,           // 10-bit Bayer
	EpPixelFormatGBRG10,           // 10-bit Bayer
	EpPixelFormatGRBG10,           // 10-bit Bayer
	EpPixelFormatRGGB10,           // 10-bit Bayer
	EpPixelFormatRAW12,            // 12-bit Bayer packed into uint16s (unspecified filter layout. e.g. the app requesting doesn't know)
	EpPixelFormatBGGR12,           // 12-bit Bayer
	EpPixelFormatGBRG12,           // 12-bit Bayer
	EpPixelFormatGRBG12,           // 12-bit Bayer
	EpPixelFormatRGGB12,           // 12-bit Bayer
	EpPixelFormatRAW16,            // 16-bit Bayer packed into uint16s (unspecified filter layout. e.g. the app requesting doesn't know)
	EpPixelFormatBGRu8,
	EpPixelFormatRGBXu8,
	EpPixelFormatYUYV8,
	EpPixelFormatUYVY8,
	EpPixelFormatMJPEG,
	EpPixelFormatH264,
	EpPixelFormatZ_RGB_5,          // Z-pixmap type, 5 bits/channel:     XBBBBBGGGGGRRRRR
	EpPixelFormatZ_RGB_565,        // Z-pixmap type, 5-6-5 bits/channel: BBBBBGGGGGGRRRRR
	EpPixelFormatZ_RGB_4,          // Z-pixmap type, 4 bits/channel:     XXXXBBBBGGGGRRRR
	EpPixelFormatZ_RGB_4_D,        // Z-pixmap type, 4 bits/channel:     XXXXBBBBGGGGRRRR dithered
	EpPixelFormatZ_RGB_332,        // Z-pixmap type, 3-3-2 bits/channel: BBGGGRRR
	EpPixelFormatZ_Red_8,          // Z-pixmap type, 8 bits/pixel: Red channel only
	EpPixelFormatZ_Green_8,        // Z-pixmap type, 8 bits/pixel: Green channel only
	EpPixelFormatZ_Blue_8,         // Z-pixmap type, 8 bits/pixel: Blue channel only
	EpPixelFormatZ_Alpha_8,        // Z-pixmap type, 8 bits/pixel: Alpha channel only
	EpPixelFormatZ_ColorIndex,     // Z-pixmap type, Depth bits/pixel: Colorindex
	EpPixelFormatP_RGBA,           // Separate bitplanes, Depth/4 bits/pixel: Red, Green, Blue, Alpha
	EpPixelFormatP_RGB,            // Separate bitplanes, Depth/3 bits/pixel: Red, Green, Blue
	EpPixelFormatP_Gray,           // Separate bitplanes, Depth bits/pixel: Grayscale
	EpPixelFormatP_ColorIndex,     // Separate bitplanes, Depth bits/pixel: Colorindex
	EpPixelFormatZ_JPEG_RGB_8,     // Z-pixmap type, 8 bits/channel: Red, Green, Blue compressed with JPEG
	EpPixelFormatYCbCr420
};


#define EpPixelFormatCOUNT     EpPixelFormatYCbCr420

#define	EpN_ImgHeaderSize  268



#define EpPALETTEFORMAT_ARGB16  0x01  // 16 bits (4 bits per channel): Alpha, Blue, Green, Red
#define EpPALETTEFORMAT_ARGB32  0x02  // 32 bits (8 bits per channel): Alpha, Blue, Green, Red
#define EpPALETTEFORMAT_ARGB64  0x04  // 64 bits (16 bits per channel): Alpha, Blue, Green, Red
#define EpPALETTEFORMAT_RGBA32  0x08  // 32 bits (8 bits per channel): Red, Green, Blue, Alpha


#define EpM_GLVertex2i(v)  glVertex2i((v)[0], (v)[1])


#define EpGLPIXELFORMAT  GL_RGBA
#define EpGLPIXELTYPE    GL_UNSIGNED_BYTE



//----------------------------------------------------------------
// Image structure for inlining into C/C++ source
//----------------------------------------------------------------
#define _EpCImage  1
typedef struct
{
	int       SizeX, SizeY,
            ComponentsPerPixel, ComponentType;
	uint8_t*  ImageBuffer_u8;
} EpCImage;

typedef EpCImage*              EpCImagePtr;
typedef struct EpImageClass_S  EpImageClass;

#ifndef EpImage_DEF
#define EpImage_DEF  1
typedef struct EpImage_S       EpImage;
typedef EpImage*               EpImagePtr;
EList_t(EpImagePtr);
EListA_t(EpImagePtr);
#endif


#define EpImageClassCore\
	EBaseClassCore(EpImage)

struct EpImageClass_S
{
	EpImageClassCore;
};



typedef struct EpImageComponent_S  EpImageComponent;

typedef int  (*EpImageEditFunc)(EpImage* PImage, EpImageComponent* PComponent, int);
typedef int  (*EpImageFunc)(EpImage* PImage, EpImageComponent* PComponent);
typedef int  (*EpImageCopyFunc)(EpImage* PSrcImage, EpImageComponent* PSrcComponent, EpImage* PDstImage, EpImageComponent* PDstComponent);
typedef int  (*EpImageChangeFunc)(EpImage* PImage, EpImageComponent* PComponent, const EChangeFlags PChangeFlags);


typedef struct EpImageComponentClass_S   EpImageComponentClass;
typedef struct EpImageComponentClass_S*  EpImageComponentClassPtr;
EList_t(EpImageComponentClassPtr);

typedef void            (*EpImageComponentGUIFunc)(EpImage* PImage, EpImageComponent* PInfo, void* PPanel, void* PDrawer, const int PAction);

struct EpImageComponentClass_S
{
	ECoreClassCore(EpImageComponent);

// Or-ed flags of EComponentVISIBLE, EComponentCOPY, EComponentSAVE, EComponentREMOVABLE etc.
// E.g. some components are generated internally and are not supposed to be saved to files etc.
	uint16_t                 InternalFlags;

	EpImageFunc              Init;    // Constructor
	EpImageCopyFunc          Copy;    // Copy-constructor
	EpImageFunc              Free;    // Cestructor

	EpImageEditFunc          Edit;
	EpImageChangeFunc        Change;

	EpImageComponentGUIFunc  GUI;

	EpImage*                 Icon;
};


#define EpImageComponentCore\
	EObjectCore(EpImageComponent);\
/* Or-ed flags of EComponentVISIBLE, EComponentCOPY, EComponentSAVE, EComponentREMOVABLE etc. */\
/* E.g. some components are generated internally and are not supposed to be saved to files etc.  */\
/* These flags are set by code, in the class' constructor, etc. and are not saved into files.  */\
	uint16_t     InternalFlags;\


// General ImageComponent structure (these are the first fields common in all ImageComponent structures)
//
struct EpImageComponent_S
{
	EpImageComponentCore;
};

#define EpPixelBufferPIXELDATA_STATIC        0x01  // The pixel data is statically allocated. Don't free (e.g. inlined Images)
#define EpPixelBufferCOMPONENT_NAMES_STATIC  0x02  // The name data is statically allocated. Don't free (e.g. built-in names)

typedef struct
{
	EObjectCore(EObject);

	char**         ComponentNames;

	float          WavelengthMin, WavelengthMax;  // For EcSPECTRAL PixelFormat.Type
	float*         SpectrumToR;
	float*         SpectrumToG;
	float*         SpectrumToB;

	EpPixelFormat  PixelFormat;
	int            BytesPerPixel;
	EIndex         BytesPerRow;
	uint16_t       RowByteAlignment;  // Some GPUs etc. don't like pixels starting on odd addresses
	uint16_t       Flags;             // EpPixelBufferPIXELDATA_STATIC ...
	union
	{
		int8_t*    i8;
		uint8_t*   u8;
		int16_t*   i16;
		uint16_t*  u16;
		float*     f32;
	};

// This counter allows for identifying which derived PixelBuffers need updating. E.g. if an RGBAf32 PixelBuffer
// has a higher ChangeCount than an RGBA8 PixelBuffer, it means that tonemapping needs to be (re)done.
//
	EChanges       Changes;
} EpPixelBuffer, *EpPixelBufferPtr;
EListA_t(EpPixelBufferPtr);


#define EpImageCore\
	EObjectCore(EpImage);\
\
/* Unique ID of this Image. This ensures that we can identify Images, even if it we free Images and a freed pointer gets reused for a new allocation.  */\
	EIndex            ID;\
\
	EIndex2           Size;\
\
	char              LineAlignment,\
	                  PaletteFormat;\
\
	int               QFactor;             /* Quality-factor for lossy compression algorithms like JPEG  */\
	EBool             Compress;            /* Compression in destination file  */\
\
	EListA_s(, EpPixelBufferPtr, PixelBuffers);\
\
	EcRGBAiColor*     RGBAiColors;         /* Color palette for color-indexed images           */\
	int               NumOfColors;\
	int               NumOfValidPixels;    /* For read, if a file is not a complete image      */\
\
	EList(, EpImageComponent*, Components);    /* Runtime-typed ObjectComponents  */\
	EIndex            ChangeCount;\
\
	char*             FileName;\
	char*             Software;            /* Name of software that created the Image */\
	char*             Comment;\
\
	ETime             CreatedTime_ms;      /* Image creation time. Milliseconds since 1970-01-01 00:00 */\
	uint16_t          CreatedTimeSubSecDigits;\
\
	ETime             Loaded_ms;           /* Last time the Image was loaded (e.g. from a file). UNIX time, in ms. -1 : was not loaded */\
	uint16_t          ColorSpace           /* EcLINEAR, EcsRGB, EcAdobeRGB etc. */

//------------------------------------------------------------------------
// Base image for file-IO and image manipulating functions
//------------------------------------------------------------------------
struct EpImage_S
{
	EpImageCore;
};


typedef struct
{
	EIndex  OriginalImageID;
	EListA(, EpImage*, Images);
} EpScaledImage, *EpScaledImagePtr;
EListA_t(EpScaledImagePtr);



//--------------------------------------------------------
// Base for GPU framebuffers
//--------------------------------------------------------
#define EpGPU2DBufferCore\
	int          RefCnt;\
	const char*  API;   /* EpAPI_OpenGL, etc. */\
	EInt32_2     Size

typedef struct
{
	EpGPU2DBufferCore;
} EpGPU2DBuffer;


#define EpGPUFrameBufferCore\
	EObjectCore(EObject);\
	const char*     API;                 /* EpAPI_OpenGL, etc. */\
	EIndex2         Size,                /* Virtual size (always <= AllocatedSize) this is separate, to minimize physical reallocation calls */\
	                AllocatedSize;       /* Actual allocated size (via OpenGL etc.)  */\
\
	uint16_t        PixelFormat,         /* EpRGBA, EpRGB, EpGRAYA, EpGRAY */\
	                ColorComponentType;  /* EResUINT8, EResFLOAT16 */\
\
	EpGPU2DBuffer*  DepthBuffer

typedef struct
{
	EpGPUFrameBufferCore;
} EpGPUFrameBuffer;


// Cubemap layouts for single-image visualization
enum
{
	EpCubemapNONE = 0,
	EpCubemap3x2,
	EpCubemap1x6
};


//----------------------------------------
// Special Image file format IDs
//----------------------------------------
#define EpFileFormatNONE            NULL
#define EpFileFormatFROM_EXTENSION  NULL  // Get format from filename extension (saving)
#define EpFileFormatAUTOMATIC       NULL  // Automatic format recognition (reading)


typedef struct EpImageFile_S      EpImageFile;
typedef struct EpImageIOModule_S  EpImageIOModule;

typedef int  (*EpLoadFunc)(EpImageFile* PImageFile, EpImage* PImage);
typedef int  (*EpSaveFunc)(EpImageFile* PImageFile, EpImage* PImage, const EpToneMapper* PToneMapper);
typedef int  (*EpIOOpenFunc)(EpImageFile* PImageFile, const uint16_t PMode,  EpImage* PImage);
typedef int  (*EpIOCloseFunc)(EpImageFile* PImageFile);

#ifndef XeWidget_DEF
typedef struct _XeWidget_S*  XeWidget;
#endif

#define EpImageIOModuleCore\
	EIOModuleCore;  /* Inherited from EIOModule */\
\
	void           (*Init)(EpImageIOModule* PIOModule);\
	void           (*Free)(EpImageIOModule* PIOModule);\
	EpIOOpenFunc   Open;                /* Function to open an image file and read its header, or close it  */\
	EBool          NeedOpenFile;        /* Need an open FILE* descriptor in LImageFile for Open()     */\
	EpIOCloseFunc  Close;               /* Function to close image file and free allocated resources  */\
	EpLoadFunc     Load;                /* Function to read an image file                             */\
	EpSaveFunc     Save;                /* Function to write an image to a file                       */\
	void           (*GUIForLoad)(EpImage* PImage, EpImageIOModule* PIOModule, XeWidget PParentW, const uint16_t PAction);\
	void           (*GUIForSave)(EpImage* PImage, EpImageIOModule* PIOModule, XeWidget PParentW, const uint16_t PAction)


struct EpImageIOModule_S
{
	EpImageIOModuleCore;
};


// Flags for EpImageFile
//
#define EpIOFlagKEEP_DATA_FOR_LOSSLESS    0x0001
#define EpIOFlagKEEP_DATA_FOR_LOSSY       0x0002
#define EpIOFlagNO_COPY                   0x0004
#define EpIOFlagCHANNELS_TO_PIXELBUFFERS  0x0008    // Load multiple channels (e.g. from a multi-channel EXR) to separate PixelBuffers

typedef struct
{
	char*     Name;
	uint32_t  Target;  // EpRED, EpGREEN etc.
} EpChannel;


struct EpImageFile_S
{
	EFileCore;                                      // Inherited from EFile

	void*                 Handle;                   // Format-specific internal data
	uint16_t              Flags;                    // EpIOFlagKEEP_DATA_FOR_LOSSLESS, etc.

// If not empty, it specifies where to load channels from a multi-channel file (e.g. EXR).
// If the EpIOFlagCHANNELS_TO_PIXELBUFFERS is set, the channels (other than R,G,B,A) will be loaded into separate PixelBuffers
//
	EList(, EpChannel, ChannelTargets);

	int                   IOStatus;
	EIndex2               RegionStart, RegionSize;
	EIndex2               DstPosition;

// If >= 2 (and if the IOModule supports it), skip pixels and rows on reading and only read every Nth pixel (used for reading thumbnail images etc).
	EIndex2               PixelStep;

	int                   Verbosity;                // Verbosity level for debugging etc.
	uint32_t              DarkSubtract : 1,         // Do dark field subtraction when loading a RAW file (default: TRUE)
	                      Denoise : 1,              // Do denoising when loading a RAW file (default: TRUE)
	                      ColorTransform : 1,       // Do color transform (3x3 matrix multiply) when loading a RAW file (default: TRUE)
	                      Crop : 1,                 // Do crop when loading a RAW file (default: TRUE)
	                      AllocPixelsOnOpen : 1;    // Used by EpImageFile_Open

// If there are MipMaps in a file (DDS, KTX etc), only load this range. Used by thumbnail loading, etc. If MipsStart is -1, load all available levels
	int                   MipsStart, MipsEnd;

	XeProgressIndicator*  ProgressIndicator;        // If not NULL, Image Load and Save functions may use this to show their progress

// Video (MKV etc.)
//
	EIndex                NumOfFrames;
	EIndex                RequestedFrame;           // For Read() methods in formats that support multi-frame files (e.g. multi-page TIFF)

	int                   PixelFormatID;
	ETime                 StartTime_us;
	ETime                 CurrentFrameTimeStamp_us;
};




//
// This ImageComponent is used for preserving the original data for lossy file formats, so we don't have to re-encode them
//
typedef struct
{
	EpImageComponentCore;

	EpImageIOModule*  IOModule;    // The IOModule that was used to load the image (e.g. JPEG)
	uint8_t*          Data;EIndex  Data_Bytes;
}	EpImageFileInfo;


//
// This ImageComponent is used for storing sub-images on Images, such as MIP levels
//
typedef struct
{
	EpImageComponentCore;

	EListA_s(, EpImagePtr, SubImages);
	EIndex  CurrentSubImageIndex;
}	EpSubImagesInfo;


#define EpBandColorsMAX  8
typedef struct
{
	EcRGBAf32Color  Colors[EpBandColorsMAX];
	int             NColors;
} EpBand;


// Plugins
//
#define	EpPLUGIN_ALLOC_STEP  8


// Scaling filter types
//
enum
{
	EpFilterNONE = 0,
	EpFilterNEAREST,
	EpFilterBOX,
	EpFilterTRIANGLE,
	EpFilterQUADRATIC,
	EpFilterMITCHELL,
	EpFilterGAUSSIAN,
	EpFilterSOLID_CENTER_WITH_GAUSSIAN_FALLOFF,
	EpFilterQUICK      // Quick 25%, 1/3 and 50% scale with simple pixel averaging (good for anti-aliasing)
};


// Image intensity metering modes
//
enum
{
	EpMeterAVERAGE,
	EpMeter16PIXELMAX,
	EpMeterMIDDLE_SPOT,
	EpMeter4SPOT,
	EpMeter5SPOT
};


// What changed in an input of a Tool, for undo/redo etc.
//
#define EpChgPOSITION  0x0000001
#define EpChgSIZE      0x0000002
#define	EpChgPIXELS    0x0000004

#define	EpChgSUBIMAGE  0x2000000  // If only a part of the image changed, this is OR-ed to the flags

#define EpChgALL       0xFFFFFFFF



typedef struct
{
	EpImageComponentCore;

	char*   Artist;EIndex  ArtistN;
	char*   CameraMake;EIndex CameraMakeN;
	char*   CameraModel;EIndex  CameraModelN;
	char*   BodySerialNumber;EIndex  BodySerialNumberN;
	char*   LensMake;EIndex  LensMakeN;
	char*   LensModel;EIndex  LensModelN;
	char*   GPSPositionString;EIndex  GPSPositionStringN;
	char*   SubSecTimeOriginal;
	double  ExposureTime;EIndex  ExposureTimeN;
	float   Aperture;EIndex  ApertureN;
	float   ISO;EIndex  ISON;
	float   FocalLength;EIndex  FocalLengthN;
	float   SubjectDistance;EIndex  SubjectDistanceN;
} EpEXIF;

extern void  EpEXIF_ClassRegister(void);
extern void  EpEXIF_Clear(EpEXIF* PEXIF);


// Image stats
//
typedef struct
{
	float  Min[EcMAX_NUM_OF_SPECTRAL_SAMPLES], Max[EcMAX_NUM_OF_SPECTRAL_SAMPLES];
} EpRanges_f32;

typedef struct
{
	uint16_t  Min[EcMAX_NUM_OF_SPECTRAL_SAMPLES], Max[EcMAX_NUM_OF_SPECTRAL_SAMPLES];
} EpRanges_u16;

typedef struct
{
	uint8_t  Min[EcMAX_NUM_OF_SPECTRAL_SAMPLES], Max[EcMAX_NUM_OF_SPECTRAL_SAMPLES];
} EpRanges_u8;

typedef struct
{
	EpRanges_f32  Ranges_f32;  // Always filled out, even if u16, u8 etc. are used

	union
	{
		EpRanges_u16  Ranges_u16;
		EpRanges_u8   Ranges_u8;
	};

	float  Means[EcMAX_NUM_OF_SPECTRAL_SAMPLES];
} EpPixelStats;



//--------------------------------
// Macros
//--------------------------------


//================================================================================================
// Create an EpImage from a "CStruct" image (inlined image: mostly used for icons)
// There are no checks, so be careful with 3-component (RGB) etc. images!
//================================================================================================
#define EpM_CImageToRGBA8Image_sp(pCImage, pImage) do\
{\
	if(pImage == NULL)\
	{\
		E_NewAssign(EpImage, pImage);\
		(pImage)->Size.X = (pCImage).SizeX;(pImage)->Size.Y = (pCImage).SizeY;\
		EpImage_SetPixels(pImage,  EpRGBA, 0, EResUINT8,  (pCImage).ImageBuffer_u8, TRUE);\
	}\
/*\
	else\
	{\
		printf("%s() %s:%d %s is not NULL\n", __FUNCTION__, __FILE__, __LINE__, #pImage);fflush(stdout);\
	}\
*/\
} while(0)


#define EpM_CImageToRGBA8Image_pp(pCImage, pImage) do\
{\
	if(pImage == NULL)\
	{\
		E_NewAssign(EpImage, pImage);\
		(pImage)->Size.X = (pCImage)->SizeX;(pImage)->Size.Y = (pCImage)->SizeY;\
		EpImage_SetPixels(pImage,  EpRGBA, 0, EResUINT8,  (pCImage)->ImageBuffer_u8, TRUE);\
	}\
/*\
	else\
	{\
		printf("%s() %s:%d %s is not NULL\n", __FUNCTION__, __FILE__, __LINE__, #pImage);fflush(stdout);\
	}\
*/\
} while(0)


//================================================================================================
// Create an EpImage from a "CStruct" image (inlined image: mostly used for icons)
// There are no checks, so be careful with 3-component (RGB) etc. images!
//================================================================================================
#define EpM_CImageToRGBA8Image_ps(pCImage, pImage) do\
{\
	EpImage_Init(&pImage);\
	(pImage).Size.X = (pCImage)->SizeX;(pImage).Size.Y = (pCImage)->SizeY;\
	EpImage_SetPixels(&(pImage), EpRGBA, 0, EResUINT8,  (pCImage)->ImageBuffer_u8, TRUE);\
} while(0)




#define EpM_CreateIconStates1_sp(pName) do\
{\
	EpM_CImageToRGBA8Image_sp(Image_##pName,         _Image_##pName);        EM_ObjectDebugNameM_p(_Image_##pName);\
} while(0)


#define EpM_CreateIconStates2_sp(pName) do\
{\
	EpM_CImageToRGBA8Image_sp(Image_##pName,          _Image_##pName);         EM_ObjectDebugNameM_p(_Image_##pName);\
	EpM_CImageToRGBA8Image_sp(Image_##pName##_Active, _Image_##pName##_Active);EM_ObjectDebugNameM_p(_Image_##pName##_Active);\
} while(0)


#define EpM_CreateIconStates3_sp(pName) do\
{\
	EpM_CImageToRGBA8Image_sp(Image_##pName,          _Image_##pName);         EM_ObjectDebugNameM_p(_Image_##pName);\
	EpM_CImageToRGBA8Image_sp(Image_##pName##_Active, _Image_##pName##_Active);EM_ObjectDebugNameM_p(_Image_##pName##_Active);\
	EpM_CImageToRGBA8Image_sp(Image_##pName##_Armed,  _Image_##pName##_Armed); EM_ObjectDebugNameM_p(_Image_##pName##_Armed);\
} while(0)


#define EpM_CreateIconStates3_pp(pName) do\
{\
	EpM_CImageToRGBA8Image_pp(Image_##pName,          _Image_##pName);         EM_ObjectDebugNameM_p(_Image_##pName);\
	EpM_CImageToRGBA8Image_pp(Image_##pName##_Active, _Image_##pName##_Active);EM_ObjectDebugNameM_p(_Image_##pName##_Active);\
	EpM_CImageToRGBA8Image_pp(Image_##pName##_Armed,  _Image_##pName##_Armed); EM_ObjectDebugNameM_p(_Image_##pName##_Armed);\
} while(0)


#define EpM_CreateIconStates5_sp(pName) do\
{\
	EpM_CImageToRGBA8Image_sp(Image_##pName,            _Image_##pName);           EM_ObjectDebugNameM_p(_Image_##pName);\
	EpM_CImageToRGBA8Image_sp(Image_##pName##_Active,   _Image_##pName##_Active);  EM_ObjectDebugNameM_p(_Image_##pName##_Active);\
	EpM_CImageToRGBA8Image_sp(Image_##pName##_Armed,    _Image_##pName##_Armed);   EM_ObjectDebugNameM_p(_Image_##pName##_Armed);\
	EpM_CImageToRGBA8Image_sp(Image_##pName##_Running,  _Image_##pName##_Running); EM_ObjectDebugNameM_p(_Image_##pName##_Running);\
	EpM_CImageToRGBA8Image_sp(Image_##pName##_Big,      _Image_##pName##_Big);     EM_ObjectDebugNameM_p(_Image_##pName##_Big);\
} while(0)


//
// See also
//  EpImage_New
//
#define EpImage_NewAssign(pSizeX, pSizeY,  pPixelType, pComponentsPerPixel, pPixelComponentType,  pClear,  pDst) do\
{\
	EpImage*  lImage;ENew(lImage);if(lImage)\
	{\
		EM_ObjectInit(EpImage, lImage, EpImage_class);\
\
		if(pSizeX > 0 && pSizeY > 0)\
		{\
			lImage->Size.X = pSizeX;\
			lImage->Size.Y = pSizeY;\
\
			if(pPixelType != 0 && EpImage_PixelBufferAdd(lImage,  pPixelType, pComponentsPerPixel, pPixelComponentType,  EpALLOC_PIXELS|(pClear ? EpCLEAR : 0),  NULL) != E_SUCCESS)\
			{\
				E_Delete(lImage);\
			}\
		}\
	}\
	E_Assign(lImage, pDst);\
} while(0)


#define EpImage_NewAssignNoChkNoFree(pSizeX, pSizeY,  pPixelType, pComponentsPerPixel, pPixelComponentType,  pClear,  pDst) do\
{\
	EpImage*  lImage;ENew(lImage);if(lImage)\
	{\
		EM_ObjectInit(EpImage, lImage, EpImage_class);\
\
		if(pSizeX > 0 && pSizeY > 0)\
		{\
			lImage->Size.X = pSizeX;\
			lImage->Size.Y = pSizeY;\
\
			if(pPixelType != 0 && EpImage_PixelBufferAdd(lImage,  pPixelType, pComponentsPerPixel, pPixelComponentType,  EpALLOC_PIXELS|(pClear ? EpCLEAR : 0),  NULL) != E_SUCCESS)\
			{\
				E_Delete(lImage);\
			}\
		}\
	}\
	E_AssignNoChkNoFree(lImage, pDst);\
} while(0)


#define EpImage_NewAssignToMember(pSizeX, pSizeY,  pPixelType, pComponentsPerPixel, pPixelComponentType,  pClear,  pDstObject,pDstMember) do\
{\
	EpImage*  lImage;ENew(lImage);if(lImage)\
	{\
		EM_ObjectInit(EpImage, lImage, EpImage_class);\
\
		if(pSizeX > 0 && pSizeY > 0)\
		{\
			lImage->Size.X = pSizeX;\
			lImage->Size.Y = pSizeY;\
\
			if(pPixelType != 0 && EpImage_PixelBufferAdd(lImage,  pPixelType, pComponentsPerPixel, pPixelComponentType,  EpALLOC_PIXELS|(pClear ? EpCLEAR : 0),  NULL) != E_SUCCESS)\
			{\
				E_Delete(lImage);\
			}\
		}\
	}\
	E_AssignToMember(lImage,  pDstObject,pDstMember);\
} while(0)


//================================================================================================
// Image reader template function
//================================================================================================
#define EpM_ImageLoad(pImageFile,  pSrcComponentCType, pSrcNComponents,  pScanlineLoadFunc, pPixelLoadFunc,  pDstPixelType, pDstPixelNComponents, pDstPixelComponentType,\
 pStartX, pStepX,  pDstSizeX, pDstSizeY,  pImage) do\
{\
	EpPixelBuffer*  lDstPixelBuffer;\
	EpImage_PixelBufferAdd(pImage,  pDstPixelType, pDstPixelNComponents, pDstPixelComponentType,  EpCHECK_IF_EXISTS|EpDELETE_OTHERS,  &lDstPixelBuffer);\
	if(lDstPixelBuffer)\
	{\
		const EIndex  lSrcBytesPerPixel = sizeof(pSrcComponentCType) * pSrcNComponents;\
		const EIndex  lDstBytesPerPixel = lDstPixelBuffer->BytesPerPixel;\
if(0)\
{\
	const int  sl = 4096;char  s[sl];\
	printf("%s() %s:%d  [%s%s%s] %slDstBytesPerPixel%s %lld\n",  __FUNCTION__, __FILE__, __LINE__,  ECodeGreen, EpImage_PixelFormatsToString(PImage,  s, sl), ECodeNormal,\
	 ECodeGreen, ECodeNormal, (long long)lDstBytesPerPixel);\
	fflush(stdout);\
}\
		const EIndex  lSrcByteStride = lSrcBytesPerPixel * LPixelStep.X;\
		if(pImageFile->RegionSize.X > 0)\
		{\
			const EIndex  lRegionSizeX = pImageFile->RegionSize.X, lRegionSizeY = pImageFile->RegionSize.Y;\
\
			EpImage_Resize(pImage,  lRegionSizeX, lRegionSizeY,  FALSE);\
			uint8_t*  lDstPixels = lDstPixelBuffer->u8;if(lDstPixels)\
			{\
				EIndex  lSrcY = pImageFile->RegionStart.Y, lDstY = 0, lSrcYLoaded = -1;(void)lSrcYLoaded;;for(;lDstY < lRegionSizeY;lSrcY++, lDstY++)\
				{\
					pScanlineLoadFunc(lDstY,  lSrcBytesPerPixel, pSrcNComponents, lSrcByteStride,  pPixelLoadFunc,  lDstBytesPerPixel,  pStartX, pStepX,  lSrcY,  lRegionSizeX);\
					M_ProgressUpdate(lDstY,  LDstEndY, LProgressMask);\
				}\
				pImage->NumOfValidPixels = lRegionSizeX * lRegionSizeY;\
				EChanges_Bump(&lDstPixelBuffer->Changes);\
				LResult = E_SUCCESS;\
			}\
			else LResult = E_NO_MEMORY;\
		}\
		else\
		{\
			EpImage_Resize(pImage,  pDstSizeX, pDstSizeY,  FALSE);\
			uint8_t*  lDstPixels = lDstPixelBuffer->u8;if(lDstPixels)\
			{\
/* lSrcYLoaded is for file formats that don't support random row access (i.e. they need to be read sequentially). It starts from -1 (no rows read yet).*/\
				EIndex  lSrcY = 0, lDstYC = 0, lSrcYLoaded = -1;(void)lSrcYLoaded;for(;lDstYC < LDstEndY;lDstYC++, lSrcY += LDirectionY * LPixelStep.Y)\
				{\
					pScanlineLoadFunc(lDstYC,  lSrcBytesPerPixel, pSrcNComponents, lSrcByteStride,  pPixelLoadFunc,  lDstBytesPerPixel,  pStartX, pStepX,  lSrcY,  pDstSizeX);\
					M_ProgressUpdate(lDstYC, LDstEndY,  LProgressMask);\
				}\
				pImage->NumOfValidPixels = pDstSizeX * pDstSizeY;\
				EChanges_Bump(&lDstPixelBuffer->Changes);\
				LResult = E_SUCCESS;\
			}\
			else LResult = E_NO_MEMORY;\
		}\
	}\
	else LResult = E_NO_MEMORY;\
} while(0)


//
// Icon definition macros
//

// Neutral
//
#define EpIconDef(pQualifier, p)\
extern EpCImage        Image_##p;\
pQualifier EpImagePtr  _Image_##p

#define EpIconDefI(pQualifier, p)\
extern EpCImage    Image_##p;\
pQualifier EpImagePtr  _Image_##p = NULL


// Neutral, Active
//
#define EpIconDef2I(pQualifier, p)\
extern EpCImage        Image_##p, Image_##p##_Active;\
pQualifier EpImagePtr  _Image_##p = NULL, _Image_##p##_Active = NULL


// Neutral, Active, Armed
//
#define EpIconDef3I(pQualifier, p)\
extern EpCImage        Image_##p, Image_##p##_Active, Image_##p##_Armed;\
pQualifier EpImagePtr  _Image_##p = NULL, _Image_##p##_Active = NULL, _Image_##p##_Armed = NULL

// Neutral, Active, Armed
//
#define EpIconDef3I_p(pQualifier, p)\
extern EpCImagePtr     Image_##p, Image_##p##_Active, Image_##p##_Armed;\
pQualifier EpImagePtr _Image_##p = NULL, _Image_##p##_Active = NULL, _Image_##p##_Armed = NULL

// Neutral, Active, Armed, Running, Big
//
#define XeIconDef5I(pQualifier, p)\
extern EpCImage        Image_##p, Image_##p##_Active, Image_##p##_Armed, Image_##p##_Running, Image_##p##_Big;\
pQualifier EpImagePtr  _Image_##p = NULL, _Image_##p##_Active = NULL, _Image_##p##_Armed = NULL, _Image_##p##_Running = NULL, _Image_##p##_Big = NULL



#define EpIconFree(p) do\
{\
	E_DeleteChk(_Image_##p);\
} while(0)

#define EpIconFree2(p) do\
{\
	E_DeleteChk(_Image_##p);\
	E_DeleteChk(_Image_##p##_Active);\
} while(0)

#define EpIconFree3(p) do\
{\
	E_DeleteChk(_Image_##p);\
	E_DeleteChk(_Image_##p##_Active);\
	E_DeleteChk(_Image_##p##_Armed);\
} while(0)

#define EpIconFree5(p) do\
{\
	E_DeleteChk(_Image_##p);\
	E_DeleteChk(_Image_##p##_Active);\
	E_DeleteChk(_Image_##p##_Armed);\
	E_DeleteChk(_Image_##p##_Running);\
	E_DeleteChk(_Image_##p##_Big);\
} while(0)


#define EpM_ColorSaturationRGB8(pSPixel, pDPixel,  pSaturation) do\
{\
	int        lR = pSPixel->R, lG = pSPixel->G, lB = pSPixel->B;\
	const int  lBW = (LRIT * lR + LGIT * lG + LBIT * lB) >> 8;\
\
	lR = lBW + pSaturation * lR;lG = lBW + pSaturation * lG;lB = lBW + pSaturation * lB;\
	if(lR < 0) lR = 0;else if(lR > 255) lR = 255;\
	if(lG < 0) lG = 0;else if(lG > 255) lG = 255;\
	if(lB < 0) lB = 0;else if(lB > 255) lB = 255;\
	pDPixel->R = lR;\
	pDPixel->G = lG;\
	pDPixel->B = lB;\
} while(0);

#define EpM_ColorSaturationRGB16(pSPixel, pDPixel,  pSaturation) do\
{\
	float        lR = pSPixel->R, lG = pSPixel->G, lB = pSPixel->B;\
	const float  lBW = (LRT * lR + LGT * lG + LBT * lB) * EInv65536N;\
\
	lR = lBW + pSaturation * lR;lG = lBW + pSaturation * lG;lB = lBW + pSaturation * lB;\
	if(lR < 0) lR = 0;else if(lR > 65535) lR = 65535;\
	if(lG < 0) lG = 0;else if(lG > 65535) lG = 65535;\
	if(lB < 0) lB = 0;else if(lB > 65535) lB = 65535;\
	pDPixel->R = lR;\
	pDPixel->G = lG;\
	pDPixel->B = lB;\
} while(0);

#define EpM_ColorSaturationRGBf32(pSPixel, pDPixel,  pSaturation) do\
{\
	float        lR = pSPixel->R, lG = pSPixel->G, lB = pSPixel->B;\
	const float  lBW = (LRT * lR + LGT * lG + LBT * lB);\
\
	lR = lBW + pSaturation * lR;lG = lBW + pSaturation * lG;lB = lBW + pSaturation * lB;\
	if(lR < 0.0f) lR = 0.0f;\
	if(lG < 0.0f) lG = 0.0f;\
	if(lB < 0.0f) lB = 0.0f;\
	pDPixel->R = lR;\
	pDPixel->G = lG;\
	pDPixel->B = lB;\
} while(0);


static inline EIndex EpPixelFormat_ActiveComponents(const EpPixelFormat* PPixelFormat)
{
	switch(PPixelFormat->Type)
	{
		case EpGRAY:        return(1);
		case EpGRAYA:       return(2);
		case EpCOLORINDEX:  return(1);
		case EpRG:          return(2);
		case EpRGB:         return(3);
		case EpRGBA:        return(4);
		case EpDEPTH:       return(1);
		case EpSPECTRAL:    return(PPixelFormat->NComponents);
	}
	return(0);
}


//================================================
// externs
//================================================

//--------------------------------
// Image.c
//--------------------------------
// Verbosity flags
enum
{
	EpVbPIXELBUFFERS   = 0x0001,
	EpVbTEXTURES       = 0x0002,
	EpVbTEXTUREMAPPING = 0x0004,
	EpVbPOLYGONS       = 0x0008,
	EpVbOPENGL         = 0x0010,
};

extern uint32_t  Ep_Verbosity;


EList_s(extern, EpImageComponentClassPtr, EpImageComponent_Classes);
extern void (*_EpImageComponent_GUIFromResources)(EpImage* PImage, EpImageComponent* PComponent,  void* PPanel, void* PDrawer, const int PAction);

extern const char              EpAPI_X11[], EpAPI_OpenGL[], EpAPI_Vulkan[];

extern uint8_t                 Ep_GammaTable8[256], Ep_InvGammaTable8[256];

// Always use unsigned values in response tables. This changes the mapping, but it saves a subtraction per pixel.
extern EBool                   Ep_ResponseTablesAlwaysUnsigned;

extern EpImageClass            EpImage_class[];
extern EpImageComponentClass*  EpSubImagesInfo_class;
extern EpImage*                EpIcon_FileImage;  // Generic image file icon

extern const char*             EpStringMIPLevelNames[];

extern EpImageComponentClass*  EpGeoTIFFInfo_class;
extern EpImageComponentClass*  EpEXIFInfo_Class;


extern EpCoordinate        Ep_SnapCoordinateTo(EpCoordinate PF, EpCoordinate PS);

extern void                EpImage_Init(EpImage* PImage);

extern EpImage*            EpImage_New(const EIndex PSizeX, const EIndex PSizeY,  const int PPixelType, const int PPixelComponents, const int PPixelComponentType,
                            const EBool PClear);

extern EpImage*            EpImage_NewC(EpImageClass* PClass,  const EIndex PSizeX, const EIndex PSizeY,
                            const int PPixelType, const int PComponentsPerPixel, const int PPixelComponentType,  const EBool PClear);

extern void                EpImage_FreeContents(EpImage* PImage);
extern void                EpImage_CopyContents(EpImage* PImageS, EpImage* PImageD);

extern int                 EpImage_CopyPixelData(const EpImage* PSImage, EpImage* PDImage);

extern EpImageComponentClass*  EpImageComponent_ClassByName(const char* PName);
extern EpImageComponentClass*  EpImageComponent_ClassRegister(EpImageComponentClass* PClassDescriptor);
extern void                    EpImageComponent_ClassDeactivate(EpImageComponentClass* PClass);
extern void                    EpImageComponent_ClassesFree(void);
extern int                     EpImageComponent_Remove(EpImage* PImage, EpImageComponent* PInfo);
extern int                     EpImageComponent_RemoveAll(EpImage* PImage);
extern EpImageComponent*       EpImageComponent_Add(EpImage* PImage, EpImageComponentClass* PClass);
extern EpImageComponent*       EpImageComponent_Copy(EpImage* PSImage, EpImageComponent* PSInfo, EpImage* PDImage);
extern EIndex                  EpImageComponent_CopyAll(EpImage* PSImage, EpImage* PDImage, const EBool PAllowMultiples);

extern EpImageComponent*       EpImageComponent_ByClass(EpImage* PImage, EpImageComponentClass* PClass, const EBool PAdd);

extern int                     EpImageSize_Fit(const EIndex2 PRefSize,  const EIndex2 PSizeMin, const EIndex2 PSizeMax,  EIndex2* PSizeOut);

extern void                    EpToneMapper_Init(EpToneMapper* PToneMapper);
extern void                    EpToneMapper_FreeContents(EpToneMapper* PToneMapper);
extern void                    EpToneMapper_Clear(EpToneMapper* PToneMapper);

extern EBool                   EpToneMapper_UpdateRGBA(EpToneMapper* PToneMapper, const EpImage* PImage,
                                EpConvertComponentFunc PConvertComponentProcR,
                                EpConvertComponentFunc PConvertComponentProcG,
                                EpConvertComponentFunc PConvertComponentProcB,
                                EpConvertComponentFunc PConvertComponentProcA,
                                void* PStruct, const int PTableSize);


extern void             EpExposure_Init(EpExposure* PExposure);
extern void             EpExposure_FreeContents(EpExposure* PExposure);
extern void             EpExposure_Update(EpExposure* PExposure, EpToneMapper* PToneMapper, const EpImage* PImage);

extern float            Ep_ToneMapComponent(const EIndex PComponentIndex, const float PComponentValue, const void* PExposure);

extern void             Ep_Init(void);
extern void             Ep_Free(void);

extern int              EpImage_Gain(const EpImage* PSImage, EpImage* PDImage, const float PGain);
extern EpImage*         EpImage_GetSubImage(EpImage* PImage);

extern int              Ep_MipLevels(const EIndex PSizeX, const EIndex PSizeY,  const EIndex PMinSizeX, const EIndex PMinSizeY);

extern char*            EpChangeFlags_ToString(const EChangeFlags PFlags, const uint16_t PControlFlags,  char* POutString);


extern const char  Ep_R[], Ep_G[], Ep_B[], Ep_A[],  Ep_X[], Ep_Y[], Ep_Z[];

extern const char*  Ep_RGB[];
extern const char*  Ep_RGBA[];
extern const char*  Ep_XYZ[];

extern const char  Ep_Display[];


//--------------------------------
// Camera.c
//--------------------------------
extern int              EpCameraInterface_ClassesFree(void);


//--------------------------------
// Pixels.c
//--------------------------------
extern EBool               EpImage_HasPixelData(const EpImage* PSImage);

extern int                 Ep_PixelTypeToFormat(const int PPixelType, const int PComponentType);

extern int                 EpImage_SetPixels(EpImage* PImage, const int PPixelType, const int PComponentsPerPixel, const int PPixelComponentType,
                            void* PPixels, const EBool PStatic);


// Actions for EpImage_PixelBufferAdd
//
#define  EpCLEAR                0x0001    // Clear new PixelBuffer to black
#define  EpCHECK_IF_EXISTS      0x0002    // Check if a PixelBuffer with the given pixel format already exists
#define  EpALLOC_PIXELS         0x0004    // Check if a PixelBuffer with the given pixel format already exists
#define  EpDELETE_OTHERS        0x0008    // Delete PixelBuffers other than the once specified
#define  EpCREATE_FROM_RICHEST  0x0010    // Create new PixelBuffer from richest existing PixelBuffer

extern int             Ep_PixelFormatParamsToComponentsInfo(const int PPixelType, const int PComponentType,  int* PComponentsPerPixel, int* PBytesPerComponent);

extern void            EpPixelBuffer_Init(EpPixelBuffer* PThis);
extern void            EpPixelBuffer_FreeContents(EpPixelBuffer* PPixelBuffer);


extern int             EpImage_PixelBufferAdd(EpImage* PImage,  const int PPixelType, const int PPixelComponents, const int PPixelComponentType,  const uint16_t PFlags,
                        EpPixelBuffer** PPixelBufferRet);

extern EpPixelBuffer*  EpImage_PixelBufferByFormat(EpImage* PImage,  const int PPixelType, const int PComponentsPerPixel, const int PComponentType,
                        const EBool PAdd,  int* PResult);

extern int             EpImage_PixelBufferDel(EpImage* PImage, EpPixelBuffer* PPixelBuffer);

enum
{
	EpPixFREE_PIXELBUFFERS = 0x0001,
	EpPixSET_SIZE_TO_0x0   = 0x0002
};

extern EIndex          EpImage_PixelDataFree(EpImage* PImage, const uint16_t PFlags);

extern EpPixelBuffer*  EpImage_PixelBuffer_ByTemplate(const EpImage* PImage, const EpPixelBuffer* PTemplate);
extern EpPixelBuffer*  EpImage_PixelBufferGetByComponenType(const EpImage* PImage, const int PType);
extern EpPixelBuffer*  EpImage_PixelBufferRichest(const EpImage* PImage);

extern char*          Ep_PixelTypeToString(const int PPixelType, char* PStr);
extern char*          EpPixelFormatID_ToString(const int PPixelFormat, const EBool PExpandedName,  char* PStr);
extern int            EpPixelFormatIDToPixelType(const int PPixelFormat);

extern EIndex         EpPixelBuffer_NActiveChannels(const EpPixelBuffer* PPixelBuffer);
extern EIndex         EpPixelBuffer_AlphaIndex(const EpPixelBuffer* PPixelBuffer);
extern EpChannelMask  EpPixelBuffer_ChannelsSupported(const EpPixelBuffer* PPixelBuffer, const EBool PDerived);

extern char*         EpPixelBuffer_FormatToString(const EpPixelBuffer* PPixelBuffer,  char* PStr, const EIndex PMaxLen);

extern int           Ep_PixelTypeToRichness(const int PPixelType);

extern EBool         EpPixelFormat_Equal(const EpPixelFormat* P0, const EpPixelFormat* P1);
extern char*         EpPixelFormat_ToString(const EpPixelFormat* PFormat,  char* PStr, const EIndex PMaxLen);

extern char*         EpImage_PixelFormatsToString(const EpImage* PImage,  char* PStr, const EIndex PMaxLen);

extern void          Ep_RGB8ToRGBX8(const EpRGB8Pixel*  PSrcImage, EpRGBA8Pixel* PDstImage, const EIndex PNumOfPixels);
extern void          Ep_RGBX8ToRGB8(const EpRGBA8Pixel* PSrcImage, EpRGB8Pixel*  PDstImage, const EIndex PNumOfPixels);

extern int           EpImage_HDRToSDR(EpImage* PSImage, EpImage* PDImage, const EpToneMapper* PToneMapper, const EBool PUpdateIfExists, const EBool PRemoveOrigBuffers);

extern int           EpImage_RGBAf32ToRGBA8(EpImage* PSImage, EpImage* PDImage,  const EpToneMapper* PToneMapper, const EBool PUpdateIfExists);
extern int           EpImage_RGBA16ToRGBA8(EpImage* PImage,   EpImage* PDImage,  const EpToneMapper* PToneMapper, const EBool PUpdateIfExists, const EBool PDeleteSourcePixelBuffer);
extern int           EpImage_RGBA8ToRGBf32(EpImage* PImage);

extern int           EpImage_RGBf32ToRGBX8(EpImage* PSImage, EpImage* PDImage,  const EpToneMapper* PToneMapper, const EBool PUpdateIfExists);
extern int           EpImage_RGB16ToRGBX8(EpImage* PSImage, EpImage* PDImage,  const EpToneMapper* PToneMapper, const EBool PUpdateIfExists);

extern int           EpImage_RGB8ToRGBX8(EpImage* PImage, const EpRGB8Pixel* PRGB8Pixels);
extern EpRGB8Pixel*  EpImage_RGBX8ToRGB8(EpImage* PImage, EpRGB8Pixel* PRGB8Pixels);

extern int           EpImage_ToRG8(EpImage* PSImage, EpImage* PDImage, const EpToneMapper* PToneMapper, const EBool PUpdateIfExists);

extern void          EpImage_ColorIndex8ToRGBX8(EpImage* PImage);

extern int           EpImage_GrayA16ToGrayA8(EpImage* PSImage, EpImage* PDImage,  const EpToneMapper* PToneMapper, const EBool PUpdateIfExists, const EBool PDeleteSourcePixelBuffer);
extern int           EpImage_GrayAf32ToGrayA8(EpImage* PSImage,  EpImage* PDImage,  const EpToneMapper* PToneMapper, const EBool PUpdateIfExists);
extern int           EpImage_Grayf32ToGray8(EpImage* PSImage,  EpImage* PDImage,  const EpToneMapper* PToneMapper, const EBool PUpdateIfExists);
extern int           EpImage_Gray16ToGray8(EpImage* PSImage, EpImage* PDImage,  const EpToneMapper* PToneMapper, const EBool PUpdateIfExists, const EBool PDeleteSourcePixelBuffer);

extern EpImage*      EpImage_FromCImage(const EpCImage* PCImage, const EBool PPixelDataStatic);
extern EpImage*      EpImage_FromCImageC(const EpCImage* PCImage, EpImageClass* PClass, const EBool PPixelDataStatic);

extern int           EpImage_CopyPixelBuffers(const EpImage* PSImage, EpImage* PDImage,  const EBool PAllocatePixelData, const EBool PCopyPixelData);
extern int           EpImage_CopyPixels(const EpImage* PSImage, EpImage* PDImage);


extern void          EpImage_MoveContents(EpImage* PSImage, EpImage* PDImage);

extern void          EpPixelBuffer_AllocPixels(EpPixelBuffer* PPixelBuffer,  const EIndex PSizeX, const EIndex PSizeY,  const EBool PClear);

extern int           EpImage_Resize(EpImage* PImage,  const EIndex PNewSizeX, const EIndex PNewSizeY,  const EBool PClear);

extern int           EpImage_Clear(EpImage* PImage, EpImage* PResultImage, const EcRGBAiColor* PColor, const EpChannelFlags PChannels);

extern EBool         EpPixelBuffer_HasAlpha(const EpPixelBuffer* PPixelBuffer);

extern EBool         EpImage_HasIntensity(const EpImage* PImage);
extern EBool         EpImage_HasRed(const EpImage* PImage);
extern EBool         EpImage_HasGreen(const EpImage* PImage);
extern EBool         EpImage_HasBlue(const EpImage* PImage);
extern EBool         EpImage_HasAlpha(const EpImage* PImage);

extern EBool         EpImage_IsHDR(const EpImage* PImage);

extern int           EpImage_AlphaAdd(EpImage* PSImage, EpImage* PDImage, const int PAlpha);
extern void          EpImage_AlphaDel(EpImage* PImage);

extern int           EpImage_GetPixelColor(const EpImage* PImage,  const EIndex PX, const EIndex PY,  EcColor* PColor, EcRGBAf32Color* PRGBAfColor, EcRGBAiColor* PRGBAiColor,
                      uint16_t* PComponentType);

extern int           EpImage_GetPixelColorF(const EpImage* PImage,  const EIndex PX, const EIndex PY,  EcRGBAf32Color* PColor);
extern int           EpImage_GetPixelColorAvg(EpImage* PSImage,  const EIndex PPX, const EIndex PPY,  const EIndex PSampeKernelSize, EcRGBAf32Color* PRGBAf32Color);
extern int           EpImage_SetPixelColorRGBAi(EpImage* PImage,  const EIndex PX, const EIndex PY,  const EcRGBAiColor* PColor, const uint32_t PBlendMode,
                      const EpChannelFlags PChannels);

extern int           EpImage_SetPixelColorRGBAf(EpImage* PImage,  const EIndex PX, const EIndex PY,  const EcRGBAf32Color* PColor, const uint32_t PBlendMode,
                      const float PGamma,  const EpChannelFlags PChannels);

extern int           EpImage_CreateRGBAf32(const EpImage* PSImage, EpImage* PDImage, const EBool PUpdate, const EBool PDeleteOriginalPixelBuffers,  EpPixelBuffer** PPixelBuffer);
extern int           EpImage_CreateRGBAu16(const EpImage* PSImage, EpImage* PDImage, const EBool PUpdate, const EBool PDeleteOriginalPixelBuffers,  EpPixelBuffer** PPixelBuffer);
extern int           EpImage_CreateRGBA8(const EpImage* PSImage, EpImage* PDImage,  const EBool PUpdate, const EBool PDeleteOriginalPixelBuffers,  EpPixelBuffer** PPixelBuffer);

extern int           EpImage_CreateRGBf32(const EpImage* PSImage, EpImage* PDImage, const EBool PUpdate, const EBool PDeleteOriginalPixelBuffers,  EpPixelBuffer** PPixelBuffer);
extern int           EpImage_CreateRGBf32Mult(const EpImage* PSImage, EpImage* PDImage, const EBool PUpdate, const EBool PDeleteOriginalPixelBuffers, const float PMult,
                      EpPixelBuffer** PPixelBuffer);

extern int           EpImage_CreateRGBu16(const EpImage* PSImage, EpImage* PDImage, const EBool PUpdate, const EBool PDeleteOriginalPixelBuffers,  EpPixelBuffer** PPixelBuffer);
extern int           EpImage_CreateRGBX8(const EpImage* PSImage, EpImage* PDImage,  const EBool PUpdate, const EBool PDeleteOriginalPixelBuffers,  EpPixelBuffer** PPixelBuffer);

extern int           EpImage_CreateGrayAf32(const EpImage* PSImage, EpImage* PDImage, const EBool PUpdate, const EBool PDeleteOriginalPixelBuffers,  EpPixelBuffer** PPixelBuffer);
extern int           EpImage_CreateGrayA16(const EpImage* PSImage, EpImage* PDImage, const EBool PUpdate, const EBool PDeleteOriginalPixelBuffers,  EpPixelBuffer** PPixelBuffer);
extern int           EpImage_CreateGrayA8(const EpImage* PSImage, EpImage* PDImage, const EBool PUpdate, const EBool PDeleteOriginalPixelBuffers,  EpPixelBuffer** PPixelBuffer);

extern int           EpImage_CreateGrayf32Mult(const EpImage* PSImage, EpImage* PDImage, const uint32_t PFromChannels, const EBool PUpdate,
                      const EBool PDeleteOriginalPixelBuffers, const float PMult,  EpPixelBuffer** PPixelBuffer);

extern int           EpImage_CreateGrayf32(const EpImage* PSImage, EpImage* PDImage, const EBool PUpdate, const EBool PDeleteOriginalPixelBuffers,  EpPixelBuffer** PPixelBuffer);
extern int           EpImage_CreateGrayu16(const EpImage* PSImage, EpImage* PDImage, const EBool PUpdate, const EBool PDeleteOriginalPixelBuffers,  EpPixelBuffer** PPixelBuffer);

extern int           EpImage_CreateGray8FromChannels(const EpImage* PSImage, EpImage* PDImage, const uint32_t PFromChannels, const EBool PUpdate,
                      const EBool PDeleteOriginalPixelBuffers,  EpPixelBuffer** PPixelBuffer);

extern int           EpImage_CreateGray8(const EpImage* PSImage, EpImage* PDImage, const EBool PUpdate, const EBool PDeleteOriginalPixelBuffers,  EpPixelBuffer** PPixelBuffer);

extern int           EpImage_CreatePixelFormat(const EpImage* PSImage, EpImage* PDImage,  const int PPixelType, const int PComponentsPerPixel, const int PComponentType,
                      const EBool PUpdate, const EBool PDeleteOriginalPixelBuffers);

extern int           EpImage_RowConvertToFloats(const EpImage* PSrcImage, const EpPixelBuffer* PSrcPixelBuffer,  EpImage* PDstImage, const EIndex PDstNComponents,
                      float* PRow, const EIndex PY);

extern void          EpImage_RowConvertFromFloats(EpImage* POutImage, EpPixelBuffer* PDPixelBuffer, const float* PRow, const EIndex PSrcComponentsPerPixel, const EIndex PY);

extern EIndex        EpImage_CorrectPixelValues(EpImage* PImage);

extern int           EpImage_Convolve(EpImage* PSImage, EpImage* PDImage, const float* PKernel, const EIndex PKernelSizeX, const EIndex PKernelSizeY);

extern int           EpImage_EdgeDetect(EpImage* PSImage, const float* PXKernel, const float* PYKernel, const EIndex PKernelSize,  EpImage* PXImage, EpImage* PYImage,
                      EpImage* PDImage, float* PGX, float* PGY);


extern int            EpImage_MultiplyColorByAlpha(EpImage* PImage);


//--------------------------------
// Spectral.c
//--------------------------------
extern int            EpPixelBuffer_SpectrumToRGBConversionInit(EpPixelBuffer* PPixelBuffer);
extern int            EpImage_SpectralToRGB(const EpImage* PSrcImage, EpImage* PDstImage);


//--------------------------------
// Scale.c
//--------------------------------
extern EFlags    _EpScale_Verbosity;

extern int       EpPixels_Scale50Percent_u8(uint8_t* PSrcPixels,  const EIndex PSizeX, const EIndex PSizeY, const EIndex PNComponents,  uint8_t* PDstPixels);
extern int       EpPixels_Scale50Percent_u16(uint16_t* PSrcPixels,  const EIndex PSizeX, const EIndex PSizeY, const EIndex PNComponents,  uint16_t* PDstPixels);
extern int       EpPixels_Scale50Percent_i16(int16_t* PSrcPixels,  const EIndex PSizeX, const EIndex PSizeY, const EIndex PNComponents,  int16_t* PDstPixels);

extern int       EpImage_ScaleQuick50Percent(const EpImage* PSImage, EpImage* PDImage);

extern void      EpImage_CorrectNewSize(const EpImage* PImage, EIndex2* PNewSize);

extern EBool     EpImage_Scale(const EpImage* PImageS, EpImage* PImageD,  const EIndex PNewSizeX, const EIndex PNewSizeY,  int PFilterType, double PBlurFactor,
                  const EIndex PNThreads,  void (*LShowProgressProc)(float, void*), void* PShowProgressProcData);

extern EBool     EpImage_ScaleAlpha(EpImage* PImageS, EpImage* PImageD,  const EIndex PNewSizeX, const EIndex PNewSizeY,  const int PFilterType, double PBlurFactor,
                  void (*LShowProgressProc)(float, void*), void* PShowProgressProcData);

extern void      Ep_ScaleFree(void);


//--------------------------------
// IO.c
//--------------------------------
EList(extern, EpImageIOModule*, EpImage_FileFormats);
extern ELogFunc     Ep_LogFunc;

extern EpImageComponentClass*  EpImageFileInfo_class;

extern int          EpImage_IOReadStatus;

extern char*        EpImage_IOPluginPath;

EList(extern, char*, Ep_Extensions);

extern const char*  Ep_GetBaseFileName(const char* PFileName, char* PNameRet, const int PMaxLen);

extern EpImageIOModule*  EpImageFormat_ByName(const char* PName);
extern EpImageIOModule*  EpImageFormat_ByExtension(const char* PExtension);
extern uint32_t*         Ep_ABGRToRGBA(uint32_t* PABGRImage,  const EIndex PSizeX, const EIndex PSizeY);

extern EpImageIOModule*  EpImage_IOModuleAdd(EpImageIOModule* PDescriptor);
extern void              EpImage_IOModuleRemove(EpImageIOModule* PFormat, const EBool PFree);
extern void              EpImage_IOModuleDeactivate(EpImageIOModule* PFormat);

extern EpImageFile*      EpImageFile_Open(const char* PFileName, EpImageIOModule* PFormat, EpImageIOModule** PFileFormatRet, EpImage* PImage, const EBool PAllocPixels,
                          const uint16_t PMode);

extern int               EpImageFile_SaveFrame(EpImageFile* PImageFile, EpImage* PImage,  const uint8_t* PBuffer, const EIndex PBufferSize);

extern void              EpImageFile_Init(EpImageFile* PImageFile);
extern EpImageFile*      EpImageFile_New(const char* PFileName, EpImageIOModule* PFormat);
extern void              EpImageFile_FreeContents(EpImageFile* PImageFile);
extern void              EpImageFile_Close(EpImageFile* PImageFile);

extern int               EpImage_FileReadRegion(EpImageFile* PImageFile,  const EIndex PSrcX, const EIndex PSrcY,  const EIndex PSizeX, const EIndex PSizeY,
                          const EIndex PDstX, const EIndex PDstY,  EpImage* PImage);

extern int               EpImage_LoadFromFile(const char* PFileName, EpImageIOModule* PFormat, XeProgressIndicator* PProgressIndicator,
                          EpImage* PImage, EpImageIOModule** PFileFormatRet);

extern int               EpImage_LoadFromFileAdv(const char* PFileName, EpImageIOModule* PFormat, EpImageIOModule** PFileFormatRet, EpImageFile* PImageFile, EpImage* PImageD);

extern int               EpImage_LoadFromOpenFile(EpImageFile* PImageFile, EpImage* PImage, const EIndex PFrame);

extern int               EpImage_LoadFromMemory(EpImageIOModule* PFormat,  const uint8_t* PBuffer, const EIndex PBufferSize,  const uint16_t PFlags,  EpImage* PImageD);

extern int               EpImage_LoadNumberedFile(const char* PBaseFileName, const int PFrameNumber, const char* PFileExtension, int* PDigitsPtr, EpImageIOModule* PFormat,
                          EpImageIOModule** PFileFormatRet, EpImage* PImage);

extern int               EpImage_SaveToFile(EpImage* PImage, const EpToneMapper* PToneMapper,  const char* PName, char* PNameRet, const int PNameMaxLen, EpImageIOModule* PFormat);
extern int               EpImage_SaveToFileAdv(EpImage* PImage, const EpToneMapper* PToneMapper,  const char* PFileName, char* PFileNameRet, const EIndex PNameMaxLen,
                          XeProgressIndicator* PProgressIndicator, EpImageIOModule* PFormat);

extern int               EpImage_SaveToOpenFile(EpImage* PImage, FILE* PFile, EpImageIOModule* PFormat);
extern int               EpImage_SaveToMemory(EpImage* PImage, const char* PFileName, EpImageIOModule* PFormat, const EpToneMapper* PToneMapper,
                          uint8_t** PBufferP, EIndex* PBufferSizeP);

extern int               Ep_BufferSaveToImageFile(void* PPixels,  const EIndex PSizeX, const EIndex PSizeY,
                          const int PPxelType, const int PComponentsPerPixel, const uint16_t PPixelComponentType,  const char* PFileName);

extern void              EpImage_FileFree(EpImageFile* PImageFile);

extern int               EpLUT_CubeLoad(EpLUT* PLUT, const char* PPath);
extern int               EpLUT_CubeSave(const EpLUT* PLUT, const char* PPath);

typedef void  (*EpCacheAreaReadTileFunc)(const char* PPath,
               const EIndex PTotalSamplesPerRow, const EIndex PTileSamplesPerRow,  const EIndex PTotalSamplesPerCol, const EIndex PTileSamplesPerCol,
               EIndex PLonI, EIndex PLatI,  const EIndex PUStartCell, const EIndex PVStartCell,  const EIndex PSrcUCells, const EIndex PSrcVCells,
               const EIndex PUStep, const EIndex PVStep,  const EIndex PDstUCells, const EIndex PDstUCell, const EIndex PDstVCell, void* PBuffer);

extern void  Ep_CacheArea(const char* PPath, const EIndex PTotalSamplesPerRow, const EIndex PTotalSamplesPerCol, const EIndex PTileSamplesPerRow, const EIndex PTileSamplesPerCol,
              EpCacheAreaReadTileFunc PLoadSubTile,
              const EIndex PStartUCell, const EIndex PSrcTotalUCells, const EIndex PUStep,  const EIndex PStartVCell, const EIndex PSrcTotalVCells, const EIndex PVStep,
              void* PBuffer, void (*PProgressFunc)(const double PFractionComplete));


extern EBool  Ep_IOModuleSetResource1b(EpImageIOModule* PObject, const char* PName, const EBool PValue);



extern const float  EpKernel_Sobel3x3X[];
extern const float  EpKernel_Sobel3x3Y[];
extern const float  EpKernel_Scharr3x3X[];
extern const float  EpKernel_Scharr3x3Y[];


//--------------------------------
// ToneMap.c
//--------------------------------
extern int   EpToneMapper_Apply(EpToneMapper* PToneMapper,  const EpImage* PSImage, EpImage* PDImage, const EpRegion* PRegion, const uint32_t PChannels, const EIndex PNThreads,
              void* PObject);

extern void  (*Ep_ToneMapFree)(void);


// These are in graphics API-dependent source files
//
extern void             EpGPU2DBuffer_Init(const char* PAPI, EpGPU2DBuffer* PBuffer);
extern EpGPU2DBuffer*   EpGPU2DBuffer_New(void);
extern void             EpGPU2DBuffer_Free(EpGPU2DBuffer* PBuffer);

extern EpGPUFrameBuffer*  EpGPUFrameBuffer_New(const char* PName);
extern void               EpGPUFrameBuffer_Init(EpGPUFrameBuffer* PFBO, const char* PAPI, const char* PName, const EBool PStatic);

extern int                EpGPUFrameBuffer_Resize(EpGPUFrameBuffer* PFBO,  const EIndex PNewSizeX, const EIndex PNewSizeY,
                           const short PPixelFormat, const short PComponenType, EpGPU2DBuffer* PDepthBuffer, const uint16_t PFlags);

extern int                EpGPUFrameBuffer_Save(EpGPUFrameBuffer* PFBO, const char* PFileName, void* PFormat);
extern int                EpGPUFrameBuffer_IsDrawable(EpGPUFrameBuffer* PFBO);

extern void  EpLUT_Init(EpLUT* PLUT, const EBool PStatic);
extern void  EpLUT_FreeContents(EpLUT* PLUT);

//----------------------------------------
// esrc/Tools/Image/Plugins.c
//----------------------------------------
extern int     EpImage_IOPluginsLoad(const char* PAppName, const char* PCommandLine, const char* PFileName, const int PVerbosity);
extern int     Ep_PluginsLoad(const char* PPath, const char* PFileName);
extern void    Ep_PluginsFree(void);

#if defined (__cplusplus) && (!(defined (__CPLUSLIBS)))
}	// Close scope of 'extern "C"' declaration
#endif


#endif // _EImage_h
