Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions Source/FreeImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -859,6 +859,21 @@ FI_ENUM(FREE_IMAGE_ALPHA_OPERATION) {
};


// Message struct ---------------------------------------------------------


FI_STRUCT(FIMESSAGE);

FI_ENUM(FREE_IMAGE_SEVERITY) {
FISEV_VERBOSE = 0,
FISEV_INFO = 200,
FISEV_WARNING = 300,
FISEV_ERROR = 400,
FISEV_NONE = 0x1000
};




#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -895,6 +910,40 @@ DLL_API void DLL_CALLCONV FreeImage_SetOutputMessageStdCall(FreeImage_OutputMess
DLL_API void DLL_CALLCONV FreeImage_SetOutputMessage(FreeImage_OutputMessageFunction omf);
DLL_API void DLL_CALLCONV FreeImage_OutputMessageProc(int fif, const char *fmt, ...);


/**
* ctx - Opaque handle for message processing context
* func - Address of message processing function
*/
typedef void (DLL_CALLCONV *FreeImage_ProcessMessageFunction)(void* ctx, const FIMESSAGE* msg);

/**
* Adds a message processing function for this thread only.
* The `func` must not be nullptr.
* On success retuns non-zero ID of the registered processor, that can later be used in FreeImage_RemoveProcessMessageFunction()
*/
DLL_API uint32_t DLL_CALLCONV FreeImage_AddProcessMessageFunction(void* ctx, FreeImage_ProcessMessageFunction func);

/**
* Removes a previously added message processor.
* Returns true on success, false if processor ID is not valid.
*/
DLL_API FIBOOL DLL_CALLCONV FreeImage_RemoveProcessMessageFunction(uint32_t id);

/**
* Invokes message processor for this message instance
*/
DLL_API void DLL_CALLCONV FreeImage_ProcessMessage(const FIMESSAGE* msg);


DLL_API FIMESSAGE* DLL_CALLCONV FreeImage_CreateMessage(FREE_IMAGE_FORMAT scope, FREE_IMAGE_SEVERITY severity, const char* what);
DLL_API void DLL_CALLCONV FreeImage_DeleteMessage(FIMESSAGE* msg);
DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetMessageScope(const FIMESSAGE* msg);
DLL_API FREE_IMAGE_SEVERITY DLL_CALLCONV FreeImage_GetMessageSeverity(const FIMESSAGE* msg);
DLL_API const char* DLL_CALLCONV FreeImage_GetMessageString(const FIMESSAGE* msg);



// Allocate / Clone / Unload routines ---------------------------------------

DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Allocate(int width, int height, int bpp, unsigned red_mask FI_DEFAULT(0), unsigned green_mask FI_DEFAULT(0), unsigned blue_mask FI_DEFAULT(0));
Expand Down
166 changes: 160 additions & 6 deletions Source/FreeImage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include <cassert>
#include <filesystem>
#include <functional>
#include <limits>
#include <memory>
#include <optional>
Expand Down Expand Up @@ -250,6 +251,15 @@ namespace fi
eSrcAlpha = FIAO_SrcAlpha
};

enum class Severity
{
eVerbose = FISEV_VERBOSE,
eInfo = FISEV_INFO,
eWarning = FISEV_WARNING,
eError = FISEV_ERROR,
eNone = FISEV_NONE
};


class ImageError
: public std::runtime_error
Expand Down Expand Up @@ -325,6 +335,148 @@ namespace fi
}


/**
* Const access to a message allocated inside FreeImage
*/
class MessageView
{
public:
explicit
MessageView(const FIMESSAGE* handle)
: mHandle(handle)
{ }

MessageView(const MessageView&) = default;
MessageView(MessageView&&) noexcept = default;

// no need to release
~MessageView() = default;

MessageView& operator=(const MessageView&) = default;
MessageView& operator=(MessageView&&) noexcept = default;

operator bool() const {
return (mHandle != nullptr);
}

const char* GetCString() const {
return FreeImage_GetMessageString(mHandle);
}

std::string GetString() const {
const char* str = FreeImage_GetMessageString(mHandle);
return str ? std::string(str) : std::string();
}

Severity GetSeverity() const {
return static_cast<Severity>(FreeImage_GetMessageSeverity(mHandle));
}

ImageFormat GetScope() const {
return static_cast<ImageFormat>(FreeImage_GetMessageScope(mHandle));
}

protected:
const FIMESSAGE* mHandle;
};


/**
* Mutable user allocated message instance
*/
class Message
: public MessageView
{
public:
Message(ImageFormat scope, Severity severity, const char* what)
: MessageView(FREEIMAGERE_CHECKED_CALL(FreeImage_CreateMessage, static_cast<FREE_IMAGE_FORMAT>(scope), static_cast<FREE_IMAGE_SEVERITY>(severity), what))
{ }

Message(ImageFormat scope, Severity severity, const std::string& what)
: Message(scope, severity, what.c_str())
{ }

Message(const Message&) = delete;

Message(Message&& other) noexcept
: MessageView(other.mHandle)
{
other.mHandle = nullptr;
}

// not virtual, just reusing methods MessageView
~Message() {
FreeImage_DeleteMessage(GetMutable());
}

Message& operator=(const Message&) = delete;

Message& operator=(Message&& other) noexcept
{
if (this != &other) {
FreeImage_DeleteMessage(GetMutable());
mHandle = other.mHandle;
other.mHandle = nullptr;
}
return *this;
}

private:
FIMESSAGE* GetMutable() {
// Message created by FreeImage_CreateMessage() is actually a dynamic object, so can safely remove const
return const_cast<FIMESSAGE*>(mHandle);
}
};


using MessageProcessFunction = std::function<void(const MessageView&)>;


/**
* Registers a message processor for life time of this guard instance
*/
class MessageProcessFunctionGuard
{
public:
MessageProcessFunctionGuard(MessageProcessFunction func)
: mFunc(std::move(func))
{
mProcId = FREEIMAGERE_CHECKED_CALL(FreeImage_AddProcessMessageFunction, this, &MessageProcessFunctionGuard::Wrapper);
}

MessageProcessFunctionGuard(const MessageProcessFunctionGuard&) = delete;
MessageProcessFunctionGuard(MessageProcessFunctionGuard&& other) noexcept = delete;

~MessageProcessFunctionGuard()
{
if (mProcId) {
FreeImage_RemoveProcessMessageFunction(mProcId);
}
}

MessageProcessFunctionGuard& operator=(const MessageProcessFunctionGuard&) = delete;
MessageProcessFunctionGuard& operator=(MessageProcessFunctionGuard&& other) noexcept = delete;

/**
* Do not call FreeImage_RemoveProcessMessageFunction() in destcrutor
*/
uint32_t Release() {
const uint32_t tmp = mProcId;
mProcId = 0;
return tmp;
}

private:
static
void DLL_CALLCONV Wrapper(void* thiz, const FIMESSAGE* msg) {
static_cast<MessageProcessFunctionGuard*>(thiz)->mFunc(MessageView(msg));
}

MessageProcessFunction mFunc;
uint32_t mProcId{ 0 };
};



class Tag
{
Expand Down Expand Up @@ -359,13 +511,15 @@ namespace fi

Tag& operator=(Tag&& other) noexcept
{
if (mCallDelete && mHandle) {
FreeImage_DeleteTag(mHandle);
if (this != &other) {
if (mCallDelete) {
FreeImage_DeleteTag(mHandle);
}
mHandle = other.mHandle;
mCallDelete = other.mCallDelete;
other.mHandle = nullptr;
other.mCallDelete = false;
}
mHandle = other.mHandle;
mCallDelete = other.mCallDelete;
other.mHandle = nullptr;
other.mCallDelete = false;
return *this;
}

Expand Down
Loading