2019-05-29 04:18:11 +02:00
|
|
|
// Matrix Construct
|
|
|
|
//
|
|
|
|
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
|
|
|
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
|
|
|
//
|
|
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
|
|
// copyright notice and this permission notice is present in all copies. The
|
|
|
|
// full license for this software is available in the LICENSE file.
|
|
|
|
|
|
|
|
#include <RB_INC_MAGICK_API_H
|
|
|
|
|
|
|
|
namespace ircd::magick
|
|
|
|
{
|
2019-05-29 07:08:46 +02:00
|
|
|
static void handle_exception(const ::ExceptionType, const char *, const char *);
|
|
|
|
static void handle_fatal(const ::ExceptionType, const char *, const char *) noexcept;
|
|
|
|
static void handle_error(const ::ExceptionType, const char *, const char *) noexcept;
|
|
|
|
static void handle_warning(const ::ExceptionType, const char *, const char *) noexcept;
|
|
|
|
static void handle_log(const ::ExceptionType, const char *) noexcept;
|
2019-05-29 13:55:09 +02:00
|
|
|
static uint handle_monitor(const char *, const int64_t, const uint64_t, ExceptionInfo *) noexcept;
|
2019-05-29 07:08:46 +02:00
|
|
|
|
|
|
|
template<class R, class F, class... A> static R call(F&&, A&&...);
|
|
|
|
template<class R, class F, class... A> static R callex(F&&, A&&...);
|
|
|
|
template<class F, class... A> static void callpf(F&&, A&&...);
|
|
|
|
|
2019-05-29 04:18:11 +02:00
|
|
|
static void init();
|
|
|
|
static void fini();
|
2019-05-29 07:08:46 +02:00
|
|
|
|
|
|
|
extern log::log log;
|
2019-05-29 04:18:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ircd::mapi::header
|
|
|
|
IRCD_MODULE
|
|
|
|
{
|
|
|
|
"GraphicsMagick Library support for media manipulation",
|
|
|
|
ircd::magick::init,
|
|
|
|
ircd::magick::fini
|
|
|
|
};
|
|
|
|
|
2019-05-29 07:08:46 +02:00
|
|
|
decltype(ircd::magick::log)
|
|
|
|
ircd::magick::log
|
|
|
|
{
|
|
|
|
"magick"
|
|
|
|
};
|
|
|
|
|
2019-05-29 04:18:11 +02:00
|
|
|
//
|
|
|
|
// init
|
|
|
|
//
|
|
|
|
|
|
|
|
void
|
|
|
|
ircd::magick::init()
|
|
|
|
{
|
2019-05-29 07:08:46 +02:00
|
|
|
const auto version
|
2019-05-29 04:18:11 +02:00
|
|
|
{
|
2019-05-29 07:08:46 +02:00
|
|
|
magick::version()
|
2019-05-29 04:18:11 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
log::debug
|
|
|
|
{
|
2019-05-29 13:38:33 +02:00
|
|
|
log, "Initializing Magick Library version inc:%lu [%s] lib:%lu [%s]",
|
2019-05-29 04:18:11 +02:00
|
|
|
ulong(MagickLibVersion),
|
|
|
|
MagickLibVersionText,
|
2019-05-29 07:08:46 +02:00
|
|
|
std::get<0>(version),
|
|
|
|
std::get<1>(version),
|
2019-05-29 04:18:11 +02:00
|
|
|
};
|
|
|
|
|
2019-05-29 07:08:46 +02:00
|
|
|
if(std::get<0>(version) != ulong(MagickLibVersion))
|
2019-05-29 04:18:11 +02:00
|
|
|
log::warning
|
|
|
|
{
|
2019-05-29 13:38:33 +02:00
|
|
|
log, "Magick Library version mismatch headers:%lu library:%lu",
|
2019-05-29 04:18:11 +02:00
|
|
|
ulong(MagickLibVersion),
|
2019-05-29 07:08:46 +02:00
|
|
|
std::get<0>(version),
|
2019-05-29 04:18:11 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
::InitializeMagick(nullptr);
|
2019-05-29 13:40:58 +02:00
|
|
|
::SetLogMethod(handle_log);
|
|
|
|
::SetWarningHandler(handle_warning);
|
|
|
|
::SetErrorHandler(handle_error);
|
|
|
|
::SetFatalErrorHandler(handle_fatal);
|
2019-05-29 13:55:09 +02:00
|
|
|
::SetMonitorHandler(handle_monitor);
|
2019-05-29 13:40:58 +02:00
|
|
|
::SetMagickResourceLimit(ThreadsResource, 1UL);
|
|
|
|
|
|
|
|
log::debug
|
|
|
|
{
|
|
|
|
log, "resource settings: pixel max:%lu:%lu height:%lu:%lu width:%lu:%lu; threads:%lu:%lu",
|
|
|
|
::GetMagickResource(PixelsResource),
|
|
|
|
::GetMagickResourceLimit(PixelsResource),
|
|
|
|
::GetMagickResource(HeightResource),
|
|
|
|
::GetMagickResourceLimit(HeightResource),
|
|
|
|
::GetMagickResource(WidthResource),
|
|
|
|
::GetMagickResourceLimit(WidthResource),
|
|
|
|
::GetMagickResource(ThreadsResource),
|
|
|
|
::GetMagickResourceLimit(ThreadsResource),
|
|
|
|
};
|
2019-05-29 04:18:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ircd::magick::fini()
|
|
|
|
{
|
|
|
|
log::debug
|
|
|
|
{
|
|
|
|
"Shutting down Magick Library..."
|
|
|
|
};
|
|
|
|
|
|
|
|
::DestroyMagick();
|
|
|
|
}
|
2019-05-29 07:08:46 +02:00
|
|
|
|
|
|
|
std::tuple<ulong, ircd::string_view>
|
|
|
|
ircd::magick::version()
|
|
|
|
{
|
|
|
|
ulong number(0);
|
|
|
|
const char *const string
|
|
|
|
{
|
|
|
|
::GetMagickVersion(&number)
|
|
|
|
};
|
|
|
|
|
|
|
|
return { number, string };
|
|
|
|
}
|
|
|
|
|
2019-05-29 08:25:03 +02:00
|
|
|
//
|
|
|
|
// thumbnail
|
|
|
|
//
|
|
|
|
|
|
|
|
ircd::magick::thumbnail::thumbnail(const const_buffer &in,
|
|
|
|
const mutable_buffer &out,
|
|
|
|
const std::pair<size_t, size_t> &xy)
|
|
|
|
:const_buffer{[&in, &out, &xy]
|
|
|
|
{
|
|
|
|
const custom_ptr<::ImageInfo> input_info
|
|
|
|
{
|
|
|
|
::CloneImageInfo(nullptr), ::DestroyImageInfo
|
|
|
|
};
|
|
|
|
|
|
|
|
const custom_ptr<::ImageInfo> output_info
|
|
|
|
{
|
|
|
|
::CloneImageInfo(nullptr), ::DestroyImageInfo
|
|
|
|
};
|
|
|
|
|
|
|
|
const custom_ptr<::Image> input
|
|
|
|
{
|
|
|
|
callex<::Image *>(::BlobToImage, input_info.get(), data(in), size(in)), ::DestroyImage // pollock
|
|
|
|
};
|
|
|
|
|
|
|
|
const custom_ptr<::Image> output
|
|
|
|
{
|
|
|
|
callex<::Image *>(::ThumbnailImage, input.get(), xy.first, xy.second), ::DestroyImage
|
|
|
|
};
|
|
|
|
|
|
|
|
size_t output_size(0);
|
|
|
|
const auto output_data
|
|
|
|
{
|
|
|
|
callex<void *>(::ImageToBlob, output_info.get(), output.get(), &output_size)
|
|
|
|
};
|
|
|
|
|
|
|
|
const const_buffer result
|
|
|
|
{
|
|
|
|
reinterpret_cast<char *>(output_data), output_size
|
|
|
|
};
|
|
|
|
|
|
|
|
return const_buffer
|
|
|
|
{
|
|
|
|
data(out), copy(out, result)
|
|
|
|
};
|
|
|
|
}()}
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-05-29 07:08:46 +02:00
|
|
|
//
|
|
|
|
// util
|
|
|
|
//
|
|
|
|
|
|
|
|
template<class return_t,
|
|
|
|
class function,
|
|
|
|
class... args>
|
|
|
|
return_t
|
|
|
|
ircd::magick::callex(function&& f,
|
|
|
|
args&&... a)
|
|
|
|
{
|
2019-05-29 13:40:58 +02:00
|
|
|
const auto error_handler
|
|
|
|
{
|
|
|
|
::SetErrorHandler(handle_exception)
|
|
|
|
};
|
|
|
|
|
2019-05-29 07:08:46 +02:00
|
|
|
const unwind reset{[&]
|
|
|
|
{
|
|
|
|
::SetErrorHandler(error_handler);
|
|
|
|
}};
|
|
|
|
|
|
|
|
::ExceptionInfo ei;
|
|
|
|
GetExceptionInfo(&ei); // initializer
|
|
|
|
const unwind destroy{[&ei]
|
|
|
|
{
|
|
|
|
::DestroyExceptionInfo(&ei);
|
|
|
|
}};
|
|
|
|
|
|
|
|
const auto ret
|
|
|
|
{
|
|
|
|
f(std::forward<args>(a)..., &ei)
|
|
|
|
};
|
|
|
|
|
|
|
|
// exception comes out of here; if this is not safe we'll have to
|
|
|
|
// convey with a global or inspect ExceptionInfo manually.
|
|
|
|
::CatchException(&ei);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class function,
|
|
|
|
class... args>
|
|
|
|
void
|
|
|
|
ircd::magick::callpf(function&& f,
|
|
|
|
args&&... a)
|
|
|
|
{
|
|
|
|
if(!call(f, std::forward<args>(a)...))
|
|
|
|
throw error{};
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class return_t,
|
|
|
|
class function,
|
|
|
|
class... args>
|
|
|
|
return_t
|
|
|
|
ircd::magick::call(function&& f,
|
|
|
|
args&&... a)
|
|
|
|
{
|
|
|
|
return f(std::forward<args>(a)...);
|
|
|
|
}
|
|
|
|
|
2019-05-29 13:55:09 +02:00
|
|
|
uint
|
|
|
|
ircd::magick::handle_monitor(const char *text,
|
|
|
|
const int64_t quantum,
|
|
|
|
const uint64_t span,
|
|
|
|
ExceptionInfo *ei)
|
|
|
|
noexcept
|
|
|
|
{
|
|
|
|
log::debug
|
|
|
|
{
|
|
|
|
log, "progress [%s] %ld:%ld",
|
|
|
|
text,
|
|
|
|
quantum,
|
|
|
|
span
|
|
|
|
};
|
|
|
|
|
|
|
|
return true; // return false to interrupt
|
|
|
|
}
|
|
|
|
|
2019-05-29 07:08:46 +02:00
|
|
|
void
|
|
|
|
ircd::magick::handle_log(const ::ExceptionType type,
|
|
|
|
const char *const message)
|
|
|
|
noexcept
|
|
|
|
{
|
|
|
|
log::debug
|
|
|
|
{
|
|
|
|
log, "%s :%s",
|
|
|
|
::GetLocaleExceptionMessage(type, nullptr),
|
|
|
|
message
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ircd::magick::handle_warning(const ::ExceptionType type,
|
|
|
|
const char *const reason,
|
|
|
|
const char *const description)
|
|
|
|
noexcept
|
|
|
|
{
|
|
|
|
log::warning
|
|
|
|
{
|
|
|
|
log, "%s %s :%s",
|
|
|
|
::GetLocaleExceptionMessage(type, nullptr),
|
|
|
|
reason,
|
|
|
|
description
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ircd::magick::handle_error(const ::ExceptionType type,
|
|
|
|
const char *const reason,
|
|
|
|
const char *const description)
|
|
|
|
noexcept
|
|
|
|
{
|
|
|
|
log::error
|
|
|
|
{
|
|
|
|
log, "%s %s :%s",
|
|
|
|
::GetLocaleExceptionMessage(type, nullptr),
|
|
|
|
reason,
|
|
|
|
description
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
[[noreturn]] void
|
|
|
|
ircd::magick::handle_fatal(const ::ExceptionType type,
|
|
|
|
const char *const reason,
|
|
|
|
const char *const description)
|
|
|
|
noexcept
|
|
|
|
{
|
|
|
|
log::critical
|
|
|
|
{
|
|
|
|
log, "%s %s :%s",
|
|
|
|
::GetLocaleExceptionMessage(type, nullptr),
|
|
|
|
reason,
|
|
|
|
description
|
|
|
|
};
|
|
|
|
|
|
|
|
ircd::terminate();
|
|
|
|
}
|
|
|
|
|
|
|
|
[[noreturn]] void
|
|
|
|
ircd::magick::handle_exception(const ::ExceptionType type,
|
|
|
|
const char *const reason,
|
|
|
|
const char *const description)
|
|
|
|
{
|
|
|
|
throw error
|
|
|
|
{
|
|
|
|
"%s %s :%s",
|
|
|
|
::GetLocaleExceptionMessage(type, nullptr),
|
|
|
|
reason,
|
|
|
|
description
|
|
|
|
};
|
|
|
|
}
|